windows-nt/Source/XPSP1/NT/net/dlc/driver/dlctimr.c
2020-09-26 16:20:57 +08:00

410 lines
10 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1991 Microsoft Corporation
Copyright (c) 1991 Nokia Data Systems AB
Module Name:
dlctimr.c
Abstract:
This module implements timer services of NT DLC API.
Contents:
DirTimerSet
DirTimerCancelGroup
DirTimerCancel
SearchTimerCommand
AbortCommandsWithFlag
Author:
Antti Saarenheimo 02-Sep-1991
Environment:
Kernel mode
Revision History:
--*/
#include <dlc.h>
NTSTATUS
DirTimerSet(
IN PIRP pIrp,
IN PDLC_FILE_CONTEXT pFileContext,
IN PNT_DLC_PARMS pDlcParms,
IN ULONG InputBufferLength,
IN ULONG OutputBufferLength
)
/*++
Routine Description:
Procedure queues a timer set command to a special timer command
queue. The timer commands are queue by the cumulative time in
such way, that only the timer tick needs to decrement (and possibly
to complete) only the first command in the queue.
Arguments:
pIrp - current io request packet
pFileContext - DLC adapter context
pDlcParms - the current parameter block
InputBufferLength - the length of input parameters
OutputBufferLength - the length of output parameters
Return Value:
NTSTATUS:
STATUS_SUCCESS
--*/
{
PDLC_COMMAND* ppNode;
PDLC_COMMAND pDlcCommand;
UINT TimerTicks;
UNREFERENCED_PARAMETER(InputBufferLength);
UNREFERENCED_PARAMETER(OutputBufferLength);
//
// Check the timer value (I don't know what 13107 half seconds
// means, this is just as in IBM spec).
//
TimerTicks = pDlcParms->Async.Ccb.u.dir.usParameter0 + 1;
if (TimerTicks > 13108) {
return DLC_STATUS_TIMER_ERROR;
}
//
// DIR.TIMER.CANCEL returns wrong error code !!!!
// (0x0a insted of TIMER_ERROR)
//
pDlcCommand = (PDLC_COMMAND)ALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool);
if (pDlcCommand == NULL) {
return DLC_STATUS_NO_MEMORY;
}
pDlcCommand->Event = 0;
pDlcCommand->pIrp = pIrp;
pDlcCommand->StationId = 0;
pDlcCommand->StationIdMask = (USHORT)(-1);
pDlcCommand->AbortHandle = pDlcParms->Async.Ccb.pCcbAddress;
//
// find the right place in the list to put this timer
//
for (ppNode = &pFileContext->pTimerQueue; ; ) {
if (*ppNode == NULL) {
pDlcCommand->LlcPacket.pNext = NULL;
break;
} else if ((*ppNode)->Overlay.TimerTicks >= TimerTicks) {
(*ppNode)->Overlay.TimerTicks -= TimerTicks;
pDlcCommand->LlcPacket.pNext = (PLLC_PACKET)*ppNode;
break;
} else {
TimerTicks -= (*ppNode)->Overlay.TimerTicks;
}
ppNode = (PDLC_COMMAND *)&(*ppNode)->LlcPacket.pNext;
}
*ppNode = pDlcCommand;
pDlcCommand->Overlay.TimerTicks = TimerTicks;
return STATUS_PENDING;
}
NTSTATUS
DirTimerCancelGroup(
IN PIRP pIrp,
IN PDLC_FILE_CONTEXT pFileContext,
IN PNT_DLC_PARMS pDlcParms,
IN ULONG InputBufferLength,
IN ULONG OutputBufferLength
)
/*++
Routine Description:
Procedure cancels all DirTimerSet commands having the given
command completion flag.
Arguments:
pIrp - current io request packet
pFileContext - DLC adapter context
pDlcParms - the current parameter block
InputBufferLength - the length of input parameters
Return Value:
NTSTATUS:
STATUS_SUCCESS
--*/
{
UNREFERENCED_PARAMETER(pIrp);
UNREFERENCED_PARAMETER(InputBufferLength);
UNREFERENCED_PARAMETER(OutputBufferLength);
//
// All terminated DirTimerSet commands are chained to the
// CCB pointer of this cancel group command.
// Terminate the link list of the canceled CCBs.
//
pDlcParms->InputCcb.pCcbAddress = NULL;
AbortCommandsWithFlag(pFileContext,
pDlcParms->InputCcb.u.ulParameter, // CompletionFlag
&pDlcParms->InputCcb.pCcbAddress,
DLC_STATUS_CANCELLED_BY_USER
);
return STATUS_SUCCESS;
}
NTSTATUS
DirTimerCancel(
IN PIRP pIrp,
IN PDLC_FILE_CONTEXT pFileContext,
IN PNT_DLC_PARMS pDlcParms,
IN ULONG InputBufferLength,
IN ULONG OutputBufferLength
)
/*++
Routine Description:
This primitive cancels the given timer command in a
special timer queue.
Arguments:
pIrp - current io request packet
pFileContext - DLC process specific adapter context
pDlcParms - the current parameter block
InputBufferLength - the length of input parameters
Return Value:
NTSTATUS:
STATUS_SUCCESS
DLC_STATUS_TIMER_ERROR
--*/
{
PDLC_COMMAND pDlcCommand;
PDLC_COMMAND *ppDlcCommand;
PVOID pCcbAddress = NULL;
UNREFERENCED_PARAMETER(pIrp);
UNREFERENCED_PARAMETER(InputBufferLength);
UNREFERENCED_PARAMETER(OutputBufferLength);
ppDlcCommand = SearchTimerCommand(&pFileContext->pTimerQueue,
pDlcParms->DlcCancelCommand.CcbAddress,
FALSE
);
//
// if the timer queue is not empty, cancel the timed DLC request else
// return an error
//
if (ppDlcCommand != NULL && *ppDlcCommand != NULL) {
pDlcCommand = *ppDlcCommand;
*ppDlcCommand = (PDLC_COMMAND)pDlcCommand->LlcPacket.pNext;
// >>> SNA bug #10126
//
// If there's a next timer after the canceled one we need to update
// it's tick count. Things will go really wrong if the next timer's tick
// count is 0 (it expires at the same time as the canceled one) because
// the timer tick routine (LlcEventIndication) first decrements the tick
// value and then checks if the result is 0.
//
if( *ppDlcCommand )
{
(*ppDlcCommand)->Overlay.TimerTicks += pDlcCommand->Overlay.TimerTicks;
if((*ppDlcCommand)->Overlay.TimerTicks == 0)
{
(*ppDlcCommand)->Overlay.TimerTicks++;
}
}
// >>> SNA bug #10126
#if LLC_DBG
pDlcCommand->LlcPacket.pNext = NULL;
#endif
CancelDlcCommand(pFileContext,
pDlcCommand,
&pCcbAddress,
DLC_STATUS_CANCELLED_BY_USER,
TRUE
);
return STATUS_SUCCESS;
} else {
return DLC_STATUS_TIMER_ERROR;
}
}
PDLC_COMMAND*
SearchTimerCommand(
IN PDLC_COMMAND *ppQueue,
IN PVOID pSearchHandle,
IN BOOLEAN SearchCompletionFlags
)
/*++
Routine Description:
This primitive cancels the given timer command in a
special timer queue.
Arguments:
ppQueue - the base address of the command queue
pSearchHandle - command completion flag or ccb address of
the timer command.
SearchCompletionFlags - ste TRUE, if we are searching a completion flag
Return Value:
PDLC_COMMAND * the address of the address of the found timer command
--*/
{
PDLC_COMMAND pCmd;
for (; *ppQueue != NULL; ppQueue = (PDLC_COMMAND *)&(*ppQueue)->LlcPacket.pNext) {
pCmd = *ppQueue;
//
// A Timer command can be cancelled either by its CCB address
// or by its command completion flag. The boolean flag
// defines the used search condition.
// We will rather space than speed optimize the rarely used
// procedures like this one.
//
if (pSearchHandle
== (SearchCompletionFlags
? (PVOID)
UlongToPtr(((PNT_DLC_CCB)pCmd->pIrp->AssociatedIrp.SystemBuffer)->CommandCompletionFlag)
: pCmd->AbortHandle)) {
return ppQueue;
}
}
return NULL;
}
VOID
AbortCommandsWithFlag(
IN PDLC_FILE_CONTEXT pFileContext,
IN ULONG CommandCompletionFlag,
IN OUT PVOID *ppCcbLink,
IN UINT CancelStatus
)
/*++
Routine Description:
The command cancels all (timer) commands having the given command
completion flag.
Arguments:
pFileContext - process specific adapetr context
EventMask - the event mask defining the canceled command
CommandCompletionFlag - the command completion flag of the canceled
commands
ppCcbLink - the canceled commands are linked by their next CCB pointer
fields together. The caller must provide the next CCB address
in this parameter (usually *ppCcbLink == NULL) and the function
will return the address of the last canceled CCB field.
Return Value:
DLC_STATUS_TIMER_ERROR - no mathing command was found
STATUS_SUCCESS - the command was canceled
--*/
{
PDLC_COMMAND pDlcCommand;
PDLC_COMMAND *ppQueue;
PVOID pNextCcb = NULL;
ppQueue = &pFileContext->pTimerQueue;
for (;;) {
ppQueue = SearchTimerCommand(ppQueue,
(PVOID)UlongToPtr(CommandCompletionFlag),
TRUE
);
if (ppQueue != NULL) {
pDlcCommand = *ppQueue;
*ppQueue = (PDLC_COMMAND)pDlcCommand->LlcPacket.pNext;
#if LLC_DBG
pDlcCommand->LlcPacket.pNext = NULL;
#endif
*ppCcbLink = ((PNT_DLC_PARMS)pDlcCommand->pIrp->AssociatedIrp.SystemBuffer)->Async.Ccb.pCcbAddress;
//
// We must suppress any kind of command
// completion indications to the applications.
// It is very intersting to see, if Io- system hangs up
// because of this modification.
//
pDlcCommand->pIrp->UserEvent = NULL;
pDlcCommand->pIrp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
pDlcCommand->pIrp->Overlay.AsynchronousParameters.UserApcContext = NULL;
CompleteAsyncCommand(pFileContext, CancelStatus, pDlcCommand->pIrp, pNextCcb, FALSE);
pNextCcb = *ppCcbLink;
DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pDlcCommand);
} else {
//
// This procedure do not care if we find any commands
// or not. Everything is ok, when there are no commands
// in the queue.
//
return;
}
}
}