Source code of Windows XP (NT5)
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.

2438 lines
69 KiB

  1. /*++
  2. Copyright (c) 1989, 1990, 1991 Microsoft Corporation
  3. Module Name:
  4. connobj.c
  5. Abstract:
  6. This module contains code which implements the TP_CONNECTION object.
  7. Routines are provided to create, destroy, reference, and dereference,
  8. transport connection objects.
  9. A word about connection reference counts:
  10. With TDI version 2, connections live on even after they have been stopped.
  11. This necessitated changing the way NBF handles connection reference counts,
  12. making the stopping of a connection only another way station in the life
  13. of a connection, rather than its demise. Reference counts now work like
  14. this:
  15. Connection State Reference Count Flags
  16. ------------------ ----------------- --------
  17. Opened, no activity 1 0
  18. Open, Associated 2 FLAGS2_ASSOCIATED
  19. Open, Assoc., Connected 3 FLAGS_READY
  20. Above + activity >3 varies
  21. Open, Assoc., Stopping >3 FLAGS_STOPPING
  22. Open, Assoc., Stopped 3 FLAGS_STOPPING
  23. Open, Disassoc. Complete 2 FLAGS_STOPPING
  24. FLAGS2_ASSOCIATED == 0
  25. Closing 1 FLAGS2_CLOSING
  26. Closed 0 FLAGS2_CLOSING
  27. Note that keeping the stopping flag set when the connection has fully
  28. stopped avoids using the connection until it is connected again; the
  29. CLOSING flag serves the same purpose. This allows a connection to run
  30. down in its own time.
  31. Author:
  32. David Beaver (dbeaver) 1 July 1991
  33. Environment:
  34. Kernel mode
  35. Revision History:
  36. --*/
  37. #include "precomp.h"
  38. #pragma hdrstop
  39. #ifdef RASAUTODIAL
  40. #include <acd.h>
  41. #include <acdapi.h>
  42. #endif // RASAUTODIAL
  43. #ifdef RASAUTODIAL
  44. extern BOOLEAN fAcdLoadedG;
  45. extern ACD_DRIVER AcdDriverG;
  46. //
  47. // Imported routines
  48. //
  49. BOOLEAN
  50. NbfAttemptAutoDial(
  51. IN PTP_CONNECTION Connection,
  52. IN ULONG ulFlags,
  53. IN ACD_CONNECT_CALLBACK pProc,
  54. IN PVOID pArg
  55. );
  56. VOID
  57. NbfRetryTdiConnect(
  58. IN BOOLEAN fSuccess,
  59. IN PVOID *pArgs
  60. );
  61. BOOLEAN
  62. NbfCancelTdiConnect(
  63. IN PDEVICE_OBJECT pDeviceObject,
  64. IN PIRP pIrp
  65. );
  66. #endif // RASAUTODIAL
  67. VOID
  68. ConnectionEstablishmentTimeout(
  69. IN PKDPC Dpc,
  70. IN PVOID DeferredContext,
  71. IN PVOID SystemArgument1,
  72. IN PVOID SystemArgument2
  73. )
  74. /*++
  75. Routine Description:
  76. This routine is executed as a DPC at DISPATCH_LEVEL when the timeout
  77. period for the NAME_QUERY/NAME_RECOGNIZED protocol expires. The retry
  78. count in the Connection object is decremented, and if it reaches 0,
  79. the connection is aborted. If the retry count has not reached zero,
  80. then the NAME QUERY is retried. The following cases are covered by
  81. this routine:
  82. 1. Initial NAME_QUERY timeout for find_name portion of connection setup.
  83. NQ(find_name) ------------------->
  84. [TIMEOUT]
  85. NQ(find_name) ------------------->
  86. <------------------- NR(find_name)
  87. 2. Secondary NAME_QUERY timeout for connection setup.
  88. NQ(connection) ------------------->
  89. [TIMEOUT]
  90. NQ(connection) ------------------->
  91. <------------------- NR(connection)
  92. There is another case where the data link connection does not get
  93. established within a reasonable amount of time. This is handled by
  94. the link layer routines.
  95. Arguments:
  96. Dpc - Pointer to a system DPC object.
  97. DeferredContext - Pointer to the TP_CONNECTION block representing the
  98. request that has timed out.
  99. SystemArgument1 - Not used.
  100. SystemArgument2 - Not used.
  101. Return Value:
  102. none.
  103. --*/
  104. {
  105. PTP_CONNECTION Connection;
  106. Dpc, SystemArgument1, SystemArgument2; // prevent compiler warnings
  107. ENTER_NBF;
  108. Connection = (PTP_CONNECTION)DeferredContext;
  109. IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
  110. NbfPrint1 ("ConnectionEstablishmentTimeout: Entered for connection %lx.\n",
  111. Connection);
  112. }
  113. //
  114. // If this connection is being run down, then we can't do anything.
  115. //
  116. ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  117. if (Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) {
  118. RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  119. NbfDereferenceConnection ("Connect timed out", Connection, CREF_TIMER);
  120. LEAVE_NBF;
  121. return;
  122. }
  123. if (Connection->Flags2 & (CONNECTION_FLAGS2_WAIT_NR_FN | CONNECTION_FLAGS2_WAIT_NR)) {
  124. //
  125. // We are waiting for a commital or non-commital NAME_RECOGNIZED frame.
  126. // Decrement the retry count, and possibly resend the NAME_QUERY.
  127. //
  128. if (--(Connection->Retries) == 0) { // if retry count exhausted.
  129. NTSTATUS StopStatus;
  130. //
  131. // See if we got a no listens response, or just
  132. // nothing.
  133. //
  134. if ((Connection->Flags2 & CONNECTION_FLAGS2_NO_LISTEN) != 0) {
  135. Connection->Flags2 &= ~CONNECTION_FLAGS2_NO_LISTEN;
  136. StopStatus = STATUS_REMOTE_NOT_LISTENING; // no listens
  137. } else {
  138. StopStatus = STATUS_BAD_NETWORK_PATH; // name not found.
  139. }
  140. #ifdef RASAUTODIAL
  141. //
  142. // If this is a connect operation that has
  143. // returned with STATUS_BAD_NETWORK_PATH, then
  144. // attempt to create an automatic connection.
  145. //
  146. if (fAcdLoadedG &&
  147. StopStatus == STATUS_BAD_NETWORK_PATH)
  148. {
  149. KIRQL adirql;
  150. BOOLEAN fEnabled;
  151. ACQUIRE_SPIN_LOCK(&AcdDriverG.SpinLock, &adirql);
  152. fEnabled = AcdDriverG.fEnabled;
  153. RELEASE_SPIN_LOCK(&AcdDriverG.SpinLock, adirql);
  154. if (fEnabled && NbfAttemptAutoDial(
  155. Connection,
  156. 0,
  157. NbfRetryTdiConnect,
  158. Connection))
  159. {
  160. RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  161. goto done;
  162. }
  163. }
  164. #endif // RASAUTODIAL
  165. RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  166. NbfStopConnection (Connection, StopStatus);
  167. } else {
  168. RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  169. //
  170. // We make source routing optional on every second
  171. // name query (whenever Retries is even).
  172. //
  173. NbfSendNameQuery (
  174. Connection,
  175. (BOOLEAN)((Connection->Retries & 1) ? FALSE : TRUE));
  176. NbfStartConnectionTimer (
  177. Connection,
  178. ConnectionEstablishmentTimeout,
  179. Connection->Provider->NameQueryTimeout);
  180. }
  181. } else {
  182. RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  183. }
  184. //
  185. // Dereference the connection, to account for the fact that the
  186. // timer went off. Note that if we restarted the timer using
  187. // NbfStartConnectionTimer, the reference count has already been
  188. // incremented to account for the new timer.
  189. //
  190. done:
  191. NbfDereferenceConnection ("Timer timed out",Connection, CREF_TIMER);
  192. LEAVE_NBF;
  193. return;
  194. } /* ConnectionEstablishmentTimeout */
  195. VOID
  196. NbfAllocateConnection(
  197. IN PDEVICE_CONTEXT DeviceContext,
  198. OUT PTP_CONNECTION *TransportConnection
  199. )
  200. /*++
  201. Routine Description:
  202. This routine allocates storage for a transport connection. Some
  203. minimal initialization is done.
  204. NOTE: This routine is called with the device context spinlock
  205. held, or at such a time as synchronization is unnecessary.
  206. Arguments:
  207. DeviceContext - the device context for this connection to be
  208. associated with.
  209. TransportConnection - Pointer to a place where this routine will
  210. return a pointer to a transport connection structure. Returns
  211. NULL if the storage cannot be allocated.
  212. Return Value:
  213. None.
  214. --*/
  215. {
  216. PTP_CONNECTION Connection;
  217. if ((DeviceContext->MemoryLimit != 0) &&
  218. ((DeviceContext->MemoryUsage + sizeof(TP_CONNECTION)) >
  219. DeviceContext->MemoryLimit)) {
  220. PANIC("NBF: Could not allocate connection: limit\n");
  221. NbfWriteResourceErrorLog(
  222. DeviceContext,
  223. EVENT_TRANSPORT_RESOURCE_LIMIT,
  224. 103,
  225. sizeof(TP_CONNECTION),
  226. CONNECTION_RESOURCE_ID);
  227. *TransportConnection = NULL;
  228. return;
  229. }
  230. Connection = (PTP_CONNECTION)ExAllocatePoolWithTag (
  231. NonPagedPool,
  232. sizeof (TP_CONNECTION),
  233. NBF_MEM_TAG_TP_CONNECTION);
  234. if (Connection == NULL) {
  235. PANIC("NBF: Could not allocate connection: no pool\n");
  236. NbfWriteResourceErrorLog(
  237. DeviceContext,
  238. EVENT_TRANSPORT_RESOURCE_POOL,
  239. 203,
  240. sizeof(TP_CONNECTION),
  241. CONNECTION_RESOURCE_ID);
  242. *TransportConnection = NULL;
  243. return;
  244. }
  245. RtlZeroMemory (Connection, sizeof(TP_CONNECTION));
  246. IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
  247. NbfPrint1 ("ExAllocatePool Connection %08x\n", Connection);
  248. }
  249. DeviceContext->MemoryUsage += sizeof(TP_CONNECTION);
  250. ++DeviceContext->ConnectionAllocated;
  251. Connection->Type = NBF_CONNECTION_SIGNATURE;
  252. Connection->Size = sizeof (TP_CONNECTION);
  253. Connection->Provider = DeviceContext;
  254. Connection->ProviderInterlock = &DeviceContext->Interlock;
  255. KeInitializeSpinLock (&Connection->SpinLock);
  256. KeInitializeDpc (
  257. &Connection->Dpc,
  258. ConnectionEstablishmentTimeout,
  259. (PVOID)Connection);
  260. KeInitializeTimer (&Connection->Timer);
  261. InitializeListHead (&Connection->LinkList);
  262. InitializeListHead (&Connection->AddressFileList);
  263. InitializeListHead (&Connection->AddressList);
  264. InitializeListHead (&Connection->PacketWaitLinkage);
  265. InitializeListHead (&Connection->PacketizeLinkage);
  266. InitializeListHead (&Connection->SendQueue);
  267. InitializeListHead (&Connection->ReceiveQueue);
  268. InitializeListHead (&Connection->InProgressRequest);
  269. InitializeListHead (&Connection->DeferredQueue);
  270. NbfAddSendPacket (DeviceContext);
  271. NbfAddSendPacket (DeviceContext);
  272. NbfAddUIFrame (DeviceContext);
  273. *TransportConnection = Connection;
  274. } /* NbfAllocateConnection */
  275. VOID
  276. NbfDeallocateConnection(
  277. IN PDEVICE_CONTEXT DeviceContext,
  278. IN PTP_CONNECTION TransportConnection
  279. )
  280. /*++
  281. Routine Description:
  282. This routine frees storage for a transport connection.
  283. NOTE: This routine is called with the device context spinlock
  284. held, or at such a time as synchronization is unnecessary.
  285. Arguments:
  286. DeviceContext - the device context for this connection to be
  287. associated with.
  288. TransportConnection - Pointer to a transport connection structure.
  289. Return Value:
  290. None.
  291. --*/
  292. {
  293. IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
  294. NbfPrint1 ("ExFreePool Connection: %08x\n", TransportConnection);
  295. }
  296. ExFreePool (TransportConnection);
  297. --DeviceContext->ConnectionAllocated;
  298. DeviceContext->MemoryUsage -= sizeof(TP_CONNECTION);
  299. NbfRemoveSendPacket (DeviceContext);
  300. NbfRemoveSendPacket (DeviceContext);
  301. NbfRemoveUIFrame (DeviceContext);
  302. } /* NbfDeallocateConnection */
  303. NTSTATUS
  304. NbfCreateConnection(
  305. IN PDEVICE_CONTEXT DeviceContext,
  306. OUT PTP_CONNECTION *TransportConnection
  307. )
  308. /*++
  309. Routine Description:
  310. This routine creates a transport connection. The reference count in the
  311. connection is automatically set to 1, and the reference count in the
  312. DeviceContext is incremented.
  313. Arguments:
  314. Address - the address for this connection to be associated with.
  315. TransportConnection - Pointer to a place where this routine will
  316. return a pointer to a transport connection structure.
  317. Return Value:
  318. NTSTATUS - status of operation.
  319. --*/
  320. {
  321. PTP_CONNECTION Connection;
  322. KIRQL oldirql;
  323. PLIST_ENTRY p;
  324. IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
  325. NbfPrint0 ("NbfCreateConnection: Entered.\n");
  326. }
  327. ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
  328. p = RemoveHeadList (&DeviceContext->ConnectionPool);
  329. if (p == &DeviceContext->ConnectionPool) {
  330. if ((DeviceContext->ConnectionMaxAllocated == 0) ||
  331. (DeviceContext->ConnectionAllocated < DeviceContext->ConnectionMaxAllocated)) {
  332. NbfAllocateConnection (DeviceContext, &Connection);
  333. IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
  334. NbfPrint1 ("NBF: Allocated connection at %lx\n", Connection);
  335. }
  336. } else {
  337. NbfWriteResourceErrorLog(
  338. DeviceContext,
  339. EVENT_TRANSPORT_RESOURCE_SPECIFIC,
  340. 403,
  341. sizeof(TP_CONNECTION),
  342. CONNECTION_RESOURCE_ID);
  343. Connection = NULL;
  344. }
  345. if (Connection == NULL) {
  346. ++DeviceContext->ConnectionExhausted;
  347. RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
  348. PANIC ("NbfCreateConnection: Could not allocate connection object!\n");
  349. return STATUS_INSUFFICIENT_RESOURCES;
  350. }
  351. } else {
  352. Connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
  353. #if DBG
  354. InitializeListHead (p);
  355. #endif
  356. }
  357. ++DeviceContext->ConnectionInUse;
  358. if (DeviceContext->ConnectionInUse > DeviceContext->ConnectionMaxInUse) {
  359. ++DeviceContext->ConnectionMaxInUse;
  360. }
  361. DeviceContext->ConnectionTotal += DeviceContext->ConnectionInUse;
  362. ++DeviceContext->ConnectionSamples;
  363. RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
  364. IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
  365. NbfPrint1 ("NbfCreateConnection: Connection at %lx.\n", Connection);
  366. }
  367. //
  368. // We have two references; one is for creation, and the
  369. // other is a temporary one so that the connection won't
  370. // go away before the creator has a chance to access it.
  371. //
  372. Connection->SpecialRefCount = 1;
  373. Connection->ReferenceCount = -1; // this is -1 based
  374. #if DBG
  375. {
  376. UINT Counter;
  377. for (Counter = 0; Counter < NUMBER_OF_CREFS; Counter++) {
  378. Connection->RefTypes[Counter] = 0;
  379. }
  380. // This reference is removed by NbfCloseConnection
  381. Connection->RefTypes[CREF_SPECIAL_CREATION] = 1;
  382. }
  383. #endif
  384. //
  385. // Initialize the request queues & components of this connection.
  386. //
  387. InitializeListHead (&Connection->SendQueue);
  388. InitializeListHead (&Connection->ReceiveQueue);
  389. InitializeListHead (&Connection->InProgressRequest);
  390. InitializeListHead (&Connection->AddressList);
  391. InitializeListHead (&Connection->AddressFileList);
  392. Connection->SpecialReceiveIrp = (PIRP)NULL;
  393. Connection->Flags = 0;
  394. Connection->Flags2 = 0;
  395. Connection->DeferredFlags = 0;
  396. Connection->Lsn = 0;
  397. Connection->Rsn = 0;
  398. Connection->Retries = 0; // no retries yet.
  399. Connection->MessageBytesReceived = 0; // no data yet
  400. Connection->MessageBytesAcked = 0;
  401. Connection->MessageInitAccepted = 0;
  402. Connection->ReceiveBytesUnaccepted = 0;
  403. Connection->CurrentReceiveAckQueueable = FALSE;
  404. Connection->CurrentReceiveSynchronous = FALSE;
  405. Connection->ConsecutiveSends = 0;
  406. Connection->ConsecutiveReceives = 0;
  407. Connection->Link = NULL; // no datalink connection yet.
  408. Connection->LinkSpinLock = NULL;
  409. Connection->Context = NULL; // no context yet.
  410. Connection->Status = STATUS_PENDING; // default NbfStopConnection status.
  411. Connection->SendState = CONNECTION_SENDSTATE_IDLE;
  412. Connection->CurrentReceiveIrp = (PIRP)NULL;
  413. Connection->DisconnectIrp = (PIRP)NULL;
  414. Connection->CloseIrp = (PIRP)NULL;
  415. Connection->AddressFile = NULL;
  416. Connection->IndicationInProgress = FALSE;
  417. Connection->OnDataAckQueue = FALSE;
  418. Connection->OnPacketWaitQueue = FALSE;
  419. Connection->TransferBytesPending = 0;
  420. Connection->TotalTransferBytesPending = 0;
  421. RtlZeroMemory (&Connection->NetbiosHeader, sizeof(NBF_HDR_CONNECTION));
  422. #if PKT_LOG
  423. RtlZeroMemory (&Connection->LastNRecvs, sizeof(PKT_LOG_QUE));
  424. RtlZeroMemory (&Connection->LastNSends, sizeof(PKT_LOG_QUE));
  425. RtlZeroMemory (&Connection->LastNIndcs, sizeof(PKT_IND_QUE));
  426. #endif // PKT_LOG
  427. #if DBG
  428. Connection->Destroyed = FALSE;
  429. Connection->TotalReferences = 0;
  430. Connection->TotalDereferences = 0;
  431. Connection->NextRefLoc = 0;
  432. ExInterlockedInsertHeadList (&NbfGlobalConnectionList, &Connection->GlobalLinkage, &NbfGlobalInterlock);
  433. StoreConnectionHistory (Connection, TRUE);
  434. #endif
  435. //
  436. // Now assign this connection an ID. This is used later to identify the
  437. // connection across multiple processes.
  438. //
  439. // The high bit of the ID is not user, it is off for connection
  440. // initiating NAME.QUERY frames and on for ones that are the result
  441. // of a FIND.NAME request.
  442. //
  443. ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
  444. Connection->ConnectionId = DeviceContext->UniqueIdentifier;
  445. ++DeviceContext->UniqueIdentifier;
  446. if (DeviceContext->UniqueIdentifier == 0x8000) {
  447. DeviceContext->UniqueIdentifier = 1;
  448. }
  449. NbfReferenceDeviceContext ("Create Connection", DeviceContext, DCREF_CONNECTION);
  450. RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
  451. *TransportConnection = Connection; // return the connection.
  452. return STATUS_SUCCESS;
  453. } /* NbfCreateConnection */
  454. NTSTATUS
  455. NbfVerifyConnectionObject (
  456. IN PTP_CONNECTION Connection
  457. )
  458. /*++
  459. Routine Description:
  460. This routine is called to verify that the pointer given us in a file
  461. object is in fact a valid connection object.
  462. Arguments:
  463. Connection - potential pointer to a TP_CONNECTION object.
  464. Return Value:
  465. STATUS_SUCCESS if all is well; STATUS_INVALID_CONNECTION otherwise
  466. --*/
  467. {
  468. KIRQL oldirql;
  469. NTSTATUS status = STATUS_SUCCESS;
  470. //
  471. // try to verify the connection signature. If the signature is valid,
  472. // get the connection spinlock, check its state, and increment the
  473. // reference count if it's ok to use it. Note that being in the stopping
  474. // state is an OK place to be and reference the connection; we can
  475. // disassociate the address while running down.
  476. //
  477. try {
  478. if ((Connection != (PTP_CONNECTION)NULL) &&
  479. (Connection->Size == sizeof (TP_CONNECTION)) &&
  480. (Connection->Type == NBF_CONNECTION_SIGNATURE)) {
  481. ACQUIRE_C_SPIN_LOCK (&Connection->SpinLock, &oldirql);
  482. if ((Connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0) {
  483. NbfReferenceConnection ("Verify Temp Use", Connection, CREF_BY_ID);
  484. } else {
  485. status = STATUS_INVALID_CONNECTION;
  486. }
  487. RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql);
  488. } else {
  489. status = STATUS_INVALID_CONNECTION;
  490. }
  491. } except(EXCEPTION_EXECUTE_HANDLER) {
  492. return GetExceptionCode();
  493. }
  494. return status;
  495. }
  496. NTSTATUS
  497. NbfDestroyAssociation(
  498. IN PTP_CONNECTION TransportConnection
  499. )
  500. /*++
  501. Routine Description:
  502. This routine destroys the association between a transport connection and
  503. the address it was formerly associated with. The only action taken is
  504. to disassociate the address and remove the connection from all address
  505. queues.
  506. This routine is only called by NbfDereferenceConnection. The reason for
  507. this is that there may be multiple streams of execution which are
  508. simultaneously referencing the same connection object, and it should
  509. not be deleted out from under an interested stream of execution.
  510. Arguments:
  511. TransportConnection - Pointer to a transport connection structure to
  512. be destroyed.
  513. Return Value:
  514. NTSTATUS - status of operation.
  515. --*/
  516. {
  517. KIRQL oldirql, oldirql2;
  518. PTP_ADDRESS address;
  519. PTP_ADDRESS_FILE addressFile;
  520. BOOLEAN NotAssociated = FALSE;
  521. IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
  522. NbfPrint1 ("NbfDestroyAssociation: Entered for connection %lx.\n",
  523. TransportConnection);
  524. }
  525. try {
  526. ACQUIRE_C_SPIN_LOCK (&TransportConnection->SpinLock, &oldirql2);
  527. if ((TransportConnection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) == 0) {
  528. #if DBG
  529. if (!(IsListEmpty(&TransportConnection->AddressList)) ||
  530. !(IsListEmpty(&TransportConnection->AddressFileList))) {
  531. DbgPrint ("NBF: C %lx, AF %lx, freed while still queued\n",
  532. TransportConnection, TransportConnection->AddressFile);
  533. DbgBreakPoint();
  534. }
  535. #endif
  536. RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql2);
  537. NotAssociated = TRUE;
  538. } else {
  539. TransportConnection->Flags2 &= ~CONNECTION_FLAGS2_ASSOCIATED;
  540. RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql2);
  541. }
  542. } except(EXCEPTION_EXECUTE_HANDLER) {
  543. DbgPrint ("NBF: Got exception 1 in NbfDestroyAssociation\n");
  544. DbgBreakPoint();
  545. RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql2);
  546. }
  547. if (NotAssociated) {
  548. return STATUS_SUCCESS;
  549. }
  550. addressFile = TransportConnection->AddressFile;
  551. address = addressFile->Address;
  552. //
  553. // Delink this connection from its associated address connection
  554. // database. To do this we must spin lock on the address object as
  555. // well as on the connection,
  556. //
  557. ACQUIRE_SPIN_LOCK (&address->SpinLock, &oldirql);
  558. try {
  559. ACQUIRE_C_SPIN_LOCK (&TransportConnection->SpinLock, &oldirql2);
  560. RemoveEntryList (&TransportConnection->AddressFileList);
  561. RemoveEntryList (&TransportConnection->AddressList);
  562. InitializeListHead (&TransportConnection->AddressList);
  563. InitializeListHead (&TransportConnection->AddressFileList);
  564. //
  565. // remove the association between the address and the connection.
  566. //
  567. TransportConnection->AddressFile = NULL;
  568. RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql2);
  569. } except(EXCEPTION_EXECUTE_HANDLER) {
  570. DbgPrint ("NBF: Got exception 2 in NbfDestroyAssociation\n");
  571. DbgBreakPoint();
  572. RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql2);
  573. }
  574. RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
  575. //
  576. // and remove a reference to the address
  577. //
  578. NbfDereferenceAddress ("Destroy association", address, AREF_CONNECTION);
  579. return STATUS_SUCCESS;
  580. } /* NbfDestroyAssociation */
  581. NTSTATUS
  582. NbfIndicateDisconnect(
  583. IN PTP_CONNECTION TransportConnection
  584. )
  585. /*++
  586. Routine Description:
  587. This routine indicates a remote disconnection on this connection if it
  588. is necessary to do so. No other action is taken here.
  589. This routine is only called by NbfDereferenceConnection. The reason for
  590. this is that there may be multiple streams of execution which are
  591. simultaneously referencing the same connection object, and it should
  592. not be deleted out from under an interested stream of execution.
  593. Arguments:
  594. TransportConnection - Pointer to a transport connection structure to
  595. be destroyed.
  596. Return Value:
  597. NTSTATUS - status of operation.
  598. --*/
  599. {
  600. PTP_ADDRESS_FILE addressFile;
  601. PDEVICE_CONTEXT DeviceContext;
  602. ULONG DisconnectReason;
  603. PIRP DisconnectIrp;
  604. KIRQL oldirql;
  605. ULONG Lflags2;
  606. IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
  607. NbfPrint1 ("NbfIndicateDisconnect: Entered for connection %lx.\n",
  608. TransportConnection);
  609. }
  610. try {
  611. ACQUIRE_C_SPIN_LOCK (&TransportConnection->SpinLock, &oldirql);
  612. if (((TransportConnection->Flags2 & CONNECTION_FLAGS2_REQ_COMPLETED) != 0)) {
  613. ASSERT (TransportConnection->Lsn == 0);
  614. //
  615. // Turn off all but the still-relevant bits in the flags.
  616. //
  617. Lflags2 = TransportConnection->Flags2;
  618. TransportConnection->Flags2 &=
  619. (CONNECTION_FLAGS2_ASSOCIATED |
  620. CONNECTION_FLAGS2_DISASSOCIATED |
  621. CONNECTION_FLAGS2_CLOSING);
  622. TransportConnection->Flags2 |= CONNECTION_FLAGS2_STOPPING;
  623. //
  624. // Clean up other stuff -- basically everything gets
  625. // done here except for the flags and the status, since
  626. // they are used to block other requests. When the connection
  627. // is given back to us (in Accept, Connect, or Listen)
  628. // they are cleared.
  629. //
  630. TransportConnection->NetbiosHeader.TransmitCorrelator = 0;
  631. TransportConnection->Retries = 0; // no retries yet.
  632. TransportConnection->MessageBytesReceived = 0; // no data yet
  633. TransportConnection->MessageBytesAcked = 0;
  634. TransportConnection->MessageInitAccepted = 0;
  635. TransportConnection->ReceiveBytesUnaccepted = 0;
  636. TransportConnection->ConsecutiveSends = 0;
  637. TransportConnection->ConsecutiveReceives = 0;
  638. TransportConnection->SendState = CONNECTION_SENDSTATE_IDLE;
  639. TransportConnection->TransmittedTsdus = 0;
  640. TransportConnection->ReceivedTsdus = 0;
  641. TransportConnection->CurrentReceiveIrp = (PIRP)NULL;
  642. DisconnectIrp = TransportConnection->DisconnectIrp;
  643. TransportConnection->DisconnectIrp = (PIRP)NULL;
  644. if ((TransportConnection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) != 0) {
  645. addressFile = TransportConnection->AddressFile;
  646. } else {
  647. addressFile = NULL;
  648. }
  649. RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql);
  650. DeviceContext = TransportConnection->Provider;
  651. //
  652. // If this connection was stopped by a call to TdiDisconnect,
  653. // we have to complete that. We save the Irp so we can return
  654. // the connection to the pool before we complete the request.
  655. //
  656. if (DisconnectIrp != (PIRP)NULL ||
  657. (Lflags2 & CONNECTION_FLAGS2_LDISC) != 0) {
  658. if (DisconnectIrp != (PIRP)NULL) {
  659. IF_NBFDBG (NBF_DEBUG_SETUP) {
  660. NbfPrint1("IndicateDisconnect %lx, complete IRP\n", TransportConnection);
  661. }
  662. //
  663. // Now complete the IRP if needed. This will be non-null
  664. // only if TdiDisconnect was called, and we have not
  665. // yet completed it.
  666. //
  667. DisconnectIrp->IoStatus.Information = 0;
  668. DisconnectIrp->IoStatus.Status = STATUS_SUCCESS;
  669. IoCompleteRequest (DisconnectIrp, IO_NETWORK_INCREMENT);
  670. }
  671. } else if ((TransportConnection->Status != STATUS_LOCAL_DISCONNECT) &&
  672. (addressFile != NULL) &&
  673. (addressFile->RegisteredDisconnectHandler == TRUE)) {
  674. //
  675. // This was a remotely spawned disconnect, so indicate that
  676. // to our client. Note that in the comparison above we
  677. // check the status first, since if it is LOCAL_DISCONNECT
  678. // addressFile may be NULL (This is sort of a hack
  679. // for PDK2, we should really indicate the disconnect inside
  680. // NbfStopConnection, where we know addressFile is valid).
  681. //
  682. IF_NBFDBG (NBF_DEBUG_SETUP) {
  683. NbfPrint1("IndicateDisconnect %lx, indicate\n", TransportConnection);
  684. }
  685. //
  686. // if the disconnection was remotely spawned, then indicate
  687. // disconnect. In the case that a disconnect was issued at
  688. // the same time as the connection went down remotely, we
  689. // won't do this because DisconnectIrp will be non-NULL.
  690. //
  691. IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
  692. NbfPrint1 ("NbfIndicateDisconnect calling DisconnectHandler, refcnt=%ld\n",
  693. TransportConnection->ReferenceCount);
  694. }
  695. //
  696. // Invoke the user's disconnection event handler, if any. We do this here
  697. // so that any outstanding sends will complete before we tear down the
  698. // connection.
  699. //
  700. DisconnectReason = 0;
  701. if (TransportConnection->Flags2 & CONNECTION_FLAGS2_ABORT) {
  702. DisconnectReason |= TDI_DISCONNECT_ABORT;
  703. }
  704. if (TransportConnection->Flags2 & CONNECTION_FLAGS2_DESTROY) {
  705. DisconnectReason |= TDI_DISCONNECT_RELEASE;
  706. }
  707. (*addressFile->DisconnectHandler)(
  708. addressFile->DisconnectHandlerContext,
  709. TransportConnection->Context,
  710. 0,
  711. NULL,
  712. 0,
  713. NULL,
  714. TDI_DISCONNECT_ABORT);
  715. #if MAGIC
  716. if (NbfEnableMagic) {
  717. extern VOID NbfSendMagicBullet (PDEVICE_CONTEXT, PTP_LINK);
  718. NbfSendMagicBullet (DeviceContext, NULL);
  719. }
  720. #endif
  721. }
  722. } else {
  723. //
  724. // The client does not yet think that this connection
  725. // is up...generally this happens due to request count
  726. // fluctuation during connection setup.
  727. //
  728. RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql);
  729. }
  730. } except(EXCEPTION_EXECUTE_HANDLER) {
  731. DbgPrint ("NBF: Got exception in NbfIndicateDisconnect\n");
  732. DbgBreakPoint();
  733. RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql);
  734. }
  735. return STATUS_SUCCESS;
  736. } /* NbfIndicateDisconnect */
  737. NTSTATUS
  738. NbfDestroyConnection(
  739. IN PTP_CONNECTION TransportConnection
  740. )
  741. /*++
  742. Routine Description:
  743. This routine destroys a transport connection and removes all references
  744. made by it to other objects in the transport. The connection structure
  745. is returned to our lookaside list. It is assumed that the caller
  746. has removed all IRPs from the connections's queues first.
  747. This routine is only called by NbfDereferenceConnection. The reason for
  748. this is that there may be multiple streams of execution which are
  749. simultaneously referencing the same connection object, and it should
  750. not be deleted out from under an interested stream of execution.
  751. Arguments:
  752. TransportConnection - Pointer to a transport connection structure to
  753. be destroyed.
  754. Return Value:
  755. NTSTATUS - status of operation.
  756. --*/
  757. {
  758. KIRQL oldirql;
  759. PDEVICE_CONTEXT DeviceContext;
  760. PIRP CloseIrp;
  761. IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
  762. NbfPrint1 ("NbfDestroyConnection: Entered for connection %lx.\n",
  763. TransportConnection);
  764. }
  765. #if DBG
  766. if (TransportConnection->Destroyed) {
  767. NbfPrint1 ("attempt to destroy already-destroyed connection 0x%lx\n", TransportConnection);
  768. DbgBreakPoint ();
  769. }
  770. if (!(TransportConnection->Flags2 & CONNECTION_FLAGS2_STOPPING)) {
  771. NbfPrint1 ("attempt to destroy unstopped connection 0x%lx\n", TransportConnection);
  772. DbgBreakPoint ();
  773. }
  774. TransportConnection->Destroyed = TRUE;
  775. ACQUIRE_SPIN_LOCK (&NbfGlobalInterlock, &oldirql);
  776. RemoveEntryList (&TransportConnection->GlobalLinkage);
  777. RELEASE_SPIN_LOCK (&NbfGlobalInterlock, oldirql);
  778. #endif
  779. DeviceContext = TransportConnection->Provider;
  780. //
  781. // Destroy any association that this connection has.
  782. //
  783. NbfDestroyAssociation (TransportConnection);
  784. //
  785. // Clear out any associated nasties hanging around the connection. Note
  786. // that the current flags are set to STOPPING; this way anyone that may
  787. // maliciously try to use the connection after it's dead and gone will
  788. // just get ignored.
  789. //
  790. ASSERT (TransportConnection->Lsn == 0);
  791. TransportConnection->Flags = 0;
  792. TransportConnection->Flags2 = CONNECTION_FLAGS2_CLOSING;
  793. TransportConnection->NetbiosHeader.TransmitCorrelator = 0;
  794. TransportConnection->Retries = 0; // no retries yet.
  795. TransportConnection->MessageBytesReceived = 0; // no data yet
  796. TransportConnection->MessageBytesAcked = 0;
  797. TransportConnection->MessageInitAccepted = 0;
  798. TransportConnection->ReceiveBytesUnaccepted = 0;
  799. //
  800. // Now complete the close IRP. This will be set to non-null
  801. // when CloseConnection was called.
  802. //
  803. CloseIrp = TransportConnection->CloseIrp;
  804. if (CloseIrp != (PIRP)NULL) {
  805. TransportConnection->CloseIrp = (PIRP)NULL;
  806. CloseIrp->IoStatus.Information = 0;
  807. CloseIrp->IoStatus.Status = STATUS_SUCCESS;
  808. IoCompleteRequest (CloseIrp, IO_NETWORK_INCREMENT);
  809. } else {
  810. #if DBG
  811. NbfPrint1("Connection %x destroyed, no CloseIrp!!\n", TransportConnection);
  812. #endif
  813. }
  814. //
  815. // Return the connection to the provider's pool.
  816. //
  817. ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
  818. DeviceContext->ConnectionTotal += DeviceContext->ConnectionInUse;
  819. ++DeviceContext->ConnectionSamples;
  820. --DeviceContext->ConnectionInUse;
  821. if ((DeviceContext->ConnectionAllocated - DeviceContext->ConnectionInUse) >
  822. DeviceContext->ConnectionInitAllocated) {
  823. NbfDeallocateConnection (DeviceContext, TransportConnection);
  824. IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
  825. NbfPrint1 ("NBF: Deallocated connection at %lx\n", TransportConnection);
  826. }
  827. } else {
  828. InsertTailList (&DeviceContext->ConnectionPool, &TransportConnection->LinkList);
  829. }
  830. RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
  831. NbfDereferenceDeviceContext ("Destroy Connection", DeviceContext, DCREF_CONNECTION);
  832. return STATUS_SUCCESS;
  833. } /* NbfDestroyConnection */
  834. #if DBG
  835. VOID
  836. NbfRefConnection(
  837. IN PTP_CONNECTION TransportConnection
  838. )
  839. /*++
  840. Routine Description:
  841. This routine increments the reference count on a transport connection.
  842. Arguments:
  843. TransportConnection - Pointer to a transport connection object.
  844. Return Value:
  845. none.
  846. --*/
  847. {
  848. LONG result;
  849. IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
  850. NbfPrint2 ("NbfReferenceConnection: entered for connection %lx, "
  851. "current level=%ld.\n",
  852. TransportConnection,
  853. TransportConnection->ReferenceCount);
  854. }
  855. #if DBG
  856. StoreConnectionHistory( TransportConnection, TRUE );
  857. #endif
  858. result = InterlockedIncrement (&TransportConnection->ReferenceCount);
  859. if (result == 0) {
  860. //
  861. // The first increment causes us to increment the
  862. // "ref count is not zero" special ref.
  863. //
  864. ExInterlockedAddUlong(
  865. (PULONG)(&TransportConnection->SpecialRefCount),
  866. 1,
  867. TransportConnection->ProviderInterlock);
  868. #if DBG
  869. ++TransportConnection->RefTypes[CREF_SPECIAL_TEMP];
  870. #endif
  871. }
  872. ASSERT (result >= 0);
  873. } /* NbfRefConnection */
  874. #endif
  875. VOID
  876. NbfDerefConnection(
  877. IN PTP_CONNECTION TransportConnection
  878. )
  879. /*++
  880. Routine Description:
  881. This routine dereferences a transport connection by decrementing the
  882. reference count contained in the structure. If, after being
  883. decremented, the reference count is zero, then this routine calls
  884. NbfDestroyConnection to remove it from the system.
  885. Arguments:
  886. TransportConnection - Pointer to a transport connection object.
  887. Return Value:
  888. none.
  889. --*/
  890. {
  891. LONG result;
  892. IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
  893. NbfPrint2 ("NbfDereferenceConnection: entered for connection %lx, "
  894. "current level=%ld.\n",
  895. TransportConnection,
  896. TransportConnection->ReferenceCount);
  897. }
  898. #if DBG
  899. StoreConnectionHistory( TransportConnection, FALSE );
  900. #endif
  901. result = InterlockedDecrement (&TransportConnection->ReferenceCount);
  902. //
  903. // If all the normal references to this connection are gone, then
  904. // we can remove the special reference that stood for
  905. // "the regular ref count is non-zero".
  906. //
  907. if (result < 0) {
  908. //
  909. // If the refcount is -1, then we need to disconnect from
  910. // the link and indicate disconnect. However, we need to
  911. // do this before we actually do the special deref, since
  912. // otherwise the connection might go away while we
  913. // are doing that.
  914. //
  915. // Note that both these routines are protected in that if they
  916. // are called twice, the second call will have no effect.
  917. //
  918. //
  919. // If both the connection and its link are active, then they have
  920. // mutual references to each other. We remove the link's
  921. // reference to the connection in NbfStopConnection, now
  922. // the reference count has fallen enough that we know it
  923. // is okay to remove the connection's reference to the
  924. // link.
  925. //
  926. if (NbfDisconnectFromLink (TransportConnection, TRUE)) {
  927. //
  928. // if the reference count goes to one, we can safely indicate the
  929. // user about disconnect states. That reference should
  930. // be for the connection's creation.
  931. //
  932. NbfIndicateDisconnect (TransportConnection);
  933. }
  934. //
  935. // Now it is OK to let the connection go away.
  936. //
  937. NbfDereferenceConnectionSpecial ("Regular ref gone", TransportConnection, CREF_SPECIAL_TEMP);
  938. }
  939. } /* NbfDerefConnection */
  940. VOID
  941. NbfDerefConnectionSpecial(
  942. IN PTP_CONNECTION TransportConnection
  943. )
  944. /*++
  945. Routine Description:
  946. This routines completes the dereferencing of a connection.
  947. It may be called any time, but it does not do its work until
  948. the regular reference count is also 0.
  949. Arguments:
  950. TransportConnection - Pointer to a transport connection object.
  951. Return Value:
  952. none.
  953. --*/
  954. {
  955. KIRQL oldirql;
  956. IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
  957. NbfPrint3 ("NbfDereferenceConnectionSpecial: entered for connection %lx, "
  958. "current level=%ld (%ld).\n",
  959. TransportConnection,
  960. TransportConnection->ReferenceCount,
  961. TransportConnection->SpecialRefCount);
  962. }
  963. #if DBG
  964. StoreConnectionHistory( TransportConnection, FALSE );
  965. #endif
  966. ACQUIRE_SPIN_LOCK (TransportConnection->ProviderInterlock, &oldirql);
  967. --TransportConnection->SpecialRefCount;
  968. if ((TransportConnection->SpecialRefCount == 0) &&
  969. (TransportConnection->ReferenceCount == -1)) {
  970. //
  971. // If we have deleted all references to this connection, then we can
  972. // destroy the object. It is okay to have already released the spin
  973. // lock at this point because there is no possible way that another
  974. // stream of execution has access to the connection any longer.
  975. //
  976. #if DBG
  977. {
  978. BOOLEAN TimerCancelled;
  979. TimerCancelled = KeCancelTimer (&TransportConnection->Timer);
  980. // ASSERT (TimerCancelled);
  981. }
  982. #endif
  983. RELEASE_SPIN_LOCK (TransportConnection->ProviderInterlock, oldirql);
  984. NbfDestroyConnection (TransportConnection);
  985. } else {
  986. RELEASE_SPIN_LOCK (TransportConnection->ProviderInterlock, oldirql);
  987. }
  988. } /* NbfDerefConnectionSpecial */
  989. VOID
  990. NbfClearConnectionLsn(
  991. IN PTP_CONNECTION TransportConnection
  992. )
  993. /*++
  994. Routine Description:
  995. This routine clears the LSN field in a connection. To do this is
  996. acquires the device context lock, and modifies the table value
  997. for that LSN depending on the type of the connection.
  998. NOTE: This routine is called with the connection spinlock held,
  999. or in a state where nobody else will be accessing the
  1000. connection.
  1001. Arguments:
  1002. TransportConnection - Pointer to a transport connection object.
  1003. Return Value:
  1004. none.
  1005. --*/
  1006. {
  1007. PDEVICE_CONTEXT DeviceContext;
  1008. KIRQL oldirql;
  1009. DeviceContext = TransportConnection->Provider;
  1010. ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
  1011. if (TransportConnection->Lsn != 0) {
  1012. if (TransportConnection->Flags2 & CONNECTION_FLAGS2_GROUP_LSN) {
  1013. //
  1014. // It was to a group address; the count should be
  1015. // LSN_TABLE_MAX.
  1016. //
  1017. ASSERT(DeviceContext->LsnTable[TransportConnection->Lsn] == LSN_TABLE_MAX);
  1018. DeviceContext->LsnTable[TransportConnection->Lsn] = 0;
  1019. TransportConnection->Flags2 &= ~CONNECTION_FLAGS2_GROUP_LSN;
  1020. } else {
  1021. ASSERT(DeviceContext->LsnTable[TransportConnection->Lsn] > 0);
  1022. --(DeviceContext->LsnTable[TransportConnection->Lsn]);
  1023. }
  1024. TransportConnection->Lsn = 0;
  1025. }
  1026. RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
  1027. }
  1028. PTP_CONNECTION
  1029. NbfLookupConnectionById(
  1030. IN PTP_ADDRESS Address,
  1031. IN USHORT ConnectionId
  1032. )
  1033. /*++
  1034. Routine Description:
  1035. This routine accepts a connection identifier and an address and
  1036. returns a pointer to the connection object, TP_CONNECTION. If the
  1037. connection identifier is not found on the address, then NULL is returned.
  1038. This routine automatically increments the reference count of the
  1039. TP_CONNECTION structure if it is found. It is assumed that the
  1040. TP_ADDRESS structure is already held with a reference count.
  1041. Arguments:
  1042. Address - Pointer to a transport address object.
  1043. ConnectionId - Identifier of the connection for this address.
  1044. Return Value:
  1045. A pointer to the connection we found
  1046. --*/
  1047. {
  1048. KIRQL oldirql, oldirql1;
  1049. PLIST_ENTRY p;
  1050. PTP_CONNECTION Connection;
  1051. BOOLEAN Found = FALSE;
  1052. IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
  1053. NbfPrint2 ("NbfLookupConnectionById: entered, Address: %lx ID: %lx\n",
  1054. Address, ConnectionId);
  1055. }
  1056. //
  1057. // Currently, this implementation is inefficient, but brute force so
  1058. // that a system can get up and running. Later, a cache of the mappings
  1059. // of popular connection id's and pointers to their TP_CONNECTION structures
  1060. // will be searched first.
  1061. //
  1062. ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
  1063. for (p=Address->ConnectionDatabase.Flink;
  1064. p != &Address->ConnectionDatabase;
  1065. p=p->Flink) {
  1066. Connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressList);
  1067. try {
  1068. ACQUIRE_C_SPIN_LOCK (&Connection->SpinLock, &oldirql1);
  1069. if (((Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) == 0) &&
  1070. (Connection->ConnectionId == ConnectionId)) {
  1071. // This reference is removed by the calling function
  1072. NbfReferenceConnection ("Lookup up for request", Connection, CREF_BY_ID);
  1073. Found = TRUE;
  1074. }
  1075. RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql1);
  1076. } except(EXCEPTION_EXECUTE_HANDLER) {
  1077. DbgPrint ("NBF: Got exception in NbfLookupConnectionById\n");
  1078. DbgBreakPoint();
  1079. RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql1);
  1080. }
  1081. if (Found) {
  1082. RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
  1083. return Connection;
  1084. }
  1085. }
  1086. RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
  1087. return NULL;
  1088. } /* NbfLookupConnectionById */
  1089. PTP_CONNECTION
  1090. NbfLookupConnectionByContext(
  1091. IN PTP_ADDRESS Address,
  1092. IN CONNECTION_CONTEXT ConnectionContext
  1093. )
  1094. /*++
  1095. Routine Description:
  1096. This routine accepts a connection identifier and an address and
  1097. returns a pointer to the connection object, TP_CONNECTION. If the
  1098. connection identifier is not found on the address, then NULL is returned.
  1099. This routine automatically increments the reference count of the
  1100. TP_CONNECTION structure if it is found. It is assumed that the
  1101. TP_ADDRESS structure is already held with a reference count.
  1102. Should the ConnectionDatabase go in the address file?
  1103. Arguments:
  1104. Address - Pointer to a transport address object.
  1105. ConnectionContext - Connection Context for this address.
  1106. Return Value:
  1107. A pointer to the connection we found
  1108. --*/
  1109. {
  1110. KIRQL oldirql, oldirql1;
  1111. PLIST_ENTRY p;
  1112. BOOLEAN Found = FALSE;
  1113. PTP_CONNECTION Connection;
  1114. IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
  1115. NbfPrint2 ("NbfLookupConnectionByContext: entered, Address: %lx Context: %lx\n",
  1116. Address, ConnectionContext);
  1117. }
  1118. //
  1119. // Currently, this implementation is inefficient, but brute force so
  1120. // that a system can get up and running. Later, a cache of the mappings
  1121. // of popular connection id's and pointers to their TP_CONNECTION structures
  1122. // will be searched first.
  1123. //
  1124. ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
  1125. for (p=Address->ConnectionDatabase.Flink;
  1126. p != &Address->ConnectionDatabase;
  1127. p=p->Flink) {
  1128. Connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressList);
  1129. try {
  1130. ACQUIRE_C_SPIN_LOCK (&Connection->SpinLock, &oldirql1);
  1131. if (Connection->Context == ConnectionContext) {
  1132. // This reference is removed by the calling function
  1133. NbfReferenceConnection ("Lookup up for request", Connection, CREF_LISTENING);
  1134. Found = TRUE;
  1135. }
  1136. RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql1);
  1137. } except(EXCEPTION_EXECUTE_HANDLER) {
  1138. DbgPrint ("NBF: Got exception in NbfLookupConnectionById\n");
  1139. DbgBreakPoint();
  1140. RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql1);
  1141. }
  1142. if (Found) {
  1143. RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
  1144. return Connection;
  1145. }
  1146. }
  1147. RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
  1148. return NULL;
  1149. } /* NbfLookupConnectionByContext */
  1150. PTP_CONNECTION
  1151. NbfLookupListeningConnection(
  1152. IN PTP_ADDRESS Address,
  1153. IN PUCHAR RemoteName
  1154. )
  1155. /*++
  1156. Routine Description:
  1157. This routine scans the connection database on an address to find
  1158. a TP_CONNECTION object which has LSN=0 and CONNECTION_FLAGS_WAIT_NQ
  1159. flag set. It returns a pointer to the found connection object (and
  1160. simultaneously resets the flag) or NULL if it could not be found.
  1161. The reference count is also incremented atomically on the connection.
  1162. The list is scanned for listens posted to this specific remote
  1163. name, or to those with no remote name specified.
  1164. Arguments:
  1165. Address - Pointer to a transport address object.
  1166. RemoteName - The name of the remote.
  1167. Return Value:
  1168. NTSTATUS - status of operation.
  1169. --*/
  1170. {
  1171. KIRQL oldirql, oldirql1;
  1172. PTP_CONNECTION Connection;
  1173. PLIST_ENTRY p, q;
  1174. PTP_REQUEST ListenRequest;
  1175. IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
  1176. NbfPrint0 ("NbfLookupListeningConnection: Entered.\n");
  1177. }
  1178. //
  1179. // Currently, this implementation is inefficient, but brute force so
  1180. // that a system can get up and running. Later, a cache of the mappings
  1181. // of popular connection id's and pointers to their TP_CONNECTION structures
  1182. // will be searched first.
  1183. //
  1184. ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
  1185. for (p=Address->ConnectionDatabase.Flink;
  1186. p != &Address->ConnectionDatabase;
  1187. p=p->Flink) {
  1188. Connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressList);
  1189. ACQUIRE_C_SPIN_LOCK (&Connection->SpinLock, &oldirql1);
  1190. if ((Connection->Lsn == 0) &&
  1191. (Connection->Flags2 & CONNECTION_FLAGS2_WAIT_NQ)) {
  1192. q = Connection->InProgressRequest.Flink;
  1193. if (q != &Connection->InProgressRequest) {
  1194. ListenRequest = CONTAINING_RECORD (q, TP_REQUEST, Linkage);
  1195. if ((ListenRequest->Buffer2 != NULL) &&
  1196. (!RtlEqualMemory(
  1197. ListenRequest->Buffer2,
  1198. RemoteName,
  1199. NETBIOS_NAME_LENGTH))) {
  1200. RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql1);
  1201. continue;
  1202. }
  1203. } else {
  1204. RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql1);
  1205. continue;
  1206. }
  1207. // This reference is removed by the calling function
  1208. NbfReferenceConnection ("Found Listening", Connection, CREF_LISTENING);
  1209. Connection->Flags2 &= ~CONNECTION_FLAGS2_WAIT_NQ;
  1210. RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql1);
  1211. RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
  1212. IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
  1213. NbfPrint1 ("NbfLookupListeningConnection: Found Connection %lx\n",Connection);
  1214. }
  1215. return Connection;
  1216. }
  1217. RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql1);
  1218. }
  1219. RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
  1220. IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
  1221. NbfPrint0 ("NbfLookupListeningConnection: Found No Connection!\n");
  1222. }
  1223. return NULL;
  1224. } /* NbfLookupListeningConnection */
  1225. VOID
  1226. NbfStopConnection(
  1227. IN PTP_CONNECTION Connection,
  1228. IN NTSTATUS Status
  1229. )
  1230. /*++
  1231. Routine Description:
  1232. This routine is called to terminate all activity on a connection and
  1233. destroy the object. This is done in a graceful manner; i.e., all
  1234. outstanding requests are terminated by cancelling them, etc. It is
  1235. assumed that the caller has a reference to this connection object,
  1236. but this routine will do the dereference for the one issued at creation
  1237. time.
  1238. Orderly release is a function of this routine, but it is not a provided
  1239. service of this transport provider, so there is no code to do it here.
  1240. NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
  1241. Arguments:
  1242. Connection - Pointer to a TP_CONNECTION object.
  1243. Status - The status that caused us to stop the connection. This
  1244. will determine what status pending requests are aborted with,
  1245. and also how we proceed during the stop (whether to send a
  1246. session end, and whether to indicate disconnect).
  1247. Return Value:
  1248. none.
  1249. --*/
  1250. {
  1251. KIRQL cancelirql;
  1252. PLIST_ENTRY p;
  1253. PIRP Irp;
  1254. PTP_REQUEST Request;
  1255. BOOLEAN TimerWasCleared;
  1256. ULONG DisconnectReason;
  1257. PULONG StopCounter;
  1258. PDEVICE_CONTEXT DeviceContext;
  1259. IF_NBFDBG (NBF_DEBUG_TEARDOWN | NBF_DEBUG_PNP) {
  1260. NbfPrint3 ("NbfStopConnection: Entered for connection %lx LSN %x RSN %x.\n",
  1261. Connection, Connection->Lsn, Connection->Rsn);
  1262. }
  1263. ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
  1264. DeviceContext = Connection->Provider;
  1265. ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  1266. if (!(Connection->Flags2 & CONNECTION_FLAGS2_STOPPING)) {
  1267. //
  1268. // We are stopping the connection, record statistics
  1269. // about it.
  1270. //
  1271. if (Connection->Flags & CONNECTION_FLAGS_READY) {
  1272. DECREMENT_COUNTER (DeviceContext, OpenConnections);
  1273. }
  1274. Connection->Flags2 |= CONNECTION_FLAGS2_STOPPING;
  1275. Connection->Flags2 &= ~CONNECTION_FLAGS2_REMOTE_VALID;
  1276. Connection->Status = Status;
  1277. if (Connection->Link != NULL) {
  1278. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1279. Connection->Flags &= ~(CONNECTION_FLAGS_READY|
  1280. CONNECTION_FLAGS_WAIT_SI|
  1281. CONNECTION_FLAGS_WAIT_SC); // no longer open for business
  1282. Connection->SendState = CONNECTION_SENDSTATE_IDLE;
  1283. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1284. }
  1285. //
  1286. // If this flag was on, turn it off.
  1287. //
  1288. Connection->Flags &= ~CONNECTION_FLAGS_W_RESYNCH;
  1289. //
  1290. // Stop the timer if it was running.
  1291. //
  1292. TimerWasCleared = KeCancelTimer (&Connection->Timer);
  1293. IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
  1294. NbfPrint2 ("NbfStopConnection: Timer for connection %lx "
  1295. "%s canceled.\n", Connection,
  1296. TimerWasCleared ? "was" : "was NOT" );
  1297. }
  1298. switch (Status) {
  1299. case STATUS_LOCAL_DISCONNECT:
  1300. StopCounter = &DeviceContext->Statistics.LocalDisconnects;
  1301. break;
  1302. case STATUS_REMOTE_DISCONNECT:
  1303. StopCounter = &DeviceContext->Statistics.RemoteDisconnects;
  1304. break;
  1305. case STATUS_LINK_FAILED:
  1306. StopCounter = &DeviceContext->Statistics.LinkFailures;
  1307. break;
  1308. case STATUS_IO_TIMEOUT:
  1309. StopCounter = &DeviceContext->Statistics.SessionTimeouts;
  1310. break;
  1311. case STATUS_CANCELLED:
  1312. StopCounter = &DeviceContext->Statistics.CancelledConnections;
  1313. break;
  1314. case STATUS_REMOTE_RESOURCES:
  1315. StopCounter = &DeviceContext->Statistics.RemoteResourceFailures;
  1316. break;
  1317. case STATUS_INSUFFICIENT_RESOURCES:
  1318. StopCounter = &DeviceContext->Statistics.LocalResourceFailures;
  1319. break;
  1320. case STATUS_BAD_NETWORK_PATH:
  1321. StopCounter = &DeviceContext->Statistics.NotFoundFailures;
  1322. break;
  1323. case STATUS_REMOTE_NOT_LISTENING:
  1324. StopCounter = &DeviceContext->Statistics.NoListenFailures;
  1325. break;
  1326. default:
  1327. StopCounter = NULL;
  1328. break;
  1329. }
  1330. if (StopCounter != NULL) {
  1331. (*StopCounter)++;
  1332. }
  1333. RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  1334. //
  1335. // Run down all TdiConnect/TdiDisconnect/TdiListen requests.
  1336. //
  1337. IoAcquireCancelSpinLock(&cancelirql);
  1338. ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  1339. while (TRUE) {
  1340. p = RemoveHeadList (&Connection->InProgressRequest);
  1341. if (p == &Connection->InProgressRequest) {
  1342. break;
  1343. }
  1344. RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  1345. Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
  1346. IoSetCancelRoutine(Request->IoRequestPacket, NULL);
  1347. IoReleaseCancelSpinLock(cancelirql);
  1348. #if DBG
  1349. IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
  1350. LARGE_INTEGER MilliSeconds, Time;
  1351. ULONG junk;
  1352. KeQuerySystemTime (&Time);
  1353. MilliSeconds.LowPart = Time.LowPart;
  1354. MilliSeconds.HighPart = Time.HighPart;
  1355. MilliSeconds.QuadPart = MilliSeconds.QuadPart -
  1356. (Request->Time).QuadPart;
  1357. MilliSeconds = RtlExtendedLargeIntegerDivide (MilliSeconds, 10000L, &junk);
  1358. NbfPrint3 ("NbfStopConnection: Canceling pending CONNECT, Irp: %lx Time Pending: %ld%ld msec\n",
  1359. Request->IoRequestPacket, MilliSeconds.HighPart, MilliSeconds.LowPart);
  1360. }
  1361. #endif
  1362. NbfCompleteRequest (Request, Connection->Status, 0);
  1363. IoAcquireCancelSpinLock(&cancelirql);
  1364. ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  1365. }
  1366. if (Connection->Link == NULL) {
  1367. //
  1368. // We are stopping early on.
  1369. //
  1370. RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  1371. IoReleaseCancelSpinLock (cancelirql);
  1372. if (TimerWasCleared) {
  1373. NbfDereferenceConnection ("Stopping timer", Connection, CREF_TIMER); // account for timer reference.
  1374. }
  1375. ASSERT (Connection->SendState == CONNECTION_SENDSTATE_IDLE);
  1376. ASSERT (!Connection->OnPacketWaitQueue);
  1377. ASSERT (!Connection->OnDataAckQueue);
  1378. ASSERT (!(Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_ACK));
  1379. ASSERT (IsListEmpty(&Connection->SendQueue));
  1380. ASSERT (IsListEmpty(&Connection->ReceiveQueue));
  1381. return;
  1382. }
  1383. RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  1384. IoReleaseCancelSpinLock (cancelirql);
  1385. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1386. //
  1387. // If this connection is waiting to packetize,
  1388. // remove it from the device context queue it is on.
  1389. //
  1390. // NOTE: If the connection is currently in the
  1391. // packetize queue, it will eventually go to get
  1392. // packetized and at that point it will get
  1393. // removed.
  1394. //
  1395. if (Connection->OnPacketWaitQueue) {
  1396. IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
  1397. NbfPrint1("Stop waiting connection, flags %lx\n",
  1398. Connection->Flags);
  1399. }
  1400. ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
  1401. Connection->OnPacketWaitQueue = FALSE;
  1402. ASSERT ((Connection->Flags & CONNECTION_FLAGS_SEND_SE) == 0);
  1403. Connection->Flags &= ~(CONNECTION_FLAGS_STARVED|CONNECTION_FLAGS_W_PACKETIZE);
  1404. RemoveEntryList (&Connection->PacketWaitLinkage);
  1405. RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
  1406. }
  1407. //
  1408. // If we are on the data ack queue, then take ourselves off.
  1409. //
  1410. ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
  1411. if (Connection->OnDataAckQueue) {
  1412. RemoveEntryList (&Connection->DataAckLinkage);
  1413. Connection->OnDataAckQueue = FALSE;
  1414. DeviceContext->DataAckQueueChanged = TRUE;
  1415. }
  1416. RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
  1417. //
  1418. // If this connection is waiting to send a piggyback ack,
  1419. // remove it from the device context queue for that, and
  1420. // send a data ack (which will get there before the
  1421. // SessionEnd).
  1422. //
  1423. if ((Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_ACK) != 0) {
  1424. #if DBG
  1425. {
  1426. extern ULONG NbfDebugPiggybackAcks;
  1427. if (NbfDebugPiggybackAcks) {
  1428. NbfPrint1("Stop waiting connection, deferred flags %lx\n",
  1429. Connection->DeferredFlags);
  1430. }
  1431. }
  1432. #endif
  1433. Connection->DeferredFlags &=
  1434. ~(CONNECTION_FLAGS_DEFERRED_ACK | CONNECTION_FLAGS_DEFERRED_NOT_Q);
  1435. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1436. NbfSendDataAck (Connection);
  1437. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1438. }
  1439. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1440. if (TimerWasCleared) {
  1441. NbfDereferenceConnection ("Stopping timer", Connection, CREF_TIMER); // account for timer reference.
  1442. }
  1443. IoAcquireCancelSpinLock(&cancelirql);
  1444. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1445. //
  1446. // Run down all TdiSend requests on this connection.
  1447. //
  1448. while (TRUE) {
  1449. p = RemoveHeadList (&Connection->SendQueue);
  1450. if (p == &Connection->SendQueue) {
  1451. break;
  1452. }
  1453. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1454. Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
  1455. IoSetCancelRoutine(Irp, NULL);
  1456. IoReleaseCancelSpinLock(cancelirql);
  1457. #if DBG
  1458. IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
  1459. NbfPrint1("NbfStopConnection: Canceling pending SEND, Irp: %lx\n",
  1460. Irp);
  1461. }
  1462. #endif
  1463. NbfCompleteSendIrp (Irp, Connection->Status, 0);
  1464. IoAcquireCancelSpinLock(&cancelirql);
  1465. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1466. ++Connection->TransmissionErrors;
  1467. }
  1468. //
  1469. // NOTE: We hold the connection spinlock AND the
  1470. // cancel spinlock here.
  1471. //
  1472. Connection->Flags &= ~CONNECTION_FLAGS_ACTIVE_RECEIVE;
  1473. //
  1474. // Run down all TdiReceive requests on this connection.
  1475. //
  1476. while (TRUE) {
  1477. p = RemoveHeadList (&Connection->ReceiveQueue);
  1478. if (p == &Connection->ReceiveQueue) {
  1479. break;
  1480. }
  1481. Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
  1482. IoSetCancelRoutine(Irp, NULL);
  1483. #if DBG
  1484. IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
  1485. NbfPrint1 ("NbfStopConnection: Canceling pending RECEIVE, Irp: %lx\n",
  1486. Irp);
  1487. }
  1488. #endif
  1489. //
  1490. // It is OK to call this with the locks held.
  1491. //
  1492. NbfCompleteReceiveIrp (Irp, Connection->Status, 0);
  1493. ++Connection->ReceiveErrors;
  1494. }
  1495. //
  1496. // NOTE: We hold the connection spinlock AND the
  1497. // cancel spinlock here.
  1498. //
  1499. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1500. IoReleaseCancelSpinLock(cancelirql);
  1501. //
  1502. // If we aren't DESTROYing the link, then send a SESSION_END frame
  1503. // to the remote side. When the SESSION_END frame is acknowleged,
  1504. // we will decrement the connection's reference count by one, removing
  1505. // its creation reference. This will cause the connection object to
  1506. // be disposed of, and will begin running down the link.
  1507. // DGB: add logic to avoid blowing away link if one doesn't exist yet.
  1508. //
  1509. ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  1510. DisconnectReason = 0;
  1511. if (Connection->Flags2 & CONNECTION_FLAGS2_ABORT) {
  1512. DisconnectReason |= TDI_DISCONNECT_ABORT;
  1513. }
  1514. if (Connection->Flags2 & CONNECTION_FLAGS2_DESTROY) {
  1515. DisconnectReason |= TDI_DISCONNECT_RELEASE;
  1516. }
  1517. if (Connection->Link != NULL) {
  1518. RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  1519. if ((Status == STATUS_LOCAL_DISCONNECT) ||
  1520. (Status == STATUS_CANCELLED)) {
  1521. //
  1522. // (note that a connection should only get stopped
  1523. // with STATUS_INSUFFICIENT_RESOURCES if it is not
  1524. // yet connected to the remote).
  1525. //
  1526. //
  1527. // If this is done, when this packet is destroyed
  1528. // it will dereference the connection for CREF_LINK.
  1529. //
  1530. NbfSendSessionEnd (
  1531. Connection,
  1532. (BOOLEAN)((DisconnectReason & TDI_DISCONNECT_ABORT) != 0));
  1533. } else {
  1534. //
  1535. // Not attached to the link anymore; this dereference
  1536. // will allow our reference to fall below 3, which
  1537. // will cause NbfDisconnectFromLink to be called.
  1538. //
  1539. NbfDereferenceConnection("Stopped", Connection, CREF_LINK);
  1540. }
  1541. } else {
  1542. RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  1543. }
  1544. //
  1545. // Note that we've blocked all new requests being queued during the
  1546. // time we have been in this teardown code; NbfDestroyConnection also
  1547. // sets the connection flags to STOPPING when returning the
  1548. // connection to the queue. This avoids lingerers using non-existent
  1549. // connections.
  1550. //
  1551. } else {
  1552. //
  1553. // The connection was already stopping; it may have a
  1554. // SESSION_END pending in which case we should kill
  1555. // it.
  1556. //
  1557. if ((Status != STATUS_LOCAL_DISCONNECT) &&
  1558. (Status != STATUS_CANCELLED)) {
  1559. if (Connection->Flags & CONNECTION_FLAGS_SEND_SE) {
  1560. ASSERT (Connection->Link != NULL);
  1561. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1562. Connection->Flags &= ~CONNECTION_FLAGS_SEND_SE;
  1563. if (Connection->OnPacketWaitQueue) {
  1564. ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
  1565. #if DBG
  1566. DbgPrint ("NBF: Removing connection %lx from PacketWait for SESSION_END\n", Connection);
  1567. #endif
  1568. Connection->OnPacketWaitQueue = FALSE;
  1569. RemoveEntryList (&Connection->PacketWaitLinkage);
  1570. RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
  1571. }
  1572. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1573. RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  1574. NbfDereferenceConnection("Stopped again", Connection, CREF_LINK);
  1575. return;
  1576. }
  1577. }
  1578. RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  1579. }
  1580. } /* NbfStopConnection */
  1581. VOID
  1582. NbfCancelConnection(
  1583. IN PDEVICE_OBJECT DeviceObject,
  1584. IN PIRP Irp
  1585. )
  1586. /*++
  1587. Routine Description:
  1588. This routine is called by the I/O system to cancel a connect
  1589. or a listen. It is simple since there can only be one of these
  1590. active on a connection; we just stop the connection, the IRP
  1591. will get completed as part of normal session teardown.
  1592. NOTE: This routine is called with the CancelSpinLock held and
  1593. is responsible for releasing it.
  1594. Arguments:
  1595. DeviceObject - Pointer to the device object for this driver.
  1596. Irp - Pointer to the request packet representing the I/O request.
  1597. Return Value:
  1598. none.
  1599. --*/
  1600. {
  1601. KIRQL oldirql;
  1602. PIO_STACK_LOCATION IrpSp;
  1603. PTP_CONNECTION Connection;
  1604. PTP_REQUEST Request;
  1605. PLIST_ENTRY p;
  1606. BOOLEAN fCanceled = TRUE;
  1607. UNREFERENCED_PARAMETER (DeviceObject);
  1608. //
  1609. // Get a pointer to the current stack location in the IRP. This is where
  1610. // the function codes and parameters are stored.
  1611. //
  1612. IrpSp = IoGetCurrentIrpStackLocation (Irp);
  1613. ASSERT ((IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
  1614. (IrpSp->MinorFunction == TDI_CONNECT || IrpSp->MinorFunction == TDI_LISTEN));
  1615. Connection = IrpSp->FileObject->FsContext;
  1616. //
  1617. // Since this IRP is still in the cancellable state, we know
  1618. // that the connection is still around (although it may be in
  1619. // the process of being torn down).
  1620. //
  1621. ACQUIRE_C_SPIN_LOCK (&Connection->SpinLock, &oldirql);
  1622. NbfReferenceConnection ("Cancelling Send", Connection, CREF_TEMP);
  1623. p = RemoveHeadList (&Connection->InProgressRequest);
  1624. ASSERT (p != &Connection->InProgressRequest);
  1625. RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql);
  1626. Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
  1627. ASSERT (Request->IoRequestPacket == Irp);
  1628. #ifdef RASAUTODIAL
  1629. //
  1630. // If there's an automatic connection in
  1631. // progress, cancel it.
  1632. //
  1633. if (Connection->Flags2 & CONNECTION_FLAGS2_AUTOCONNECTING)
  1634. fCanceled = NbfCancelTdiConnect(NULL, Irp);
  1635. #endif // RASAUTODIAL
  1636. if (fCanceled)
  1637. IoSetCancelRoutine(Request->IoRequestPacket, NULL);
  1638. IoReleaseCancelSpinLock(Irp->CancelIrql);
  1639. if (fCanceled) {
  1640. IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
  1641. NbfPrint2("NBF: Cancelled in-progress connect/listen %lx on %lx\n",
  1642. Request->IoRequestPacket, Connection);
  1643. }
  1644. KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
  1645. NbfCompleteRequest (Request, STATUS_CANCELLED, 0);
  1646. NbfStopConnection (Connection, STATUS_LOCAL_DISCONNECT); // prevent indication to clients
  1647. KeLowerIrql (oldirql);
  1648. }
  1649. NbfDereferenceConnection ("Cancel done", Connection, CREF_TEMP);
  1650. }
  1651. #if 0
  1652. VOID
  1653. NbfWaitConnectionOnLink(
  1654. IN PTP_CONNECTION Connection,
  1655. IN ULONG Flags
  1656. )
  1657. /*++
  1658. Routine Description:
  1659. This routine is called to suspend a connection's activities because
  1660. the specified session-oriented frame could not be sent due to link
  1661. problems. Routines in FRAMESND.C call this.
  1662. NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
  1663. Arguments:
  1664. Connection - Pointer to a TP_CONNECTION object.
  1665. Flags - Field containing bitflag set to indicate starved frame to be sent.
  1666. Return Value:
  1667. none.
  1668. --*/
  1669. {
  1670. IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
  1671. NbfPrint0 ("NbfWaitConnectionOnLink: Entered.\n");
  1672. }
  1673. ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  1674. if (((Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) == 0) ||
  1675. (Flags == CONNECTION_FLAGS_SEND_SE)) {
  1676. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1677. Connection->Flags |= Flags;
  1678. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1679. }
  1680. RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  1681. } /* NbfWaitConnectionOnLink */
  1682. #endif
  1683. VOID
  1684. NbfStartConnectionTimer(
  1685. IN PTP_CONNECTION Connection,
  1686. IN PKDEFERRED_ROUTINE TimeoutFunction,
  1687. IN ULONG WaitTime
  1688. )
  1689. /*++
  1690. Routine Description:
  1691. This routine is called to start a timeout on NAME_QUERY/NAME_RECOGNIZED
  1692. activities on a connection.
  1693. Arguments:
  1694. TransportConnection - Pointer to a TP_CONNECTION object.
  1695. TimeoutFunction - The function to call when the timer fires.
  1696. WaitTime - a longword containing the low order time to wait.
  1697. Return Value:
  1698. none.
  1699. --*/
  1700. {
  1701. LARGE_INTEGER Timeout;
  1702. BOOLEAN AlreadyInserted;
  1703. IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
  1704. NbfPrint1 ("NbfStartConnectionTimer: Entered for connection %lx.\n",
  1705. Connection );
  1706. }
  1707. //
  1708. // Start the timer. Unlike the link timers, this is simply a kernel-
  1709. // managed object.
  1710. //
  1711. Timeout.LowPart = (ULONG)(-(LONG)WaitTime);
  1712. Timeout.HighPart = -1;
  1713. //
  1714. // Take the lock so we synchronize the cancelling with
  1715. // restarting the timer. This is so two threads won't
  1716. // both fail to cancel and then start the timer at the
  1717. // same time (it messes up the reference count).
  1718. //
  1719. ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  1720. AlreadyInserted = KeCancelTimer (&Connection->Timer);
  1721. KeInitializeDpc (
  1722. &Connection->Dpc,
  1723. TimeoutFunction,
  1724. (PVOID)Connection);
  1725. KeSetTimer (
  1726. &Connection->Timer,
  1727. Timeout,
  1728. &Connection->Dpc);
  1729. RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
  1730. //
  1731. // If the timer wasn't already running, reference the connection to
  1732. // account for the new timer. If the timer was already started,
  1733. // then KeCancelTimer will have returned TRUE. In this
  1734. // case, the prior call to NbfStartConnectionTimer referenced the
  1735. // connection, so we don't do it again here.
  1736. //
  1737. if ( !AlreadyInserted ) {
  1738. // This reference is removed in ConnectionEstablishmentTimeout,
  1739. // or when the timer is cancelled.
  1740. NbfReferenceConnection ("starting timer", Connection, CREF_TIMER);
  1741. }
  1742. } /* NbfStartConnectionTimer */