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.

2327 lines
65 KiB

  1. /*++
  2. Copyright (c) 1989, 1990, 1991 Microsoft Corporation
  3. Module Name:
  4. link.c
  5. Abstract:
  6. This module contains code which implements the TP_LINK object.
  7. Routines are provided to create, destroy, reference, and dereference,
  8. transport link objects.
  9. Author:
  10. David Beaver (dbeaver) 1-July-1991
  11. Environment:
  12. Kernel mode
  13. Revision History:
  14. --*/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. extern ULONG StartTimerLinkDeferredAdd;
  18. extern ULONG StartTimerLinkDeferredDelete;
  19. #if DBG
  20. // The following is here for debugging purposes to make it easy to change
  21. // the maximum packet size.
  22. ULONG MaxUserPacketData = 18000;
  23. #endif
  24. #if 0
  25. VOID
  26. DisconnectCompletionHandler(
  27. IN PTP_LINK TransportLink
  28. )
  29. /*++
  30. Routine Description:
  31. This routine is called as an I/O completion handler at the time a
  32. TdiDisconnect request is completed. Here we dereference the link
  33. object, and optionally reference it again and start up the link if
  34. some transport connection started up on the link during the time we
  35. were trying to shut it down.
  36. Arguments:
  37. TransportLink - Pointer to a transport link object.
  38. Return Value:
  39. none.
  40. --*/
  41. {
  42. IF_NBFDBG (NBF_DEBUG_LINK) {
  43. NbfPrint1 ("DisconnectCompletionHandler: Entered for link %lx.\n",
  44. TransportLink);
  45. }
  46. //
  47. // The following call will dereference this link for the last time,
  48. // unless another transport connection has been assigned to the link
  49. // during the time the data link layer was bringing the link down and
  50. // when we got here. If this condition exists, then now is the time
  51. // to bring the link back up, else destroy it.
  52. //
  53. // don't forget to check for bringing it back up again.
  54. NbfDereferenceLink ("Disconnecting", TransportLink, LREF_CONNECTION); // this makes it go away.
  55. #if DBG
  56. NbfPrint0("Disconnecting Completion Handler\n");
  57. #endif
  58. } /* DisconnectCompletionHandler */
  59. #endif
  60. VOID
  61. NbfCompleteLink(
  62. IN PTP_LINK Link
  63. )
  64. /*++
  65. Routine Description:
  66. This routine is called by the UA-r/x handler, NbfWaitLink, and
  67. NbfActivateLink to startup the NBF connections associated with
  68. a link because they were waiting for the link to become established.
  69. When we get here, the link has been established, so we need to
  70. start the next set of connection-establishment protocols:
  71. SESSION_INIT ----------------->
  72. <----------------- SESSION_CONFIRM
  73. (TdiConnect completes) (TdiListen completes)
  74. NOTE: THIS ROUTINE MUST BE CALLED FROM DPC LEVEL.
  75. Arguments:
  76. Link - Pointer to a transport link object.
  77. Return Value:
  78. none.
  79. --*/
  80. {
  81. PTP_CONNECTION Connection;
  82. BOOLEAN TimerWasCleared;
  83. IF_NBFDBG (NBF_DEBUG_LINK) {
  84. NbfPrint1 ("NbfCompleteLink: Entered for link %lx.\n", Link);
  85. }
  86. ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
  87. //
  88. // Officially declare that this link is ready for I-frame business.
  89. //
  90. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
  91. //
  92. // We can now send and receive I-frames on this link. We are in ABME.
  93. //
  94. //
  95. // This probably isn't necessary, but to be safe for now.. (adb 6/28)
  96. //
  97. if (Link->State == LINK_STATE_ADM) {
  98. // Moving out of ADM, add special reference
  99. NbfReferenceLinkSpecial("To READY in NbfCompleteLink", Link, LREF_NOT_ADM);
  100. }
  101. Link->State = LINK_STATE_READY;
  102. Link->SendState = SEND_STATE_READY;
  103. Link->ReceiveState = RECEIVE_STATE_READY;
  104. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  105. //
  106. // Complete all of the listens first, so they will be expecting
  107. // incoming SESSION_INITIALIZEs. Then do the connects.
  108. //
  109. // This creates a connection reference which is removed below.
  110. while ((Connection=NbfLookupPendingListenOnLink (Link)) != NULL) {
  111. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  112. //
  113. // This loop looks unnecessary, let's make sure... - adb 9/11/91
  114. //
  115. ASSERT(Connection->Flags & CONNECTION_FLAGS_WAIT_SI);
  116. Connection->Flags |= CONNECTION_FLAGS_WAIT_SI; // wait session initialize.
  117. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  118. NbfDereferenceConnection ("Pending listen", Connection, CREF_P_LINK);
  119. } /* while */
  120. //
  121. // And do the connects. If there are connections in progress, they'll
  122. // also have timers associated with them. Cancel those timers.
  123. //
  124. while ((Connection=NbfLookupPendingConnectOnLink (Link)) != NULL) {
  125. TimerWasCleared = KeCancelTimer (&Connection->Timer);
  126. IF_NBFDBG (NBF_DEBUG_LINK) {
  127. NbfPrint2 ("NbfCompleteLink: Timer for connection %lx %s canceled.\n",
  128. Connection, TimerWasCleared ? "was" : "was NOT" );
  129. }
  130. if (TimerWasCleared) {
  131. NbfDereferenceConnection("Cancel timer", Connection, CREF_TIMER);
  132. }
  133. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  134. Connection->Flags |= CONNECTION_FLAGS_WAIT_SC; // wait session confirm.
  135. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  136. //
  137. // No timeout for this frame is required since the link is responsible
  138. // for reliable delivery. If we can't send this frame, however, the
  139. // data link connection will happily keep quiet without timeouts.
  140. //
  141. NbfSendSessionInitialize (Connection);
  142. NbfDereferenceConnection ("NbfCompleteLink", Connection, CREF_P_CONNECT);
  143. } /* while */
  144. } /* NbfCompleteLink */
  145. VOID
  146. NbfAllocateLink(
  147. IN PDEVICE_CONTEXT DeviceContext,
  148. OUT PTP_LINK *TransportLink
  149. )
  150. /*++
  151. Routine Description:
  152. This routine allocates storage for a data link connection. It
  153. performs minimal initialization of the object.
  154. NOTE: This routine is called with the device context spinlock
  155. held, or at such a time as synchronization is unnecessary.
  156. Arguments:
  157. DeviceContext - Pointer to the device context (which is really just
  158. the device object with its extension) to be associated with the
  159. link.
  160. TransportLink - Pointer to a place where this routine will return a
  161. pointer to an allocated transport link structure. Returns
  162. NULL if no storage can be allocated.
  163. Return Value:
  164. None.
  165. --*/
  166. {
  167. PTP_LINK Link;
  168. if ((DeviceContext->MemoryLimit != 0) &&
  169. ((DeviceContext->MemoryUsage + sizeof(TP_LINK)) >
  170. DeviceContext->MemoryLimit)) {
  171. PANIC("NBF: Could not allocate link: limit\n");
  172. NbfWriteResourceErrorLog(
  173. DeviceContext,
  174. EVENT_TRANSPORT_RESOURCE_LIMIT,
  175. 105,
  176. sizeof(TP_LINK),
  177. LINK_RESOURCE_ID);
  178. *TransportLink = NULL;
  179. return;
  180. }
  181. Link = (PTP_LINK)ExAllocatePoolWithTag (
  182. NonPagedPool,
  183. sizeof (TP_LINK),
  184. NBF_MEM_TAG_TP_LINK);
  185. if (Link == NULL) {
  186. PANIC("NBF: Could not allocate link: no pool\n");
  187. NbfWriteResourceErrorLog(
  188. DeviceContext,
  189. EVENT_TRANSPORT_RESOURCE_POOL,
  190. 205,
  191. sizeof(TP_LINK),
  192. LINK_RESOURCE_ID);
  193. *TransportLink = NULL;
  194. return;
  195. }
  196. RtlZeroMemory (Link, sizeof(TP_LINK));
  197. IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
  198. NbfPrint1 ("ExAllocatePool Link %08x\n", Link);
  199. }
  200. ++DeviceContext->LinkAllocated;
  201. DeviceContext->MemoryUsage += sizeof(TP_LINK);
  202. Link->Type = NBF_LINK_SIGNATURE;
  203. Link->Size = sizeof (TP_LINK);
  204. KeInitializeSpinLock (&Link->SpinLock);
  205. Link->Provider = DeviceContext;
  206. Link->ProviderInterlock = &DeviceContext->Interlock;
  207. InitializeListHead (&Link->Linkage);
  208. InitializeListHead (&Link->ConnectionDatabase);
  209. InitializeListHead (&Link->WackQ);
  210. InitializeListHead (&Link->NdisSendQueue);
  211. InitializeListHead (&Link->ShortList);
  212. Link->OnShortList = FALSE;
  213. InitializeListHead (&Link->LongList);
  214. Link->OnLongList = FALSE;
  215. InitializeListHead (&Link->PurgeList);
  216. Link->T1 = 0; // 0 indicates they are not in the list
  217. Link->T2 = 0;
  218. Link->Ti = 0;
  219. NbfAddSendPacket (DeviceContext);
  220. NbfAddReceivePacket (DeviceContext);
  221. *TransportLink = Link;
  222. } /* NbfAllocateLink */
  223. VOID
  224. NbfDeallocateLink(
  225. IN PDEVICE_CONTEXT DeviceContext,
  226. IN PTP_LINK TransportLink
  227. )
  228. /*++
  229. Routine Description:
  230. This routine frees storage for a data link connection.
  231. NOTE: This routine is called with the device context spinlock
  232. held, or at such a time as synchronization is unnecessary.
  233. Arguments:
  234. DeviceContext - Pointer to the device context (which is really just
  235. the device object with its extension) to be associated with the
  236. link.
  237. TransportLink - Pointer to the transport link structure.
  238. Return Value:
  239. None.
  240. --*/
  241. {
  242. IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
  243. NbfPrint1 ("ExFreePool Link: %08x\n", TransportLink);
  244. }
  245. ExFreePool (TransportLink);
  246. --DeviceContext->LinkAllocated;
  247. DeviceContext->MemoryUsage -= sizeof(TP_LINK);
  248. NbfRemoveSendPacket (DeviceContext);
  249. NbfRemoveReceivePacket (DeviceContext);
  250. } /* NbfDeallocateLink */
  251. NTSTATUS
  252. NbfCreateLink(
  253. IN PDEVICE_CONTEXT DeviceContext,
  254. IN PHARDWARE_ADDRESS HardwareAddress,
  255. IN PUCHAR SourceRouting,
  256. IN UINT SourceRoutingLength,
  257. IN USHORT LoopbackLinkIndex,
  258. OUT PTP_LINK *TransportLink
  259. )
  260. /*++
  261. Routine Description:
  262. This routine creates a data link connection between the local
  263. data link station and the specified remote data link address.
  264. As an option (Passive=TRUE), the caller may specify that instead
  265. of a Connect activity, a Listen is to be performed instead.
  266. Normally, if a link to the remote address is not already active,
  267. then a link object is allocated, the reference count in the link
  268. is set to 1, and the reference count of the device context is
  269. incremented.
  270. If a link is already active to the remote address, then the existing
  271. link object is referenced with NbfReferenceLink() so that it can be
  272. shared between the transport connections.
  273. NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
  274. Arguments:
  275. DeviceContext - Pointer to the device context (which is really just
  276. the device object with its extension) to be associated with the
  277. link.
  278. HardwareAddress - Pointer to a HARDWARE_ADDRESS type containing the
  279. hardware address of the REMOTE link station to connect to/listen for.
  280. LoopbackLinkIndex - In the case that this turns out to be created
  281. as one of the LoopbackLinks, this will indicate which one to
  282. use.
  283. TransportLink - Pointer to a place where this routine will return a
  284. pointer to an allocated transport link structure.
  285. Return Value:
  286. NTSTATUS - status of operation.
  287. --*/
  288. {
  289. PTP_LINK Link;
  290. PLIST_ENTRY p;
  291. UCHAR TempSR[MAX_SOURCE_ROUTING];
  292. PUCHAR ResponseSR;
  293. USHORT i;
  294. ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
  295. IF_NBFDBG (NBF_DEBUG_LINK) {
  296. NbfPrint1 ("NbfCreateLink: Entered, DeviceContext: %lx\n", DeviceContext);
  297. }
  298. //
  299. // Walk the list of addresses to see if we already have a link to this
  300. // remote address.
  301. //
  302. // This adds a reference if the link is found.
  303. Link = NbfFindLink (DeviceContext, HardwareAddress->Address);
  304. if (Link == (PTP_LINK)NULL) {
  305. //
  306. // If necessary, check whether we are looking for one of
  307. // the loopback links (NbfFindLink won't find those).
  308. //
  309. if (RtlEqualMemory(
  310. HardwareAddress->Address,
  311. DeviceContext->LocalAddress.Address,
  312. DeviceContext->MacInfo.AddressLength)) {
  313. ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
  314. Link = DeviceContext->LoopbackLinks[LoopbackLinkIndex];
  315. if (Link != (PTP_LINK)NULL) {
  316. //
  317. // Add a reference to simulate the one from NbfFindLink
  318. //
  319. // This needs to be atomically done with the assignment above.
  320. //
  321. NbfReferenceLink ("Found loopback link", Link, LREF_TREE);
  322. RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
  323. } else {
  324. RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
  325. //
  326. // May have the first loopback link; need to make sure the
  327. // buffer for indications is allocated.
  328. //
  329. if (DeviceContext->LookaheadContiguous == NULL) {
  330. DeviceContext->LookaheadContiguous =
  331. ExAllocatePoolWithTag (
  332. NonPagedPool,
  333. NBF_MAX_LOOPBACK_LOOKAHEAD,
  334. NBF_MEM_TAG_LOOPBACK_BUFFER);
  335. if (DeviceContext->LookaheadContiguous == NULL) {
  336. PANIC ("NbfCreateLink: Could not allocate loopback buffer!\n");
  337. return STATUS_INSUFFICIENT_RESOURCES;
  338. }
  339. }
  340. }
  341. }
  342. }
  343. if (Link != (PTP_LINK)NULL) {
  344. //
  345. // Found the link structure here, so use the existing link.
  346. //
  347. #if DBG
  348. //
  349. // These two operations have no net effect, so if not in debug
  350. // mode we can remove them.
  351. //
  352. // This reference is removed by NbfDisconnectFromLink
  353. // (this assumes that NbfConnectToLink is always called
  354. // if this function returns success).
  355. NbfReferenceLink ("New Ref, Found existing link", Link, LREF_CONNECTION); // extra reference.
  356. // Now we can remove the NbfFindLinkInTree reference.
  357. NbfDereferenceLink ("Found link in tree", Link, LREF_TREE);
  358. #endif
  359. *TransportLink = Link; // return pointer to the link.
  360. IF_NBFDBG (NBF_DEBUG_LINK) {
  361. NbfPrint0 ("NbfCreateLink: returning ptr to existing link object.\n");
  362. }
  363. return STATUS_SUCCESS; // all done.
  364. } /* if LINK != NULL */
  365. //
  366. // We don't have an existing link, so we have to create one.
  367. //
  368. IF_NBFDBG (NBF_DEBUG_LINK) {
  369. NbfPrint0 ("NbfCreateLink: using new link object.\n");
  370. }
  371. ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
  372. p = RemoveHeadList (&DeviceContext->LinkPool);
  373. if (p == &DeviceContext->LinkPool) {
  374. if ((DeviceContext->LinkMaxAllocated == 0) ||
  375. (DeviceContext->LinkAllocated < DeviceContext->LinkMaxAllocated)) {
  376. NbfAllocateLink (DeviceContext, &Link);
  377. IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
  378. NbfPrint1 ("NBF: Allocated link at %lx\n", Link);
  379. }
  380. } else {
  381. NbfWriteResourceErrorLog(
  382. DeviceContext,
  383. EVENT_TRANSPORT_RESOURCE_SPECIFIC,
  384. 405,
  385. sizeof(TP_LINK),
  386. LINK_RESOURCE_ID);
  387. Link = NULL;
  388. }
  389. if (Link == NULL) {
  390. ++DeviceContext->LinkExhausted;
  391. RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
  392. PANIC ("NbfCreateConnection: Could not allocate link object!\n");
  393. return STATUS_INSUFFICIENT_RESOURCES;
  394. }
  395. } else {
  396. Link = CONTAINING_RECORD (p, TP_LINK, Linkage);
  397. }
  398. ++DeviceContext->LinkInUse;
  399. ASSERT(DeviceContext->LinkInUse > 0);
  400. if (DeviceContext->LinkInUse > DeviceContext->LinkMaxInUse) {
  401. ++DeviceContext->LinkMaxInUse;
  402. }
  403. DeviceContext->LinkTotal += DeviceContext->LinkInUse;
  404. ++DeviceContext->LinkSamples;
  405. RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
  406. IF_NBFDBG (NBF_DEBUG_LINK) {
  407. NbfPrint1 ("NbfCreateLink: Link at %lx.\n", Link);
  408. }
  409. //
  410. // Initialize all of the static data for this link.
  411. //
  412. Link->SpecialRefCount = 1;
  413. Link->ReferenceCount = 0;
  414. #if DBG
  415. {
  416. UINT Counter;
  417. for (Counter = 0; Counter < NUMBER_OF_LREFS; Counter++) {
  418. Link->RefTypes[Counter] = 0;
  419. }
  420. // This reference is removed by NbfDisconnectFromLink
  421. // (this assumes that NbfConnectToLink is always called
  422. // if this function returns success).
  423. //
  424. Link->RefTypes[LREF_CONNECTION] = 1;
  425. Link->RefTypes[LREF_SPECIAL_TEMP] = 1;
  426. }
  427. Link->Destroyed = FALSE;
  428. Link->TotalReferences = 0;
  429. Link->TotalDereferences = 0;
  430. Link->NextRefLoc = 0;
  431. ExInterlockedInsertHeadList (&NbfGlobalLinkList, &Link->GlobalLinkage, &NbfGlobalInterlock);
  432. StoreLinkHistory (Link, TRUE);
  433. #endif
  434. Link->Flags = 0; // in the beginning, the link is closed.
  435. Link->DeferredFlags = 0;
  436. Link->State = LINK_STATE_ADM; // async disconnected mode.
  437. Link->NdisSendsInProgress = 0;
  438. Link->ResendingPackets = FALSE;
  439. //
  440. // Initialize the counters
  441. //
  442. Link->FrmrsReceived = 0;
  443. Link->FrmrsTransmitted = 0;
  444. Link->ErrorIFramesReceived = 0;
  445. Link->ErrorIFramesTransmitted = 0;
  446. Link->AbortedTransmissions = 0;
  447. Link->BuffersNotAvailable = 0;
  448. Link->SuccessfulTransmits = 0;
  449. Link->SuccessfulReceives = 0;
  450. Link->T1Expirations = 0;
  451. Link->TiExpirations = 0;
  452. #if DBG
  453. Link->CreatePacketFailures = 0;
  454. #endif
  455. //
  456. // At first, the delay and throughput are unknown.
  457. //
  458. Link->Delay = 0xffffffff;
  459. Link->Throughput.HighPart = 0xffffffff;
  460. Link->Throughput.LowPart = 0xffffffff;
  461. Link->ThroughputAccurate = FALSE;
  462. Link->CurrentT1Backoff = FALSE;
  463. Link->OnDeferredRrQueue = FALSE;
  464. InitializeListHead (&Link->DeferredRrLinkage);
  465. //
  466. // Determine the maximum sized data frame that can be sent
  467. // on this link, based on the source routing information and
  468. // the size of the MAC header ("data frame" means the frame
  469. // without the MAC header). We don't assume the worst case
  470. // about source routing since we create a link in response
  471. // to a received frame, so if there is no source routing it
  472. // is because we are not going over a bridge. The exception
  473. // is if we are creating a link to a group name, in which
  474. // case we come back later and hack the MaxFrameSize in.
  475. //
  476. MacReturnMaxDataSize(
  477. &DeviceContext->MacInfo,
  478. SourceRouting,
  479. SourceRoutingLength,
  480. DeviceContext->CurSendPacketSize,
  481. FALSE,
  482. (PUINT)&(Link->MaxFrameSize));
  483. #if DBG
  484. if (Link->MaxFrameSize > MaxUserPacketData) {
  485. Link->MaxFrameSize = MaxUserPacketData;
  486. }
  487. #endif
  488. // Link->Provider = DeviceContext;
  489. //
  490. // Build the default MAC header. I-frames go out as
  491. // non-broadcast source routing.
  492. //
  493. if (SourceRouting != NULL) {
  494. RtlCopyMemory(
  495. TempSR,
  496. SourceRouting,
  497. SourceRoutingLength);
  498. MacCreateNonBroadcastReplySR(
  499. &DeviceContext->MacInfo,
  500. TempSR,
  501. SourceRoutingLength,
  502. &ResponseSR);
  503. } else {
  504. ResponseSR = NULL;
  505. }
  506. MacConstructHeader (
  507. &DeviceContext->MacInfo,
  508. Link->Header,
  509. HardwareAddress->Address,
  510. DeviceContext->LocalAddress.Address,
  511. 0, // PacketLength, filled in later
  512. ResponseSR,
  513. SourceRoutingLength,
  514. (PUINT)&(Link->HeaderLength));
  515. //
  516. // We optimize for fourteen-byte headers by putting
  517. // the correct Dsap/Ssap at the end, so we can fill
  518. // in new packets as one 16-byte move.
  519. //
  520. if (Link->HeaderLength <= 14) {
  521. Link->Header[Link->HeaderLength] = DSAP_NETBIOS_OVER_LLC;
  522. Link->Header[Link->HeaderLength+1] = DSAP_NETBIOS_OVER_LLC;
  523. }
  524. Link->RespondToPoll = FALSE;
  525. Link->NumberOfConnectors = 0;
  526. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
  527. NbfResetLink (Link);
  528. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  529. Link->ActiveConnectionCount = 0;
  530. if (!IsListEmpty(&Link->ConnectionDatabase)) {
  531. //
  532. // Not good; we've got something left over...
  533. //
  534. #if DBG
  535. NbfPrint1 ("NbfCreateLink: Link 0x%lx has connections at startup, disconnecting...\n", Link);
  536. DbgBreakPoint();
  537. #endif
  538. //
  539. // This won't work, the link ref count will be bad.
  540. //
  541. NbfStopLink (Link);
  542. }
  543. for (i=0; i<(USHORT)DeviceContext->MacInfo.AddressLength; i++) {
  544. Link->HardwareAddress.Address[i] = HardwareAddress->Address[i];
  545. }
  546. MacReturnMagicAddress (&DeviceContext->MacInfo, HardwareAddress, &Link->MagicAddress);
  547. //
  548. // Determine if this is a loopback link.
  549. //
  550. if (RtlEqualMemory(
  551. HardwareAddress->Address,
  552. DeviceContext->LocalAddress.Address,
  553. DeviceContext->MacInfo.AddressLength)) {
  554. ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
  555. //
  556. // Yes, just fill it in, no need to do deferred processing
  557. // since this link does not go in the tree.
  558. //
  559. if (LoopbackLinkIndex == LISTENER_LINK) {
  560. Link->LoopbackDestinationIndex = LOOPBACK_TO_CONNECTOR;
  561. } else {
  562. Link->LoopbackDestinationIndex = LOOPBACK_TO_LISTENER;
  563. }
  564. Link->Loopback = TRUE;
  565. DeviceContext->LoopbackLinks[LoopbackLinkIndex] = Link;
  566. RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
  567. } else {
  568. Link->Loopback = FALSE;
  569. //
  570. // Now put the link in the deferred operations queue and go away. We'll
  571. // insert this link in the tree at some future time (soon).
  572. //
  573. IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
  574. NbfPrint6 ("NbfCreateLink: link to deferred queue %lx %lx %lx %lx %lx Flags: %lx \n",
  575. Link, Link->DeferredList.Flink, Link->DeferredList.Blink,
  576. DeviceContext->LinkDeferred.Flink, DeviceContext->LinkDeferred.Blink,
  577. Link->Flags);
  578. }
  579. //
  580. // We should not have any deferred flags yet!
  581. //
  582. ASSERT ((Link->DeferredFlags & LINK_FLAGS_DEFERRED_MASK) == 0);
  583. ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
  584. ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
  585. if ((Link->DeferredFlags & LINK_FLAGS_DEFERRED_DELETE) == 0) {
  586. Link->DeferredFlags |= LINK_FLAGS_DEFERRED_ADD;
  587. InsertTailList (&DeviceContext->LinkDeferred, &Link->DeferredList);
  588. if (!(DeviceContext->a.i.LinkDeferredActive)) {
  589. StartTimerLinkDeferredAdd++;
  590. NbfStartShortTimer (DeviceContext);
  591. DeviceContext->a.i.LinkDeferredActive = TRUE;
  592. }
  593. }
  594. else {
  595. Link->DeferredFlags = LINK_FLAGS_DEFERRED_ADD;
  596. if (!(DeviceContext->a.i.LinkDeferredActive)) {
  597. StartTimerLinkDeferredAdd++;
  598. NbfStartShortTimer (DeviceContext);
  599. DeviceContext->a.i.LinkDeferredActive = TRUE;
  600. }
  601. }
  602. RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
  603. RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
  604. IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
  605. NbfPrint6 ("NbfCreateLink: link on deferred queue %lx %lx %lx %lx %lx Flags: %lx \n",
  606. Link, Link->DeferredList.Flink, Link->DeferredList.Blink,
  607. DeviceContext->LinkDeferred.Flink, DeviceContext->LinkDeferred.Blink,
  608. Link->DeferredFlags);
  609. }
  610. }
  611. #if PKT_LOG
  612. RtlZeroMemory (&Link->LastNRecvs, sizeof(PKT_LOG_QUE));
  613. RtlZeroMemory (&Link->LastNSends, sizeof(PKT_LOG_QUE));
  614. #endif // PKT_LOG
  615. NbfReferenceDeviceContext ("Create Link", DeviceContext, DCREF_LINK); // count refs to the device context.
  616. *TransportLink = Link; // return a pointer to the link object.
  617. return STATUS_SUCCESS;
  618. } /* NbfCreateLink */
  619. NTSTATUS
  620. NbfDestroyLink(
  621. IN PTP_LINK TransportLink
  622. )
  623. /*++
  624. Routine Description:
  625. This routine destroys a transport link and removes all references
  626. made to it by other objects in the transport. The link is expected
  627. to still be on the splay tree of links. This routine merely marks the
  628. link as needing to be deleted and pushes it onto the deferred operations
  629. queue. The deferred operations processor actually removes the link from
  630. tree and returns the link to pool.
  631. Arguments:
  632. TransportLink - Pointer to a transport link structure to be destroyed.
  633. Return Value:
  634. NTSTATUS - status of operation.
  635. --*/
  636. {
  637. KIRQL oldirql;
  638. PTP_PACKET packet;
  639. PLIST_ENTRY pkt;
  640. PDEVICE_CONTEXT DeviceContext;
  641. IF_NBFDBG (NBF_DEBUG_LINK) {
  642. NbfPrint1 ("NbfDestroyLink: Entered for link %lx.\n", TransportLink);
  643. }
  644. #if DBG
  645. if (TransportLink->Destroyed) {
  646. NbfPrint1 ("attempt to destroy already-destroyed link 0x%lx\n", TransportLink);
  647. DbgBreakPoint ();
  648. }
  649. TransportLink->Destroyed = TRUE;
  650. #if 1
  651. ACQUIRE_SPIN_LOCK (&NbfGlobalInterlock, &oldirql);
  652. RemoveEntryList (&TransportLink->GlobalLinkage);
  653. RELEASE_SPIN_LOCK (&NbfGlobalInterlock, oldirql);
  654. #else
  655. ExInterlockedRemoveHeadList (TransportLink->GlobalLinkage.Blink, &NbfGlobalInterlock);
  656. #endif
  657. #endif
  658. DeviceContext = TransportLink->Provider;
  659. //
  660. // In case there's a holdover from the DISC link shutdown protocol
  661. //
  662. //
  663. // We had better be in ADM, otherwise the reference count should
  664. // be non-zero and what are we doing in NbfDestroyLink?
  665. //
  666. ASSERT(TransportLink->State == LINK_STATE_ADM);
  667. // TransportLink->State = LINK_STATE_ADM;
  668. StopT1 (TransportLink);
  669. StopT2 (TransportLink);
  670. StopTi (TransportLink);
  671. //
  672. // Make sure we are not in the deferred timer queue.
  673. //
  674. ACQUIRE_SPIN_LOCK (&DeviceContext->TimerSpinLock, &oldirql);
  675. if (TransportLink->OnShortList) {
  676. TransportLink->OnShortList = FALSE;
  677. RemoveEntryList (&TransportLink->ShortList);
  678. }
  679. if (TransportLink->OnLongList) {
  680. TransportLink->OnLongList = FALSE;
  681. RemoveEntryList (&TransportLink->LongList);
  682. }
  683. RELEASE_SPIN_LOCK (&DeviceContext->TimerSpinLock, oldirql);
  684. ASSERT (!TransportLink->OnDeferredRrQueue);
  685. //
  686. // Now free this link object's resources.
  687. // later, we'll spin through the WackQ and verify that sequencing
  688. // is correct and we've gotten an implicit ack for these packets. This
  689. // maybe should be handled in ResendLlcPackets for non-final, non-command
  690. // packets.
  691. //
  692. while (!IsListEmpty (&TransportLink->WackQ)) {
  693. pkt = RemoveHeadList (&TransportLink->WackQ);
  694. packet = CONTAINING_RECORD (pkt, TP_PACKET, Linkage);
  695. #if DBG
  696. // IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
  697. NbfPrint1 ("NbfDereferenceLink: Destroying packets on Link WackQ! %lx\n", packet);
  698. // }
  699. #endif
  700. NbfDereferencePacket (packet);
  701. }
  702. //
  703. // The NDIS send queue should be empty!!
  704. //
  705. ASSERT (IsListEmpty (&TransportLink->NdisSendQueue));
  706. #if DBG
  707. if (!IsListEmpty (&TransportLink->ConnectionDatabase)) {
  708. NbfPrint1 ("NbfDestroyLink: link 0x%lx still has connections\n", TransportLink);
  709. DbgBreakPoint ();
  710. }
  711. #endif
  712. ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
  713. DeviceContext->LinkTotal += DeviceContext->LinkInUse;
  714. ++DeviceContext->LinkSamples;
  715. ASSERT(DeviceContext->LinkInUse > 0);
  716. --DeviceContext->LinkInUse;
  717. ASSERT(DeviceContext->LinkAllocated > DeviceContext->LinkInUse);
  718. if ((DeviceContext->LinkAllocated - DeviceContext->LinkInUse) >
  719. DeviceContext->LinkInitAllocated) {
  720. NbfDeallocateLink (DeviceContext, TransportLink);
  721. IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
  722. NbfPrint1 ("NBF: Deallocated link at %lx\n", TransportLink);
  723. }
  724. } else {
  725. InsertTailList (&DeviceContext->LinkPool, &TransportLink->Linkage);
  726. }
  727. RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
  728. NbfDereferenceDeviceContext ("Destroy Link", DeviceContext, DCREF_LINK); // just housekeeping.
  729. return STATUS_SUCCESS;
  730. } /* NbfDestroyLink */
  731. VOID
  732. NbfDisconnectLink(
  733. IN PTP_LINK Link
  734. )
  735. /*++
  736. Routine Description:
  737. This routine calls the data link provider to disconnect a data link
  738. connection associated with a TP_LINK object.
  739. Arguments:
  740. Link - Pointer to a transport link object.
  741. Return Value:
  742. none.
  743. --*/
  744. {
  745. KIRQL oldirql;
  746. IF_NBFDBG (NBF_DEBUG_LINK) {
  747. NbfPrint1 ("NbfDisconnectLink: Entered for link %lx.\n", Link);
  748. }
  749. ACQUIRE_SPIN_LOCK (&Link->SpinLock, &oldirql);
  750. if ((Link->Flags & LINK_FLAGS_LOCAL_DISC) != 0) {
  751. Link->Flags &= ~LINK_FLAGS_LOCAL_DISC;
  752. if (Link->State == LINK_STATE_ADM) {
  753. RELEASE_SPIN_LOCK (&Link->SpinLock, oldirql);
  754. } else {
  755. PLIST_ENTRY p;
  756. PTP_PACKET packet;
  757. Link->State = LINK_STATE_W_DISC_RSP; // we are awaiting a DISC/f.
  758. Link->SendState = SEND_STATE_DOWN;
  759. Link->ReceiveState = RECEIVE_STATE_DOWN;
  760. StopT1 (Link);
  761. StopT2 (Link);
  762. StopTi (Link);
  763. //
  764. // check for left over packets on the link WackQ; we'll never get
  765. // acked for these if the link is in W_DISC_RSP.
  766. //
  767. while (!IsListEmpty (&Link->WackQ)) {
  768. p = RemoveHeadList (&Link->WackQ);
  769. RELEASE_SPIN_LOCK (&Link->SpinLock, oldirql);
  770. packet = CONTAINING_RECORD (p, TP_PACKET, Linkage);
  771. NbfDereferencePacket (packet);
  772. ACQUIRE_SPIN_LOCK (&Link->SpinLock, &oldirql);
  773. }
  774. Link->SendRetries = (UCHAR)Link->LlcRetries;
  775. StartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME)); // retransmit timer.
  776. RELEASE_SPIN_LOCK (&Link->SpinLock, oldirql);
  777. NbfSendDisc (Link, TRUE); // send DISC-c/p.
  778. }
  779. } else {
  780. RELEASE_SPIN_LOCK (&Link->SpinLock, oldirql);
  781. }
  782. } /* NbfDisconnectLink */
  783. #if DBG
  784. VOID
  785. NbfRefLink(
  786. IN PTP_LINK TransportLink
  787. )
  788. /*++
  789. Routine Description:
  790. This routine increments the reference count on a transport link. If we are
  791. currently in the state waiting for disconnect response, we do not
  792. reference; this avoids the link "bouncing" during disconnect (trying to
  793. disconnect multiple times).
  794. Arguments:
  795. TransportLink - Pointer to a transport link object.
  796. Return Value:
  797. none.
  798. --*/
  799. {
  800. LONG result;
  801. IF_NBFDBG (NBF_DEBUG_LINK) {
  802. NbfPrint2 ("NbfReferenceLink: Entered for link %lx, current level=%ld.\n",
  803. TransportLink, TransportLink->ReferenceCount);
  804. }
  805. #if DBG
  806. StoreLinkHistory( TransportLink, TRUE );
  807. #endif
  808. result = InterlockedIncrement (&TransportLink->ReferenceCount);
  809. if (result == 0) {
  810. //
  811. // The first increment causes us to increment the
  812. // "ref count is not zero" special ref.
  813. //
  814. NbfReferenceLinkSpecial ("first ref", TransportLink, LREF_SPECIAL_TEMP);
  815. }
  816. ASSERT (result >= 0);
  817. } /* NbfRefLink */
  818. #endif
  819. VOID
  820. NbfDerefLink(
  821. IN PTP_LINK TransportLink
  822. )
  823. /*++
  824. Routine Description:
  825. This routine dereferences a transport link by decrementing the
  826. reference count contained in the structure.
  827. There are two special reference counts, 1 and 0. If, after dereferencing,
  828. the reference count is one (1), then we initiate a disconnect protocol
  829. sequence (DISC/UA) to terminate the connection. When this request
  830. completes, the completion routine will dereference the link object again.
  831. While this protocol is in progress, we will not allow the link to be
  832. incremented again.
  833. If the reference count becomes 0 after dereferencing, then we are in
  834. the disconnection request completion handler, and we should actually
  835. destroy the link object. We place the link on the deferred operations
  836. queue and let the link get deleted later at a safe time.
  837. Warning: Watch out for cases where a link is going down, and it is
  838. suddenly needed again. Keep a bitflag for that in the link object.
  839. Arguments:
  840. TransportLink - Pointer to a transport link object.
  841. Return Value:
  842. none.
  843. --*/
  844. {
  845. LONG result;
  846. IF_NBFDBG (NBF_DEBUG_LINK) {
  847. NbfPrint2 ("NbfDereferenceLink: Entered for link %lx, current level=%ld.\n",
  848. TransportLink, TransportLink->ReferenceCount);
  849. }
  850. #if DBG
  851. StoreLinkHistory( TransportLink, FALSE );
  852. #endif
  853. result = InterlockedDecrement(&TransportLink->ReferenceCount);
  854. //
  855. // If all the normal references to this link are gone, then
  856. // we can remove the special reference that stood for
  857. // "the regular ref count is non-zero".
  858. //
  859. if (result < 0) {
  860. //
  861. // If the refcount is -1 we want to call DisconnectLink,
  862. // we do this before removing the special ref so that
  863. // the link does not go away during the call.
  864. //
  865. IF_NBFDBG (NBF_DEBUG_LINK) {
  866. NbfPrint0 ("NbfDereferenceLink: refcnt=1, disconnecting Link object.\n");
  867. }
  868. NbfDisconnectLink (TransportLink);
  869. //
  870. // Now it is OK to let the link go away.
  871. //
  872. NbfDereferenceLinkSpecial ("Regular ref 0", TransportLink, LREF_SPECIAL_TEMP);
  873. }
  874. } /* NbfDerefLink */
  875. VOID
  876. NbfRefLinkSpecial(
  877. IN PTP_LINK TransportLink
  878. )
  879. /*++
  880. Routine Description:
  881. This routine increments the special reference count on a transport link.
  882. Arguments:
  883. TransportLink - Pointer to a transport link object.
  884. Return Value:
  885. none.
  886. --*/
  887. {
  888. ULONG result;
  889. IF_NBFDBG (NBF_DEBUG_LINK) {
  890. NbfPrint3 ("NbfRefLinkSpecial: Entered for link %lx, current level=%ld (%ld).\n",
  891. TransportLink, TransportLink->ReferenceCount, TransportLink->SpecialRefCount);
  892. }
  893. #if DBG
  894. StoreLinkHistory( TransportLink, TRUE );
  895. #endif
  896. result = ExInterlockedAddUlong (
  897. (PULONG)&TransportLink->SpecialRefCount,
  898. 1,
  899. TransportLink->ProviderInterlock);
  900. } /* NbfRefLinkSpecial */
  901. VOID
  902. NbfDerefLinkSpecial(
  903. IN PTP_LINK TransportLink
  904. )
  905. /*++
  906. Routine Description:
  907. This routine dereferences a transport link by decrementing the
  908. special reference count contained in the structure.
  909. The special reference may be decremented at any time, however
  910. the effect of those dereferences only happen when the normal
  911. reference count is 0, to prevent the link from going away
  912. while the operations due to the ->0 transition of the
  913. normal reference count are done.
  914. If the special reference count becomes 0 after dereferencing, then we
  915. are in the disconnection request completion handler, and we should actually
  916. destroy the link object. We place the link on the deferred operations
  917. queue and let the link get deleted later at a safe time.
  918. Warning: Watch out for cases where a link is going down, and it is
  919. suddenly needed again. Keep a bitflag for that in the link object.
  920. Arguments:
  921. TransportLink - Pointer to a transport link object.
  922. Return Value:
  923. none.
  924. --*/
  925. {
  926. KIRQL oldirql, oldirql1;
  927. ULONG OldRefCount;
  928. PDEVICE_CONTEXT DeviceContext = TransportLink->Provider;
  929. IF_NBFDBG (NBF_DEBUG_LINK) {
  930. NbfPrint3 ("NbfDerefLinkSpecial: Entered for link %lx, current level=%ld (%ld).\n",
  931. TransportLink, TransportLink->ReferenceCount, TransportLink->SpecialRefCount);
  932. }
  933. #if DBG
  934. StoreLinkHistory( TransportLink, FALSE );
  935. #endif
  936. //
  937. // Links stay in the device context tree with a ref count
  938. // of 0. Routines that scan this queue check the DEFERRED_DELETE
  939. // flag, so we need to synchronize the decrementing of the
  940. // ref count with setting that flag. DeviceContext->LinkSpinLock
  941. // is used to synchronize this.
  942. //
  943. ACQUIRE_SPIN_LOCK (&DeviceContext->LinkSpinLock, &oldirql1);
  944. OldRefCount = ExInterlockedAddUlong (
  945. (PULONG)&TransportLink->SpecialRefCount,
  946. (ULONG)-1,
  947. TransportLink->ProviderInterlock);
  948. ASSERT (OldRefCount > 0);
  949. if ((OldRefCount == 1) &&
  950. (TransportLink->ReferenceCount == -1)) {
  951. if (TransportLink->Loopback) {
  952. //
  953. // It is a loopback link, hence not in the link
  954. // tree so we don't need to queue a deferred removal.
  955. //
  956. if (TransportLink == DeviceContext->LoopbackLinks[0]) {
  957. DeviceContext->LoopbackLinks[0] = NULL;
  958. } else if (TransportLink == DeviceContext->LoopbackLinks[1]) {
  959. DeviceContext->LoopbackLinks[1] = NULL;
  960. } else {
  961. #if DBG
  962. NbfPrint0("Destroying unknown loopback link!!\n");
  963. #endif
  964. ASSERT(FALSE);
  965. }
  966. NbfDestroyLink (TransportLink);
  967. RELEASE_SPIN_LOCK (&DeviceContext->LinkSpinLock, oldirql1);
  968. } else {
  969. //
  970. // Not only are all transport connections gone, but the data link
  971. // provider does not have a reference to this object, so we can
  972. // safely delete it from the system. Make sure we haven't already
  973. // been here before we try to insert this link.
  974. //
  975. IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
  976. NbfPrint6 ("NbfDerefLink: link to deferred queue %lx %lx %lx %lx %lx Flags: %lx \n",
  977. TransportLink, TransportLink->DeferredList.Flink,
  978. TransportLink->DeferredList.Blink, DeviceContext->LinkDeferred.Flink,
  979. DeviceContext->LinkDeferred.Blink, TransportLink->Flags);
  980. }
  981. ACQUIRE_SPIN_LOCK (&DeviceContext->TimerSpinLock, &oldirql);
  982. if ((TransportLink->DeferredFlags & LINK_FLAGS_DEFERRED_MASK) == 0) {
  983. TransportLink->DeferredFlags |= LINK_FLAGS_DEFERRED_DELETE;
  984. InsertTailList (&DeviceContext->LinkDeferred, &TransportLink->DeferredList);
  985. if (!(DeviceContext->a.i.LinkDeferredActive)) {
  986. StartTimerLinkDeferredDelete++;
  987. NbfStartShortTimer (DeviceContext);
  988. DeviceContext->a.i.LinkDeferredActive = TRUE;
  989. }
  990. } else {
  991. TransportLink->DeferredFlags |= LINK_FLAGS_DEFERRED_DELETE;
  992. }
  993. RELEASE_SPIN_LOCK (&DeviceContext->TimerSpinLock, oldirql);
  994. RELEASE_SPIN_LOCK (&DeviceContext->LinkSpinLock, oldirql1);
  995. IF_NBFDBG (NBF_DEBUG_LINK) {
  996. NbfPrint0 ("NbfDereferenceLink: refcnt=0, link placed on deferred operations queue.\n");
  997. }
  998. IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
  999. NbfPrint6 ("NbfDerefLink: link on deferred queue %lx %lx %lx %lx %lx Flags: %lx \n",
  1000. TransportLink, TransportLink->DeferredList.Flink,
  1001. TransportLink->DeferredList.Blink, DeviceContext->LinkDeferred.Flink,
  1002. DeviceContext->LinkDeferred.Blink, TransportLink->DeferredFlags);
  1003. }
  1004. }
  1005. } else {
  1006. RELEASE_SPIN_LOCK (&DeviceContext->LinkSpinLock, oldirql1);
  1007. }
  1008. } /* NbfDerefLinkSpecial */
  1009. NTSTATUS
  1010. NbfAssignGroupLsn(
  1011. IN PTP_CONNECTION TransportConnection
  1012. )
  1013. /*++
  1014. Routine Description:
  1015. This routine is called to assign a global LSN to the connection
  1016. in question. If successful, it fills in the connection's LSN
  1017. appropriately.
  1018. Arguments:
  1019. TransportConnection - Pointer to a transport connection object.
  1020. Return Value:
  1021. STATUS_SUCCESS if we got an LSN for the connection;
  1022. STATUS_INSUFFICIENT_RESOURCES if we didn't.
  1023. --*/
  1024. {
  1025. KIRQL oldirql;
  1026. UCHAR Lsn;
  1027. PDEVICE_CONTEXT DeviceContext;
  1028. BOOLEAN FoundLsn = FALSE;
  1029. DeviceContext = TransportConnection->Provider;
  1030. ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
  1031. //
  1032. // Scan through the device context tables to find an LSN that
  1033. // is not in use, starting with NextLsnStart+128.
  1034. //
  1035. Lsn = (UCHAR)DeviceContext->NextLsnStart;
  1036. do {
  1037. if (DeviceContext->LsnTable[Lsn] == 0) {
  1038. DeviceContext->LsnTable[Lsn] = LSN_TABLE_MAX;
  1039. FoundLsn = TRUE;
  1040. break;
  1041. }
  1042. Lsn = (Lsn % NETBIOS_SESSION_LIMIT) + 1;
  1043. } while (Lsn != DeviceContext->NextLsnStart);
  1044. DeviceContext->NextLsnStart = (DeviceContext->NextLsnStart % 64) + 1;
  1045. if (!FoundLsn) {
  1046. //
  1047. // Could not find an empty LSN; have to fail.
  1048. //
  1049. RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
  1050. return STATUS_INSUFFICIENT_RESOURCES;
  1051. }
  1052. TransportConnection->Lsn = Lsn;
  1053. RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
  1054. return STATUS_SUCCESS;
  1055. }
  1056. NTSTATUS
  1057. NbfConnectToLink(
  1058. IN PTP_LINK Link,
  1059. IN PTP_CONNECTION TransportConnection
  1060. )
  1061. /*++
  1062. Routine Description:
  1063. This routine is called to establish a linkage between a transport
  1064. connection and a transport link. We find a session number in one
  1065. of two ways. If the last connection on the link's list has a number less
  1066. than the maximum session number, we simply increment it's number and
  1067. assign it to this session. If that doesn't work, we scan through the
  1068. sessions associated with this link until we find a hole in the LSNs;
  1069. we then use the first number in that hole. If that fails, we've used
  1070. the number of sessions we can create on this link and we fail.
  1071. It is assumed that the caller holds at least temporary references
  1072. on both the connection and link objects, or they could go away during
  1073. the call sequence or during this routine's execution.
  1074. Arguments:
  1075. Link - Pointer to a transport link object.
  1076. TransportConnection - Pointer to a transport connection object.
  1077. Return Value:
  1078. STATUS_SUCCESS if we got an LSN for the connection;
  1079. STATUS_INSUFFICIENT_RESOURCES if we didn't.
  1080. --*/
  1081. {
  1082. KIRQL oldirql;
  1083. UCHAR lastSession=0;
  1084. PTP_CONNECTION connection;
  1085. PLIST_ENTRY p;
  1086. PDEVICE_CONTEXT DeviceContext;
  1087. UCHAR Lsn;
  1088. BOOLEAN FoundLsn;
  1089. //
  1090. // Assign an LSN for a new connection. If this connection makes for more
  1091. // connections than the maximum, blow off the creation.
  1092. //
  1093. IF_NBFDBG (NBF_DEBUG_LINK) {
  1094. NbfPrint2 ("NbfConnectToLink: Entered for connection %lx, link %lx.\n",
  1095. TransportConnection, Link);
  1096. }
  1097. DeviceContext = Link->Provider;
  1098. ACQUIRE_SPIN_LOCK (&Link->SpinLock, &oldirql);
  1099. #if DBG
  1100. if (!(IsListEmpty(&TransportConnection->LinkList)) ||
  1101. (TransportConnection->Link != NULL)) {
  1102. DbgPrint ("Connecting C %lx to L %lx, appears to be in use\n", TransportConnection, Link);
  1103. DbgBreakPoint();
  1104. }
  1105. #endif
  1106. if ((TransportConnection->Flags2 & CONNECTION_FLAGS2_GROUP_LSN) == 0) {
  1107. //
  1108. // This connection is to a remote unique name, which means
  1109. // we need to assign the LSN here based on the link. We
  1110. // scan through our LSN table starting with NextLsnStart
  1111. // (which cycles from 1 to 64) to find an LSN which is not
  1112. // used by any connections on this link.
  1113. //
  1114. ASSERT (TransportConnection->Lsn == 0);
  1115. FoundLsn = FALSE;
  1116. Lsn = (UCHAR)DeviceContext->NextLsnStart;
  1117. //
  1118. // First scan through the database until we reach
  1119. // Lsn (or hit the end of the database).
  1120. //
  1121. for (p = Link->ConnectionDatabase.Flink;
  1122. p != &Link->ConnectionDatabase;
  1123. p = p->Flink) {
  1124. connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
  1125. if (connection->Lsn >= Lsn) {
  1126. break;
  1127. }
  1128. }
  1129. //
  1130. // p now points to the first element after Lsn's spot.
  1131. // We now scan forwards until we hit NETBIOS_SESSION_LIMIT,
  1132. // looking for an Lsn that is available.
  1133. //
  1134. for ( ; Lsn <= NETBIOS_SESSION_LIMIT; ++Lsn) {
  1135. //
  1136. // At some point (perhaps right away) we may
  1137. // pass the end of the database without finding
  1138. // an LSN. If we have not yet done this, see
  1139. // if we need to skip this lsn because it is
  1140. // in use by a connection on this link.
  1141. //
  1142. if (p != &Link->ConnectionDatabase) {
  1143. if (connection->Lsn == Lsn) {
  1144. p = p->Flink;
  1145. if (p != &Link->ConnectionDatabase) {
  1146. connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
  1147. }
  1148. continue;
  1149. }
  1150. }
  1151. //
  1152. // This lsn is not in use on this link, see if
  1153. // there is room for it to be used.
  1154. //
  1155. if (DeviceContext->LsnTable[Lsn] < LSN_TABLE_MAX) {
  1156. ++(DeviceContext->LsnTable[Lsn]);
  1157. TransportConnection->Lsn = Lsn;
  1158. InsertTailList (p, &TransportConnection->LinkList);
  1159. FoundLsn = TRUE;
  1160. break;
  1161. }
  1162. }
  1163. DeviceContext->NextLsnStart = (DeviceContext->NextLsnStart % 64) + 1;
  1164. } else {
  1165. //
  1166. // This connection is to a group name; we already assigned
  1167. // the LSN on a global basis.
  1168. //
  1169. FoundLsn = TRUE;
  1170. //
  1171. // Find the spot for this LSN in the database.
  1172. //
  1173. p = Link->ConnectionDatabase.Flink;
  1174. while (p != &Link->ConnectionDatabase) {
  1175. connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
  1176. if (TransportConnection->Lsn < connection->Lsn) {
  1177. InsertTailList (p, &TransportConnection->LinkList);
  1178. break;
  1179. }
  1180. p = p->Flink;
  1181. }
  1182. if (p == &Link->ConnectionDatabase) {
  1183. InsertTailList (&Link->ConnectionDatabase, &TransportConnection->LinkList);
  1184. }
  1185. }
  1186. if (!FoundLsn) {
  1187. ULONG DumpData = NETBIOS_SESSION_LIMIT;
  1188. ASSERT (Link->ActiveConnectionCount == NETBIOS_SESSION_LIMIT);
  1189. RELEASE_SPIN_LOCK (&Link->SpinLock, oldirql);
  1190. PANIC ("NbfConnectToLink: PANIC! too many active connections!\n");
  1191. NbfWriteGeneralErrorLog(
  1192. DeviceContext,
  1193. EVENT_TRANSPORT_TOO_MANY_LINKS,
  1194. 602,
  1195. STATUS_INSUFFICIENT_RESOURCES,
  1196. NULL,
  1197. 1,
  1198. &DumpData);
  1199. return STATUS_INSUFFICIENT_RESOURCES;
  1200. }
  1201. TransportConnection->Link = Link;
  1202. TransportConnection->LinkSpinLock = &Link->SpinLock;
  1203. TransportConnection->Flags |= CONNECTION_FLAGS_WAIT_LINK_UP;
  1204. TransportConnection->LastPacketsSent = Link->PacketsSent;
  1205. TransportConnection->LastPacketsResent = Link->PacketsResent;
  1206. Link->ActiveConnectionCount++;
  1207. //
  1208. // Note that the connection is already inserted in the
  1209. // link's ConnectionDatabase.
  1210. //
  1211. // This reference is removed in NbfDisconnectFromLink
  1212. NbfReferenceConnection("Adding link", TransportConnection, CREF_LINK);
  1213. RELEASE_SPIN_LOCK (&Link->SpinLock, oldirql);
  1214. return STATUS_SUCCESS; // we did it!
  1215. } /* NbfConnectToLink */
  1216. BOOLEAN
  1217. NbfDisconnectFromLink(
  1218. IN PTP_CONNECTION TransportConnection,
  1219. IN BOOLEAN VerifyReferenceCount
  1220. )
  1221. /*++
  1222. Routine Description:
  1223. This routine is called to terminate a linkage between a transport
  1224. connection and its associated transport link. If it turns out that
  1225. this is the last connection to be removed from this link, then the
  1226. link's disconnection protocol is engaged.
  1227. Arguments:
  1228. TransportConnection - Pointer to a transport connection object.
  1229. VerifyReferenceCount - TRUE if we should check that the refcount
  1230. is still -1 before removing the connection from the link.
  1231. If it is not, it means someone just referenced us and we
  1232. exit.
  1233. Return Value:
  1234. FALSE if VerifyReferenceCount was TRUE but the refcount was
  1235. not -1; TRUE otherwise.
  1236. --*/
  1237. {
  1238. KIRQL oldirql, oldirql1;
  1239. PTP_LINK Link;
  1240. IF_NBFDBG (NBF_DEBUG_LINK) {
  1241. NbfPrint2 ("NbfDisconnectFromLink: Entered for connection %lx, link %lx.\n",
  1242. TransportConnection, TransportConnection->Link);
  1243. }
  1244. ACQUIRE_C_SPIN_LOCK (&TransportConnection->SpinLock, &oldirql);
  1245. Link = TransportConnection->Link;
  1246. if (Link != NULL) {
  1247. ACQUIRE_SPIN_LOCK (&Link->SpinLock, &oldirql1);
  1248. if ((VerifyReferenceCount) &&
  1249. (TransportConnection->ReferenceCount != -1)) {
  1250. RELEASE_SPIN_LOCK (&Link->SpinLock, oldirql1);
  1251. RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql);
  1252. return FALSE;
  1253. }
  1254. TransportConnection->Link = NULL;
  1255. TransportConnection->LinkSpinLock = NULL;
  1256. RemoveEntryList (&TransportConnection->LinkList);
  1257. #if DBG
  1258. InitializeListHead (&TransportConnection->LinkList);
  1259. #endif
  1260. //
  1261. // If this was the last connection being serviced by this link,
  1262. // then we can shut the link down. It still has a reference
  1263. // from the device context, which will go away in the DM/UA
  1264. // DLC frame handler.
  1265. //
  1266. if (--Link->ActiveConnectionCount == 0) {
  1267. //
  1268. // only want to send DISC if the remote was NOT the originator
  1269. // of the disconnect.
  1270. //
  1271. if ((TransportConnection->Status == STATUS_LOCAL_DISCONNECT) ||
  1272. (TransportConnection->Status == STATUS_CANCELLED)) {
  1273. //
  1274. // This is a local disconnect of the last connection
  1275. // on the link, let's get the disconnect ball rolling.
  1276. //
  1277. Link->Flags |= LINK_FLAGS_LOCAL_DISC;
  1278. //
  1279. // When the link reference count drops down to 1,
  1280. // that will cause the DISC to get sent.
  1281. //
  1282. }
  1283. }
  1284. RELEASE_SPIN_LOCK (&Link->SpinLock, oldirql1);
  1285. //
  1286. // Clear these now that we are off the link's database.
  1287. //
  1288. NbfClearConnectionLsn (TransportConnection);
  1289. TransportConnection->Rsn = 0;
  1290. RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql);
  1291. if ((TransportConnection->Flags2 & CONNECTION_FLAGS2_CONNECTOR) != 0) {
  1292. (VOID)InterlockedDecrement(&Link->NumberOfConnectors);
  1293. }
  1294. //
  1295. // All done with this connection's reference to link.
  1296. //
  1297. NbfDereferenceLink ("Disconnecting connection",Link, LREF_CONNECTION);
  1298. } else {
  1299. //
  1300. // A group LSN may have been assigned even though Link is NULL.
  1301. //
  1302. if ((TransportConnection->Flags2 & CONNECTION_FLAGS2_GROUP_LSN) != 0) {
  1303. NbfClearConnectionLsn (TransportConnection);
  1304. }
  1305. RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql);
  1306. }
  1307. return TRUE;
  1308. } /* NbfDisconnectFromLink */
  1309. PTP_CONNECTION
  1310. NbfLookupPendingListenOnLink(
  1311. IN PTP_LINK Link
  1312. )
  1313. /*++
  1314. Routine Description:
  1315. This routine scans the LSN database on a transport link object to find
  1316. a TP_CONNECTION object which has the CONNECTION_FLAGS_WAIT_LINK_UP and
  1317. CONNECTION_FLAGS2_LISTENER flags set. It returns a pointer to the found
  1318. connection object (and simultaneously resets the LINK_UP flag) or NULL
  1319. if it could not be found. The reference count is also incremented
  1320. atomically on the connection.
  1321. NOTE: THIS ROUTINE MUST BE CALLED FROM DPC LEVEL.
  1322. Arguments:
  1323. Link - Pointer to a transport link object.
  1324. Return Value:
  1325. NTSTATUS - status of operation.
  1326. --*/
  1327. {
  1328. PTP_CONNECTION connection;
  1329. PLIST_ENTRY p;
  1330. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
  1331. for (p = Link->ConnectionDatabase.Flink;
  1332. p != &Link->ConnectionDatabase;
  1333. p = p->Flink) {
  1334. connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
  1335. if ((connection->Flags & CONNECTION_FLAGS_WAIT_LINK_UP) &&
  1336. (connection->Flags2 & CONNECTION_FLAGS2_LISTENER) &&
  1337. ((connection->Flags2 & CONNECTION_FLAGS2_STOPPING) == 0)) {
  1338. // This reference is removed by the calling function
  1339. NbfReferenceConnection ("Found Pending Listen", connection, CREF_P_LINK);
  1340. connection->Flags &= ~CONNECTION_FLAGS_WAIT_LINK_UP;
  1341. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  1342. return connection;
  1343. }
  1344. }
  1345. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  1346. return NULL;
  1347. } /* NbfLookupPendingListenOnLink */
  1348. PTP_CONNECTION
  1349. NbfLookupPendingConnectOnLink(
  1350. IN PTP_LINK Link
  1351. )
  1352. /*++
  1353. Routine Description:
  1354. This routine scans the LSN database on a transport link object to find
  1355. a TP_CONNECTION object which has the CONNECTION_FLAGS_WAIT_LINK_UP and
  1356. CONNECTION_FLAGS2_CONNECTOR flags set. It returns a pointer to the found
  1357. connection object (and simultaneously resets the LINK_UP flag) or NULL
  1358. if it could not be found. The reference count is also incremented
  1359. atomically on the connection.
  1360. NOTE: THIS ROUTINE MUST BE CALLED FROM DPC LEVEL.
  1361. Arguments:
  1362. Link - Pointer to a transport link object.
  1363. Return Value:
  1364. NTSTATUS - status of operation.
  1365. --*/
  1366. {
  1367. PTP_CONNECTION connection;
  1368. PLIST_ENTRY p;
  1369. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
  1370. for (p = Link->ConnectionDatabase.Flink;
  1371. p != &Link->ConnectionDatabase;
  1372. p = p->Flink) {
  1373. connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
  1374. if ((connection->Flags & CONNECTION_FLAGS_WAIT_LINK_UP) &&
  1375. (connection->Flags2 & CONNECTION_FLAGS2_CONNECTOR) &&
  1376. ((connection->Flags2 & CONNECTION_FLAGS2_STOPPING) == 0)) {
  1377. // This reference is removed by the calling function
  1378. NbfReferenceConnection ("Found pending Connect", connection, CREF_P_CONNECT);
  1379. connection->Flags &= ~CONNECTION_FLAGS_WAIT_LINK_UP;
  1380. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  1381. return connection;
  1382. }
  1383. }
  1384. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  1385. return NULL;
  1386. } /* NbfLookupPendingConnectOnLink */
  1387. VOID
  1388. NbfActivateLink(
  1389. IN PTP_LINK Link
  1390. )
  1391. /*++
  1392. Routine Description:
  1393. This routine activates a link if it is not already active. The other
  1394. related routines, NbfCreateLink and NbfConnectToLink, simply set up data
  1395. structures which represent active links so that we can reuse links
  1396. wherever possible.
  1397. NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
  1398. Arguments:
  1399. Link - Pointer to a transport link object.
  1400. Return Value:
  1401. none.
  1402. --*/
  1403. {
  1404. IF_NBFDBG (NBF_DEBUG_LINK) {
  1405. NbfPrint1 ("NbfActivateLink: Entered for link %lx.\n", Link);
  1406. }
  1407. ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
  1408. switch (Link->State) {
  1409. case LINK_STATE_READY:
  1410. NbfCompleteLink (Link);
  1411. break;
  1412. case LINK_STATE_ADM:
  1413. // Moving out of ADM, add reference
  1414. NbfReferenceLinkSpecial("Wait on ADM", Link, LREF_NOT_ADM);
  1415. //
  1416. // Intentionally fall through to the next case.
  1417. //
  1418. case LINK_STATE_W_DISC_RSP:
  1419. case LINK_STATE_CONNECTING:
  1420. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
  1421. Link->State = LINK_STATE_CONNECTING;
  1422. Link->SendState = SEND_STATE_DOWN;
  1423. Link->ReceiveState = RECEIVE_STATE_DOWN;
  1424. Link->SendRetries = (UCHAR)Link->LlcRetries;
  1425. NbfSendSabme (Link, TRUE); // send SABME/p, StartT1, release lock
  1426. break;
  1427. }
  1428. } /* NbfActivateLink */
  1429. VOID
  1430. NbfWaitLink(
  1431. IN PTP_LINK Link
  1432. )
  1433. /*++
  1434. Routine Description:
  1435. This routine waits for a remote link activation if it is not already
  1436. active.
  1437. NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
  1438. Arguments:
  1439. Link - Pointer to a transport link object.
  1440. Return Value:
  1441. none.
  1442. --*/
  1443. {
  1444. IF_NBFDBG (NBF_DEBUG_LINK) {
  1445. NbfPrint1 ("NbfWaitLink: Entered for link %lx.\n", Link);
  1446. }
  1447. ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
  1448. switch (Link->State) {
  1449. case LINK_STATE_READY:
  1450. NbfCompleteLink (Link);
  1451. break;
  1452. case LINK_STATE_W_DISC_RSP:
  1453. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
  1454. Link->State = LINK_STATE_CONNECTING;
  1455. Link->SendState = SEND_STATE_DOWN;
  1456. Link->ReceiveState = RECEIVE_STATE_DOWN;
  1457. NbfSendSabme (Link, TRUE); // send SABME/p, StartT1, release lock
  1458. break;
  1459. }
  1460. } /* NbfWaitLink */
  1461. VOID
  1462. NbfStopLink(
  1463. IN PTP_LINK Link
  1464. )
  1465. /*++
  1466. Routine Description:
  1467. This routine terminates a link and all outstanding connections attached
  1468. to the link. It is called from routines such as ExpireT2Timer, because
  1469. the remote connection partner seems dead or inoperative. As a consequence
  1470. of this routine being called, every outstanding connection will have its
  1471. disconnect handler called (in NbfStopConnection).
  1472. NOTE: THIS ROUTINE MUST BE CALLED FROM DPC LEVEL.
  1473. Arguments:
  1474. Link - Pointer to a transport link object.
  1475. Return Value:
  1476. none.
  1477. --*/
  1478. {
  1479. PLIST_ENTRY p;
  1480. PTP_PACKET packet;
  1481. PTP_CONNECTION connection;
  1482. IF_NBFDBG (NBF_DEBUG_LINK) {
  1483. NbfPrint1 ("NbfStopLink: Entered for link %lx.\n", Link);
  1484. }
  1485. ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
  1486. // Take a reference so the link won't go away inside this function
  1487. NbfReferenceLink("Temp in NbfStopLink", Link, LREF_STOPPING);
  1488. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
  1489. StopT1 (Link);
  1490. StopT2 (Link);
  1491. StopTi (Link);
  1492. p = RemoveHeadList (&Link->ConnectionDatabase);
  1493. while (p != &Link->ConnectionDatabase) {
  1494. //
  1495. // This will allow this connection to be "removed"
  1496. // from its link's list in NbfDisconnectFromLink, even if
  1497. // its not on a list.
  1498. //
  1499. InitializeListHead (p);
  1500. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  1501. connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
  1502. IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
  1503. NbfPrint1 ("NbfStopLink stopping connection, refcnt=%ld",
  1504. connection->ReferenceCount);
  1505. }
  1506. #if DBG
  1507. if (NbfDisconnectDebug) {
  1508. STRING remoteName, localName;
  1509. remoteName.Length = NETBIOS_NAME_LENGTH - 1;
  1510. remoteName.Buffer = connection->RemoteName;
  1511. localName.Length = NETBIOS_NAME_LENGTH - 1;
  1512. localName.Buffer = connection->AddressFile->Address->NetworkName->NetbiosName;
  1513. NbfPrint2( "TpStopLink stopping connection to %S from %S\n",
  1514. &remoteName, &localName );
  1515. }
  1516. #endif
  1517. NbfStopConnection (connection, STATUS_LINK_FAILED);
  1518. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
  1519. p = RemoveHeadList (&Link->ConnectionDatabase);
  1520. }
  1521. //
  1522. // We hold the link spinlock here.
  1523. //
  1524. //
  1525. // check for left over packets on the link WackQ; we'll never get
  1526. // acked for these if the link is in ADM mode.
  1527. //
  1528. while (!IsListEmpty (&Link->WackQ)) {
  1529. p = RemoveHeadList (&Link->WackQ);
  1530. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  1531. packet = CONTAINING_RECORD (p, TP_PACKET, Linkage);
  1532. NbfDereferencePacket (packet);
  1533. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
  1534. }
  1535. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  1536. StopT1 (Link);
  1537. StopT2 (Link);
  1538. StopTi (Link);
  1539. //
  1540. // Make sure we are not waiting for a deferred RR to be sent.
  1541. //
  1542. if (Link->OnDeferredRrQueue) {
  1543. ACQUIRE_DPC_SPIN_LOCK (Link->ProviderInterlock);
  1544. if (Link->OnDeferredRrQueue) {
  1545. RemoveEntryList (&Link->DeferredRrLinkage);
  1546. Link->OnDeferredRrQueue = FALSE;
  1547. }
  1548. RELEASE_DPC_SPIN_LOCK (Link->ProviderInterlock);
  1549. }
  1550. // Remove the temporary reference.
  1551. NbfDereferenceLink ("Temp in NbfStopLink", Link, LREF_STOPPING);
  1552. } /* NbfStopLink */
  1553. VOID
  1554. NbfResetLink(
  1555. IN PTP_LINK Link
  1556. )
  1557. /*++
  1558. Routine Description:
  1559. This routine is called by DLC.C routines only to reset this link
  1560. object and restart in-progress transport data transfers.
  1561. NOTE: This routine is called with the link spinlock acquired
  1562. at *OldIrqlP, and will return with it held, although it may
  1563. release it in the interim.
  1564. Arguments:
  1565. Link - Pointer to a transport link object.
  1566. OldIrqlP - Pointer to where the IRQL at which Link->SpinLock
  1567. was acquired is stored.
  1568. Return Value:
  1569. none.
  1570. --*/
  1571. {
  1572. PTP_PACKET packet;
  1573. PLIST_ENTRY p;
  1574. IF_NBFDBG (NBF_DEBUG_LINK) {
  1575. NbfPrint1 ("NbfResetLink: Entered for link %lx.\n", Link);
  1576. }
  1577. //
  1578. // Reset the link state to waiting for connection to start.
  1579. // Note that this is NOT the same as initiating a new link, as some things
  1580. // don't change, such as provider (devicecontext binding stays the same),
  1581. // Max Packet Length (can't change if provider doesn't), and other things
  1582. // that would bind this link structure to a different provider or provider
  1583. // type. Note also that we acquire the spinlock because, in the case of a
  1584. // link that's dropped (remotely) and is restarting, activities on this
  1585. // link could be occurring while we're in this routine.
  1586. //
  1587. StopT1 (Link);
  1588. StopT2 (Link);
  1589. // StopTi (Link);
  1590. Link->Flags = 0; // clear this, keep DeferredFlags
  1591. Link->SendState = SEND_STATE_DOWN; // send side is down.
  1592. Link->NextSend = 0;
  1593. Link->LastAckReceived = 0;
  1594. if (Link->Provider->MacInfo.MediumAsync) {
  1595. Link->SendWindowSize = (UCHAR)Link->Provider->RecommendedSendWindow;
  1596. Link->PrevWindowSize = (UCHAR)Link->Provider->RecommendedSendWindow;
  1597. } else {
  1598. Link->SendWindowSize = (UCHAR)1;
  1599. Link->PrevWindowSize = (UCHAR)1;
  1600. }
  1601. Link->WindowsUntilIncrease = 1;
  1602. Link->LinkBusy = FALSE;
  1603. Link->ConsecutiveLastPacketLost = 0;
  1604. //
  1605. // check for left over packets on the link WackQ; we'll never get
  1606. // acked for these if the link is resetting.
  1607. //
  1608. while (!IsListEmpty (&Link->WackQ)) {
  1609. p = RemoveHeadList (&Link->WackQ);
  1610. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  1611. packet = CONTAINING_RECORD (p, TP_PACKET, Linkage);
  1612. NbfDereferencePacket (packet);
  1613. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
  1614. }
  1615. Link->ReceiveState = RECEIVE_STATE_DOWN; // receive side down.
  1616. Link->NextReceive = 0;
  1617. Link->LastAckSent = 0;
  1618. Link->ReceiveWindowSize = 1;
  1619. Link->WindowErrors = 0;
  1620. Link->BestWindowSize = 1;
  1621. Link->WorstWindowSize = (UCHAR)Link->MaxWindowSize;
  1622. Link->Flags |= LINK_FLAGS_JUMP_START;
  1623. //
  1624. // This must be accurate before we set up timeouts.
  1625. //
  1626. Link->CurrentT1Timeout = Link->Provider->DefaultT1Timeout;
  1627. Link->BaseT1Timeout = Link->Provider->DefaultT1Timeout << DLC_TIMER_ACCURACY;
  1628. Link->MinimumBaseT1Timeout = Link->Provider->MinimumT1Timeout << DLC_TIMER_ACCURACY;
  1629. Link->BaseT1RecalcThreshhold = Link->MaxFrameSize / 2;
  1630. Link->CurrentPollRetransmits = 0;
  1631. Link->CurrentT1Backoff = FALSE;
  1632. Link->CurrentPollOutstanding = FALSE;
  1633. Link->RemoteNoPoll = TRUE;
  1634. Link->ConsecutiveIFrames = 0;
  1635. Link->T2Timeout = Link->Provider->DefaultT2Timeout;
  1636. Link->TiTimeout = Link->Provider->DefaultTiTimeout;
  1637. Link->LlcRetries = Link->Provider->LlcRetries;
  1638. Link->MaxWindowSize = Link->Provider->LlcMaxWindowSize;
  1639. Link->SendRetries = (UCHAR)Link->LlcRetries;
  1640. } /* NbfResetLink */
  1641. VOID
  1642. NbfDumpLinkInfo (
  1643. IN PTP_LINK Link
  1644. )
  1645. /*++
  1646. Routine Description:
  1647. This routine is called when any of the link timers fire and the
  1648. link send state is not ready. This gives us a way to track the
  1649. link state when strange things are happening.
  1650. Arguments:
  1651. Link - Pointer to a transport link object.
  1652. Return Value:
  1653. none.
  1654. --*/
  1655. {
  1656. Link; // avoid compiler warnings in non-debug versions
  1657. #if DBG
  1658. NbfPrint4 ("NbfDumpLinkInfo: Link %lx : State: %x SendState: %x ReceiveState: %x\n",
  1659. Link, Link->State, Link->SendState, Link->ReceiveState);
  1660. NbfPrint1 (" Flags: %lx\n",Link->Flags);
  1661. NbfPrint4 (" NextReceive: %d LastAckRcvd: %d NextSend: %d LastAckSent: %d\n",
  1662. Link->NextReceive, Link->LastAckReceived, Link->NextSend, Link->LastAckSent);
  1663. #endif
  1664. }