diff options
Diffstat (limited to 'private/ntos/tdi/isnp/nb/timer.c')
-rw-r--r-- | private/ntos/tdi/isnp/nb/timer.c | 1233 |
1 files changed, 1233 insertions, 0 deletions
diff --git a/private/ntos/tdi/isnp/nb/timer.c b/private/ntos/tdi/isnp/nb/timer.c new file mode 100644 index 000000000..381b120e5 --- /dev/null +++ b/private/ntos/tdi/isnp/nb/timer.c @@ -0,0 +1,1233 @@ +/*++ + +Copyright (c) 1989-1993 Microsoft Corporation + +Module Name: + + timer.c + +Abstract: + + This module contains code which implements the timers for + netbios. + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#include "precomp.h" +#pragma hdrstop + + +ULONG NbiTickIncrement = 0; +ULONG NbiShortTimerDeltaTicks = 0; + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,NbiInitializeTimers) +#endif + + +VOID +NbiStartRetransmit( + IN PCONNECTION Connection + ) + +/*++ + +Routine Description: + + This routine starts the retransmit timer for the given connection. + The connection is inserted on the short list if it isn't on already. + + NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL. + +Arguments: + + Connection - pointer to the connection. + +Return Value: + + None. + +--*/ + +{ + PDEVICE Device = NbiDevice; + NB_DEFINE_LOCK_HANDLE (LockHandle) + + // + // Insert us in the queue if we aren't in it. + // + + Connection->Retransmit = + Device->ShortAbsoluteTime + Connection->CurrentRetransmitTimeout; + + if (!Connection->OnShortList) { + + CTEAssert (KeGetCurrentIrql() == DISPATCH_LEVEL); + + NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle); + + if (!Connection->OnShortList) { + Connection->OnShortList = TRUE; + InsertTailList (&Device->ShortList, &Connection->ShortList); + } + + if (!Device->ShortListActive) { + NbiStartShortTimer (Device); + Device->ShortListActive = TRUE; + } + + NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle); + } + +} /* NbiStartRetransmit */ + + +VOID +NbiStartWatchdog( + IN PCONNECTION Connection + ) + +/*++ + +Routine Description: + + This routine starts the watchdog timer for a connection. + + NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL. + +Arguments: + + Connection - pointer to the connection. + +Return Value: + + None. + +--*/ + +{ + PDEVICE Device = NbiDevice; + NB_DEFINE_LOCK_HANDLE (LockHandle); + + + Connection->Watchdog = Device->LongAbsoluteTime + Connection->WatchdogTimeout; + + if (!Connection->OnLongList) { + + ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL); + + NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle); + + if (!Connection->OnLongList) { + Connection->OnLongList = TRUE; + InsertTailList (&Device->LongList, &Connection->LongList); + } + + NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle); + } + +} /* NbiStartWatchdog */ + +#if DBG + +VOID +NbiStopRetransmit( + IN PCONNECTION Connection + ) + +/*++ + +Routine Description: + + This routine stops the retransmit timer for a connection. + +Arguments: + + Connection - pointer to the connection. + +Return Value: + + None. + +--*/ + +{ + Connection->Retransmit = 0; + +} /* NbiStopRetransmit */ + + +VOID +NbiStopWatchdog( + IN PCONNECTION Connection + ) + +/*++ + +Routine Description: + + This routine stops the watchdog timer for a connection. + +Arguments: + + Connection - pointer to the connection. + +Return Value: + + None. + +--*/ + +{ + Connection->Watchdog = 0; + +} /* NbiStopWatchdog */ +#endif + + +VOID +NbiExpireRetransmit( + IN PCONNECTION Connection + ) + +/*++ + +Routine Description: + + This routine is called when the connection's retransmit timer + expires. It is called from NbiShortTimeout. + +Arguments: + + Connection - Pointer to the connection whose timer has expired. + +Return Value: + + none. + +--*/ + +{ + PDEVICE Device = NbiDevice; + BOOLEAN SendFindRoute; + NB_DEFINE_LOCK_HANDLE (LockHandle); + + NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle); + + if (Connection->State == CONNECTION_STATE_ACTIVE) { + + SendFindRoute = FALSE; + + ++Device->Statistics.ResponseTimerExpirations; + + if (!(Connection->NewNetbios) && + (Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK)) { + + if (--Connection->Retries == 0) { + + // + // Shut down the connection. This will send + // out half the usual number of session end + // frames. + // + + NB_DEBUG2 (CONNECTION, ("Wait for ack timeout of active connection %lx\n", Connection)); + + // + // This free the connection lock. + // + + NbiStopConnection( + Connection, + STATUS_LINK_FAILED + NB_LOCK_HANDLE_ARG (LockHandle) + ); + + } else { + + // + // Set our current packetize location back to the + // spot of the last ack, and start up again. + // + // BUGBUG: Should we send a probe here? + // + + Connection->CurrentSend = Connection->UnAckedSend; + Connection->RetransmitThisWindow = TRUE; + if (Connection->CurrentRetransmitTimeout < (Connection->BaseRetransmitTimeout*8)) { + Connection->CurrentRetransmitTimeout = + (Connection->CurrentRetransmitTimeout * 3) / 2; + } + + NB_DEBUG2 (SEND, ("Connection %lx retransmit timeout\n", Connection)); + + // + // After half the retries, send a find route unless we + // are already doing one, or the connection is to network + // 0. When this completes we update the local target, + // for whatever good that does. + // + + if ((!Connection->FindRouteInProgress) && + (Connection->Retries == (Device->KeepAliveCount/2)) && + (*(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork != 0)) { + + SendFindRoute = TRUE; + Connection->FindRouteInProgress = TRUE; + NbiReferenceConnectionSync (Connection, CREF_FIND_ROUTE); + + } + + // + // This releases the lock. + // + + NbiPacketizeSend( + Connection + NB_LOCK_HANDLE_ARG(LockHandle) + ); + + } + + } else if ((Connection->SubState == CONNECTION_SUBSTATE_A_W_PROBE) || + (Connection->SubState == CONNECTION_SUBSTATE_A_REMOTE_W) || + (Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK)) { + + if (--Connection->Retries == 0) { + + // + // Shut down the connection. This will send + // out half the usual number of session end + // frames. + // + + NB_DEBUG2 (CONNECTION, ("Probe timeout of active connection %lx\n", Connection)); + + // + // This free the connection lock. + // + + NbiStopConnection( + Connection, + STATUS_LINK_FAILED + NB_LOCK_HANDLE_ARG (LockHandle) + ); + + } else { + + Connection->RetransmitThisWindow = TRUE; + if (Connection->CurrentRetransmitTimeout < (Connection->BaseRetransmitTimeout*8)) { + Connection->CurrentRetransmitTimeout = + (Connection->CurrentRetransmitTimeout * 3) / 2; + } + + NbiStartRetransmit (Connection); + + // + // After half the retries, send a find route unless we + // are already doing one, or the connection is to network + // 0. When this completes we update the local target, + // for whatever good that does. + // + + if ((!Connection->FindRouteInProgress) && + (Connection->Retries == (Device->KeepAliveCount/2)) && + (*(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork != 0)) { + + SendFindRoute = TRUE; + Connection->FindRouteInProgress = TRUE; + NbiReferenceConnectionSync (Connection, CREF_FIND_ROUTE); + + } + + // + // Set this so we know to retransmit when the ack + // is received. + // + + if (Connection->SubState != CONNECTION_SUBSTATE_A_W_PROBE) { + Connection->ResponseTimeout = TRUE; + } + + + // + // This releases the lock. + // + + NbiSendDataAck( + Connection, + NbiAckQuery + NB_LOCK_HANDLE_ARG(LockHandle)); + + + } + + } else { + + NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle); + + } + + if (SendFindRoute) { + + Connection->FindRouteRequest.Identifier = IDENTIFIER_NB; + *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network = + *(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork; + RtlCopyMemory(Connection->FindRouteRequest.Node,Connection->RemoteHeader.DestinationNode,6); + Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_FORCE_RIP; + + (*Device->Bind.FindRouteHandler)( + &Connection->FindRouteRequest); + + } + + } else { + + NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle); + + } + +} /* NbiExpireRetansmit */ + + +VOID +NbiExpireWatchdog( + IN PCONNECTION Connection + ) + +/*++ + +Routine Description: + + This routine is called when the connection's watchdog timer + expires. It is called from NbiLongTimeout. + +Arguments: + + Connection - Pointer to the connection whose timer has expired. + +Return Value: + + none. + +--*/ + +{ + NB_DEFINE_LOCK_HANDLE (LockHandle); + + + NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle); + + // + // If we are not idle, then something else is happening + // so the watchdog is unnecessary. + // + + if ((Connection->State == CONNECTION_STATE_ACTIVE) && + (Connection->SubState == CONNECTION_SUBSTATE_A_IDLE)) { + + Connection->Retries = NbiDevice->KeepAliveCount; + Connection->SubState = CONNECTION_SUBSTATE_A_W_PROBE; + NbiStartRetransmit (Connection); + + // + // This releases the lock. + // + + NbiSendDataAck( + Connection, + NbiAckQuery + NB_LOCK_HANDLE_ARG(LockHandle)); + + } else { + + NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle); + + } + +} /* NbiExpireWatchdog */ + + +VOID +NbiShortTimeout( + IN CTEEvent * Event, + IN PVOID Context + ) + +/*++ + +Routine Description: + + This routine is called at regular intervals to see if any of + the short connection timers have expired, and if so to execute their + expiration routines. + +Arguments: + + Event - The event controlling the timer. + + Context - Points to our device. + +Return Value: + + none. + +--*/ + +{ + PLIST_ENTRY p, nextp; + PDEVICE Device = (PDEVICE)Context; + PCONNECTION Connection; + BOOLEAN RestartTimer = FALSE; + LARGE_INTEGER CurrentTick; + LARGE_INTEGER TickDifference; + ULONG TickDelta; + NB_DEFINE_LOCK_HANDLE (LockHandle); + + + NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle); + + // + // This prevents anybody from starting the timer while we + // are in this routine (the main reason for this is that it + // makes it easier to determine whether we should restart + // it at the end of this routine). + // + + Device->ProcessingShortTimer = TRUE; + + // + // Advance the up-counter used to mark time in SHORT_TIMER_DELTA units. If we + // advance it all the way to 0xf0000000, then reset it to 0x10000000. + // We also run all the lists, decreasing all counters by 0xe0000000. + // + + + KeQueryTickCount (&CurrentTick); + + TickDifference.QuadPart = CurrentTick.QuadPart - + Device->ShortTimerStart.QuadPart; + + TickDelta = TickDifference.LowPart / NbiShortTimerDeltaTicks; + if (TickDelta == 0) { + TickDelta = 1; + } + + Device->ShortAbsoluteTime += TickDelta; + + if (Device->ShortAbsoluteTime >= 0xf0000000) { + + ULONG Timeout; + + Device->ShortAbsoluteTime -= 0xe0000000; + + p = Device->ShortList.Flink; + while (p != &Device->ShortList) { + + Connection = CONTAINING_RECORD (p, CONNECTION, ShortList); + + Timeout = Connection->Retransmit; + if (Timeout) { + Connection->Retransmit = Timeout - 0xe0000000; + } + + p = p->Flink; + } + + } + + p = Device->ShortList.Flink; + while (p != &Device->ShortList) { + + Connection = CONTAINING_RECORD (p, CONNECTION, ShortList); + + ASSERT (Connection->OnShortList); + + // + // To avoid problems with the refcount being 0, don't + // do this if we are in ADM. + // + + if (Connection->State == CONNECTION_STATE_ACTIVE) { + + if (Connection->Retransmit && + (Device->ShortAbsoluteTime > Connection->Retransmit)) { + + Connection->Retransmit = 0; + NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle); + + NbiExpireRetransmit (Connection); // no locks held + + NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle); + + } + + } + + if (!Connection->OnShortList) { + + // + // The link has been taken out of the list while + // we were processing it. In this (rare) case we + // stop processing the whole list, we'll get it + // next time. + // + + break; + + } + + nextp = p->Flink; + + if (Connection->Retransmit == 0) { + + Connection->OnShortList = FALSE; + RemoveEntryList(p); + + // + // Do another check; that way if someone slipped in between + // the check of Connection->Tx and the OnShortList = FALSE and + // therefore exited without inserting, we'll catch that here. + // + + if (Connection->Retransmit != 0) { + InsertTailList(&Device->ShortList, &Connection->ShortList); + Connection->OnShortList = TRUE; + } + + } + + p = nextp; + + } + + // + // If the list is empty note that, otherwise ShortListActive + // remains TRUE. + // + + if (IsListEmpty (&Device->ShortList)) { + Device->ShortListActive = FALSE; + } + + + // + // Connection Data Ack timers. This queue is used to indicate + // that a piggyback ack is pending for this connection. We walk + // the queue, for each element we check if the connection has + // been on the queue for enough times through here, + // If so, we take it off and send an ack. Note that + // we have to be very careful how we walk the queue, since + // it may be changing while this is running. + // + + for (p = Device->DataAckConnections.Flink; + p != &Device->DataAckConnections; + p = p->Flink) { + + Connection = CONTAINING_RECORD (p, CONNECTION, DataAckLinkage); + + // + // Skip this connection if it is not queued or it is + // too recent to matter. We may skip incorrectly if + // the connection is just being queued, but that is + // OK, we will get it next time. + // + + if (!Connection->DataAckPending) { + continue; + } + + ++Connection->DataAckTimeouts; + + if (Connection->DataAckTimeouts < Device->AckDelayTime) { + continue; + } + + NbiReferenceConnectionSync (Connection, CREF_SHORT_D_ACK); + + Device->DataAckQueueChanged = FALSE; + + NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle); + + // + // Check the correct connection flag, to ensure that a + // send has not just taken him off the queue. + // + + NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle); + + if (Connection->DataAckPending) { + + // + // Yes, we were waiting to piggyback an ack, but no send + // has come along. Turn off the flags and send an ack. + // We set PiggybackAckTimeout to TRUE so that we won't try + // to piggyback a response until we get back traffic. + // + + Connection->DataAckPending = FALSE; + Connection->PiggybackAckTimeout = TRUE; + ++Device->Statistics.AckTimerExpirations; + ++Device->Statistics.PiggybackAckTimeouts; + + // + // This call releases the lock. + // + + NbiSendDataAck( + Connection, + NbiAckResponse + NB_LOCK_HANDLE_ARG(LockHandle)); + + } else { + + NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle); + + } + + NbiDereferenceConnection (Connection, CREF_SHORT_D_ACK); + + NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle); + + // + // If the list has changed, then we need to stop processing + // since p->Flink is not valid. + // + + if (Device->DataAckQueueChanged) { + break; + } + + } + + if (IsListEmpty (&Device->DataAckConnections)) { + Device->DataAckActive = FALSE; + } + + + // + // Update the real counters from the temp ones. We have + // TimerLock here, which is good enough. + // + + ADD_TO_LARGE_INTEGER( + &Device->Statistics.DataFrameBytesSent, + Device->TempFrameBytesSent); + Device->Statistics.DataFramesSent += Device->TempFramesSent; + + Device->TempFrameBytesSent = 0; + Device->TempFramesSent = 0; + + ADD_TO_LARGE_INTEGER( + &Device->Statistics.DataFrameBytesReceived, + Device->TempFrameBytesReceived); + Device->Statistics.DataFramesReceived += Device->TempFramesReceived; + + Device->TempFrameBytesReceived = 0; + Device->TempFramesReceived = 0; + + + // + // Determine if we have to restart the timer. + // + + Device->ProcessingShortTimer = FALSE; + + if ((Device->ShortListActive || Device->DataAckActive) && + (Device->State != DEVICE_STATE_STOPPING)) { + + RestartTimer = TRUE; + + } + + NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle); + + if (RestartTimer) { + + // + // Start up the timer again. Note that because we start the timer + // after doing work (above), the timer values will slip somewhat, + // depending on the load on the protocol. This is entirely acceptable + // and will prevent us from using the timer DPC in two different + // threads of execution. + // + + KeQueryTickCount(&Device->ShortTimerStart); + + CTEStartTimer( + &Device->ShortTimer, + SHORT_TIMER_DELTA, + NbiShortTimeout, + (PVOID)Device); + + } else { + + NbiDereferenceDevice (Device, DREF_SHORT_TIMER); + + } + +} /* NbiShortTimeout */ + + +VOID +NbiLongTimeout( + IN CTEEvent * Event, + IN PVOID Context + ) + +/*++ + +Routine Description: + + This routine is called at regular intervals to see if any of + the long connection timers have expired, and if so to execute their + expiration routines. + +Arguments: + + Event - The event controlling the timer. + + Context - Points to our device. + +Return Value: + + none. + +--*/ + +{ + PDEVICE Device = (PDEVICE)Context; + PLIST_ENTRY p, nextp; + LIST_ENTRY AdapterStatusList; + PREQUEST AdapterStatusRequest; + PCONNECTION Connection; + PNETBIOS_CACHE CacheName; + NB_DEFINE_LOCK_HANDLE (LockHandle) + NB_DEFINE_LOCK_HANDLE (LockHandle1) + + + // + // Advance the up-counter used to mark time in LONG_TIMER_DELTA units. If we + // advance it all the way to 0xf0000000, then reset it to 0x10000000. + // We also run all the lists, decreasing all counters by 0xe0000000. + // + + NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle); + + if (++Device->LongAbsoluteTime == 0xf0000000) { + + ULONG Timeout; + + Device->LongAbsoluteTime = 0x10000000; + + p = Device->LongList.Flink; + while (p != &Device->LongList) { + + Connection = CONTAINING_RECORD (p, CONNECTION, LongList); + + Timeout = Connection->Watchdog; + if (Timeout) { + Connection->Watchdog = Timeout - 0xe0000000; + } + + p = p->Flink; + } + + } + + + if ((Device->LongAbsoluteTime % 4) == 0) { + + p = Device->LongList.Flink; + while (p != &Device->LongList) { + + Connection = CONTAINING_RECORD (p, CONNECTION, LongList); + + ASSERT (Connection->OnLongList); + + // + // To avoid problems with the refcount being 0, don't + // do this if we are in ADM. + // + + if (Connection->State == CONNECTION_STATE_ACTIVE) { + + if (Connection->Watchdog && (Device->LongAbsoluteTime > Connection->Watchdog)) { + + Connection->Watchdog = 0; + NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle); + + NbiExpireWatchdog (Connection); // no spinlocks held + + NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle); + + } + + } + + if (!Connection->OnLongList) { + + // + // The link has been taken out of the list while + // we were processing it. In this (rare) case we + // stop processing the whole list, we'll get it + // next time. + // + +#if DBG + DbgPrint ("NBI: Stop processing LongList, %lx removed\n", Connection); +#endif + break; + + } + + nextp = p->Flink; + + if (Connection->Watchdog == 0) { + + Connection->OnLongList = FALSE; + RemoveEntryList(p); + + if (Connection->Watchdog != 0) { + InsertTailList(&Device->LongList, &Connection->LongList); + Connection->OnLongList = TRUE; + } + + } + + p = nextp; + + } + + } + + + // + // Now scan the data ack queue, looking for connections with + // no acks queued that we can get rid of. + // + // Note: The timer spinlock is held here. + // + + for (p = Device->DataAckConnections.Flink; + p != &Device->DataAckConnections; + p = p->Flink) { + + Connection = CONTAINING_RECORD (p, CONNECTION, DataAckLinkage); + + if (Connection->DataAckPending) { + continue; + } + + NbiReferenceConnectionSync (Connection, CREF_LONG_D_ACK); + + NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle); + + NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1); + NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle); + + // + // Have to check again, because the connection might + // just have been stopped, and it also might just have + // had a data ack queued. + // + + if (Connection->OnDataAckQueue) { + + Connection->OnDataAckQueue = FALSE; + + RemoveEntryList (&Connection->DataAckLinkage); + + if (Connection->DataAckPending) { + InsertTailList (&Device->DataAckConnections, &Connection->DataAckLinkage); + Connection->OnDataAckQueue = TRUE; + } + + Device->DataAckQueueChanged = TRUE; + + } + + NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle); + NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1); + + NbiDereferenceConnection (Connection, CREF_LONG_D_ACK); + + NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle); + + // + // Since we have changed the list, we can't tell if p->Flink + // is valid, so break. The effect is that we gradually peel + // connections off the queue. + // + + break; + + } + + NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle); + + + // + // Scan for any uncompleted receive IRPs, this may happen if + // the cable is pulled and we don't get any more ReceiveComplete + // indications. + + NbiReceiveComplete((USHORT)0); + + + // + // Check if any adapter status queries are getting old. + // + + InitializeListHead (&AdapterStatusList); + + NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle); + + p = Device->ActiveAdapterStatus.Flink; + + while (p != &Device->ActiveAdapterStatus) { + + AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p); + + p = p->Flink; + + if (REQUEST_INFORMATION(AdapterStatusRequest) == 1) { + + // + // BUGBUG: We should resend a certain number of times. + // + + RemoveEntryList (REQUEST_LINKAGE(AdapterStatusRequest)); + InsertTailList (&AdapterStatusList, REQUEST_LINKAGE(AdapterStatusRequest)); + + // + // We are going to abort this request, so dereference + // the cache entry it used. + // + + CacheName = (PNETBIOS_CACHE)REQUEST_STATUS(AdapterStatusRequest); + if (--CacheName->ReferenceCount == 0) { + + NB_DEBUG2 (CACHE, ("Free delete name cache entry %lx\n", CacheName)); + NbiFreeMemory( + CacheName, + sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)), + MEMORY_CACHE, + "Name deleted"); + + } + + } else { + + ++REQUEST_INFORMATION(AdapterStatusRequest); + + } + + } + + NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle); + + + for (p = AdapterStatusList.Flink; p != &AdapterStatusList; ) { + + AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p); + p = p->Flink; + + NB_DEBUG2 (QUERY, ("AdapterStatus %lx got name but no response\n", AdapterStatusRequest)); + + REQUEST_INFORMATION(AdapterStatusRequest) = 0; + REQUEST_STATUS(AdapterStatusRequest) = STATUS_IO_TIMEOUT; + + NbiCompleteRequest(AdapterStatusRequest); + NbiFreeRequest (Device, AdapterStatusRequest); + + NbiDereferenceDevice (Device, DREF_STATUS_QUERY); + + } + + // + // See if a minute has passed and we need to check for empty + // cache entries to age out. We check for 64 seconds to make + // the mod operation faster. + // + +#if defined(_PNP_POWER) + NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle); +#endif _PNP_POWER + + ++Device->CacheTimeStamp; + + if ((Device->CacheTimeStamp % 64) == 0) { + + + // + // flush all the entries which have been around for ten minutes + // (LONG_TIMER_DELTA is in milliseconds). + // + + FlushOldFromNetbiosCacheTable( Device->NameCache, (600000 / LONG_TIMER_DELTA) ); + + } + + + // + // Start up the timer again. Note that because we start the timer + // after doing work (above), the timer values will slip somewhat, + // depending on the load on the protocol. This is entirely acceptable + // and will prevent us from using the timer DPC in two different + // threads of execution. + // + + if (Device->State != DEVICE_STATE_STOPPING) { + + CTEStartTimer( + &Device->LongTimer, + LONG_TIMER_DELTA, + NbiLongTimeout, + (PVOID)Device); + + } else { +#if defined(_PNP_POWER) + Device->LongTimerRunning = FALSE; +#endif _PNP_POWER + NbiDereferenceDevice (Device, DREF_LONG_TIMER); + } + +#if defined(_PNP_POWER) + NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle); +#endif _PNP_POWER +} /* NbiLongTimeout */ + + +VOID +NbiStartShortTimer( + IN PDEVICE Device + ) + +/*++ + +Routine Description: + + This routine starts the short timer, if it is not already running. + +Arguments: + + Device - Pointer to our device context. + +Return Value: + + none. + +--*/ + +{ + + // + // Start the timer unless it the DPC is already running (in + // which case it will restart the timer itself if needed), + // or some list is active (meaning the timer is already + // queued up). + // + + if ((!Device->ProcessingShortTimer) && + (!(Device->ShortListActive)) && + (!(Device->DataAckActive))) { + + NbiReferenceDevice (Device, DREF_SHORT_TIMER); + + KeQueryTickCount(&Device->ShortTimerStart); + + CTEStartTimer( + &Device->ShortTimer, + SHORT_TIMER_DELTA, + NbiShortTimeout, + (PVOID)Device); + + } + +} /* NbiStartShortTimer */ + + +VOID +NbiInitializeTimers( + IN PDEVICE Device + ) + +/*++ + +Routine Description: + + This routine initializes the lightweight timer system for the transport + provider. + +Arguments: + + Device - Pointer to our device. + +Return Value: + + none. + +--*/ + +{ + + // + // NbiTickIncrement is the number of NT time increments + // which pass between each tick. NbiShortTimerDeltaTicks + // is the number of ticks which should happen in + // SHORT_TIMER_DELTA milliseconds (i.e. between each + // expiration of the short timer). + // + + NbiTickIncrement = KeQueryTimeIncrement(); + + if (NbiTickIncrement > (SHORT_TIMER_DELTA * MILLISECONDS)) { + NbiShortTimerDeltaTicks = 1; + } else { + NbiShortTimerDeltaTicks = (SHORT_TIMER_DELTA * MILLISECONDS) / NbiTickIncrement; + } + + // + // The AbsoluteTime cycles between 0x10000000 and 0xf0000000. + // + + Device->ShortAbsoluteTime = 0x10000000; + Device->LongAbsoluteTime = 0x10000000; + + CTEInitTimer (&Device->ShortTimer); + CTEInitTimer (&Device->LongTimer); + +#if !defined(_PNP_POWER) + // + // One reference for the long timer. + // + + NbiReferenceDevice (Device, DREF_LONG_TIMER); + + CTEStartTimer( + &Device->LongTimer, + LONG_TIMER_DELTA, + NbiLongTimeout, + (PVOID)Device); + +#endif !_PNP_POWER + + Device->TimersInitialized = TRUE; + Device->ShortListActive = FALSE; + Device->ProcessingShortTimer = FALSE; + + InitializeListHead (&Device->ShortList); + InitializeListHead (&Device->LongList); + + CTEInitLock (&Device->TimerLock.Lock); + +} /* NbiInitializeTimers */ + |