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.

1233 lines
30 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. timer.c
  5. Abstract:
  6. This module contains code which implements the timers for
  7. netbios.
  8. Environment:
  9. Kernel mode
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. ULONG NbiTickIncrement = 0;
  15. ULONG NbiShortTimerDeltaTicks = 0;
  16. #ifdef ALLOC_PRAGMA
  17. #pragma alloc_text(PAGE,NbiInitializeTimers)
  18. #endif
  19. VOID
  20. NbiStartRetransmit(
  21. IN PCONNECTION Connection
  22. )
  23. /*++
  24. Routine Description:
  25. This routine starts the retransmit timer for the given connection.
  26. The connection is inserted on the short list if it isn't on already.
  27. NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
  28. Arguments:
  29. Connection - pointer to the connection.
  30. Return Value:
  31. None.
  32. --*/
  33. {
  34. PDEVICE Device = NbiDevice;
  35. NB_DEFINE_LOCK_HANDLE (LockHandle)
  36. //
  37. // Insert us in the queue if we aren't in it.
  38. //
  39. Connection->Retransmit =
  40. Device->ShortAbsoluteTime + Connection->CurrentRetransmitTimeout;
  41. if (!Connection->OnShortList) {
  42. CTEAssert (KeGetCurrentIrql() == DISPATCH_LEVEL);
  43. NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
  44. if (!Connection->OnShortList) {
  45. Connection->OnShortList = TRUE;
  46. InsertTailList (&Device->ShortList, &Connection->ShortList);
  47. }
  48. if (!Device->ShortListActive) {
  49. NbiStartShortTimer (Device);
  50. Device->ShortListActive = TRUE;
  51. }
  52. NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
  53. }
  54. } /* NbiStartRetransmit */
  55. VOID
  56. NbiStartWatchdog(
  57. IN PCONNECTION Connection
  58. )
  59. /*++
  60. Routine Description:
  61. This routine starts the watchdog timer for a connection.
  62. NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
  63. Arguments:
  64. Connection - pointer to the connection.
  65. Return Value:
  66. None.
  67. --*/
  68. {
  69. PDEVICE Device = NbiDevice;
  70. NB_DEFINE_LOCK_HANDLE (LockHandle);
  71. Connection->Watchdog = Device->LongAbsoluteTime + Connection->WatchdogTimeout;
  72. if (!Connection->OnLongList) {
  73. ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
  74. NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
  75. if (!Connection->OnLongList) {
  76. Connection->OnLongList = TRUE;
  77. InsertTailList (&Device->LongList, &Connection->LongList);
  78. }
  79. NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
  80. }
  81. } /* NbiStartWatchdog */
  82. #if DBG
  83. VOID
  84. NbiStopRetransmit(
  85. IN PCONNECTION Connection
  86. )
  87. /*++
  88. Routine Description:
  89. This routine stops the retransmit timer for a connection.
  90. Arguments:
  91. Connection - pointer to the connection.
  92. Return Value:
  93. None.
  94. --*/
  95. {
  96. Connection->Retransmit = 0;
  97. } /* NbiStopRetransmit */
  98. VOID
  99. NbiStopWatchdog(
  100. IN PCONNECTION Connection
  101. )
  102. /*++
  103. Routine Description:
  104. This routine stops the watchdog timer for a connection.
  105. Arguments:
  106. Connection - pointer to the connection.
  107. Return Value:
  108. None.
  109. --*/
  110. {
  111. Connection->Watchdog = 0;
  112. } /* NbiStopWatchdog */
  113. #endif
  114. VOID
  115. NbiExpireRetransmit(
  116. IN PCONNECTION Connection
  117. )
  118. /*++
  119. Routine Description:
  120. This routine is called when the connection's retransmit timer
  121. expires. It is called from NbiShortTimeout.
  122. Arguments:
  123. Connection - Pointer to the connection whose timer has expired.
  124. Return Value:
  125. none.
  126. --*/
  127. {
  128. PDEVICE Device = NbiDevice;
  129. BOOLEAN SendFindRoute;
  130. NB_DEFINE_LOCK_HANDLE (LockHandle);
  131. NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
  132. if (Connection->State == CONNECTION_STATE_ACTIVE) {
  133. SendFindRoute = FALSE;
  134. ++Device->Statistics.ResponseTimerExpirations;
  135. if (!(Connection->NewNetbios) &&
  136. (Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK)) {
  137. if (--Connection->Retries == 0) {
  138. //
  139. // Shut down the connection. This will send
  140. // out half the usual number of session end
  141. // frames.
  142. //
  143. NB_DEBUG2 (CONNECTION, ("Wait for ack timeout of active connection %lx\n", Connection));
  144. //
  145. // This free the connection lock.
  146. //
  147. NbiStopConnection(
  148. Connection,
  149. STATUS_LINK_FAILED
  150. NB_LOCK_HANDLE_ARG (LockHandle)
  151. );
  152. } else {
  153. //
  154. // Set our current packetize location back to the
  155. // spot of the last ack, and start up again.
  156. //
  157. // Should we send a probe here?
  158. //
  159. Connection->CurrentSend = Connection->UnAckedSend;
  160. Connection->RetransmitThisWindow = TRUE;
  161. if (Connection->CurrentRetransmitTimeout < (Connection->BaseRetransmitTimeout*8)) {
  162. Connection->CurrentRetransmitTimeout =
  163. (Connection->CurrentRetransmitTimeout * 3) / 2;
  164. }
  165. NB_DEBUG2 (SEND, ("Connection %lx retransmit timeout\n", Connection));
  166. //
  167. // After half the retries, send a find route unless we
  168. // are already doing one, or the connection is to network
  169. // 0. When this completes we update the local target,
  170. // for whatever good that does.
  171. //
  172. if ((!Connection->FindRouteInProgress) &&
  173. (Connection->Retries == (Device->KeepAliveCount/2)) &&
  174. (*(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork != 0)) {
  175. SendFindRoute = TRUE;
  176. Connection->FindRouteInProgress = TRUE;
  177. NbiReferenceConnectionSync (Connection, CREF_FIND_ROUTE);
  178. }
  179. //
  180. // This releases the lock.
  181. //
  182. NbiPacketizeSend(
  183. Connection
  184. NB_LOCK_HANDLE_ARG(LockHandle)
  185. );
  186. }
  187. } else if ((Connection->SubState == CONNECTION_SUBSTATE_A_W_PROBE) ||
  188. (Connection->SubState == CONNECTION_SUBSTATE_A_REMOTE_W) ||
  189. (Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK)) {
  190. if (--Connection->Retries == 0) {
  191. //
  192. // Shut down the connection. This will send
  193. // out half the usual number of session end
  194. // frames.
  195. //
  196. NB_DEBUG2 (CONNECTION, ("Probe timeout of active connection %lx\n", Connection));
  197. //
  198. // This free the connection lock.
  199. //
  200. NbiStopConnection(
  201. Connection,
  202. STATUS_LINK_FAILED
  203. NB_LOCK_HANDLE_ARG (LockHandle)
  204. );
  205. } else {
  206. Connection->RetransmitThisWindow = TRUE;
  207. if (Connection->CurrentRetransmitTimeout < (Connection->BaseRetransmitTimeout*8)) {
  208. Connection->CurrentRetransmitTimeout =
  209. (Connection->CurrentRetransmitTimeout * 3) / 2;
  210. }
  211. NbiStartRetransmit (Connection);
  212. //
  213. // After half the retries, send a find route unless we
  214. // are already doing one, or the connection is to network
  215. // 0. When this completes we update the local target,
  216. // for whatever good that does.
  217. //
  218. if ((!Connection->FindRouteInProgress) &&
  219. (Connection->Retries == (Device->KeepAliveCount/2)) &&
  220. (*(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork != 0)) {
  221. SendFindRoute = TRUE;
  222. Connection->FindRouteInProgress = TRUE;
  223. NbiReferenceConnectionSync (Connection, CREF_FIND_ROUTE);
  224. }
  225. //
  226. // Set this so we know to retransmit when the ack
  227. // is received.
  228. //
  229. if (Connection->SubState != CONNECTION_SUBSTATE_A_W_PROBE) {
  230. Connection->ResponseTimeout = TRUE;
  231. }
  232. //
  233. // This releases the lock.
  234. //
  235. NbiSendDataAck(
  236. Connection,
  237. NbiAckQuery
  238. NB_LOCK_HANDLE_ARG(LockHandle));
  239. }
  240. } else {
  241. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  242. }
  243. if (SendFindRoute) {
  244. Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
  245. *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network =
  246. *(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork;
  247. RtlCopyMemory(Connection->FindRouteRequest.Node,Connection->RemoteHeader.DestinationNode,6);
  248. Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_FORCE_RIP;
  249. (*Device->Bind.FindRouteHandler)(
  250. &Connection->FindRouteRequest);
  251. }
  252. } else {
  253. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  254. }
  255. } /* NbiExpireRetansmit */
  256. VOID
  257. NbiExpireWatchdog(
  258. IN PCONNECTION Connection
  259. )
  260. /*++
  261. Routine Description:
  262. This routine is called when the connection's watchdog timer
  263. expires. It is called from NbiLongTimeout.
  264. Arguments:
  265. Connection - Pointer to the connection whose timer has expired.
  266. Return Value:
  267. none.
  268. --*/
  269. {
  270. NB_DEFINE_LOCK_HANDLE (LockHandle);
  271. NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
  272. //
  273. // If we are not idle, then something else is happening
  274. // so the watchdog is unnecessary.
  275. //
  276. if ((Connection->State == CONNECTION_STATE_ACTIVE) &&
  277. (Connection->SubState == CONNECTION_SUBSTATE_A_IDLE)) {
  278. Connection->Retries = NbiDevice->KeepAliveCount;
  279. Connection->SubState = CONNECTION_SUBSTATE_A_W_PROBE;
  280. NbiStartRetransmit (Connection);
  281. //
  282. // This releases the lock.
  283. //
  284. NbiSendDataAck(
  285. Connection,
  286. NbiAckQuery
  287. NB_LOCK_HANDLE_ARG(LockHandle));
  288. } else {
  289. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  290. }
  291. } /* NbiExpireWatchdog */
  292. VOID
  293. NbiShortTimeout(
  294. IN CTEEvent * Event,
  295. IN PVOID Context
  296. )
  297. /*++
  298. Routine Description:
  299. This routine is called at regular intervals to see if any of
  300. the short connection timers have expired, and if so to execute their
  301. expiration routines.
  302. Arguments:
  303. Event - The event controlling the timer.
  304. Context - Points to our device.
  305. Return Value:
  306. none.
  307. --*/
  308. {
  309. PLIST_ENTRY p, nextp;
  310. PDEVICE Device = (PDEVICE)Context;
  311. PCONNECTION Connection;
  312. BOOLEAN RestartTimer = FALSE;
  313. LARGE_INTEGER CurrentTick;
  314. LARGE_INTEGER TickDifference;
  315. ULONG TickDelta;
  316. NB_DEFINE_LOCK_HANDLE (LockHandle);
  317. NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
  318. //
  319. // This prevents anybody from starting the timer while we
  320. // are in this routine (the main reason for this is that it
  321. // makes it easier to determine whether we should restart
  322. // it at the end of this routine).
  323. //
  324. Device->ProcessingShortTimer = TRUE;
  325. //
  326. // Advance the up-counter used to mark time in SHORT_TIMER_DELTA units. If we
  327. // advance it all the way to 0xf0000000, then reset it to 0x10000000.
  328. // We also run all the lists, decreasing all counters by 0xe0000000.
  329. //
  330. KeQueryTickCount (&CurrentTick);
  331. TickDifference.QuadPart = CurrentTick.QuadPart -
  332. Device->ShortTimerStart.QuadPart;
  333. TickDelta = TickDifference.LowPart / NbiShortTimerDeltaTicks;
  334. if (TickDelta == 0) {
  335. TickDelta = 1;
  336. }
  337. Device->ShortAbsoluteTime += TickDelta;
  338. if (Device->ShortAbsoluteTime >= 0xf0000000) {
  339. ULONG Timeout;
  340. Device->ShortAbsoluteTime -= 0xe0000000;
  341. p = Device->ShortList.Flink;
  342. while (p != &Device->ShortList) {
  343. Connection = CONTAINING_RECORD (p, CONNECTION, ShortList);
  344. Timeout = Connection->Retransmit;
  345. if (Timeout) {
  346. Connection->Retransmit = Timeout - 0xe0000000;
  347. }
  348. p = p->Flink;
  349. }
  350. }
  351. p = Device->ShortList.Flink;
  352. while (p != &Device->ShortList) {
  353. Connection = CONTAINING_RECORD (p, CONNECTION, ShortList);
  354. ASSERT (Connection->OnShortList);
  355. //
  356. // To avoid problems with the refcount being 0, don't
  357. // do this if we are in ADM.
  358. //
  359. if (Connection->State == CONNECTION_STATE_ACTIVE) {
  360. if (Connection->Retransmit &&
  361. (Device->ShortAbsoluteTime > Connection->Retransmit)) {
  362. Connection->Retransmit = 0;
  363. NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
  364. NbiExpireRetransmit (Connection); // no locks held
  365. NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
  366. }
  367. }
  368. if (!Connection->OnShortList) {
  369. //
  370. // The link has been taken out of the list while
  371. // we were processing it. In this (rare) case we
  372. // stop processing the whole list, we'll get it
  373. // next time.
  374. //
  375. break;
  376. }
  377. nextp = p->Flink;
  378. if (Connection->Retransmit == 0) {
  379. Connection->OnShortList = FALSE;
  380. RemoveEntryList(p);
  381. //
  382. // Do another check; that way if someone slipped in between
  383. // the check of Connection->Tx and the OnShortList = FALSE and
  384. // therefore exited without inserting, we'll catch that here.
  385. //
  386. if (Connection->Retransmit != 0) {
  387. InsertTailList(&Device->ShortList, &Connection->ShortList);
  388. Connection->OnShortList = TRUE;
  389. }
  390. }
  391. p = nextp;
  392. }
  393. //
  394. // If the list is empty note that, otherwise ShortListActive
  395. // remains TRUE.
  396. //
  397. if (IsListEmpty (&Device->ShortList)) {
  398. Device->ShortListActive = FALSE;
  399. }
  400. //
  401. // Connection Data Ack timers. This queue is used to indicate
  402. // that a piggyback ack is pending for this connection. We walk
  403. // the queue, for each element we check if the connection has
  404. // been on the queue for enough times through here,
  405. // If so, we take it off and send an ack. Note that
  406. // we have to be very careful how we walk the queue, since
  407. // it may be changing while this is running.
  408. //
  409. for (p = Device->DataAckConnections.Flink;
  410. p != &Device->DataAckConnections;
  411. p = p->Flink) {
  412. Connection = CONTAINING_RECORD (p, CONNECTION, DataAckLinkage);
  413. //
  414. // Skip this connection if it is not queued or it is
  415. // too recent to matter. We may skip incorrectly if
  416. // the connection is just being queued, but that is
  417. // OK, we will get it next time.
  418. //
  419. if (!Connection->DataAckPending) {
  420. continue;
  421. }
  422. ++Connection->DataAckTimeouts;
  423. if (Connection->DataAckTimeouts < Device->AckDelayTime) {
  424. continue;
  425. }
  426. NbiReferenceConnectionSync (Connection, CREF_SHORT_D_ACK);
  427. Device->DataAckQueueChanged = FALSE;
  428. NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
  429. //
  430. // Check the correct connection flag, to ensure that a
  431. // send has not just taken him off the queue.
  432. //
  433. NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
  434. if (Connection->DataAckPending) {
  435. //
  436. // Yes, we were waiting to piggyback an ack, but no send
  437. // has come along. Turn off the flags and send an ack.
  438. // We set PiggybackAckTimeout to TRUE so that we won't try
  439. // to piggyback a response until we get back traffic.
  440. //
  441. Connection->DataAckPending = FALSE;
  442. Connection->PiggybackAckTimeout = TRUE;
  443. ++Device->Statistics.AckTimerExpirations;
  444. ++Device->Statistics.PiggybackAckTimeouts;
  445. //
  446. // This call releases the lock.
  447. //
  448. NbiSendDataAck(
  449. Connection,
  450. NbiAckResponse
  451. NB_LOCK_HANDLE_ARG(LockHandle));
  452. } else {
  453. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  454. }
  455. NbiDereferenceConnection (Connection, CREF_SHORT_D_ACK);
  456. NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
  457. //
  458. // If the list has changed, then we need to stop processing
  459. // since p->Flink is not valid.
  460. //
  461. if (Device->DataAckQueueChanged) {
  462. break;
  463. }
  464. }
  465. if (IsListEmpty (&Device->DataAckConnections)) {
  466. Device->DataAckActive = FALSE;
  467. }
  468. //
  469. // Update the real counters from the temp ones. We have
  470. // TimerLock here, which is good enough.
  471. //
  472. ADD_TO_LARGE_INTEGER(
  473. &Device->Statistics.DataFrameBytesSent,
  474. Device->TempFrameBytesSent);
  475. Device->Statistics.DataFramesSent += Device->TempFramesSent;
  476. Device->TempFrameBytesSent = 0;
  477. Device->TempFramesSent = 0;
  478. ADD_TO_LARGE_INTEGER(
  479. &Device->Statistics.DataFrameBytesReceived,
  480. Device->TempFrameBytesReceived);
  481. Device->Statistics.DataFramesReceived += Device->TempFramesReceived;
  482. Device->TempFrameBytesReceived = 0;
  483. Device->TempFramesReceived = 0;
  484. //
  485. // Determine if we have to restart the timer.
  486. //
  487. Device->ProcessingShortTimer = FALSE;
  488. if ((Device->ShortListActive || Device->DataAckActive) &&
  489. (Device->State != DEVICE_STATE_STOPPING)) {
  490. RestartTimer = TRUE;
  491. }
  492. NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
  493. if (RestartTimer) {
  494. //
  495. // Start up the timer again. Note that because we start the timer
  496. // after doing work (above), the timer values will slip somewhat,
  497. // depending on the load on the protocol. This is entirely acceptable
  498. // and will prevent us from using the timer DPC in two different
  499. // threads of execution.
  500. //
  501. KeQueryTickCount(&Device->ShortTimerStart);
  502. CTEStartTimer(
  503. &Device->ShortTimer,
  504. SHORT_TIMER_DELTA,
  505. NbiShortTimeout,
  506. (PVOID)Device);
  507. } else {
  508. NbiDereferenceDevice (Device, DREF_SHORT_TIMER);
  509. }
  510. } /* NbiShortTimeout */
  511. VOID
  512. NbiLongTimeout(
  513. IN CTEEvent * Event,
  514. IN PVOID Context
  515. )
  516. /*++
  517. Routine Description:
  518. This routine is called at regular intervals to see if any of
  519. the long connection timers have expired, and if so to execute their
  520. expiration routines.
  521. Arguments:
  522. Event - The event controlling the timer.
  523. Context - Points to our device.
  524. Return Value:
  525. none.
  526. --*/
  527. {
  528. PDEVICE Device = (PDEVICE)Context;
  529. PLIST_ENTRY p, nextp;
  530. LIST_ENTRY AdapterStatusList;
  531. PREQUEST AdapterStatusRequest;
  532. PCONNECTION Connection;
  533. PNETBIOS_CACHE CacheName;
  534. NB_DEFINE_LOCK_HANDLE (LockHandle)
  535. NB_DEFINE_LOCK_HANDLE (LockHandle1)
  536. //
  537. // Advance the up-counter used to mark time in LONG_TIMER_DELTA units. If we
  538. // advance it all the way to 0xf0000000, then reset it to 0x10000000.
  539. // We also run all the lists, decreasing all counters by 0xe0000000.
  540. //
  541. NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
  542. if (++Device->LongAbsoluteTime == 0xf0000000) {
  543. ULONG Timeout;
  544. Device->LongAbsoluteTime = 0x10000000;
  545. p = Device->LongList.Flink;
  546. while (p != &Device->LongList) {
  547. Connection = CONTAINING_RECORD (p, CONNECTION, LongList);
  548. Timeout = Connection->Watchdog;
  549. if (Timeout) {
  550. Connection->Watchdog = Timeout - 0xe0000000;
  551. }
  552. p = p->Flink;
  553. }
  554. }
  555. if ((Device->LongAbsoluteTime % 4) == 0) {
  556. p = Device->LongList.Flink;
  557. while (p != &Device->LongList) {
  558. Connection = CONTAINING_RECORD (p, CONNECTION, LongList);
  559. ASSERT (Connection->OnLongList);
  560. //
  561. // To avoid problems with the refcount being 0, don't
  562. // do this if we are in ADM.
  563. //
  564. if (Connection->State == CONNECTION_STATE_ACTIVE) {
  565. if (Connection->Watchdog && (Device->LongAbsoluteTime > Connection->Watchdog)) {
  566. Connection->Watchdog = 0;
  567. NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
  568. NbiExpireWatchdog (Connection); // no spinlocks held
  569. NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
  570. }
  571. }
  572. if (!Connection->OnLongList) {
  573. //
  574. // The link has been taken out of the list while
  575. // we were processing it. In this (rare) case we
  576. // stop processing the whole list, we'll get it
  577. // next time.
  578. //
  579. #if DBG
  580. DbgPrint ("NBI: Stop processing LongList, %lx removed\n", Connection);
  581. #endif
  582. break;
  583. }
  584. nextp = p->Flink;
  585. if (Connection->Watchdog == 0) {
  586. Connection->OnLongList = FALSE;
  587. RemoveEntryList(p);
  588. if (Connection->Watchdog != 0) {
  589. InsertTailList(&Device->LongList, &Connection->LongList);
  590. Connection->OnLongList = TRUE;
  591. }
  592. }
  593. p = nextp;
  594. }
  595. }
  596. //
  597. // Now scan the data ack queue, looking for connections with
  598. // no acks queued that we can get rid of.
  599. //
  600. // Note: The timer spinlock is held here.
  601. //
  602. for (p = Device->DataAckConnections.Flink;
  603. p != &Device->DataAckConnections;
  604. p = p->Flink) {
  605. Connection = CONTAINING_RECORD (p, CONNECTION, DataAckLinkage);
  606. if (Connection->DataAckPending) {
  607. continue;
  608. }
  609. NbiReferenceConnectionSync (Connection, CREF_LONG_D_ACK);
  610. NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
  611. NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
  612. NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
  613. //
  614. // Have to check again, because the connection might
  615. // just have been stopped, and it also might just have
  616. // had a data ack queued.
  617. //
  618. if (Connection->OnDataAckQueue) {
  619. Connection->OnDataAckQueue = FALSE;
  620. RemoveEntryList (&Connection->DataAckLinkage);
  621. if (Connection->DataAckPending) {
  622. InsertTailList (&Device->DataAckConnections, &Connection->DataAckLinkage);
  623. Connection->OnDataAckQueue = TRUE;
  624. }
  625. Device->DataAckQueueChanged = TRUE;
  626. }
  627. NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
  628. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
  629. NbiDereferenceConnection (Connection, CREF_LONG_D_ACK);
  630. NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
  631. //
  632. // Since we have changed the list, we can't tell if p->Flink
  633. // is valid, so break. The effect is that we gradually peel
  634. // connections off the queue.
  635. //
  636. break;
  637. }
  638. NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
  639. //
  640. // Scan for any uncompleted receive IRPs, this may happen if
  641. // the cable is pulled and we don't get any more ReceiveComplete
  642. // indications.
  643. NbiReceiveComplete((USHORT)0);
  644. //
  645. // Check if any adapter status queries are getting old.
  646. //
  647. InitializeListHead (&AdapterStatusList);
  648. NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
  649. p = Device->ActiveAdapterStatus.Flink;
  650. while (p != &Device->ActiveAdapterStatus) {
  651. AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p);
  652. p = p->Flink;
  653. if (REQUEST_INFORMATION(AdapterStatusRequest) == 1) {
  654. //
  655. // We should resend a certain number of times.
  656. //
  657. RemoveEntryList (REQUEST_LINKAGE(AdapterStatusRequest));
  658. InsertTailList (&AdapterStatusList, REQUEST_LINKAGE(AdapterStatusRequest));
  659. //
  660. // We are going to abort this request, so dereference
  661. // the cache entry it used.
  662. //
  663. CacheName = (PNETBIOS_CACHE)REQUEST_STATUSPTR(AdapterStatusRequest);
  664. if (--CacheName->ReferenceCount == 0) {
  665. NB_DEBUG2 (CACHE, ("Free delete name cache entry %lx\n", CacheName));
  666. NbiFreeMemory(
  667. CacheName,
  668. sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
  669. MEMORY_CACHE,
  670. "Name deleted");
  671. }
  672. } else {
  673. ++REQUEST_INFORMATION(AdapterStatusRequest);
  674. }
  675. }
  676. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
  677. for (p = AdapterStatusList.Flink; p != &AdapterStatusList; ) {
  678. AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p);
  679. p = p->Flink;
  680. NB_DEBUG2 (QUERY, ("AdapterStatus %lx got name but no response\n", AdapterStatusRequest));
  681. REQUEST_INFORMATION(AdapterStatusRequest) = 0;
  682. REQUEST_STATUS(AdapterStatusRequest) = STATUS_IO_TIMEOUT;
  683. NbiCompleteRequest(AdapterStatusRequest);
  684. NbiFreeRequest (Device, AdapterStatusRequest);
  685. NbiDereferenceDevice (Device, DREF_STATUS_QUERY);
  686. }
  687. //
  688. // See if a minute has passed and we need to check for empty
  689. // cache entries to age out. We check for 64 seconds to make
  690. // the mod operation faster.
  691. //
  692. #if defined(_PNP_POWER)
  693. NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
  694. #endif _PNP_POWER
  695. ++Device->CacheTimeStamp;
  696. if ((Device->CacheTimeStamp % 64) == 0) {
  697. //
  698. // flush all the entries which have been around for ten minutes
  699. // (LONG_TIMER_DELTA is in milliseconds).
  700. //
  701. FlushOldFromNetbiosCacheTable( Device->NameCache, (600000 / LONG_TIMER_DELTA) );
  702. }
  703. //
  704. // Start up the timer again. Note that because we start the timer
  705. // after doing work (above), the timer values will slip somewhat,
  706. // depending on the load on the protocol. This is entirely acceptable
  707. // and will prevent us from using the timer DPC in two different
  708. // threads of execution.
  709. //
  710. if (Device->State != DEVICE_STATE_STOPPING) {
  711. CTEStartTimer(
  712. &Device->LongTimer,
  713. LONG_TIMER_DELTA,
  714. NbiLongTimeout,
  715. (PVOID)Device);
  716. } else {
  717. #if defined(_PNP_POWER)
  718. Device->LongTimerRunning = FALSE;
  719. #endif _PNP_POWER
  720. NbiDereferenceDevice (Device, DREF_LONG_TIMER);
  721. }
  722. #if defined(_PNP_POWER)
  723. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
  724. #endif _PNP_POWER
  725. } /* NbiLongTimeout */
  726. VOID
  727. NbiStartShortTimer(
  728. IN PDEVICE Device
  729. )
  730. /*++
  731. Routine Description:
  732. This routine starts the short timer, if it is not already running.
  733. Arguments:
  734. Device - Pointer to our device context.
  735. Return Value:
  736. none.
  737. --*/
  738. {
  739. //
  740. // Start the timer unless it the DPC is already running (in
  741. // which case it will restart the timer itself if needed),
  742. // or some list is active (meaning the timer is already
  743. // queued up).
  744. //
  745. if ((!Device->ProcessingShortTimer) &&
  746. (!(Device->ShortListActive)) &&
  747. (!(Device->DataAckActive))) {
  748. NbiReferenceDevice (Device, DREF_SHORT_TIMER);
  749. KeQueryTickCount(&Device->ShortTimerStart);
  750. CTEStartTimer(
  751. &Device->ShortTimer,
  752. SHORT_TIMER_DELTA,
  753. NbiShortTimeout,
  754. (PVOID)Device);
  755. }
  756. } /* NbiStartShortTimer */
  757. VOID
  758. NbiInitializeTimers(
  759. IN PDEVICE Device
  760. )
  761. /*++
  762. Routine Description:
  763. This routine initializes the lightweight timer system for the transport
  764. provider.
  765. Arguments:
  766. Device - Pointer to our device.
  767. Return Value:
  768. none.
  769. --*/
  770. {
  771. //
  772. // NbiTickIncrement is the number of NT time increments
  773. // which pass between each tick. NbiShortTimerDeltaTicks
  774. // is the number of ticks which should happen in
  775. // SHORT_TIMER_DELTA milliseconds (i.e. between each
  776. // expiration of the short timer).
  777. //
  778. NbiTickIncrement = KeQueryTimeIncrement();
  779. if (NbiTickIncrement > (SHORT_TIMER_DELTA * MILLISECONDS)) {
  780. NbiShortTimerDeltaTicks = 1;
  781. } else {
  782. NbiShortTimerDeltaTicks = (SHORT_TIMER_DELTA * MILLISECONDS) / NbiTickIncrement;
  783. }
  784. //
  785. // The AbsoluteTime cycles between 0x10000000 and 0xf0000000.
  786. //
  787. Device->ShortAbsoluteTime = 0x10000000;
  788. Device->LongAbsoluteTime = 0x10000000;
  789. CTEInitTimer (&Device->ShortTimer);
  790. CTEInitTimer (&Device->LongTimer);
  791. #if !defined(_PNP_POWER)
  792. //
  793. // One reference for the long timer.
  794. //
  795. NbiReferenceDevice (Device, DREF_LONG_TIMER);
  796. CTEStartTimer(
  797. &Device->LongTimer,
  798. LONG_TIMER_DELTA,
  799. NbiLongTimeout,
  800. (PVOID)Device);
  801. #endif !_PNP_POWER
  802. Device->TimersInitialized = TRUE;
  803. Device->ShortListActive = FALSE;
  804. Device->ProcessingShortTimer = FALSE;
  805. InitializeListHead (&Device->ShortList);
  806. InitializeListHead (&Device->LongList);
  807. CTEInitLock (&Device->TimerLock.Lock);
  808. } /* NbiInitializeTimers */