345 lines
7.5 KiB
C
345 lines
7.5 KiB
C
|
|
|||
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
timer.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains code which implements the receive and send timeouts
|
|||
|
for each connection. Netbios timeouts are specified in 0.5 second units.
|
|||
|
|
|||
|
For each application using Netbios there is a single timer started
|
|||
|
when the first connection specifies a non-zero rto or sto. This regular
|
|||
|
1 second pulse is used for all connections by this application. It
|
|||
|
is stopped when the application exits (and closes the connection to
|
|||
|
\Device\Netbios).
|
|||
|
|
|||
|
If a send timesout the connection is disconnected as per Netbios 3.0.
|
|||
|
Individual receives can timeout without affecting the session.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Colin Watson (ColinW) 15-Sep-1991
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "nb.h"
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(PAGE, NbStartTimer)
|
|||
|
#pragma alloc_text(PAGE, NbTimer)
|
|||
|
#endif
|
|||
|
|
|||
|
VOID
|
|||
|
RunTimerForLana(
|
|||
|
PFCB pfcb,
|
|||
|
PLANA_INFO plana,
|
|||
|
int index
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
NbStartTimer(
|
|||
|
IN PFCB pfcb
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine starts the timer ticking for this FCB.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pfcb - Pointer to our FCB.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
none.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LARGE_INTEGER DueTime;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
DueTime.QuadPart = Int32x32To64( 500, -MILLISECONDS );
|
|||
|
|
|||
|
// This is the first connection with timeouts specified.
|
|||
|
|
|||
|
//
|
|||
|
// set up the timer so that every 500 milliseconds we scan all the
|
|||
|
// connections for timed out receive and sends.
|
|||
|
//
|
|||
|
|
|||
|
IF_NBDBG (NB_DEBUG_CALL) {
|
|||
|
NbPrint( ("Start the timer for fcb: %lx\n", pfcb));
|
|||
|
}
|
|||
|
|
|||
|
if ( pfcb->TimerRunning == TRUE ) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
KeInitializeDpc (
|
|||
|
&pfcb->Dpc,
|
|||
|
NbTimerDPC,
|
|||
|
pfcb);
|
|||
|
|
|||
|
KeInitializeTimer (&pfcb->Timer);
|
|||
|
|
|||
|
pfcb->TimerRunning = TRUE;
|
|||
|
|
|||
|
(VOID)KeSetTimer (
|
|||
|
&pfcb->Timer,
|
|||
|
DueTime,
|
|||
|
&pfcb->Dpc);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
NbTimerDPC(
|
|||
|
IN PKDPC Dpc,
|
|||
|
IN PVOID Context,
|
|||
|
IN PVOID SystemArgument1,
|
|||
|
IN PVOID SystemArgument2
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called to search for timed out send and receive
|
|||
|
requests. This routine is called at raised Irql.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - Pointer to our FCB.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
none.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PFCB pfcb = (PFCB) Context;
|
|||
|
|
|||
|
IoQueueWorkItem(
|
|||
|
pfcb->WorkEntry, NbTimer, DelayedWorkQueue, pfcb
|
|||
|
);
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER (Dpc);
|
|||
|
UNREFERENCED_PARAMETER (SystemArgument1);
|
|||
|
UNREFERENCED_PARAMETER (SystemArgument2);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
NbTimer(
|
|||
|
PDEVICE_OBJECT DeviceObject,
|
|||
|
PVOID Context
|
|||
|
)
|
|||
|
{
|
|||
|
ULONG lana_index;
|
|||
|
int index;
|
|||
|
PFCB pfcb = (PFCB) Context;
|
|||
|
|
|||
|
LARGE_INTEGER DueTime;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// For each network adapter that is allocated, scan each connection.
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
LOCK_RESOURCE(pfcb);
|
|||
|
|
|||
|
IF_NBDBG (NB_DEBUG_TIMER) {
|
|||
|
NbPrint((" NbTimeout\n" ));
|
|||
|
}
|
|||
|
|
|||
|
if ( pfcb->TimerRunning != TRUE ) {
|
|||
|
|
|||
|
//
|
|||
|
// Driver is being closed. We are trying to cancel the timer
|
|||
|
// but the dpc was already fired. Set the timer cancelled event
|
|||
|
// to the signalled state and exit.
|
|||
|
//
|
|||
|
|
|||
|
UNLOCK_RESOURCE(pfcb);
|
|||
|
KeSetEvent( pfcb->TimerCancelled, 0, FALSE);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
for ( lana_index = 0; lana_index <= pfcb->MaxLana; lana_index++ ) {
|
|||
|
|
|||
|
// For each network.
|
|||
|
|
|||
|
PLANA_INFO plana = pfcb->ppLana[lana_index];
|
|||
|
|
|||
|
if (( plana != NULL ) &&
|
|||
|
( plana->Status == NB_INITIALIZED)) {
|
|||
|
|
|||
|
// For each connection on that network.
|
|||
|
|
|||
|
for ( index = 1; index <= MAXIMUM_CONNECTION; index++) {
|
|||
|
|
|||
|
if ( plana->ConnectionBlocks[index] != NULL ) {
|
|||
|
|
|||
|
RunTimerForLana(pfcb, plana, index);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
DueTime.QuadPart = Int32x32To64( 500, -MILLISECONDS );
|
|||
|
|
|||
|
(VOID)KeSetTimer (
|
|||
|
&pfcb->Timer,
|
|||
|
DueTime,
|
|||
|
&pfcb->Dpc);
|
|||
|
|
|||
|
UNLOCK_RESOURCE(pfcb);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
RunTimerForLana(
|
|||
|
PFCB pfcb,
|
|||
|
PLANA_INFO plana,
|
|||
|
int index
|
|||
|
)
|
|||
|
{
|
|||
|
|
|||
|
KIRQL OldIrql; // Used when SpinLock held.
|
|||
|
PPCB ppcb;
|
|||
|
PCB pcb;
|
|||
|
|
|||
|
ppcb = &plana->ConnectionBlocks[index];
|
|||
|
pcb = *ppcb;
|
|||
|
|
|||
|
if (( pcb->Status != SESSION_ESTABLISHED ) &&
|
|||
|
( pcb->Status != HANGUP_PENDING )) {
|
|||
|
// Only examine valid connections.
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
LOCK_SPINLOCK( pfcb, OldIrql );
|
|||
|
|
|||
|
if (( pcb->ReceiveTimeout != 0 ) &&
|
|||
|
( !IsListEmpty( &pcb->ReceiveList))) {
|
|||
|
PDNCB pdncb;
|
|||
|
PLIST_ENTRY ReceiveEntry = pcb->ReceiveList.Flink;
|
|||
|
|
|||
|
pdncb = CONTAINING_RECORD( ReceiveEntry, DNCB, ncb_next);
|
|||
|
|
|||
|
if ( pdncb->tick_count <= 1) {
|
|||
|
PIRP Irp = pdncb->irp;
|
|||
|
|
|||
|
// Read request timed out.
|
|||
|
|
|||
|
IF_NBDBG (NB_DEBUG_TIMER) {
|
|||
|
NbPrint(("Timeout Read pncb: %lx\n", pdncb));
|
|||
|
}
|
|||
|
|
|||
|
NCB_COMPLETE( pdncb, NRC_CMDTMO );
|
|||
|
|
|||
|
RemoveEntryList( &pdncb->ncb_next );
|
|||
|
|
|||
|
IoAcquireCancelSpinLock(&Irp->CancelIrql);
|
|||
|
|
|||
|
//
|
|||
|
// Remove the cancel request for this IRP. If its cancelled then its
|
|||
|
// ok to just process it because we will be returning it to the caller.
|
|||
|
//
|
|||
|
|
|||
|
Irp->Cancel = FALSE;
|
|||
|
|
|||
|
IoSetCancelRoutine(Irp, NULL);
|
|||
|
|
|||
|
IoReleaseCancelSpinLock(Irp->CancelIrql);
|
|||
|
|
|||
|
// repair the Irp so that the NCB gets copied back.
|
|||
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|||
|
Irp->IoStatus.Information =
|
|||
|
FIELD_OFFSET( DNCB, ncb_cmd_cplt );
|
|||
|
IoCompleteRequest( Irp, IO_NETWORK_INCREMENT);
|
|||
|
|
|||
|
} else {
|
|||
|
IF_NBDBG (NB_DEBUG_TIMER) {
|
|||
|
NbPrint(("Tick Read pdncb: %lx, count: %x\n", pdncb, pdncb->tick_count));
|
|||
|
}
|
|||
|
pdncb->tick_count -= 1;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (( pcb->SendTimeout != 0 ) &&
|
|||
|
(!IsListEmpty( &pcb->SendList))) {
|
|||
|
PDNCB pdncb;
|
|||
|
PLIST_ENTRY SendEntry = pcb->SendList.Flink;
|
|||
|
|
|||
|
pdncb = CONTAINING_RECORD( SendEntry, DNCB, ncb_next);
|
|||
|
if ( pdncb->tick_count <= 1) {
|
|||
|
// Send request timed out- hangup connection.
|
|||
|
|
|||
|
IF_NBDBG (NB_DEBUG_TIMER) {
|
|||
|
NbPrint(("Timeout send pncb: %lx\n", pdncb));
|
|||
|
}
|
|||
|
|
|||
|
NCB_COMPLETE( pdncb, NRC_CMDTMO );
|
|||
|
|
|||
|
pcb->Status = SESSION_ABORTED;
|
|||
|
|
|||
|
UNLOCK_SPINLOCK( pfcb, OldIrql );
|
|||
|
|
|||
|
CloseConnection( ppcb, 1000 );
|
|||
|
|
|||
|
//
|
|||
|
// No need to worry about looking for a timed out hangup, the session
|
|||
|
// will be closed as soon as the transport cancels the send.
|
|||
|
//
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
} else {
|
|||
|
IF_NBDBG (NB_DEBUG_TIMER) {
|
|||
|
NbPrint(("Tick Write pdncb: %lx, count: %x\n", pdncb, pdncb->tick_count));
|
|||
|
}
|
|||
|
pdncb->tick_count -= 1;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (( pcb->pdncbHangup != NULL ) &&
|
|||
|
( pcb->Status == HANGUP_PENDING )) {
|
|||
|
if ( pcb->pdncbHangup->tick_count <= 1) {
|
|||
|
IF_NBDBG (NB_DEBUG_TIMER) {
|
|||
|
NbPrint(("Timeout send pncb: %lx\n", pcb->pdncbHangup));
|
|||
|
}
|
|||
|
|
|||
|
NCB_COMPLETE( pcb->pdncbHangup, NRC_CMDTMO );
|
|||
|
|
|||
|
UNLOCK_SPINLOCK( pfcb, OldIrql );
|
|||
|
|
|||
|
AbandonConnection( ppcb );
|
|||
|
|
|||
|
LOCK_SPINLOCK( pfcb, OldIrql );
|
|||
|
|
|||
|
} else {
|
|||
|
IF_NBDBG (NB_DEBUG_TIMER) {
|
|||
|
NbPrint(("Tick Hangup pdncb: %lx, count: %x\n",
|
|||
|
pcb->pdncbHangup,
|
|||
|
pcb->pdncbHangup->tick_count));
|
|||
|
}
|
|||
|
pcb->pdncbHangup->tick_count -= 1;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
UNLOCK_SPINLOCK( pfcb, OldIrql );
|
|||
|
}
|