Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1733 lines
50 KiB

  1. /*++
  2. Copyright (c) 1989, 1990, 1991 Microsoft Corporation
  3. Module Name:
  4. connect.c
  5. Abstract:
  6. This module contains code which performs the following TDI services:
  7. o TdiAccept
  8. o TdiListen
  9. o TdiConnect
  10. o TdiDisconnect
  11. o TdiAssociateAddress
  12. o TdiDisassociateAddress
  13. o OpenConnection
  14. o CloseConnection
  15. Author:
  16. David Beaver (dbeaver) 1 July 1991
  17. Environment:
  18. Kernel mode
  19. Revision History:
  20. --*/
  21. #include "precomp.h"
  22. #pragma hdrstop
  23. #ifdef notdef // RASAUTODIAL
  24. #include <acd.h>
  25. #include <acdapi.h>
  26. #endif // RASAUTODIAL
  27. #ifdef notdef // RASAUTODIAL
  28. extern BOOLEAN fAcdLoadedG;
  29. extern ACD_DRIVER AcdDriverG;
  30. //
  31. // Imported functions.
  32. //
  33. VOID
  34. NbfRetryPreTdiConnect(
  35. IN BOOLEAN fSuccess,
  36. IN PVOID *pArgs
  37. );
  38. BOOLEAN
  39. NbfAttemptAutoDial(
  40. IN PTP_CONNECTION Connection,
  41. IN ULONG ulFlags,
  42. IN ACD_CONNECT_CALLBACK pProc,
  43. IN PVOID pArg
  44. );
  45. VOID
  46. NbfCancelPreTdiConnect(
  47. IN PDEVICE_OBJECT pDeviceObject,
  48. IN PIRP pIrp
  49. );
  50. #endif // RASAUTODIAL
  51. NTSTATUS
  52. NbfTdiConnectCommon(
  53. IN PIRP Irp
  54. );
  55. NTSTATUS
  56. NbfTdiAccept(
  57. IN PIRP Irp
  58. )
  59. /*++
  60. Routine Description:
  61. This routine performs the TdiAccept request for the transport provider.
  62. Arguments:
  63. Irp - Pointer to the I/O Request Packet for this request.
  64. Return Value:
  65. NTSTATUS - status of operation.
  66. --*/
  67. {
  68. PTP_CONNECTION connection;
  69. PIO_STACK_LOCATION irpSp;
  70. KIRQL oldirql;
  71. NTSTATUS status;
  72. IF_NBFDBG (NBF_DEBUG_CONNECT) {
  73. NbfPrint0 ("NbfTdiAccept: Entered.\n");
  74. }
  75. //
  76. // Get the connection this is associated with; if there is none, get out.
  77. // This adds a connection reference of type BY_ID if successful.
  78. //
  79. irpSp = IoGetCurrentIrpStackLocation (Irp);
  80. if (irpSp->FileObject->FsContext2 != (PVOID) TDI_CONNECTION_FILE) {
  81. return STATUS_INVALID_CONNECTION;
  82. }
  83. connection = irpSp->FileObject->FsContext;
  84. //
  85. // This adds a connection reference of type BY_ID if successful.
  86. //
  87. status = NbfVerifyConnectionObject (connection);
  88. if (!NT_SUCCESS (status)) {
  89. return status;
  90. }
  91. KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
  92. //
  93. // just set the connection flags to allow reads and writes to proceed.
  94. //
  95. ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  96. //
  97. // Turn off the stopping flag for this connection.
  98. //
  99. connection->Flags2 &= ~CONNECTION_FLAGS2_STOPPING;
  100. connection->Status = STATUS_PENDING;
  101. connection->Flags2 |= CONNECTION_FLAGS2_ACCEPTED;
  102. if (connection->AddressFile->ConnectIndicationInProgress) {
  103. connection->Flags2 |= CONNECTION_FLAGS2_INDICATING;
  104. }
  105. if ((connection->Flags2 & CONNECTION_FLAGS2_WAITING_SC) != 0) {
  106. //
  107. // We previously completed a listen, now the user is
  108. // coming back with an accept, Set this flag to allow
  109. // the connection to proceed.
  110. //
  111. // If the connection has gone down in the
  112. // meantime, we have just reenabled it.
  113. //
  114. ACQUIRE_DPC_SPIN_LOCK (connection->LinkSpinLock);
  115. connection->Flags |= CONNECTION_FLAGS_READY;
  116. RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
  117. INCREMENT_COUNTER (connection->Provider, OpenConnections);
  118. //
  119. // Set this flag to enable disconnect indications; once
  120. // the client has accepted he expects those.
  121. //
  122. connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
  123. RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  124. NbfSendSessionConfirm (connection);
  125. } else {
  126. //
  127. // This accept is being called at some point before
  128. // the link is up; directly from the connection handler
  129. // or at some point slightly later. We don't set
  130. // FLAGS2_REQ_COMPLETED now because the reference
  131. // count is not high enough; we set it when we get
  132. // the session initialize.
  133. //
  134. // If the connection goes down in the meantime,
  135. // we won't indicate the disconnect.
  136. //
  137. RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  138. }
  139. NbfDereferenceConnection ("Temp TdiAccept", connection, CREF_BY_ID);
  140. KeLowerIrql (oldirql);
  141. return STATUS_SUCCESS;
  142. } /* NbfTdiAccept */
  143. NTSTATUS
  144. NbfTdiAssociateAddress(
  145. IN PIRP Irp
  146. )
  147. /*++
  148. Routine Description:
  149. This routine performs the association of the connection and the address for
  150. the user.
  151. Arguments:
  152. Irp - Pointer to the I/O Request Packet for this request.
  153. Return Value:
  154. NTSTATUS - status of operation.
  155. --*/
  156. {
  157. NTSTATUS status;
  158. PFILE_OBJECT fileObject;
  159. PTP_ADDRESS_FILE addressFile;
  160. PTP_ADDRESS oldAddress;
  161. PTP_CONNECTION connection;
  162. PIO_STACK_LOCATION irpSp;
  163. PTDI_REQUEST_KERNEL_ASSOCIATE parameters;
  164. PDEVICE_CONTEXT deviceContext;
  165. KIRQL oldirql, oldirql2;
  166. IF_NBFDBG (NBF_DEBUG_CONNECT) {
  167. NbfPrint0 ("TdiAssociateAddress: Entered.\n");
  168. }
  169. irpSp = IoGetCurrentIrpStackLocation (Irp);
  170. //
  171. // verify that the operation is taking place on a connection. At the same
  172. // time we do this, we reference the connection. This ensures it does not
  173. // get removed out from under us. Note also that we do the connection
  174. // lookup within a try/except clause, thus protecting ourselves against
  175. // really bogus handles
  176. //
  177. if (irpSp->FileObject->FsContext2 != (PVOID) TDI_CONNECTION_FILE) {
  178. return STATUS_INVALID_CONNECTION;
  179. }
  180. connection = irpSp->FileObject->FsContext;
  181. status = NbfVerifyConnectionObject (connection);
  182. if (!NT_SUCCESS (status)) {
  183. return status;
  184. }
  185. //
  186. // Make sure this connection is ready to be associated.
  187. //
  188. oldAddress = (PTP_ADDRESS)NULL;
  189. try {
  190. ACQUIRE_C_SPIN_LOCK (&connection->SpinLock, &oldirql2);
  191. if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) &&
  192. ((connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) == 0)) {
  193. //
  194. // The connection is already associated with
  195. // an active connection...bad!
  196. //
  197. RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql2);
  198. NbfDereferenceConnection ("Temp Ref Associate", connection, CREF_BY_ID);
  199. return STATUS_INVALID_CONNECTION;
  200. } else {
  201. //
  202. // See if there is an old association hanging around...
  203. // this happens if the connection has been disassociated,
  204. // but not closed.
  205. //
  206. if (connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) {
  207. IF_NBFDBG (NBF_DEBUG_CONNECT) {
  208. NbfPrint0 ("NbfTdiAssociateAddress: removing association.\n");
  209. }
  210. //
  211. // Save this; since it is non-null this address
  212. // will be dereferenced after the connection
  213. // spinlock is released.
  214. //
  215. oldAddress = connection->AddressFile->Address;
  216. //
  217. // Remove the old association.
  218. //
  219. connection->Flags2 &= ~CONNECTION_FLAGS2_ASSOCIATED;
  220. RemoveEntryList (&connection->AddressList);
  221. RemoveEntryList (&connection->AddressFileList);
  222. InitializeListHead (&connection->AddressList);
  223. InitializeListHead (&connection->AddressFileList);
  224. connection->AddressFile = NULL;
  225. }
  226. }
  227. RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql2);
  228. } except(EXCEPTION_EXECUTE_HANDLER) {
  229. DbgPrint ("NBF: Got exception 1 in NbfTdiAssociateAddress\n");
  230. DbgBreakPoint();
  231. RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql2);
  232. NbfDereferenceConnection ("Temp Ref Associate", connection, CREF_BY_ID);
  233. return GetExceptionCode();
  234. }
  235. //
  236. // If we removed an old association, dereference the
  237. // address.
  238. //
  239. if (oldAddress != (PTP_ADDRESS)NULL) {
  240. NbfDereferenceAddress("Removed old association", oldAddress, AREF_CONNECTION);
  241. }
  242. deviceContext = connection->Provider;
  243. parameters = (PTDI_REQUEST_KERNEL_ASSOCIATE)&irpSp->Parameters;
  244. //
  245. // get a pointer to the address File Object, which points us to the
  246. // transport's address object, which is where we want to put the
  247. // connection.
  248. //
  249. status = ObReferenceObjectByHandle (
  250. parameters->AddressHandle,
  251. 0L,
  252. *IoFileObjectType,
  253. Irp->RequestorMode,
  254. (PVOID *) &fileObject,
  255. NULL);
  256. if (NT_SUCCESS(status)) {
  257. if (fileObject->DeviceObject == &deviceContext->DeviceObject) {
  258. //
  259. // we might have one of our address objects; verify that.
  260. //
  261. addressFile = fileObject->FsContext;
  262. IF_NBFDBG (NBF_DEBUG_CONNECT) {
  263. NbfPrint3 ("NbfTdiAssociateAddress: Connection %lx Irp %lx AddressFile %lx \n",
  264. connection, Irp, addressFile);
  265. }
  266. if ((fileObject->FsContext2 == (PVOID) TDI_TRANSPORT_ADDRESS_FILE) &&
  267. (NT_SUCCESS (NbfVerifyAddressObject (addressFile)))) {
  268. //
  269. // have an address and connection object. Add the connection to the
  270. // address object database. Also add the connection to the address
  271. // file object db (used primarily for cleaning up). Reference the
  272. // address to account for one more reason for it staying open.
  273. //
  274. ACQUIRE_SPIN_LOCK (&addressFile->Address->SpinLock, &oldirql);
  275. if ((addressFile->Address->Flags & ADDRESS_FLAGS_STOPPING) == 0) {
  276. IF_NBFDBG (NBF_DEBUG_CONNECT) {
  277. NbfPrint2 ("NbfTdiAssociateAddress: Valid Address %lx %lx\n",
  278. addressFile->Address, addressFile);
  279. }
  280. try {
  281. ACQUIRE_C_SPIN_LOCK (&connection->SpinLock, &oldirql2);
  282. if ((connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0) {
  283. NbfReferenceAddress (
  284. "Connection associated",
  285. addressFile->Address,
  286. AREF_CONNECTION);
  287. #if DBG
  288. if (!(IsListEmpty(&connection->AddressList))) {
  289. DbgPrint ("NBF: C %lx, new A %lx, in use\n",
  290. connection, addressFile->Address);
  291. DbgBreakPoint();
  292. }
  293. #endif
  294. InsertTailList (
  295. &addressFile->Address->ConnectionDatabase,
  296. &connection->AddressList);
  297. #if DBG
  298. if (!(IsListEmpty(&connection->AddressFileList))) {
  299. DbgPrint ("NBF: C %lx, new AF %lx, in use\n",
  300. connection, addressFile);
  301. DbgBreakPoint();
  302. }
  303. #endif
  304. InsertTailList (
  305. &addressFile->ConnectionDatabase,
  306. &connection->AddressFileList);
  307. connection->AddressFile = addressFile;
  308. connection->Flags2 |= CONNECTION_FLAGS2_ASSOCIATED;
  309. connection->Flags2 &= ~CONNECTION_FLAGS2_DISASSOCIATED;
  310. if (addressFile->ConnectIndicationInProgress) {
  311. connection->Flags2 |= CONNECTION_FLAGS2_INDICATING;
  312. }
  313. status = STATUS_SUCCESS;
  314. } else {
  315. //
  316. // The connection is closing, stop the
  317. // association.
  318. //
  319. status = STATUS_INVALID_CONNECTION;
  320. }
  321. RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql2);
  322. } except(EXCEPTION_EXECUTE_HANDLER) {
  323. DbgPrint ("NBF: Got exception 2 in NbfTdiAssociateAddress\n");
  324. DbgBreakPoint();
  325. RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql2);
  326. status = GetExceptionCode();
  327. }
  328. } else {
  329. status = STATUS_INVALID_HANDLE; //should this be more informative?
  330. }
  331. RELEASE_SPIN_LOCK (&addressFile->Address->SpinLock, oldirql);
  332. NbfDereferenceAddress ("Temp associate", addressFile->Address, AREF_VERIFY);
  333. } else {
  334. status = STATUS_INVALID_HANDLE;
  335. }
  336. } else {
  337. status = STATUS_INVALID_HANDLE;
  338. }
  339. //
  340. // Note that we don't keep a reference to this file object around.
  341. // That's because the IO subsystem manages the object for us; we simply
  342. // want to keep the association. We only use this association when the
  343. // IO subsystem has asked us to close one of the file object, and then
  344. // we simply remove the association.
  345. //
  346. ObDereferenceObject (fileObject);
  347. } else {
  348. status = STATUS_INVALID_HANDLE;
  349. }
  350. NbfDereferenceConnection ("Temp Ref Associate", connection, CREF_BY_ID);
  351. return status;
  352. } /* TdiAssociateAddress */
  353. NTSTATUS
  354. NbfTdiDisassociateAddress(
  355. IN PIRP Irp
  356. )
  357. /*++
  358. Routine Description:
  359. This routine performs the disassociation of the connection and the address
  360. for the user. If the connection has not been stopped, it will be stopped
  361. here.
  362. Arguments:
  363. Irp - Pointer to the I/O Request Packet for this request.
  364. Return Value:
  365. NTSTATUS - status of operation.
  366. --*/
  367. {
  368. KIRQL oldirql;
  369. PIO_STACK_LOCATION irpSp;
  370. PTP_CONNECTION connection;
  371. NTSTATUS status;
  372. // PDEVICE_CONTEXT DeviceContext;
  373. IF_NBFDBG (NBF_DEBUG_CONNECT) {
  374. NbfPrint0 ("TdiDisassociateAddress: Entered.\n");
  375. }
  376. irpSp = IoGetCurrentIrpStackLocation (Irp);
  377. if (irpSp->FileObject->FsContext2 != (PVOID) TDI_CONNECTION_FILE) {
  378. return STATUS_INVALID_CONNECTION;
  379. }
  380. connection = irpSp->FileObject->FsContext;
  381. //
  382. // If successful this adds a reference of type BY_ID.
  383. //
  384. status = NbfVerifyConnectionObject (connection);
  385. if (!NT_SUCCESS (status)) {
  386. return status;
  387. }
  388. KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
  389. ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  390. if ((connection->Flags2 & CONNECTION_FLAGS2_STOPPING) == 0) {
  391. RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  392. NbfStopConnection (connection, STATUS_LOCAL_DISCONNECT);
  393. } else {
  394. RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  395. }
  396. //
  397. // and now we disassociate the address. This only removes
  398. // the appropriate reference for the connection, the
  399. // actually disassociation will be done later.
  400. //
  401. // The DISASSOCIATED flag is used to make sure that
  402. // only one person removes this reference.
  403. //
  404. ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  405. if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) &&
  406. ((connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) == 0)) {
  407. connection->Flags2 |= CONNECTION_FLAGS2_DISASSOCIATED;
  408. RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  409. } else {
  410. RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  411. }
  412. KeLowerIrql (oldirql);
  413. NbfDereferenceConnection ("Temp use in Associate", connection, CREF_BY_ID);
  414. return STATUS_SUCCESS;
  415. } /* TdiDisassociateAddress */
  416. NTSTATUS
  417. NbfTdiConnect(
  418. IN PIRP Irp
  419. )
  420. /*++
  421. Routine Description:
  422. This routine performs the TdiConnect request for the transport provider.
  423. Arguments:
  424. Irp - Pointer to the I/O Request Packet for this request.
  425. Return Value:
  426. NTSTATUS - status of operation.
  427. --*/
  428. {
  429. NTSTATUS status;
  430. PTP_CONNECTION connection;
  431. KIRQL oldirql;
  432. PIO_STACK_LOCATION irpSp;
  433. PTDI_REQUEST_KERNEL parameters;
  434. TDI_ADDRESS_NETBIOS * RemoteAddress;
  435. IF_NBFDBG (NBF_DEBUG_CONNECT) {
  436. NbfPrint0 ("NbfTdiConnect: Entered.\n");
  437. }
  438. //
  439. // is the file object a connection?
  440. //
  441. irpSp = IoGetCurrentIrpStackLocation (Irp);
  442. if (irpSp->FileObject->FsContext2 != (PVOID) TDI_CONNECTION_FILE) {
  443. return STATUS_INVALID_CONNECTION;
  444. }
  445. connection = irpSp->FileObject->FsContext;
  446. //
  447. // If successful this adds a reference of type BY_ID.
  448. //
  449. status = NbfVerifyConnectionObject (connection);
  450. if (!NT_SUCCESS (status)) {
  451. return status;
  452. }
  453. parameters = (PTDI_REQUEST_KERNEL)(&irpSp->Parameters);
  454. //
  455. // Check that the remote is a Netbios address.
  456. //
  457. if (!NbfValidateTdiAddress(
  458. parameters->RequestConnectionInformation->RemoteAddress,
  459. parameters->RequestConnectionInformation->RemoteAddressLength)) {
  460. NbfDereferenceConnection ("Invalid Address", connection, CREF_BY_ID);
  461. return STATUS_BAD_NETWORK_PATH;
  462. }
  463. RemoteAddress = NbfParseTdiAddress((PTRANSPORT_ADDRESS)(parameters->RequestConnectionInformation->RemoteAddress), FALSE);
  464. if (RemoteAddress == NULL) {
  465. NbfDereferenceConnection ("Not Netbios", connection, CREF_BY_ID);
  466. return STATUS_BAD_NETWORK_PATH;
  467. }
  468. //
  469. // copy the called address someplace we can use it.
  470. //
  471. connection->CalledAddress.NetbiosNameType =
  472. RemoteAddress->NetbiosNameType;
  473. RtlCopyMemory(
  474. connection->CalledAddress.NetbiosName,
  475. RemoteAddress->NetbiosName,
  476. 16);
  477. #ifdef notdef // RASAUTODIAL
  478. if (fAcdLoadedG) {
  479. KIRQL adirql;
  480. BOOLEAN fEnabled;
  481. //
  482. // See if the automatic connection driver knows
  483. // about this address before we search the
  484. // network. If it does, we return STATUS_PENDING,
  485. // and we will come back here via NbfRetryTdiConnect().
  486. //
  487. ACQUIRE_SPIN_LOCK(&AcdDriverG.SpinLock, &adirql);
  488. fEnabled = AcdDriverG.fEnabled;
  489. RELEASE_SPIN_LOCK(&AcdDriverG.SpinLock, adirql);
  490. if (fEnabled && NbfAttemptAutoDial(
  491. connection,
  492. ACD_NOTIFICATION_PRECONNECT,
  493. NbfRetryPreTdiConnect,
  494. Irp))
  495. {
  496. ACQUIRE_SPIN_LOCK(&connection->SpinLock, &oldirql);
  497. connection->Flags2 |= CONNECTION_FLAGS2_AUTOCONNECT;
  498. connection->Status = STATUS_PENDING;
  499. RELEASE_SPIN_LOCK(&connection->SpinLock, oldirql);
  500. NbfDereferenceConnection ("Automatic connection", connection, CREF_BY_ID);
  501. //
  502. // Set a special cancel routine on the irp
  503. // in case we get cancelled during the
  504. // automatic connection.
  505. //
  506. IoSetCancelRoutine(Irp, NbfCancelPreTdiConnect);
  507. return STATUS_PENDING;
  508. }
  509. }
  510. #endif // RASAUTODIAL
  511. return NbfTdiConnectCommon(Irp);
  512. } // NbfTdiConnect
  513. NTSTATUS
  514. NbfTdiConnectCommon(
  515. IN PIRP Irp
  516. )
  517. /*++
  518. Routine Description:
  519. This routine performs the TdiConnect request for the transport provider.
  520. Note: the caller needs to call NbfVerifyConnectionObject(pConnection)
  521. before calling this routine.
  522. Arguments:
  523. Irp - Pointer to the I/O Request Packet for this request.
  524. Return Value:
  525. NTSTATUS - status of operation.
  526. --*/
  527. {
  528. NTSTATUS status;
  529. PTP_CONNECTION connection;
  530. LARGE_INTEGER timeout = {0,0};
  531. KIRQL oldirql, cancelirql;
  532. PTP_REQUEST tpRequest;
  533. PIO_STACK_LOCATION irpSp;
  534. PTDI_REQUEST_KERNEL parameters;
  535. TDI_ADDRESS_NETBIOS * RemoteAddress;
  536. ULONG NameQueryTimeout;
  537. IF_NBFDBG (NBF_DEBUG_CONNECT) {
  538. NbfPrint0 ("NbfTdiConnectCommon: Entered.\n");
  539. }
  540. //
  541. // is the file object a connection?
  542. //
  543. irpSp = IoGetCurrentIrpStackLocation (Irp);
  544. connection = irpSp->FileObject->FsContext;
  545. parameters = (PTDI_REQUEST_KERNEL)(&irpSp->Parameters);
  546. //
  547. // fix up the timeout if required; no connect request should take more
  548. // than 15 seconds if there is someone out there. We'll assume that's
  549. // what the user wanted if they specify -1 as the timer length.
  550. //
  551. if (parameters->RequestSpecific != NULL) {
  552. if ((((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart == -1) &&
  553. (((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart == -1)) {
  554. IF_NBFDBG (NBF_DEBUG_RESOURCE) {
  555. NbfPrint1 ("TdiConnect: Modifying user timeout to %lx seconds.\n",
  556. TDI_TIMEOUT_CONNECT);
  557. }
  558. timeout.LowPart = (ULONG)(-TDI_TIMEOUT_CONNECT * 10000000L); // n * 10 ** 7 => 100ns units
  559. if (timeout.LowPart != 0) {
  560. timeout.HighPart = -1L;
  561. } else {
  562. timeout.HighPart = 0;
  563. }
  564. } else {
  565. timeout.LowPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart;
  566. timeout.HighPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart;
  567. }
  568. }
  569. //
  570. // We need a request object to keep track of this TDI request.
  571. // Attach this request to the new connection object.
  572. //
  573. status = NbfCreateRequest (
  574. Irp, // IRP for this request.
  575. connection, // context.
  576. REQUEST_FLAGS_CONNECTION, // partial flags.
  577. NULL,
  578. 0,
  579. timeout,
  580. &tpRequest);
  581. if (!NT_SUCCESS (status)) { // couldn't make the request.
  582. NbfDereferenceConnection ("Throw away", connection, CREF_BY_ID);
  583. return status; // return with failure.
  584. } else {
  585. // Reference the connection since NbfDestroyRequest derefs it.
  586. NbfReferenceConnection("For connect request", connection, CREF_REQUEST);
  587. KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
  588. tpRequest->Owner = ConnectionType;
  589. IoAcquireCancelSpinLock (&cancelirql);
  590. ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  591. if ((connection->Flags2 & CONNECTION_FLAGS2_STOPPING) != 0) {
  592. RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  593. IoReleaseCancelSpinLock (cancelirql);
  594. NbfCompleteRequest (
  595. tpRequest,
  596. connection->Status,
  597. 0);
  598. KeLowerIrql (oldirql);
  599. NbfDereferenceConnection("Temporary Use 1", connection, CREF_BY_ID);
  600. return STATUS_PENDING;
  601. } else {
  602. InsertTailList (&connection->InProgressRequest,&tpRequest->Linkage);
  603. //
  604. // Initialize this now, we cut these down on an async medium
  605. // that is disconnected.
  606. //
  607. connection->Retries = (USHORT)connection->Provider->NameQueryRetries;
  608. NameQueryTimeout = connection->Provider->NameQueryTimeout;
  609. if (connection->Provider->MacInfo.MediumAsync) {
  610. //
  611. // If we are on an async medium, then we need to send out
  612. // a committed NAME_QUERY frame right from the start, since
  613. // the FIND_NAME frames are not forwarded by the gateway.
  614. //
  615. connection->Flags2 |= (CONNECTION_FLAGS2_CONNECTOR | // we're the initiator.
  616. CONNECTION_FLAGS2_WAIT_NR); // wait for NAME_RECOGNIZED.
  617. //
  618. // Because we may call NbfTdiConnect twice
  619. // via an automatic connection, check to see
  620. // if an LSN has already been assigned.
  621. //
  622. if (!(connection->Flags2 & CONNECTION_FLAGS2_GROUP_LSN)) {
  623. connection->Flags2 |= CONNECTION_FLAGS2_GROUP_LSN;
  624. if (NbfAssignGroupLsn(connection) != STATUS_SUCCESS) {
  625. //
  626. // Could not find an empty LSN; have to fail.
  627. //
  628. RemoveEntryList(&tpRequest->Linkage);
  629. RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  630. IoReleaseCancelSpinLock (cancelirql);
  631. NbfCompleteRequest (
  632. tpRequest,
  633. connection->Status,
  634. 0);
  635. KeLowerIrql (oldirql);
  636. NbfDereferenceConnection("Temporary Use 1", connection, CREF_BY_ID);
  637. return STATUS_PENDING;
  638. }
  639. }
  640. if (!connection->Provider->MediumSpeedAccurate) {
  641. //
  642. // The link is not up, so we cut our timeouts down.
  643. // We still send one frame so that loopback works.
  644. //
  645. connection->Retries = 1;
  646. NameQueryTimeout = NAME_QUERY_TIMEOUT / 10;
  647. }
  648. } else {
  649. //
  650. // Normal connection, we send out a FIND_NAME first.
  651. //
  652. connection->Flags2 |= (CONNECTION_FLAGS2_CONNECTOR | // we're the initiator.
  653. CONNECTION_FLAGS2_WAIT_NR_FN); // wait for NAME_RECOGNIZED.
  654. }
  655. connection->Flags2 &= ~(CONNECTION_FLAGS2_STOPPING |
  656. CONNECTION_FLAGS2_INDICATING);
  657. connection->Status = STATUS_PENDING;
  658. RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  659. //
  660. // Check if the IRP has been cancelled.
  661. //
  662. if (Irp->Cancel) {
  663. Irp->CancelIrql = cancelirql;
  664. NbfCancelConnection((PDEVICE_OBJECT)(connection->Provider), Irp);
  665. KeLowerIrql (oldirql);
  666. NbfDereferenceConnection ("IRP cancelled", connection, CREF_BY_ID); // release lookup hold.
  667. return STATUS_PENDING;
  668. }
  669. IoSetCancelRoutine(Irp, NbfCancelConnection);
  670. IoReleaseCancelSpinLock(cancelirql);
  671. }
  672. }
  673. //
  674. // On "easily disconnected" networks, quick reregister
  675. // (one ADD_NAME_QUERY) the address if NEED_REREGISTER
  676. // is set (happens when we get a five-second period
  677. // with no multicast activity). If we are currently
  678. // quick reregistering, wait for it to complete.
  679. //
  680. if (connection->Provider->EasilyDisconnected) {
  681. PTP_ADDRESS Address;
  682. LARGE_INTEGER Timeout;
  683. //
  684. // If the address needs (or is) reregistering, then do wait,
  685. // setting a flag so the connect will be resumed when the
  686. // reregistration times out.
  687. //
  688. Address = connection->AddressFile->Address;
  689. ACQUIRE_DPC_SPIN_LOCK (&Address->SpinLock);
  690. if ((Address->Flags &
  691. (ADDRESS_FLAGS_NEED_REREGISTER | ADDRESS_FLAGS_QUICK_REREGISTER)) != 0) {
  692. connection->Flags2 |= CONNECTION_FLAGS2_W_ADDRESS;
  693. if (Address->Flags & ADDRESS_FLAGS_NEED_REREGISTER) {
  694. Address->Flags &= ~ADDRESS_FLAGS_NEED_REREGISTER;
  695. Address->Flags |= ADDRESS_FLAGS_QUICK_REREGISTER;
  696. NbfReferenceAddress ("start registration", Address, AREF_TIMER);
  697. RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
  698. //
  699. // Now start reregistration process by starting up a retransmission timer
  700. // and begin sending ADD_NAME_QUERY NetBIOS frames.
  701. //
  702. Address->Retries = 1;
  703. Timeout.LowPart = (ULONG)(-(LONG)Address->Provider->AddNameQueryTimeout);
  704. Timeout.HighPart = -1;
  705. KeSetTimer (&Address->Timer, *(PTIME)&Timeout, &Address->Dpc);
  706. (VOID)NbfSendAddNameQuery (Address); // send first ADD_NAME_QUERY.
  707. } else {
  708. RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
  709. }
  710. KeLowerIrql (oldirql);
  711. NbfDereferenceConnection("Temporary Use 4", connection, CREF_BY_ID);
  712. return STATUS_PENDING; // things are started.
  713. } else {
  714. RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
  715. }
  716. }
  717. //
  718. // Send the NAME_QUERY frame as a FIND.NAME to get a NAME_RECOGNIZED
  719. // frame back. The first time we send this frame, we are just looking
  720. // for the data link information to decide whether we already have
  721. // a link with the remote NetBIOS name. If we do, we can reuse it.
  722. // If we don't, then we make one first, and then use it. A consequence
  723. // of this is that we really engage in an extra non-committal NQ/NR
  724. // exchange up front to locate the remote guy, and then commit to an actual
  725. // LSN with a second NQ/NR sequence to establish the transport connection
  726. //
  727. NbfSendNameQuery (
  728. connection,
  729. TRUE);
  730. //
  731. // Start the connection timer (do this at the end, so that
  732. // if we get delayed in this routine the connection won't
  733. // get into an unexpected state).
  734. //
  735. NbfStartConnectionTimer (
  736. connection,
  737. ConnectionEstablishmentTimeout,
  738. NameQueryTimeout);
  739. KeLowerIrql (oldirql);
  740. NbfDereferenceConnection("Temporary Use 3", connection, CREF_BY_ID);
  741. return STATUS_PENDING; // things are started.
  742. } /* TdiConnect */
  743. NTSTATUS
  744. NbfTdiDisconnect(
  745. IN PIRP Irp
  746. )
  747. /*++
  748. Routine Description:
  749. This routine performs the TdiDisconnect request for the transport provider.
  750. Arguments:
  751. Irp - Pointer to the I/O Request Packet for this request.
  752. Return Value:
  753. NTSTATUS - status of operation.
  754. --*/
  755. {
  756. PTP_CONNECTION connection;
  757. LARGE_INTEGER timeout;
  758. PIO_STACK_LOCATION irpSp;
  759. PTDI_REQUEST_KERNEL parameters;
  760. KIRQL oldirql;
  761. NTSTATUS status;
  762. IF_NBFDBG (NBF_DEBUG_CONNECT) {
  763. NbfPrint0 ("TdiDisconnect: Entered.\n");
  764. }
  765. irpSp = IoGetCurrentIrpStackLocation (Irp);
  766. if (irpSp->FileObject->FsContext2 != (PVOID) TDI_CONNECTION_FILE) {
  767. return STATUS_INVALID_CONNECTION;
  768. }
  769. connection = irpSp->FileObject->FsContext;
  770. //
  771. // If successful this adds a reference of type BY_ID.
  772. //
  773. status = NbfVerifyConnectionObject (connection);
  774. if (!NT_SUCCESS (status)) {
  775. return status;
  776. }
  777. KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
  778. ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  779. #if DBG
  780. if (NbfDisconnectDebug) {
  781. STRING remoteName;
  782. STRING localName;
  783. remoteName.Length = NETBIOS_NAME_LENGTH - 1;
  784. remoteName.Buffer = connection->RemoteName;
  785. localName.Length = NETBIOS_NAME_LENGTH - 1;
  786. localName.Buffer = connection->AddressFile->Address->NetworkName->NetbiosName;
  787. NbfPrint2( "TdiDisconnect entered for connection to %S from %S\n",
  788. &remoteName, &localName );
  789. }
  790. #endif
  791. //
  792. // if the connection is currently stopping, there's no reason to blow
  793. // it away...
  794. //
  795. if ((connection->Flags2 & CONNECTION_FLAGS2_STOPPING) != 0) {
  796. #if 0
  797. NbfPrint2 ("TdiDisconnect: ignoring disconnect %lx, connection stopping (%lx)\n",
  798. connection, connection->Status);
  799. #endif
  800. //
  801. // In case a connect indication is in progress.
  802. //
  803. connection->Flags2 |= CONNECTION_FLAGS2_DISCONNECT;
  804. //
  805. // If possible, queue the disconnect. This flag is cleared
  806. // when the indication is about to be done.
  807. //
  808. if ((connection->Flags2 & CONNECTION_FLAGS2_REQ_COMPLETED) &&
  809. (connection->Flags2 & CONNECTION_FLAGS2_LDISC) == 0) {
  810. #if DBG
  811. DbgPrint ("NBF: Queueing disconnect irp %lx\n", Irp);
  812. #endif
  813. connection->Flags2 |= CONNECTION_FLAGS2_LDISC;
  814. status = STATUS_SUCCESS;
  815. } else {
  816. status = connection->Status;
  817. }
  818. RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  819. KeLowerIrql (oldirql);
  820. NbfDereferenceConnection ("Ignoring disconnect", connection, CREF_BY_ID); // release our lookup reference.
  821. return status;
  822. }
  823. connection->Flags2 &= ~ (CONNECTION_FLAGS2_ACCEPTED |
  824. CONNECTION_FLAGS2_PRE_ACCEPT |
  825. CONNECTION_FLAGS2_WAITING_SC);
  826. connection->Flags2 |= CONNECTION_FLAGS2_DISCONNECT;
  827. connection->Flags2 |= CONNECTION_FLAGS2_LDISC;
  828. //
  829. // Set this flag so the disconnect IRP is completed.
  830. //
  831. // If the connection goes down before we can
  832. // call NbfStopConnection with STATUS_LOCAL_DISCONNECT,
  833. // the disconnect IRP won't get completed.
  834. //
  835. connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
  836. // connection->DisconnectIrp = Irp;
  837. //
  838. // fix up the timeout if required; no disconnect request should take very
  839. // long. However, the user can cause the timeout to not happen if they
  840. // desire that.
  841. //
  842. parameters = (PTDI_REQUEST_KERNEL)(&irpSp->Parameters);
  843. //
  844. // fix up the timeout if required; no disconnect request should take more
  845. // than 15 seconds. We'll assume that's what the user wanted if they
  846. // specify -1 as the timer.
  847. //
  848. if (parameters->RequestSpecific != NULL) {
  849. if ((((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart == -1) &&
  850. (((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart == -1)) {
  851. IF_NBFDBG (NBF_DEBUG_RESOURCE) {
  852. NbfPrint1 ("TdiDisconnect: Modifying user timeout to %lx seconds.\n",
  853. TDI_TIMEOUT_CONNECT);
  854. }
  855. timeout.LowPart = (ULONG)(-TDI_TIMEOUT_DISCONNECT * 10000000L); // n * 10 ** 7 => 100ns units
  856. if (timeout.LowPart != 0) {
  857. timeout.HighPart = -1L;
  858. } else {
  859. timeout.HighPart = 0;
  860. }
  861. } else {
  862. timeout.LowPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart;
  863. timeout.HighPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart;
  864. }
  865. }
  866. //
  867. // Now the reason for the disconnect
  868. //
  869. if ((ULONG)(parameters->RequestFlags) & (ULONG)TDI_DISCONNECT_RELEASE) {
  870. connection->Flags2 |= CONNECTION_FLAGS2_DESTROY;
  871. } else if ((ULONG)(parameters->RequestFlags) & (ULONG)TDI_DISCONNECT_ABORT) {
  872. connection->Flags2 |= CONNECTION_FLAGS2_ABORT;
  873. } else if ((ULONG)(parameters->RequestFlags) & (ULONG)TDI_DISCONNECT_WAIT) {
  874. connection->Flags2 |= CONNECTION_FLAGS2_ORDREL;
  875. }
  876. RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  877. IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
  878. NbfPrint1 ("TdiDisconnect calling NbfStopConnection %lx\n", connection);
  879. }
  880. //
  881. // This will get passed to IoCompleteRequest during TdiDestroyConnection
  882. //
  883. NbfStopConnection (connection, STATUS_LOCAL_DISCONNECT); // starts the abort sequence.
  884. KeLowerIrql (oldirql);
  885. NbfDereferenceConnection ("Disconnecting", connection, CREF_BY_ID); // release our lookup reference.
  886. //
  887. // This request will be completed by TdiDestroyConnection once
  888. // the connection reference count drops to 0.
  889. //
  890. return STATUS_SUCCESS;
  891. } /* TdiDisconnect */
  892. NTSTATUS
  893. NbfTdiListen(
  894. IN PIRP Irp
  895. )
  896. /*++
  897. Routine Description:
  898. This routine performs the TdiListen request for the transport provider.
  899. Arguments:
  900. Irp - Pointer to the I/O Request Packet for this request.
  901. Return Value:
  902. NTSTATUS - status of operation.
  903. --*/
  904. {
  905. NTSTATUS status;
  906. PTP_CONNECTION connection;
  907. LARGE_INTEGER timeout = {0,0};
  908. KIRQL oldirql, cancelirql;
  909. PTP_REQUEST tpRequest;
  910. PIO_STACK_LOCATION irpSp;
  911. PTDI_REQUEST_KERNEL_LISTEN parameters;
  912. PTDI_CONNECTION_INFORMATION ListenInformation;
  913. TDI_ADDRESS_NETBIOS * ListenAddress;
  914. PVOID RequestBuffer2;
  915. ULONG RequestBuffer2Length;
  916. IF_NBFDBG (NBF_DEBUG_CONNECT) {
  917. NbfPrint0 ("TdiListen: Entered.\n");
  918. }
  919. //
  920. // validate this connection
  921. irpSp = IoGetCurrentIrpStackLocation (Irp);
  922. if (irpSp->FileObject->FsContext2 != (PVOID) TDI_CONNECTION_FILE) {
  923. return STATUS_INVALID_CONNECTION;
  924. }
  925. connection = irpSp->FileObject->FsContext;
  926. //
  927. // If successful this adds a reference of type BY_ID.
  928. //
  929. status = NbfVerifyConnectionObject (connection);
  930. if (!NT_SUCCESS (status)) {
  931. return status;
  932. }
  933. parameters = (PTDI_REQUEST_KERNEL_LISTEN)&irpSp->Parameters;
  934. //
  935. // Record the remote address if there is one.
  936. //
  937. ListenInformation = parameters->RequestConnectionInformation;
  938. if ((ListenInformation != NULL) &&
  939. (ListenInformation->RemoteAddress != NULL)) {
  940. if ((NbfValidateTdiAddress(
  941. ListenInformation->RemoteAddress,
  942. ListenInformation->RemoteAddressLength)) &&
  943. ((ListenAddress = NbfParseTdiAddress(ListenInformation->RemoteAddress, FALSE)) != NULL)) {
  944. RequestBuffer2 = (PVOID)ListenAddress->NetbiosName,
  945. RequestBuffer2Length = NETBIOS_NAME_LENGTH;
  946. } else {
  947. IF_NBFDBG (NBF_DEBUG_CONNECT) {
  948. NbfPrint0 ("TdiListen: Create Request Failed, bad address.\n");
  949. }
  950. NbfDereferenceConnection ("Bad address", connection, CREF_BY_ID);
  951. return STATUS_BAD_NETWORK_PATH;
  952. }
  953. } else {
  954. RequestBuffer2 = NULL;
  955. RequestBuffer2Length = 0;
  956. }
  957. //
  958. // We need a request object to keep track of this TDI request.
  959. // Attach this request to the new connection object.
  960. //
  961. status = NbfCreateRequest (
  962. Irp, // IRP for this request.
  963. connection, // context.
  964. REQUEST_FLAGS_CONNECTION, // partial flags.
  965. RequestBuffer2,
  966. RequestBuffer2Length,
  967. timeout, // timeout value (can be 0).
  968. &tpRequest);
  969. if (!NT_SUCCESS (status)) { // couldn't make the request.
  970. IF_NBFDBG (NBF_DEBUG_CONNECT) {
  971. NbfPrint1 ("TdiListen: Create Request Failed, reason: %lx.\n", status);
  972. }
  973. NbfDereferenceConnection ("For create", connection, CREF_BY_ID);
  974. return status; // return with failure.
  975. }
  976. // Reference the connection since NbfDestroyRequest derefs it.
  977. IoAcquireCancelSpinLock (&cancelirql);
  978. ACQUIRE_C_SPIN_LOCK (&connection->SpinLock, &oldirql);
  979. tpRequest->Owner = ConnectionType;
  980. NbfReferenceConnection("For listen request", connection, CREF_REQUEST);
  981. if ((connection->Flags2 & CONNECTION_FLAGS2_STOPPING) != 0) {
  982. RELEASE_C_SPIN_LOCK (&connection->SpinLock,oldirql);
  983. IoReleaseCancelSpinLock(cancelirql);
  984. NbfCompleteRequest (
  985. tpRequest,
  986. connection->Status,
  987. 0);
  988. NbfDereferenceConnection("Temp create", connection, CREF_BY_ID);
  989. return STATUS_PENDING;
  990. } else {
  991. InsertTailList (&connection->InProgressRequest,&tpRequest->Linkage);
  992. connection->Flags2 |= (CONNECTION_FLAGS2_LISTENER | // we're the passive one.
  993. CONNECTION_FLAGS2_WAIT_NQ); // wait for NAME_QUERY.
  994. connection->Flags2 &= ~(CONNECTION_FLAGS2_INDICATING |
  995. CONNECTION_FLAGS2_STOPPING);
  996. connection->Status = STATUS_PENDING;
  997. //
  998. // If TDI_QUERY_ACCEPT is not set, then we set PRE_ACCEPT to
  999. // indicate that when the listen completes we do not have to
  1000. // wait for a TDI_ACCEPT to continue.
  1001. //
  1002. if ((parameters->RequestFlags & TDI_QUERY_ACCEPT) == 0) {
  1003. connection->Flags2 |= CONNECTION_FLAGS2_PRE_ACCEPT;
  1004. }
  1005. RELEASE_C_SPIN_LOCK (&connection->SpinLock,oldirql);
  1006. //
  1007. // Check if the IRP has been cancelled.
  1008. //
  1009. if (Irp->Cancel) {
  1010. Irp->CancelIrql = cancelirql;
  1011. NbfCancelConnection((PDEVICE_OBJECT)(connection->Provider), Irp);
  1012. NbfDereferenceConnection ("IRP cancelled", connection, CREF_BY_ID); // release lookup hold.
  1013. return STATUS_PENDING;
  1014. }
  1015. IoSetCancelRoutine(Irp, NbfCancelConnection);
  1016. IoReleaseCancelSpinLock(cancelirql);
  1017. }
  1018. //
  1019. // Wait for an incoming NAME_QUERY frame. The remainder of the
  1020. // connectionless protocol to set up a connection is processed
  1021. // in the NAME_QUERY frame handler.
  1022. //
  1023. NbfDereferenceConnection("Temp create", connection, CREF_BY_ID);
  1024. return STATUS_PENDING; // things are started.
  1025. } /* TdiListen */
  1026. NTSTATUS
  1027. NbfOpenConnection (
  1028. IN PDEVICE_OBJECT DeviceObject,
  1029. IN PIRP Irp,
  1030. IN PIO_STACK_LOCATION IrpSp
  1031. )
  1032. /*++
  1033. Routine Description:
  1034. This routine is called to open a connection. Note that the connection that
  1035. is open is of little use until associated with an address; until then,
  1036. the only thing that can be done with it is close it.
  1037. Arguments:
  1038. DeviceObject - Pointer to the device object for this driver.
  1039. Irp - Pointer to the request packet representing the I/O request.
  1040. IrpSp - Pointer to current IRP stack frame.
  1041. Return Value:
  1042. The function value is the status of the operation.
  1043. --*/
  1044. {
  1045. PDEVICE_CONTEXT DeviceContext;
  1046. NTSTATUS status;
  1047. PTP_CONNECTION connection;
  1048. PFILE_FULL_EA_INFORMATION ea;
  1049. UNREFERENCED_PARAMETER (Irp);
  1050. IF_NBFDBG (NBF_DEBUG_CONNECT) {
  1051. NbfPrint0 ("NbfOpenConnection: Entered.\n");
  1052. }
  1053. DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
  1054. // Make sure we have a connection context specified in the EA info
  1055. ea = (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
  1056. if (ea->EaValueLength < sizeof(PVOID)) {
  1057. return STATUS_INVALID_PARAMETER;
  1058. }
  1059. // Then, try to make a connection object to represent this pending
  1060. // connection. Then fill in the relevant fields.
  1061. // In addition to the creation, if successful NbfCreateConnection
  1062. // will create a second reference which is removed once the request
  1063. // references the connection, or if the function exits before that.
  1064. status = NbfCreateConnection (DeviceContext, &connection);
  1065. if (!NT_SUCCESS (status)) {
  1066. return status; // sorry, we couldn't make one.
  1067. }
  1068. //
  1069. // set the connection context so we can connect the user to this data
  1070. // structure
  1071. //
  1072. RtlCopyMemory (
  1073. &connection->Context,
  1074. &ea->EaName[ea->EaNameLength+1],
  1075. sizeof (PVOID));
  1076. //
  1077. // let file object point at connection and connection at file object
  1078. //
  1079. IrpSp->FileObject->FsContext = (PVOID)connection;
  1080. IrpSp->FileObject->FsContext2 = (PVOID)TDI_CONNECTION_FILE;
  1081. connection->FileObject = IrpSp->FileObject;
  1082. IF_NBFDBG (NBF_DEBUG_CONNECT) {
  1083. NbfPrint1 ("NBFOpenConnection: Opened Connection %lx.\n",
  1084. connection);
  1085. }
  1086. return status;
  1087. } /* NbfOpenConnection */
  1088. #if DBG
  1089. VOID
  1090. ConnectionCloseTimeout(
  1091. IN PKDPC Dpc,
  1092. IN PVOID DeferredContext,
  1093. IN PVOID SystemArgument1,
  1094. IN PVOID SystemArgument2
  1095. )
  1096. {
  1097. PTP_CONNECTION Connection;
  1098. Dpc, SystemArgument1, SystemArgument2; // prevent compiler warnings
  1099. Connection = (PTP_CONNECTION)DeferredContext;
  1100. DbgPrint ("NBF: Close of connection %lxpending for 2 minutes\n",
  1101. Connection);
  1102. }
  1103. #endif
  1104. NTSTATUS
  1105. NbfCloseConnection (
  1106. IN PDEVICE_OBJECT DeviceObject,
  1107. IN PIRP Irp,
  1108. IN PIO_STACK_LOCATION IrpSp
  1109. )
  1110. /*++
  1111. Routine Description:
  1112. This routine is called to close a connection. There may be actions in
  1113. progress on this connection, so we note the closing IRP, mark the
  1114. connection as closing, and complete it somewhere down the road (when all
  1115. references have been removed).
  1116. Arguments:
  1117. DeviceObject - Pointer to the device object for this driver.
  1118. Irp - Pointer to the request packet representing the I/O request.
  1119. IrpSp - Pointer to current IRP stack frame.
  1120. Return Value:
  1121. The function value is the status of the operation.
  1122. --*/
  1123. {
  1124. NTSTATUS status;
  1125. KIRQL oldirql;
  1126. PTP_CONNECTION connection;
  1127. UNREFERENCED_PARAMETER (DeviceObject);
  1128. UNREFERENCED_PARAMETER (Irp);
  1129. //
  1130. // is the file object a connection?
  1131. //
  1132. connection = IrpSp->FileObject->FsContext;
  1133. IF_NBFDBG (NBF_DEBUG_CONNECT | NBF_DEBUG_PNP) {
  1134. NbfPrint1 ("NbfCloseConnection CO %lx:\n",connection);
  1135. }
  1136. KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
  1137. //
  1138. // We duplicate the code from VerifyConnectionObject,
  1139. // although we don't actually call that since it does
  1140. // a reference, which we don't want (to avoid bouncing
  1141. // the reference count up from 0 if this is a dead
  1142. // link).
  1143. //
  1144. try {
  1145. if ((connection->Size == sizeof (TP_CONNECTION)) &&
  1146. (connection->Type == NBF_CONNECTION_SIGNATURE)) {
  1147. ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  1148. if ((connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0) {
  1149. status = STATUS_SUCCESS;
  1150. } else {
  1151. status = STATUS_INVALID_CONNECTION;
  1152. }
  1153. RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  1154. } else {
  1155. status = STATUS_INVALID_CONNECTION;
  1156. }
  1157. } except(EXCEPTION_EXECUTE_HANDLER) {
  1158. KeLowerIrql (oldirql);
  1159. return GetExceptionCode();
  1160. }
  1161. if (!NT_SUCCESS (status)) {
  1162. KeLowerIrql (oldirql);
  1163. return status;
  1164. }
  1165. //
  1166. // We recognize it; is it closing already?
  1167. //
  1168. ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  1169. if ((connection->Flags2 & CONNECTION_FLAGS2_CLOSING) != 0) {
  1170. RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  1171. KeLowerIrql (oldirql);
  1172. #if DBG
  1173. NbfPrint1("Closing already-closing connection %lx\n", connection);
  1174. #endif
  1175. return STATUS_INVALID_CONNECTION;
  1176. }
  1177. connection->Flags2 |= CONNECTION_FLAGS2_CLOSING;
  1178. //
  1179. // if there is activity on the connection, tear it down.
  1180. //
  1181. if ((connection->Flags2 & CONNECTION_FLAGS2_STOPPING) == 0) {
  1182. RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  1183. NbfStopConnection (connection, STATUS_LOCAL_DISCONNECT);
  1184. ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  1185. }
  1186. //
  1187. // If the connection is still associated, disassociate it.
  1188. //
  1189. if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) &&
  1190. ((connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) == 0)) {
  1191. connection->Flags2 |= CONNECTION_FLAGS2_DISASSOCIATED;
  1192. RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  1193. } else {
  1194. RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  1195. }
  1196. //
  1197. // Save this to complete the IRP later.
  1198. //
  1199. connection->CloseIrp = Irp;
  1200. #if 0
  1201. //
  1202. // make it impossible to use this connection from the file object
  1203. //
  1204. IrpSp->FileObject->FsContext = NULL;
  1205. IrpSp->FileObject->FsContext2 = NULL;
  1206. connection->FileObject = NULL;
  1207. #endif
  1208. #if DBG
  1209. {
  1210. LARGE_INTEGER Timeout;
  1211. BOOLEAN AlreadyInserted;
  1212. Timeout.LowPart = (ULONG)(-(120*SECONDS));
  1213. Timeout.HighPart = -1;
  1214. ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  1215. AlreadyInserted = KeCancelTimer (&connection->Timer);
  1216. KeInitializeDpc (
  1217. &connection->Dpc,
  1218. ConnectionCloseTimeout,
  1219. (PVOID)connection);
  1220. KeSetTimer (
  1221. &connection->Timer,
  1222. Timeout,
  1223. &connection->Dpc);
  1224. RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  1225. if (AlreadyInserted) {
  1226. DbgPrint ("NBF: Cancelling connection timer for debug %lx\n", connection);
  1227. NbfDereferenceConnection ("debug", connection, CREF_TIMER);
  1228. }
  1229. }
  1230. #endif
  1231. KeLowerIrql (oldirql);
  1232. //
  1233. // dereference for the creation. Note that this dereference
  1234. // here won't have any effect until the regular reference count
  1235. // hits zero.
  1236. //
  1237. NbfDereferenceConnectionSpecial (" Closing Connection", connection, CREF_SPECIAL_CREATION);
  1238. return STATUS_PENDING;
  1239. } /* NbfCloseConnection */