3190 lines
84 KiB
C
3190 lines
84 KiB
C
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
araputil.c
|
|
|
|
Abstract:
|
|
|
|
This module implements utility routines needed for the ARAP functionality
|
|
|
|
Author:
|
|
|
|
Shirish Koti
|
|
|
|
Revision History:
|
|
15 Nov 1996 Initial Version
|
|
|
|
--*/
|
|
|
|
#include <atalk.h>
|
|
#pragma hdrstop
|
|
|
|
// File module number for errorlogging
|
|
#define FILENUM ARAPUTIL
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE_ARAP, DerefMnpSendBuf)
|
|
#pragma alloc_text(PAGE_ARAP, DerefArapConn)
|
|
#pragma alloc_text(PAGE_ARAP, ArapReleaseAddr)
|
|
#pragma alloc_text(PAGE_ARAP, ArapCleanup)
|
|
#pragma alloc_text(PAGE_ARAP, PrepareConnectionResponse)
|
|
#pragma alloc_text(PAGE_ARAP, ArapExtractAtalkSRP)
|
|
#pragma alloc_text(PAGE_ARAP, ArapQueueSendBytes)
|
|
#pragma alloc_text(PAGE_ARAP, ArapGetSendBuf)
|
|
#pragma alloc_text(PAGE_ARAP, ArapRefillSendQ)
|
|
#endif
|
|
|
|
//***
|
|
//
|
|
// Function: AllocArapConn
|
|
// Allocate a connection element and initialize fields
|
|
//
|
|
// Parameters: none
|
|
//
|
|
// Return: pointer to a newly allocated connection element
|
|
//
|
|
//***$
|
|
|
|
PARAPCONN
|
|
AllocArapConn(
|
|
IN ULONG LinkSpeed
|
|
)
|
|
{
|
|
|
|
PARAPCONN pArapConn;
|
|
v42bis_connection_t *pV42bis;
|
|
PUCHAR pBuf;
|
|
LONG RetryTime;
|
|
|
|
|
|
|
|
if ( (pArapConn = AtalkAllocZeroedMemory(sizeof(ARAPCONN))) == NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("AllocArapConn: alloc failed\n"));
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
//
|
|
// allocate v42bis buffers (it v42bis is enabled that is)
|
|
//
|
|
if (ArapGlobs.V42bisEnabled)
|
|
{
|
|
pV42bis = AtalkAllocZeroedMemory(sizeof(v42bis_connection_t));
|
|
|
|
if (pV42bis == NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("AllocArapConn: alloc for v42 failed\n"));
|
|
|
|
AtalkFreeMemory(pArapConn);
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
//
|
|
// allocate overflow buffer for the decode side
|
|
//
|
|
if ((pBuf = AtalkAllocZeroedMemory(MAX_P2)) == NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("AllocArapConn: alloc for v42-2 failed\n"));
|
|
|
|
AtalkFreeMemory(pArapConn);
|
|
|
|
AtalkFreeMemory(pV42bis);
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
pV42bis->decode.OverFlowBuf = pBuf;
|
|
pV42bis->decode.OverFlowBytes = 0;
|
|
|
|
pV42bis->encode.OverFlowBuf = pBuf;
|
|
pV42bis->encode.OverFlowBytes = 0;
|
|
|
|
pArapConn->pV42bis = pV42bis;
|
|
}
|
|
|
|
//
|
|
// if v42bis is not enabled, don't need no buffers!
|
|
//
|
|
else
|
|
{
|
|
pArapConn->pV42bis = NULL;
|
|
}
|
|
|
|
|
|
#if DBG
|
|
pArapConn->Signature = ARAPCONN_SIGNATURE;
|
|
|
|
//
|
|
// for debug builds, we can set registry parm to keep a trace of events
|
|
// If that setting is enabled, alloc a buffer to store the trace
|
|
//
|
|
if (ArapGlobs.SniffMode)
|
|
{
|
|
pBuf = AtalkAllocZeroedMemory(ARAP_SNIFF_BUFF_SIZE);
|
|
if (pBuf == NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("AllocArapConn: alloc for trace buffer failed\n"));
|
|
|
|
// don't fail the call if this alloc fails
|
|
}
|
|
|
|
pArapConn->pDbgTraceBuffer = pArapConn->pDbgCurrPtr = pBuf;
|
|
|
|
// put in a guard signature, to catch overrun
|
|
if (pArapConn->pDbgTraceBuffer)
|
|
{
|
|
*((DWORD *)&(pArapConn->pDbgTraceBuffer[ARAP_SNIFF_BUFF_SIZE-4])) = 0xcafebeef;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
pArapConn->State = MNP_IDLE;
|
|
|
|
// Creation refcount and a line-up refcount
|
|
pArapConn->RefCount = 2;
|
|
|
|
pArapConn->MnpState.WindowSize = ArapGlobs.MaxLTFrames;
|
|
pArapConn->MnpState.RecvCredit = pArapConn->MnpState.WindowSize;
|
|
|
|
pArapConn->LinkSpeed = LinkSpeed;
|
|
|
|
//
|
|
// T401 timer value in tick counts (1 tick = 100ms).
|
|
// we'll keep this at 1 second (i.e. 10 ticks) for a 33.6 (and faster) modem.
|
|
// If we are on a slower modem, increase it proportionately. So, a 28.8 modem
|
|
// would get RetryTime=2.0sec, 14.4 would get 3.7sec, 9600 baud would get 4.2sec etc.
|
|
//
|
|
RetryTime = 15;
|
|
if (LinkSpeed < 336)
|
|
{
|
|
RetryTime += (((336 - LinkSpeed) + 5)/10);
|
|
}
|
|
|
|
// make sure our calculation didn't go haywire...
|
|
|
|
if (RetryTime < ARAP_MIN_RETRY_INTERVAL)
|
|
{
|
|
RetryTime = ARAP_MIN_RETRY_INTERVAL;
|
|
}
|
|
else if (RetryTime > ARAP_MAX_RETRY_INTERVAL)
|
|
{
|
|
RetryTime = ARAP_MAX_RETRY_INTERVAL;
|
|
}
|
|
|
|
pArapConn->SendRetryTime = RetryTime;
|
|
pArapConn->SendRetryBaseTime = RetryTime;
|
|
|
|
// T402 is 0.5 times T401 value
|
|
pArapConn->T402Duration = (pArapConn->SendRetryTime/2);
|
|
|
|
//
|
|
// T403 should be at least 59 seconds. We don't really kill after this
|
|
// period of inactivity. We simply tell the dll and it does whatever is the
|
|
// policy: so just use whatever time period the dll tells us
|
|
//
|
|
pArapConn->T403Duration = ArapGlobs.MnpInactiveTime;
|
|
|
|
//
|
|
// T404: spec says 3 sec for 2400 baud and faster, 7 sec for anything slower
|
|
// Let's use 4 seconds here
|
|
//
|
|
pArapConn->T404Duration = 30;
|
|
|
|
// initialize all the timer values
|
|
pArapConn->LATimer = 0;
|
|
pArapConn->InactivityTimer = pArapConn->T403Duration + AtalkGetCurrentTick();
|
|
|
|
// set this to a high value for now: we'll set it when the conn is up
|
|
pArapConn->FlowControlTimer = AtalkGetCurrentTick() + 36000;
|
|
|
|
InitializeListHead(&pArapConn->MiscPktsQ);
|
|
InitializeListHead(&pArapConn->ReceiveQ);
|
|
InitializeListHead(&pArapConn->ArapDataQ);
|
|
InitializeListHead(&pArapConn->RetransmitQ);
|
|
InitializeListHead(&pArapConn->HighPriSendQ);
|
|
InitializeListHead(&pArapConn->MedPriSendQ);
|
|
InitializeListHead(&pArapConn->LowPriSendQ);
|
|
InitializeListHead(&pArapConn->SendAckedQ);
|
|
|
|
INITIALIZE_SPIN_LOCK(&pArapConn->SpinLock);
|
|
|
|
// start the retransmit timer for this connection
|
|
AtalkTimerInitialize( &pArapConn->RetryTimer,
|
|
(TIMER_ROUTINE)ArapRetryTimer,
|
|
ARAP_TIMER_INTERVAL) ;
|
|
|
|
AtalkTimerScheduleEvent(&pArapConn->RetryTimer);
|
|
|
|
pArapConn->Flags |= RETRANSMIT_TIMER_ON;
|
|
|
|
// put a timer refcount
|
|
pArapConn->RefCount++;
|
|
|
|
return( pArapConn );
|
|
}
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: ArapAcceptIrp
|
|
// Determine if the irp submitted by the dll is acceptable now
|
|
//
|
|
// Parameters: pIrp - the incoming irp
|
|
// IoControlCode - the control code (what's the irp for?)
|
|
// pfDerefDefPort - was default adapter referenced?
|
|
//
|
|
// Return: TRUE if the irp is acceptable, FALSE otherwise
|
|
//
|
|
//***$
|
|
|
|
BOOLEAN
|
|
ArapAcceptIrp(
|
|
IN PIRP pIrp,
|
|
IN ULONG IoControlCode,
|
|
IN BOOLEAN *pfDerefDefPort
|
|
)
|
|
{
|
|
|
|
KIRQL OldIrql;
|
|
PARAP_SEND_RECV_INFO pSndRcvInfo=NULL;
|
|
PARAPCONN pArapConn;
|
|
BOOLEAN fAccept=FALSE;
|
|
BOOLEAN fUnblockPnP=FALSE;
|
|
|
|
|
|
*pfDerefDefPort = FALSE;
|
|
|
|
//
|
|
// we allow these ioctls to come in any time
|
|
//
|
|
if ((IoControlCode == IOCTL_ARAP_SELECT) ||
|
|
(IoControlCode == IOCTL_ARAP_DISCONNECT) ||
|
|
(IoControlCode == IOCTL_ARAP_CONTINUE_SHUTDOWN) )
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
pArapConn = pSndRcvInfo->AtalkContext;
|
|
|
|
//
|
|
// put a IrpProcess refcount on the default port so it won't go away via pnp etc.
|
|
//
|
|
if (!AtalkReferenceRasDefPort())
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapProcessIoctl: Default port gone, or going %lx not accepted (%lx)\n",
|
|
pIrp,IoControlCode));
|
|
|
|
pSndRcvInfo->StatusCode = ARAPERR_STACK_IS_NOT_ACTIVE;
|
|
return(FALSE);
|
|
}
|
|
|
|
// note the fact that we have referenced the default adapter
|
|
*pfDerefDefPort = TRUE;
|
|
|
|
//
|
|
// now it's simple to decide whether we want to accept this irp or not
|
|
//
|
|
|
|
ACQUIRE_SPIN_LOCK(&ArapSpinLock, &OldIrql);
|
|
|
|
fAccept = (ArapStackState == ARAP_STATE_ACTIVE) ? TRUE : FALSE;
|
|
|
|
RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql);
|
|
|
|
return(fAccept);
|
|
}
|
|
|
|
//***
|
|
//
|
|
// Function: ArapCancelIrp
|
|
// Cancel the irp. Currently, only select irps are cancellable
|
|
//
|
|
// Parameters: pIrp - the incoming irp
|
|
//
|
|
// Return: none
|
|
//
|
|
//***$
|
|
VOID
|
|
ArapCancelIrp(
|
|
IN PIRP pIrp
|
|
)
|
|
{
|
|
|
|
KIRQL OldIrql;
|
|
PLIST_ENTRY pList;
|
|
PARAPCONN pArapConn;
|
|
NTSTATUS ReturnStatus=STATUS_SUCCESS;
|
|
|
|
|
|
//
|
|
// kill all connections and don't accept any more irps:
|
|
// cancelling a select irp is a blasphemy!
|
|
//
|
|
|
|
ACQUIRE_SPIN_LOCK(&ArapSpinLock, &OldIrql);
|
|
|
|
if (ArapSelectIrp == NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,("ArapCancelIrp: weird race condition!\n"));
|
|
RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql);
|
|
return;
|
|
}
|
|
|
|
ASSERT (pIrp == ArapSelectIrp);
|
|
|
|
ArapSelectIrp = NULL;
|
|
|
|
if (ArapStackState == ARAP_STATE_ACTIVE)
|
|
{
|
|
ArapStackState = ARAP_STATE_ACTIVE_WAITING;
|
|
}
|
|
else if (ArapStackState == ARAP_STATE_INACTIVE)
|
|
{
|
|
ArapStackState = ARAP_STATE_INACTIVE_WAITING;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql);
|
|
|
|
if (RasPortDesc == NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,("ArapCancelIrp: RasPortDesc is null!\n"));
|
|
|
|
ARAP_COMPLETE_IRP(pIrp, 0, STATUS_CANCELLED, &ReturnStatus);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// now, go kill all the arap connections
|
|
//
|
|
ACQUIRE_SPIN_LOCK(&RasPortDesc->pd_Lock, &OldIrql);
|
|
|
|
pList = RasPortDesc->pd_ArapConnHead.Flink;
|
|
|
|
while (pList != &RasPortDesc->pd_ArapConnHead)
|
|
{
|
|
pArapConn = CONTAINING_RECORD(pList, ARAPCONN, Linkage);
|
|
|
|
ASSERT(pArapConn->Signature == ARAPCONN_SIGNATURE);
|
|
|
|
// if this connection is already disconnected, skip it
|
|
ACQUIRE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
|
|
if (pArapConn->State == MNP_DISCONNECTED)
|
|
{
|
|
pList = pArapConn->Linkage.Flink;
|
|
RELEASE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
|
|
continue;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
|
|
RELEASE_SPIN_LOCK(&RasPortDesc->pd_Lock, OldIrql);
|
|
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
|
|
("ArapCancelIrp: killing ARAP connection %lx\n",pArapConn));
|
|
|
|
ArapCleanup(pArapConn);
|
|
|
|
ACQUIRE_SPIN_LOCK(&RasPortDesc->pd_Lock, &OldIrql);
|
|
|
|
pList = RasPortDesc->pd_ArapConnHead.Flink;
|
|
}
|
|
|
|
//
|
|
// walk through the list to see if any connection(s) disconnected but is
|
|
// waiting for a select irp to come down. We know the select irp is never
|
|
// going to come down, so pretend that dll has been told and deref the puppy
|
|
// for telling the dll (which will probably free the connection)
|
|
//
|
|
|
|
pList = RasPortDesc->pd_ArapConnHead.Flink;
|
|
|
|
while (pList != &RasPortDesc->pd_ArapConnHead)
|
|
{
|
|
pArapConn = CONTAINING_RECORD(pList, ARAPCONN, Linkage);
|
|
|
|
ASSERT(pArapConn->Signature == ARAPCONN_SIGNATURE);
|
|
|
|
ACQUIRE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
|
|
|
|
if (pArapConn->Flags & DISCONNECT_NO_IRP)
|
|
{
|
|
pArapConn->Flags &= ~DISCONNECT_NO_IRP;
|
|
|
|
RELEASE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
|
|
RELEASE_SPIN_LOCK(&RasPortDesc->pd_Lock, OldIrql);
|
|
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
|
|
("ArapCancelIrp: faking dll-completion for dead connection %lx\n",pArapConn));
|
|
|
|
DerefArapConn(pArapConn);
|
|
|
|
ACQUIRE_SPIN_LOCK(&RasPortDesc->pd_Lock, &OldIrql);
|
|
pList = RasPortDesc->pd_ArapConnHead.Flink;
|
|
}
|
|
else
|
|
{
|
|
pList = pArapConn->Linkage.Flink;
|
|
RELEASE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
|
|
}
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&RasPortDesc->pd_Lock, OldIrql);
|
|
|
|
// finally, complete that cancelled irp!
|
|
ARAP_COMPLETE_IRP(pIrp, 0, STATUS_CANCELLED, &ReturnStatus);
|
|
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapCancelIrp: select irp cancelled and completed (%lx)\n",pIrp));
|
|
}
|
|
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: ArapGetSelectIrp
|
|
// Get the select irp, after some checks
|
|
//
|
|
// Parameters: ppIrp - pointer to irp pointer, contains select irp on return
|
|
//
|
|
// Return: none
|
|
//
|
|
//***$
|
|
VOID
|
|
ArapGetSelectIrp(
|
|
IN PIRP *ppIrp
|
|
)
|
|
{
|
|
KIRQL OldIrql;
|
|
KIRQL OldIrql2;
|
|
|
|
|
|
*(ppIrp) = NULL;
|
|
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
|
|
ACQUIRE_SPIN_LOCK(&ArapSpinLock, &OldIrql2);
|
|
|
|
if (ArapSelectIrp && (!ArapSelectIrp->Cancel))
|
|
{
|
|
ArapSelectIrp->CancelRoutine = NULL;
|
|
*(ppIrp) = ArapSelectIrp;
|
|
ArapSelectIrp = NULL;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql2);
|
|
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
}
|
|
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: FindArapConnByContx
|
|
// Finds the corresponding connection element, given the dll's
|
|
// context
|
|
//
|
|
// Parameters: pDllContext - the dll context for the connection
|
|
//
|
|
// Return: pointer to the corresponding connection element, if found
|
|
//
|
|
//***$
|
|
|
|
PARAPCONN
|
|
FindArapConnByContx(
|
|
IN PVOID pDllContext
|
|
)
|
|
{
|
|
PARAPCONN pArapConn=NULL;
|
|
PARAPCONN pWalker;
|
|
PLIST_ENTRY pList;
|
|
KIRQL OldIrql;
|
|
|
|
|
|
// ARAP not configured?
|
|
if (!RasPortDesc)
|
|
{
|
|
return(NULL);
|
|
}
|
|
|
|
ACQUIRE_SPIN_LOCK(&RasPortDesc->pd_Lock, &OldIrql);
|
|
|
|
if (!(RasPortDesc->pd_Flags & PD_ACTIVE))
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("FindArapConnByContx: ArapPort not active, ignoring\n"));
|
|
|
|
RELEASE_SPIN_LOCK(&RasPortDesc->pd_Lock, OldIrql);
|
|
return(NULL);
|
|
}
|
|
|
|
pList = RasPortDesc->pd_ArapConnHead.Flink;
|
|
|
|
//
|
|
// walk through all the Arap clients to see if we find ours
|
|
//
|
|
while (pList != &RasPortDesc->pd_ArapConnHead)
|
|
{
|
|
pWalker = CONTAINING_RECORD(pList, ARAPCONN, Linkage);
|
|
|
|
pList = pWalker->Linkage.Flink;
|
|
|
|
if (pWalker->pDllContext == pDllContext)
|
|
{
|
|
pArapConn = pWalker;
|
|
break;
|
|
}
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&RasPortDesc->pd_Lock, OldIrql);
|
|
|
|
return( pArapConn );
|
|
}
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: FindAndRefArapConnByAddr
|
|
// Finds the corresponding connection element, given the network
|
|
// address (of the remote client)
|
|
//
|
|
// Parameters: destNode - network addr of the destination (remote client)
|
|
// pdwFlags - pointer to a dword to return Flags field
|
|
//
|
|
// Return: pointer to the corresponding connection element, if found
|
|
//
|
|
//***$
|
|
|
|
PARAPCONN
|
|
FindAndRefArapConnByAddr(
|
|
IN ATALK_NODEADDR destNode,
|
|
OUT DWORD *pdwFlags
|
|
)
|
|
{
|
|
PARAPCONN pArapConn=NULL;
|
|
PARAPCONN pWalker;
|
|
PLIST_ENTRY pList;
|
|
KIRQL OldIrql;
|
|
|
|
|
|
// ARAP not configured?
|
|
if (!RasPortDesc)
|
|
{
|
|
return(NULL);
|
|
}
|
|
|
|
ACQUIRE_SPIN_LOCK(&RasPortDesc->pd_Lock, &OldIrql);
|
|
|
|
if (!(RasPortDesc->pd_Flags & PD_ACTIVE))
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("FindAndRefArapConnByAddr: ArapPort not active, ignoring\n"));
|
|
|
|
RELEASE_SPIN_LOCK(&RasPortDesc->pd_Lock, OldIrql);
|
|
return(NULL);
|
|
}
|
|
|
|
pList = RasPortDesc->pd_ArapConnHead.Flink;
|
|
|
|
//
|
|
// walk through all the Arap clients to see if we find ours
|
|
//
|
|
while (pList != &RasPortDesc->pd_ArapConnHead)
|
|
{
|
|
pWalker = CONTAINING_RECORD(pList, ARAPCONN, Linkage);
|
|
|
|
pList = pWalker->Linkage.Flink;
|
|
|
|
if (ATALK_NODES_EQUAL(&pWalker->NetAddr, &destNode))
|
|
{
|
|
ACQUIRE_SPIN_LOCK_DPC(&pWalker->SpinLock);
|
|
|
|
//
|
|
// we return the pArapConn only if the MNP connection is up and
|
|
// and the ARAP connection is also up (or, if ARAP connection isn't
|
|
// up yet then only if we are searching for a node)
|
|
//
|
|
//
|
|
if ((pWalker->State == MNP_UP) &&
|
|
((pWalker->Flags & ARAP_CONNECTION_UP) ||
|
|
(pWalker->Flags & ARAP_FINDING_NODE)) )
|
|
{
|
|
pArapConn = pWalker;
|
|
pArapConn->RefCount++;
|
|
*pdwFlags = pWalker->Flags;
|
|
}
|
|
else if (pWalker->Flags & ARAP_CONNECTION_UP)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("FindAndRefArapConnByAddr: found pArapConn (%lx), but state=%ld,Flags=%lx\n",
|
|
pWalker,pWalker->State,pWalker->Flags));
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK_DPC(&pWalker->SpinLock);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&RasPortDesc->pd_Lock, OldIrql);
|
|
|
|
return(pArapConn);
|
|
|
|
}
|
|
|
|
//***
|
|
//
|
|
// Function: FindAndRefRasConnByAddr
|
|
// Finds the corresponding connection element, given the network
|
|
// address (of the remote client)
|
|
//
|
|
// Parameters: destNode - network addr of the destination (remote client)
|
|
// pdwFlags - pointer to a dword to return Flags field
|
|
// pfThisIsPPP - pointer to a bool: is this PPP or ARAP connection?
|
|
//
|
|
// Return: pointer to the corresponding connection element, if found
|
|
//
|
|
//***$
|
|
|
|
PVOID
|
|
FindAndRefRasConnByAddr(
|
|
IN ATALK_NODEADDR destNode,
|
|
OUT DWORD *pdwFlags,
|
|
OUT BOOLEAN *pfThisIsPPP
|
|
)
|
|
{
|
|
PVOID pRasConn;
|
|
|
|
|
|
// RAS not configured?
|
|
if (!RasPortDesc)
|
|
{
|
|
return(NULL);
|
|
}
|
|
|
|
pRasConn = (PVOID)FindAndRefPPPConnByAddr(destNode,pdwFlags);
|
|
|
|
if (pRasConn)
|
|
{
|
|
*pfThisIsPPP = TRUE;
|
|
return(pRasConn);
|
|
}
|
|
|
|
pRasConn = FindAndRefArapConnByAddr(destNode, pdwFlags);
|
|
|
|
*pfThisIsPPP = FALSE;
|
|
|
|
return(pRasConn);
|
|
|
|
}
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: ArapConnIsValid
|
|
// Make sure that what we think is a connection is indeed a
|
|
// connection (i.e., it's there in our list of connections)
|
|
//
|
|
// Parameters: pArapConn - the connection in question
|
|
//
|
|
// Return: TRUE if the connection is valid, FALSE otherwise
|
|
//
|
|
//***$
|
|
|
|
BOOLEAN
|
|
ArapConnIsValid(
|
|
IN PARAPCONN pArapConn
|
|
)
|
|
{
|
|
PARAPCONN pWalker;
|
|
PLIST_ENTRY pList;
|
|
KIRQL OldIrql;
|
|
BOOLEAN fIsValid=FALSE;
|
|
|
|
|
|
// ARAP not configured?
|
|
if (!RasPortDesc)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
ACQUIRE_SPIN_LOCK(&RasPortDesc->pd_Lock, &OldIrql);
|
|
|
|
pList = RasPortDesc->pd_ArapConnHead.Flink;
|
|
|
|
//
|
|
// walk through all the Arap conns and see if we find the given conn
|
|
//
|
|
while (pList != &RasPortDesc->pd_ArapConnHead)
|
|
{
|
|
pWalker = CONTAINING_RECORD(pList, ARAPCONN, Linkage);
|
|
|
|
pList = pWalker->Linkage.Flink;
|
|
|
|
if (pWalker == pArapConn)
|
|
{
|
|
ACQUIRE_SPIN_LOCK_DPC(&pWalker->SpinLock);
|
|
|
|
ASSERT(pWalker->Signature == ARAPCONN_SIGNATURE);
|
|
|
|
if (!(pWalker->Flags & ARAP_GOING_AWAY))
|
|
{
|
|
// put a validation refcount
|
|
pWalker->RefCount++;
|
|
|
|
fIsValid = TRUE;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK_DPC(&pWalker->SpinLock);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&RasPortDesc->pd_Lock, OldIrql);
|
|
|
|
return( fIsValid );
|
|
}
|
|
|
|
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: DerefMnpSendBuf
|
|
// This routine dereferences the MNP send. When the refcount
|
|
// goes to zero, we free it
|
|
//
|
|
// Parameters: pMnpSendBuf - the MNP send to be dereferenced
|
|
//
|
|
// Return: Nothing
|
|
//
|
|
//***$
|
|
|
|
VOID
|
|
DerefMnpSendBuf(
|
|
IN PMNPSENDBUF pMnpSendBuf,
|
|
IN BOOLEAN fNdisSendComplete
|
|
)
|
|
{
|
|
KIRQL OldIrql;
|
|
PARAPCONN pArapConn;
|
|
BOOLEAN fFreeIt=FALSE;
|
|
|
|
|
|
DBG_ARAP_CHECK_PAGED_CODE();
|
|
|
|
pArapConn = pMnpSendBuf->pArapConn;
|
|
|
|
ARAPTRACE(("Entered DerefMnpSendBuf (%lx %lx refcount=%d ComplFn=%lx)\n",
|
|
pArapConn,pMnpSendBuf,pMnpSendBuf->RefCount,pMnpSendBuf->ComplRoutine));
|
|
|
|
ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
|
|
|
|
//
|
|
// catch weird things like freeing twice
|
|
// (we subtract 0x100 in completion routine, to mark that it has run)
|
|
//
|
|
ASSERT((pMnpSendBuf->Signature == MNPSMSENDBUF_SIGNATURE) ||
|
|
(pMnpSendBuf->Signature == MNPSMSENDBUF_SIGNATURE-0x100) ||
|
|
(pMnpSendBuf->Signature == MNPLGSENDBUF_SIGNATURE) ||
|
|
(pMnpSendBuf->Signature == MNPLGSENDBUF_SIGNATURE-0x100));
|
|
|
|
ASSERT(pMnpSendBuf->RefCount > 0);
|
|
|
|
// Mark that Ndis completed our send
|
|
if (fNdisSendComplete)
|
|
{
|
|
pMnpSendBuf->Flags = 0;
|
|
}
|
|
|
|
pMnpSendBuf->RefCount--;
|
|
|
|
if (pMnpSendBuf->RefCount == 0)
|
|
{
|
|
fFreeIt = TRUE;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
|
|
if (!fFreeIt)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// make sure it's not still sitting on retransmit queue
|
|
ASSERT(IsListEmpty(&pMnpSendBuf->Linkage));
|
|
|
|
#if DBG
|
|
pMnpSendBuf->Signature--;
|
|
#endif
|
|
|
|
ArapNdisFreeBuf(pMnpSendBuf);
|
|
|
|
// remove that MNPSend refcount
|
|
DerefArapConn(pArapConn);
|
|
}
|
|
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: DerefArapConn
|
|
// Decrements the refcount of the connection element by 1. If the
|
|
// refcount goes to 0, releases network addr and frees it
|
|
//
|
|
// Parameters: pArapConn - connection element in question
|
|
//
|
|
// Return: none
|
|
//
|
|
//***$
|
|
|
|
VOID
|
|
DerefArapConn(
|
|
IN PARAPCONN pArapConn
|
|
)
|
|
{
|
|
|
|
KIRQL OldIrql;
|
|
BOOLEAN fKill = FALSE;
|
|
|
|
|
|
DBG_ARAP_CHECK_PAGED_CODE();
|
|
|
|
ARAPTRACE(("Entered DerefArapConn (%lx refcount=%d)\n",pArapConn,pArapConn->RefCount));
|
|
|
|
ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
|
|
|
|
ASSERT(pArapConn->Signature == ARAPCONN_SIGNATURE);
|
|
|
|
ASSERT(pArapConn->RefCount > 0);
|
|
|
|
pArapConn->RefCount--;
|
|
|
|
if (pArapConn->RefCount == 0)
|
|
{
|
|
fKill = TRUE;
|
|
pArapConn->Flags |= ARAP_GOING_AWAY;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
|
|
if (!fKill)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ASSERT(pArapConn->pRecvIoctlIrp == NULL);
|
|
|
|
ASSERT(pArapConn->pIoctlIrp == NULL);
|
|
|
|
ASSERT(IsListEmpty(&pArapConn->HighPriSendQ));
|
|
|
|
ASSERT(IsListEmpty(&pArapConn->MedPriSendQ));
|
|
|
|
ASSERT(IsListEmpty(&pArapConn->LowPriSendQ));
|
|
|
|
ASSERT(IsListEmpty(&pArapConn->SendAckedQ));
|
|
|
|
ASSERT(IsListEmpty(&pArapConn->ReceiveQ));
|
|
|
|
ASSERT(IsListEmpty(&pArapConn->ArapDataQ));
|
|
|
|
ASSERT(IsListEmpty(&pArapConn->RetransmitQ));
|
|
|
|
/* ASSERT(pArapConn->SendsPending == 0); */
|
|
|
|
ASSERT(!(pArapConn->Flags & RETRANSMIT_TIMER_ON));
|
|
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("DerefArapConn: refcount 0, freeing %lx\n", pArapConn));
|
|
|
|
|
|
ACQUIRE_SPIN_LOCK(&RasPortDesc->pd_Lock, &OldIrql);
|
|
|
|
RemoveEntryList(&pArapConn->Linkage);
|
|
|
|
RELEASE_SPIN_LOCK(&RasPortDesc->pd_Lock, OldIrql);
|
|
|
|
#if ARAP_STATIC_MODE
|
|
// "release" the network addr used by this client
|
|
ArapReleaseAddr(pArapConn);
|
|
#endif //ARAP_STATIC_MODE
|
|
|
|
// free that v42bis buffer
|
|
if (pArapConn->pV42bis)
|
|
{
|
|
// free the decode-side overflow buffer
|
|
AtalkFreeMemory(pArapConn->pV42bis->decode.OverFlowBuf);
|
|
|
|
AtalkFreeMemory(pArapConn->pV42bis);
|
|
}
|
|
|
|
#if DBG
|
|
|
|
ArapDbgDumpMnpHist(pArapConn);
|
|
|
|
// if we had allocated a sniff buffer, free it
|
|
if (pArapConn->pDbgTraceBuffer)
|
|
{
|
|
AtalkFreeMemory(pArapConn->pDbgTraceBuffer);
|
|
}
|
|
|
|
//
|
|
// let's catch if someone tries to access this after a free
|
|
//
|
|
RtlFillMemory(pArapConn,sizeof(ARAPCONN),0x7);
|
|
pArapConn->Signature = 0xDEADBEEF;
|
|
#endif
|
|
|
|
// and finally, we say good bye
|
|
AtalkFreeMemory(pArapConn);
|
|
|
|
|
|
ACQUIRE_SPIN_LOCK(&ArapSpinLock, &OldIrql);
|
|
ArapConnections--;
|
|
RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql);
|
|
|
|
#if ARAP_STATIC_MODE
|
|
// This will delete a route if this is the last connection that vanished
|
|
ArapDeleteArapRoute();
|
|
#endif //ARAP_STATIC_MODE
|
|
|
|
// connection is completely gone: see if arap pages can be unlocked
|
|
AtalkUnlockArapIfNecessary();
|
|
|
|
}
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: ArapCleanup
|
|
// Once the client goes into the disconnecting state (as a result
|
|
// of either local side or remote side initiating the disconnect)
|
|
// this routine gets called. This does all the cleanup, such as
|
|
// completing all unacked sends, uncompleted receives, stopping
|
|
// retransmit timers, completing any irp in progress.
|
|
//
|
|
// Parameters: pArapConn - connection element being cleaned up
|
|
//
|
|
// Return: none
|
|
//
|
|
//***$
|
|
|
|
VOID
|
|
ArapCleanup(
|
|
IN PARAPCONN pArapConn
|
|
)
|
|
{
|
|
|
|
KIRQL OldIrql;
|
|
PIRP pIrp;
|
|
PIRP pRcvIrp;
|
|
PIRP pDiscIrp;
|
|
PARAP_SEND_RECV_INFO pSndRcvInfo;
|
|
PARAP_SEND_RECV_INFO pDiscSndRcvInfo;
|
|
PLIST_ENTRY pSendHighList;
|
|
PLIST_ENTRY pSendMedList;
|
|
PLIST_ENTRY pSendLowList;
|
|
PLIST_ENTRY pSendAckList;
|
|
PLIST_ENTRY pRcvList;
|
|
PLIST_ENTRY pArapList;
|
|
PLIST_ENTRY pReXmitList;
|
|
PLIST_ENTRY pMiscPktList;
|
|
PMNPSENDBUF pMnpSendBuf;
|
|
PARAPBUF pArapBuf;
|
|
DWORD StatusCode;
|
|
BOOLEAN fStopTimer=FALSE;
|
|
BOOLEAN fArapConnUp=FALSE;
|
|
DWORD dwBytesToDll;
|
|
NTSTATUS ReturnStatus=STATUS_SUCCESS;
|
|
|
|
|
|
|
|
DBG_ARAP_CHECK_PAGED_CODE();
|
|
|
|
// first thing, see if we should send out a disconnect message
|
|
// we make this check without holding the lock because ArapSendLDPacket does
|
|
// the right thing. If, due to an extremely tiny window, we don't call
|
|
// ArapSendLDPacket, no big deal!
|
|
if (pArapConn->State < MNP_LDISCONNECTING)
|
|
{
|
|
ArapSendLDPacket(pArapConn, 0xFF);
|
|
}
|
|
|
|
ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
|
|
|
|
ASSERT(pArapConn->Signature == ARAPCONN_SIGNATURE);
|
|
|
|
// if we have already run the cleanup, nothing to do!
|
|
if (pArapConn->State == MNP_DISCONNECTED)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapCleanup: cleanup already done once on (%lx)\n",pArapConn));
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
return;
|
|
}
|
|
|
|
pSendHighList = pArapConn->HighPriSendQ.Flink;
|
|
InitializeListHead(&pArapConn->HighPriSendQ);
|
|
|
|
pSendMedList = pArapConn->MedPriSendQ.Flink;
|
|
InitializeListHead(&pArapConn->MedPriSendQ);
|
|
|
|
pSendLowList = pArapConn->LowPriSendQ.Flink;
|
|
InitializeListHead(&pArapConn->LowPriSendQ);
|
|
|
|
pSendAckList = pArapConn->SendAckedQ.Flink;
|
|
InitializeListHead(&pArapConn->SendAckedQ);
|
|
|
|
pRcvList = pArapConn->ReceiveQ.Flink;
|
|
InitializeListHead(&pArapConn->ReceiveQ);
|
|
|
|
pArapList = pArapConn->ArapDataQ.Flink;
|
|
InitializeListHead(&pArapConn->ArapDataQ);
|
|
|
|
pReXmitList = pArapConn->RetransmitQ.Flink;
|
|
InitializeListHead(&pArapConn->RetransmitQ);
|
|
|
|
pMiscPktList = pArapConn->MiscPktsQ.Flink;
|
|
InitializeListHead(&pArapConn->MiscPktsQ);
|
|
|
|
pIrp = pArapConn->pIoctlIrp;
|
|
pArapConn->pIoctlIrp = NULL;
|
|
|
|
pRcvIrp = pArapConn->pRecvIoctlIrp;
|
|
pArapConn->pRecvIoctlIrp = NULL;
|
|
|
|
if (pArapConn->State == MNP_RDISCONNECTING)
|
|
{
|
|
pArapConn->Flags |= ARAP_REMOTE_DISCONN;
|
|
StatusCode = ARAPERR_RDISCONNECT_COMPLETE;
|
|
}
|
|
else
|
|
{
|
|
StatusCode = ARAPERR_LDISCONNECT_COMPLETE;
|
|
}
|
|
|
|
pArapConn->State = MNP_DISCONNECTED;
|
|
pArapConn->Flags &= ~ARAP_DATA_WAITING;
|
|
|
|
// if the timer is running, stop it
|
|
if (pArapConn->Flags & RETRANSMIT_TIMER_ON)
|
|
{
|
|
fStopTimer = TRUE;
|
|
pArapConn->Flags &= ~RETRANSMIT_TIMER_ON;
|
|
|
|
// creation refcount and timer refcount better be on here
|
|
ASSERT(pArapConn->RefCount >= 2);
|
|
}
|
|
|
|
fArapConnUp = FALSE;
|
|
|
|
// was ARAP connection up?
|
|
if (pArapConn->Flags & ARAP_CONNECTION_UP)
|
|
{
|
|
fArapConnUp = TRUE;
|
|
}
|
|
|
|
#if DBG
|
|
//
|
|
// if we are sniffing, mark the sniff to indicate the end (so dll knows it
|
|
// got all the sniff info)
|
|
//
|
|
if (pArapConn->pDbgCurrPtr)
|
|
{
|
|
PSNIFF_INFO pSniff;
|
|
|
|
pSniff = (PSNIFF_INFO)(pArapConn->pDbgCurrPtr);
|
|
pSniff->Signature = ARAP_SNIFF_SIGNATURE;
|
|
pSniff->TimeStamp = (DWORD)AtalkGetCurrentTick();
|
|
pSniff->Location = 0xfedc;
|
|
pSniff->FrameLen = 0;
|
|
pArapConn->SniffedBytes += sizeof(SNIFF_INFO);
|
|
pArapConn->pDbgCurrPtr += sizeof(SNIFF_INFO);
|
|
}
|
|
#endif
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
|
|
if (fStopTimer)
|
|
{
|
|
if (AtalkTimerCancelEvent(&pArapConn->RetryTimer, NULL))
|
|
{
|
|
// remove the timer refcount
|
|
DerefArapConn(pArapConn);
|
|
}
|
|
}
|
|
|
|
//
|
|
// call completion routine for all the sends that have been acked
|
|
//
|
|
while (pSendAckList != &pArapConn->SendAckedQ)
|
|
{
|
|
pMnpSendBuf = CONTAINING_RECORD(pSendAckList,MNPSENDBUF,Linkage);
|
|
|
|
pSendAckList = pSendAckList->Flink;
|
|
|
|
#if DBG
|
|
InitializeListHead(&pMnpSendBuf->Linkage);
|
|
#endif
|
|
// call the completion routine which will do cleanup for this buffer
|
|
(pMnpSendBuf->ComplRoutine)(pMnpSendBuf,ARAPERR_NO_ERROR);
|
|
}
|
|
|
|
// whatever is on the ReceiveQ, try and send it off to the destination
|
|
// since this data came before the disconnect came in
|
|
|
|
while (1)
|
|
{
|
|
if ((pArapBuf = ArapExtractAtalkSRP(pArapConn)) == NULL)
|
|
{
|
|
// no more data left (or no complete SRP): done here
|
|
break;
|
|
}
|
|
|
|
// was ARAP connection up? route only if it's up, otherwise drop it!
|
|
if (fArapConnUp)
|
|
{
|
|
ArapRoutePacketFromWan( pArapConn, pArapBuf );
|
|
}
|
|
|
|
// we received AppleTalk data but connection wasn't up! Drop pkt
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapCleanup: (%lx) AT data, but conn not up\n",pArapConn));
|
|
}
|
|
|
|
#if DBG
|
|
//
|
|
// yeah, there is no spinlock: given our state, no one else will be
|
|
// touching this field. Besides, this is debug-only!
|
|
//
|
|
pArapConn->RecvsPending -= pArapBuf->DataSize;
|
|
#endif
|
|
|
|
// done with this buffer
|
|
ARAP_FREE_RCVBUF(pArapBuf);
|
|
}
|
|
|
|
//
|
|
// if there are any buffers left on the ReceiveQ, they are basically
|
|
// incomplete SRP's: throw them away
|
|
//
|
|
while (pRcvList != &pArapConn->ReceiveQ)
|
|
{
|
|
pArapBuf = CONTAINING_RECORD(pRcvList, ARAPBUF, Linkage);
|
|
|
|
pRcvList = pRcvList->Flink;
|
|
|
|
#if DBG
|
|
// same deal again with spinlock again...
|
|
pArapConn->RecvsPending -= pArapBuf->DataSize;
|
|
#endif
|
|
|
|
ARAP_FREE_RCVBUF(pArapBuf);
|
|
}
|
|
|
|
//
|
|
// free up all the packets on ArapDataQ: these are not going to be of
|
|
// any use, whether or not the connection was up, so best just to throw
|
|
// them away (why complicate life?)
|
|
//
|
|
while (pArapList != &pArapConn->ArapDataQ)
|
|
{
|
|
pArapBuf = CONTAINING_RECORD(pArapList, ARAPBUF, Linkage);
|
|
|
|
pArapList = pArapList->Flink;
|
|
|
|
#if DBG
|
|
// same deal again with spinlock again...
|
|
pArapConn->RecvsPending -= pArapBuf->DataSize;
|
|
#endif
|
|
|
|
ARAP_FREE_RCVBUF(pArapBuf);
|
|
}
|
|
|
|
//
|
|
// free up all the packets on the MiscPktsQ
|
|
//
|
|
while (pMiscPktList != &pArapConn->MiscPktsQ)
|
|
{
|
|
pArapBuf = CONTAINING_RECORD(pMiscPktList, ARAPBUF, Linkage);
|
|
|
|
pMiscPktList = pMiscPktList->Flink;
|
|
|
|
ARAP_FREE_RCVBUF(pArapBuf);
|
|
}
|
|
|
|
//
|
|
// call completion routine for all the sends that were waiting to be sent
|
|
// on the high priority Q
|
|
//
|
|
while (pSendHighList != &pArapConn->HighPriSendQ)
|
|
{
|
|
pMnpSendBuf = CONTAINING_RECORD(pSendHighList,MNPSENDBUF,Linkage);
|
|
|
|
pSendHighList = pSendHighList->Flink;
|
|
|
|
#if DBG
|
|
InitializeListHead(&pMnpSendBuf->Linkage);
|
|
#endif
|
|
// call the completion routine which will do cleanup for this buffer
|
|
(pMnpSendBuf->ComplRoutine)(pMnpSendBuf,ARAPERR_DISCONNECT_IN_PROGRESS);
|
|
}
|
|
|
|
//
|
|
// call completion routine for all the sends that were waiting to be sent
|
|
// on the Med priority Q
|
|
//
|
|
while (pSendMedList != &pArapConn->MedPriSendQ)
|
|
{
|
|
pMnpSendBuf = CONTAINING_RECORD(pSendMedList,MNPSENDBUF,Linkage);
|
|
|
|
pSendMedList = pSendMedList->Flink;
|
|
|
|
#if DBG
|
|
InitializeListHead(&pMnpSendBuf->Linkage);
|
|
#endif
|
|
// call the completion routine which will do cleanup for this buffer
|
|
(pMnpSendBuf->ComplRoutine)(pMnpSendBuf,ARAPERR_DISCONNECT_IN_PROGRESS);
|
|
}
|
|
|
|
//
|
|
// call completion routine for all the sends that were waiting to be sent
|
|
// on the Low priority Q
|
|
//
|
|
while (pSendLowList != &pArapConn->LowPriSendQ)
|
|
{
|
|
pMnpSendBuf = CONTAINING_RECORD(pSendLowList,MNPSENDBUF,Linkage);
|
|
|
|
pSendLowList = pSendLowList->Flink;
|
|
|
|
#if DBG
|
|
InitializeListHead(&pMnpSendBuf->Linkage);
|
|
#endif
|
|
// call the completion routine which will do cleanup for this buffer
|
|
(pMnpSendBuf->ComplRoutine)(pMnpSendBuf,ARAPERR_DISCONNECT_IN_PROGRESS);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// free up all the packets on RetransmitQ that were waiting to be acked
|
|
//
|
|
while (pReXmitList != &pArapConn->RetransmitQ)
|
|
{
|
|
pMnpSendBuf = CONTAINING_RECORD(pReXmitList, MNPSENDBUF, Linkage);
|
|
|
|
pReXmitList = pReXmitList->Flink;
|
|
|
|
#if DBG
|
|
InitializeListHead(&pMnpSendBuf->Linkage);
|
|
#endif
|
|
// call the completion routine which will do cleanup for this buffer
|
|
(pMnpSendBuf->ComplRoutine)(pMnpSendBuf,ARAPERR_DISCONNECT_IN_PROGRESS);
|
|
}
|
|
|
|
|
|
// if there was an irp in progress, complete it first!
|
|
if (pIrp)
|
|
{
|
|
pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
pSndRcvInfo->StatusCode = ARAPERR_DISCONNECT_IN_PROGRESS;
|
|
|
|
ARAP_COMPLETE_IRP(pIrp, sizeof(ARAP_SEND_RECV_INFO), STATUS_SUCCESS,
|
|
&ReturnStatus);
|
|
}
|
|
|
|
// if there was an irp in progress, complete it first!
|
|
if (pRcvIrp)
|
|
{
|
|
pSndRcvInfo = (PARAP_SEND_RECV_INFO)pRcvIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
pSndRcvInfo->StatusCode = ARAPERR_DISCONNECT_IN_PROGRESS;
|
|
|
|
ARAP_COMPLETE_IRP(pRcvIrp, sizeof(ARAP_SEND_RECV_INFO), STATUS_SUCCESS,
|
|
&ReturnStatus);
|
|
}
|
|
|
|
// if we have any sniff info, give it to dll.
|
|
ARAP_DUMP_DBG_TRACE(pArapConn);
|
|
|
|
//
|
|
// now, try telling the dll that the connection went away. (We can do this
|
|
// only using a "select" irp)
|
|
//
|
|
ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
|
|
|
|
ArapGetSelectIrp(&pDiscIrp);
|
|
|
|
// no select irp? just mark that fact, so on next select we'll tell dll
|
|
if (!pDiscIrp)
|
|
{
|
|
pArapConn->Flags |= DISCONNECT_NO_IRP;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
|
|
//
|
|
// if we did find select irp, go ahead and tell the dll
|
|
//
|
|
if (pDiscIrp)
|
|
{
|
|
dwBytesToDll = 0;
|
|
|
|
#if DBG
|
|
//
|
|
// if we have some sniff info that we couldn't deliver earlier through
|
|
// the sniff irp, then give them through this irp: it's going back
|
|
// "empty" anyway!
|
|
//
|
|
if (pArapConn->pDbgTraceBuffer && pArapConn->SniffedBytes > 0)
|
|
{
|
|
dwBytesToDll = ArapFillIrpWithSniffInfo(pArapConn,pDiscIrp);
|
|
}
|
|
#endif
|
|
|
|
pDiscSndRcvInfo = (PARAP_SEND_RECV_INFO)pDiscIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
pDiscSndRcvInfo->pDllContext = pArapConn->pDllContext;
|
|
pDiscSndRcvInfo->AtalkContext = ARAP_INVALID_CONTEXT;
|
|
pDiscSndRcvInfo->DataLen = dwBytesToDll;
|
|
pDiscSndRcvInfo->StatusCode = StatusCode;
|
|
|
|
dwBytesToDll += sizeof(ARAP_SEND_RECV_INFO);
|
|
|
|
ARAP_COMPLETE_IRP(pDiscIrp, dwBytesToDll, STATUS_SUCCESS,
|
|
&ReturnStatus);
|
|
|
|
// we told dll: remove this link
|
|
pArapConn->pDllContext = NULL;
|
|
|
|
// we told the dll, remove the connect refcount
|
|
DerefArapConn(pArapConn);
|
|
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapCleanup: told dll (%lx refcount=%d)\n",pArapConn,pArapConn->RefCount));
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapCleanup: no select irp, dll doesn't yet know (%lx) died\n", pArapConn));
|
|
}
|
|
|
|
// remove the creation refcount
|
|
DerefArapConn(pArapConn);
|
|
}
|
|
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: PrepareConnectionResponse
|
|
// This routine parses the connect request that is first sent by
|
|
// the remote client and forms a connection response (LR frame)
|
|
// based on the options negotiated.
|
|
// This routine basically does the MNP negotiation.
|
|
//
|
|
// Parameters: pArapConn - connection element being cleaned up
|
|
// pReq - buffer containting client's original connect request
|
|
// pFrame - buffer in which we put the response
|
|
// BytesWritten - how big is the connection response
|
|
//
|
|
// Return: result of the operation (ARAPERR_....)
|
|
//
|
|
//***$
|
|
|
|
DWORD
|
|
PrepareConnectionResponse(
|
|
IN PARAPCONN pArapConn,
|
|
IN PBYTE pReq, // buffer with client's request
|
|
IN DWORD ReqLen, // how big is the request
|
|
OUT PBYTE pFrame, // buffer with our response to the client
|
|
OUT USHORT * pMnpLen
|
|
)
|
|
{
|
|
PBYTE pReqEnd;
|
|
PBYTE pFrameStart;
|
|
BYTE VarLen;
|
|
KIRQL OldIrql;
|
|
BYTE NumLTFrames=0;
|
|
USHORT MaxInfoLen=0;
|
|
USHORT FrameLen;
|
|
BYTE Mandatory[5];
|
|
BOOLEAN fOptimized=FALSE;
|
|
BOOLEAN fMaxLen256=FALSE;
|
|
BOOLEAN fV42Bis=FALSE;
|
|
BOOLEAN fArapV20=TRUE;
|
|
DWORD dwReqToSkip;
|
|
DWORD dwFrameToSkip;
|
|
BYTE JunkBuffer[MNP_MINPKT_SIZE+1];
|
|
DWORD i;
|
|
BOOLEAN fNonStd=FALSE;
|
|
|
|
|
|
DBG_ARAP_CHECK_PAGED_CODE();
|
|
|
|
#if DBG
|
|
|
|
//
|
|
// validate our assumption that all the clients always send out the same
|
|
// LR request packet
|
|
//
|
|
for (i=0; i<sizeof(ArapDbgLRPacket); i++ )
|
|
{
|
|
if (pReq[3+i] != ArapDbgLRPacket[i])
|
|
{
|
|
fNonStd = TRUE;
|
|
}
|
|
}
|
|
|
|
if (fNonStd)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("Arap Prepare..Response: non-standard LR-request packet\n"));
|
|
DbgPrint(" Std : ");
|
|
for (i=0; i<sizeof(ArapDbgLRPacket); i++)
|
|
{
|
|
DbgPrint("%2X ",ArapDbgLRPacket[i]);
|
|
}
|
|
DbgPrint("\n");
|
|
DbgPrint(" This: ");
|
|
for (i=0; i<sizeof(ArapDbgLRPacket); i++)
|
|
{
|
|
DbgPrint("%2X ",pReq[3+i]);
|
|
}
|
|
DbgPrint("\n");
|
|
}
|
|
#endif
|
|
|
|
|
|
for (i=0; i<5; i++)
|
|
{
|
|
Mandatory[i] = 0;
|
|
}
|
|
|
|
|
|
//
|
|
// in case of callback, we get an LR response from the dial-in client. When
|
|
// that happens, we still want to run through this routine to make sure all
|
|
// parameters are legal, etc., and also to "configure" the connection based
|
|
// on the parms negotiated. In that case, however, there is no output frame
|
|
// needed. So, we just write the output frame to junkbuffer
|
|
// which is obviously never used.
|
|
//
|
|
if (pFrame == NULL)
|
|
{
|
|
pFrame = &JunkBuffer[0];
|
|
}
|
|
|
|
pFrameStart = pFrame;
|
|
|
|
//
|
|
// see if this is ARAP v2.0 or v1.0 connection: we know the frame is good,
|
|
// so just look at the first byte
|
|
//
|
|
if (*pReq == MNP_SYN)
|
|
{
|
|
fArapV20 = FALSE;
|
|
}
|
|
|
|
// now copy those three start flag bytes
|
|
*pFrame++ = *pReq++;
|
|
*pFrame++ = *pReq++;
|
|
*pFrame++ = *pReq++;
|
|
|
|
// first byte (after the start flag, that is) is the length byte
|
|
FrameLen = *pReq;
|
|
|
|
if ((FrameLen > ReqLen) || (FrameLen > MNP_MINPKT_SIZE))
|
|
{
|
|
ASSERT(0);
|
|
return(ARAPERR_BAD_FORMAT);
|
|
}
|
|
|
|
pReqEnd = pReq + FrameLen;
|
|
|
|
pReq += 2; // skip over length ind. and type ind.
|
|
|
|
// Constant parameter 1 must have a value of 2
|
|
if ((*pReq++) != MNP_LR_CONST1 )
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("Error: MNP_LR_CONST1 missing in conn req %lx:\n",pArapConn));
|
|
|
|
return(ARAPERR_BAD_FORMAT);
|
|
}
|
|
|
|
// we build the return frame as we parse the incoming frame: we are supposed
|
|
// to return only those options that we both receive and understand.
|
|
//
|
|
|
|
pFrame++; // we'll put the length byte at the end
|
|
*pFrame++ = MNP_LR;
|
|
*pFrame++ = MNP_LR_CONST1;
|
|
|
|
// parse all the "variable" parms until we reach end of the frame
|
|
//
|
|
while (pReq < pReqEnd)
|
|
{
|
|
switch (*pReq++)
|
|
{
|
|
//
|
|
// nothing to do here, other than verify it's valid
|
|
//
|
|
case MNP_LR_CONST2:
|
|
|
|
VarLen = *pReq++;
|
|
if ( (VarLen == 6) &&
|
|
(*(pReq ) == 1) && (*(pReq+1) == 0) &&
|
|
(*(pReq+2) == 0) && (*(pReq+3) == 0) &&
|
|
(*(pReq+4) == 0) && (*(pReq+5) == 255) )
|
|
{
|
|
*pFrame++ = MNP_LR_CONST2;
|
|
*pFrame++ = VarLen;
|
|
RtlCopyMemory(pFrame, pReq, VarLen);
|
|
pFrame += VarLen;
|
|
pReq += VarLen;
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("Error: bad MNP_LR_CONST2 in conn req %lx:\n",pArapConn));
|
|
return(ARAPERR_BAD_FORMAT);
|
|
}
|
|
|
|
Mandatory[0] = 1;
|
|
|
|
break;
|
|
|
|
//
|
|
// octet-oriented or bit-oriented framing
|
|
//
|
|
case MNP_LR_FRAMING:
|
|
|
|
pReq++; // skip over length byte
|
|
|
|
//
|
|
// we only support octet-oriented framing mode
|
|
//
|
|
if (*pReq++ < MNP_FRMMODE_OCTET)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("Error: (%lx) unsupported framing mode %d requested:\n",
|
|
pArapConn,*(pReq-1)));
|
|
|
|
ASSERT(0);
|
|
return(ARAPERR_BAD_FORMAT);
|
|
}
|
|
|
|
*pFrame++ = MNP_LR_FRAMING;
|
|
*pFrame++ = 1;
|
|
*pFrame++ = MNP_FRMMODE_OCTET;
|
|
|
|
Mandatory[1] = 1;
|
|
break;
|
|
|
|
//
|
|
// Max. number of outstanding LT frames, k
|
|
//
|
|
case MNP_LR_NUMLTFRMS:
|
|
|
|
pReq++; // skip over length byte
|
|
NumLTFrames = *pReq++;
|
|
|
|
if (NumLTFrames > ArapGlobs.MaxLTFrames)
|
|
{
|
|
NumLTFrames = ArapGlobs.MaxLTFrames;
|
|
}
|
|
|
|
*pFrame++ = MNP_LR_NUMLTFRMS;
|
|
*pFrame++ = 1;
|
|
*pFrame++ = NumLTFrames;
|
|
|
|
Mandatory[2] = 1;
|
|
break;
|
|
|
|
//
|
|
// Max. information field length, N401
|
|
//
|
|
case MNP_LR_INFOLEN:
|
|
|
|
pReq++; // skip over length byte
|
|
MaxInfoLen = *((USHORT *)pReq);
|
|
|
|
ASSERT(MaxInfoLen <= 256);
|
|
|
|
*pFrame++ = MNP_LR_INFOLEN;
|
|
*pFrame++ = 2;
|
|
|
|
// we are just copying whatever client gave
|
|
*pFrame++ = *pReq++;
|
|
*pFrame++ = *pReq++;
|
|
|
|
Mandatory[3] = 1;
|
|
break;
|
|
|
|
//
|
|
// data optimization info
|
|
//
|
|
case MNP_LR_DATAOPT:
|
|
|
|
pReq++; // skip over length byte
|
|
|
|
if ((*pReq) & 0x1)
|
|
{
|
|
fMaxLen256 = TRUE;
|
|
}
|
|
|
|
if ((*pReq) & 0x2)
|
|
{
|
|
fOptimized = TRUE;
|
|
}
|
|
|
|
*pFrame++ = MNP_LR_DATAOPT;
|
|
*pFrame++ = 1;
|
|
*pFrame++ = *pReq++;
|
|
|
|
Mandatory[4] = 1;
|
|
|
|
break;
|
|
|
|
//
|
|
// v42 parameter negotiation
|
|
//
|
|
case MNP_LR_V42BIS:
|
|
|
|
fV42Bis = v42bisInit( pArapConn,
|
|
pReq,
|
|
&dwReqToSkip,
|
|
pFrame,
|
|
&dwFrameToSkip );
|
|
|
|
pReq += dwReqToSkip;
|
|
pFrame += dwFrameToSkip;
|
|
|
|
break;
|
|
|
|
//
|
|
// what the heck is this option? just skip over it!
|
|
//
|
|
default:
|
|
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("Prepare..Response (%lx): unknown option %lx len=%ld type=%ld\n",
|
|
pArapConn, *(pReq-1), *pReq, *(pReq+1)));
|
|
|
|
VarLen = *pReq++;
|
|
pReq += VarLen;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// make sure we got all the mandatory parameters
|
|
//
|
|
for (i=0; i<5; i++)
|
|
{
|
|
if (Mandatory[i] == 0)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("PrepareConnectionResponse: parm %d missing (%lx):\n",i,pArapConn));
|
|
|
|
return(ARAPERR_BAD_FORMAT);
|
|
}
|
|
}
|
|
|
|
// copy the stop flag
|
|
*pFrame++ = (fArapV20)? MNP_ESC : MNP_DLE;
|
|
*pFrame++ = MNP_ETX;
|
|
|
|
// store all the negotiated info
|
|
pArapConn->BlockId = (fMaxLen256)? BLKID_MNP_LGSENDBUF : BLKID_MNP_SMSENDBUF;
|
|
|
|
if (fOptimized)
|
|
{
|
|
pArapConn->Flags |= MNP_OPTIMIZED_DATA;
|
|
}
|
|
|
|
if (fV42Bis)
|
|
{
|
|
pArapConn->Flags |= MNP_V42BIS_NEGOTIATED;
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("Prepare..Response: WARNING!! v42bis NOT negotiated on (%lx):\n",pArapConn));
|
|
}
|
|
|
|
if (fArapV20)
|
|
{
|
|
pArapConn->Flags |= ARAP_V20_CONNECTION;
|
|
|
|
// save the Syn,Dle,Stx,Etx bytes depeding on what connection this is
|
|
pArapConn->MnpState.SynByte = MNP_SOH;
|
|
pArapConn->MnpState.DleByte = MNP_ESC;
|
|
pArapConn->MnpState.StxByte = MNP_STX;
|
|
pArapConn->MnpState.EtxByte = MNP_ETX;
|
|
}
|
|
else
|
|
{
|
|
pArapConn->MnpState.SynByte = MNP_SYN;
|
|
pArapConn->MnpState.DleByte = MNP_DLE;
|
|
pArapConn->MnpState.StxByte = MNP_STX;
|
|
pArapConn->MnpState.EtxByte = MNP_ETX;
|
|
}
|
|
|
|
//
|
|
// if we are doing callback, we should act like the client
|
|
//
|
|
if ((pArapConn->Flags & ARAP_CALLBACK_MODE) && fArapV20)
|
|
{
|
|
pArapConn->MnpState.LTByte = MNP_LT_V20CLIENT;
|
|
}
|
|
else
|
|
{
|
|
pArapConn->MnpState.LTByte = MNP_LT;
|
|
}
|
|
|
|
pArapConn->MnpState.WindowSize = NumLTFrames;
|
|
|
|
pArapConn->MnpState.UnAckedLimit = (NumLTFrames/2);
|
|
|
|
if (pArapConn->MnpState.UnAckedLimit == 0)
|
|
{
|
|
pArapConn->MnpState.UnAckedLimit = 1;
|
|
}
|
|
|
|
pArapConn->MnpState.MaxPktSize = MaxInfoLen;
|
|
pArapConn->MnpState.SendCredit = NumLTFrames;
|
|
|
|
// how big is the mnp frame
|
|
if (pMnpLen)
|
|
{
|
|
*pMnpLen = (USHORT)(pFrame - pFrameStart);
|
|
|
|
// write the length byte
|
|
// (length byte is after the 3 start flag bytes: that's why (pFrameStart+3))
|
|
// (and exclude (3 start + 2 stop + 1 len bytes):that's why (*pMnpLen) - 6)
|
|
|
|
*(pFrameStart+3) = (*pMnpLen) - 6;
|
|
|
|
}
|
|
|
|
return( ARAPERR_NO_ERROR );
|
|
}
|
|
|
|
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: ArapExtractAtalkSRP
|
|
// This routine extracts one complete SRP out of the receive
|
|
// buffer queue. One SRP could be split up into multiple receive
|
|
// buffers, or one receive buffer could contain several SRPs: it
|
|
// depends on how the client sent the data.
|
|
//
|
|
// Parameters: pArapConn - connection element in question
|
|
//
|
|
// Return: Pointer to a buffer containing one complete SRP
|
|
// NULL if there is no data, or if a complete SRP hasn't yet arrived
|
|
//
|
|
//***$
|
|
|
|
PARAPBUF
|
|
ArapExtractAtalkSRP(
|
|
IN PARAPCONN pArapConn
|
|
)
|
|
{
|
|
KIRQL OldIrql;
|
|
USHORT BytesInThisBuffer;
|
|
USHORT SrpLen;
|
|
USHORT SrpModLen;
|
|
PARAPBUF pArapBuf=NULL;
|
|
PARAPBUF pRecvBufNew=NULL;
|
|
PARAPBUF pReturnBuf=NULL;
|
|
PARAPBUF pNextRecvBuf=NULL;
|
|
PLIST_ENTRY pRcvList;
|
|
DWORD BytesOnQ;
|
|
USHORT BytesRemaining;
|
|
USHORT BytesToCopy;
|
|
BYTE DGroupByte;
|
|
BYTE TmpArray[4];
|
|
USHORT i;
|
|
|
|
|
|
DBG_ARAP_CHECK_PAGED_CODE();
|
|
|
|
ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
|
|
|
|
ARAP_CHECK_RCVQ_INTEGRITY(pArapConn);
|
|
|
|
ArapSRP_TryNext:
|
|
|
|
// list is empty?
|
|
if ((pRcvList = pArapConn->ReceiveQ.Flink) == &pArapConn->ReceiveQ)
|
|
{
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
return(NULL);
|
|
}
|
|
|
|
pArapBuf = CONTAINING_RECORD(pRcvList, ARAPBUF, Linkage);
|
|
|
|
// Debug only: make sure first few bytes are right...
|
|
ARAP_CHECK_RCVQ_INTEGRITY(pArapConn);
|
|
|
|
BytesInThisBuffer = pArapBuf->DataSize;
|
|
|
|
//
|
|
// if datasize goes to 0, we free the buffer right away. Also, at indicate time
|
|
// if datasize is 0, we never insert a buffer: so this had better be non-zero!
|
|
//
|
|
ASSERT(BytesInThisBuffer > 0);
|
|
|
|
//
|
|
// most common case: we at least have the 2 length bytes in the first buffer
|
|
//
|
|
if (BytesInThisBuffer >= sizeof(USHORT))
|
|
{
|
|
// get the SRP length from the length field (network to host order)
|
|
GETSHORT2SHORT(&SrpLen, pArapBuf->CurrentBuffer);
|
|
}
|
|
//
|
|
// alright, last byte of the first buffer is the 1st length byte.
|
|
// pick up the 2nd length byte from the next buffer
|
|
//
|
|
else
|
|
{
|
|
ARAP_BYTES_ON_RECVQ(pArapConn, &BytesOnQ);
|
|
|
|
if (BytesOnQ < sizeof(USHORT))
|
|
{
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
return(NULL);
|
|
}
|
|
|
|
pRcvList = pArapBuf->Linkage.Flink;
|
|
|
|
ASSERT(pRcvList != &pArapConn->ReceiveQ);
|
|
|
|
pNextRecvBuf = CONTAINING_RECORD(pRcvList, ARAPBUF, Linkage);
|
|
|
|
TmpArray[0] = pArapBuf->CurrentBuffer[0];
|
|
TmpArray[1] = pNextRecvBuf->CurrentBuffer[0];
|
|
|
|
GETSHORT2SHORT(&SrpLen, &TmpArray[0]);
|
|
}
|
|
|
|
if (SrpLen > ARAP_MAXPKT_SIZE_INCOMING)
|
|
{
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapExtractSRP: (%lx) too big a packet (%ld)\n",pArapConn,SrpLen));
|
|
|
|
// can't recover! kill connection here
|
|
ArapCleanup(pArapConn);
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
// add the 2 len bytes. We will always deal with an SRP along
|
|
// with these 2 len bytes
|
|
SrpModLen = SrpLen + sizeof(USHORT);
|
|
|
|
//
|
|
// let's deal with the simplest case first
|
|
// (the whole pkt is just one complete SRP):
|
|
//
|
|
if (SrpModLen == BytesInThisBuffer)
|
|
{
|
|
RemoveEntryList(&pArapBuf->Linkage);
|
|
|
|
// length of the SRP pkt, plus the 2 length bytes
|
|
pArapBuf->DataSize = SrpModLen;
|
|
|
|
pReturnBuf = pArapBuf;
|
|
}
|
|
|
|
//
|
|
// The packet contains more than one SRP
|
|
// allocate a new buffer and copy the SRP, leaving remaining bytes behind
|
|
//
|
|
else if (SrpModLen < BytesInThisBuffer)
|
|
{
|
|
ARAP_GET_RIGHTSIZE_RCVBUF(SrpModLen, &pRecvBufNew);
|
|
if (pRecvBufNew == NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapExtractSRP: (%lx) mem alloc failed\n",pArapConn));
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
RtlCopyMemory( &pRecvBufNew->Buffer[0],
|
|
pArapBuf->CurrentBuffer,
|
|
SrpModLen);
|
|
|
|
pRecvBufNew->DataSize = SrpModLen;
|
|
|
|
// changes to reflect the bytes we 'removed' in the original buffer
|
|
pArapBuf->DataSize -= SrpModLen;
|
|
pArapBuf->CurrentBuffer = pArapBuf->CurrentBuffer + SrpModLen;
|
|
|
|
pReturnBuf = pRecvBufNew;
|
|
|
|
// Debug only: make sure what we're leaving behind is good...
|
|
ARAP_CHECK_RCVQ_INTEGRITY(pArapConn);
|
|
}
|
|
|
|
//
|
|
// packet contains a partial SRP (this is a rare case, but possible)
|
|
// we must traverse the queue until we "collect" the whole SRP. If we still
|
|
// can't get one complete SRP, it's not arrived yet!
|
|
//
|
|
else // if (SrpModLen > BytesInThisBuffer)
|
|
{
|
|
ARAP_BYTES_ON_RECVQ(pArapConn, &BytesOnQ);
|
|
|
|
//
|
|
// if we have a full srp (split up across multiple buffers on the Q)
|
|
//
|
|
if (BytesOnQ >= SrpModLen)
|
|
{
|
|
|
|
//
|
|
// allocate a new buffer to hold this fragmented SRP
|
|
//
|
|
ARAP_GET_RIGHTSIZE_RCVBUF(SrpModLen, &pRecvBufNew);
|
|
|
|
if (pRecvBufNew == NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapExtractSRP: (%lx) mem alloc failed at II\n",pArapConn));
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
pRecvBufNew->DataSize = SrpModLen;
|
|
|
|
pNextRecvBuf = pArapBuf;
|
|
|
|
BytesRemaining = SrpModLen;
|
|
|
|
while (BytesRemaining)
|
|
{
|
|
BytesToCopy = (BytesRemaining > pNextRecvBuf->DataSize) ?
|
|
pNextRecvBuf->DataSize : BytesRemaining;
|
|
|
|
RtlCopyMemory( pRecvBufNew->CurrentBuffer,
|
|
pNextRecvBuf->CurrentBuffer,
|
|
BytesToCopy );
|
|
|
|
pRecvBufNew->CurrentBuffer += BytesToCopy;
|
|
|
|
pNextRecvBuf->CurrentBuffer += BytesToCopy;
|
|
|
|
pNextRecvBuf->DataSize -= BytesToCopy;
|
|
|
|
BytesRemaining -= BytesToCopy;
|
|
|
|
pRcvList = pNextRecvBuf->Linkage.Flink;
|
|
|
|
// are we done with this buffer? if so, unlink it and free it
|
|
if (pNextRecvBuf->DataSize == 0)
|
|
{
|
|
RemoveEntryList(&pNextRecvBuf->Linkage);
|
|
|
|
ARAP_FREE_RCVBUF(pNextRecvBuf);
|
|
}
|
|
else
|
|
{
|
|
// didn't free up the buffer? we had better be done!
|
|
ASSERT(BytesRemaining == 0);
|
|
|
|
// Debug only: make sure what we're leaving behind is good...
|
|
ARAP_CHECK_RCVQ_INTEGRITY(pArapConn);
|
|
}
|
|
|
|
// there should be more data on the queue or we should be done
|
|
ASSERT(pRcvList != &pArapConn->ReceiveQ || BytesRemaining == 0);
|
|
|
|
pNextRecvBuf = CONTAINING_RECORD(pRcvList, ARAPBUF, Linkage);
|
|
}
|
|
|
|
pRecvBufNew->CurrentBuffer = &pRecvBufNew->Buffer[0];
|
|
|
|
pReturnBuf = pRecvBufNew;
|
|
}
|
|
else
|
|
{
|
|
pReturnBuf = NULL;
|
|
}
|
|
}
|
|
|
|
if (pReturnBuf)
|
|
{
|
|
DGroupByte = pReturnBuf->CurrentBuffer[ARAP_DGROUP_OFFSET];
|
|
|
|
#if DBG
|
|
|
|
ARAP_DBG_TRACE(pArapConn,21105,pReturnBuf,0,0,0);
|
|
|
|
GETSHORT2SHORT(&SrpLen, pReturnBuf->CurrentBuffer);
|
|
|
|
ASSERT(pReturnBuf->DataSize == SrpLen+2);
|
|
ASSERT(SrpLen <= ARAP_MAXPKT_SIZE_INCOMING);
|
|
|
|
if (DGroupByte != 0x10 && DGroupByte != 0x50 &&
|
|
(pArapConn->Flags & ARAP_CONNECTION_UP))
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapExtract: DGrpByte %x\n",DGroupByte));
|
|
ASSERT(0);
|
|
}
|
|
|
|
//
|
|
// see if we have an arap packet embedded inside another arap packet
|
|
// This is an expensive way, but it's debug only: who cares!
|
|
//
|
|
for (i=6; i<(pReturnBuf->DataSize-6); i++)
|
|
{
|
|
if ((pReturnBuf->CurrentBuffer[i] == 0x10) ||
|
|
(pReturnBuf->CurrentBuffer[i] == 0x50))
|
|
{
|
|
if (pReturnBuf->CurrentBuffer[i+1] == 0)
|
|
{
|
|
if (pReturnBuf->CurrentBuffer[i+2] == 0)
|
|
{
|
|
if (pReturnBuf->CurrentBuffer[i+3] == 0x2)
|
|
{
|
|
if (pReturnBuf->CurrentBuffer[i+4] == 0)
|
|
{
|
|
if (pReturnBuf->CurrentBuffer[i+5] == 0)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapExtract: ERROR?: embedded arap packet at %lx? (%lx)\n",
|
|
&pReturnBuf->CurrentBuffer[i],pReturnBuf));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// is it out-of-band ARAP data? If so, put it on its own queue, and
|
|
// try to extract another SRP
|
|
//
|
|
if (!(DGroupByte & ARAP_SFLAG_PKT_DATA))
|
|
{
|
|
InsertTailList(&pArapConn->ArapDataQ, &pReturnBuf->Linkage);
|
|
goto ArapSRP_TryNext;
|
|
}
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
|
|
return(pReturnBuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: ArapQueueSendBytes
|
|
// This routine takes compressed data and puts it into MNP packets
|
|
// ready to be sent out. If the last unsent buffer on the queue
|
|
// has some room left, it first stuffs as many bytes as possible
|
|
// in that buffer. After that, if necessary, it allocates a new
|
|
// buffer and puts the remaining bytes in that buffer.
|
|
// The max data in any buffer can only be the negotiated maximum
|
|
// MNP data length (64 or 256 bytes)
|
|
//
|
|
// Parameters: pArapConn - connection element in question
|
|
// pCompressedDataBuffer - pointer to the data to be sent out
|
|
// CompressedDataLen - size of the outgoing data
|
|
// Priority - priority of the send
|
|
//
|
|
// Return: Error code
|
|
//
|
|
//
|
|
// NOTES: IMPORTANT: spinlock must be held before calling this routine
|
|
//
|
|
//***$
|
|
|
|
DWORD
|
|
ArapQueueSendBytes(
|
|
IN PARAPCONN pArapConn,
|
|
IN PBYTE pCompressedDataBuffer,
|
|
IN DWORD CompressedDataLen,
|
|
IN DWORD Priority
|
|
)
|
|
{
|
|
DWORD StatusCode;
|
|
PLIST_ENTRY pSendQHead;
|
|
PMNPSENDBUF pMnpSendBuf=NULL;
|
|
PBYTE pFrame, pFrameStart;
|
|
DWORD dwRemainingBytes;
|
|
PMNPSENDBUF pTailMnpSendBuf=NULL;
|
|
PMNPSENDBUF pFirstMnpSendBuf=NULL;
|
|
USHORT DataLenInThisPkt;
|
|
PLIST_ENTRY pList;
|
|
USHORT DataSizeOfOrgTailSend;
|
|
PBYTE FreeBufferOfOrgTailSend;
|
|
BYTE NumSendsOfOrgTailSend;
|
|
BOOLEAN fNeedNewBuffer;
|
|
PLIST_ENTRY pSendList;
|
|
USHORT BytesFree;
|
|
PBYTE pCompressedData;
|
|
BYTE DbgStartSeq;
|
|
|
|
|
|
|
|
DBG_ARAP_CHECK_PAGED_CODE();
|
|
|
|
if (Priority == ARAP_SEND_PRIORITY_HIGH)
|
|
{
|
|
pSendQHead = &pArapConn->HighPriSendQ;
|
|
}
|
|
else if (Priority == ARAP_SEND_PRIORITY_MED)
|
|
{
|
|
pSendQHead = &pArapConn->MedPriSendQ;
|
|
}
|
|
else
|
|
{
|
|
pSendQHead = &pArapConn->LowPriSendQ;
|
|
}
|
|
|
|
#if DBG
|
|
DbgStartSeq = pArapConn->MnpState.NextToSend;
|
|
#endif
|
|
|
|
//
|
|
// first, find the last send-buffer on the queue and see if its buffer has
|
|
// any bytes free that we can use
|
|
//
|
|
|
|
fNeedNewBuffer = TRUE;
|
|
|
|
if (!IsListEmpty(pSendQHead))
|
|
{
|
|
pList = pSendQHead->Blink;
|
|
|
|
pTailMnpSendBuf = CONTAINING_RECORD(pList, MNPSENDBUF, Linkage);
|
|
|
|
BytesFree = pTailMnpSendBuf->BytesFree;
|
|
|
|
//
|
|
// if there are more than 3 bytes free, we will use the part of this
|
|
// buffer that's free: otherwise, let's go for a new one
|
|
//
|
|
if (BytesFree > ARAP_HDRSIZE)
|
|
{
|
|
pMnpSendBuf = pTailMnpSendBuf;
|
|
|
|
pFrame = pTailMnpSendBuf->FreeBuffer;
|
|
|
|
pFrameStart = pFrame;
|
|
|
|
fNeedNewBuffer = FALSE;
|
|
|
|
// save these, in case we have to bail out
|
|
DataSizeOfOrgTailSend = pTailMnpSendBuf->DataSize;
|
|
FreeBufferOfOrgTailSend = pTailMnpSendBuf->FreeBuffer;
|
|
NumSendsOfOrgTailSend = pMnpSendBuf->NumSends;
|
|
|
|
// mark that we are stuffing one more send into this buffer
|
|
pMnpSendBuf->NumSends++;
|
|
}
|
|
else
|
|
{
|
|
pTailMnpSendBuf = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
dwRemainingBytes = CompressedDataLen;
|
|
|
|
pCompressedData = pCompressedDataBuffer;
|
|
|
|
// we are adding so many more bytes to our send queue
|
|
pArapConn->SendsPending += CompressedDataLen;
|
|
|
|
while (dwRemainingBytes)
|
|
{
|
|
if (fNeedNewBuffer)
|
|
{
|
|
pMnpSendBuf = ArapGetSendBuf(pArapConn, Priority);
|
|
if (pMnpSendBuf == NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapQueueSendBytes: ArapGetSendBuf failed (%lx)\n", pArapConn));
|
|
|
|
StatusCode = ARAPERR_OUT_OF_RESOURCES;
|
|
goto ArapQueueSendBytes_ErrExit;
|
|
}
|
|
|
|
// put MNPSend refcount
|
|
pArapConn->RefCount++;
|
|
|
|
BytesFree = pMnpSendBuf->BytesFree;
|
|
|
|
pFrameStart = pFrame = pMnpSendBuf->FreeBuffer;
|
|
|
|
//
|
|
// remeber the first buffer, in case we have to bail out!
|
|
//
|
|
if (!pFirstMnpSendBuf)
|
|
{
|
|
pFirstMnpSendBuf = pMnpSendBuf;
|
|
}
|
|
|
|
// put this send on the appropriate send queue
|
|
InsertTailList(pSendQHead, &pMnpSendBuf->Linkage);
|
|
|
|
pMnpSendBuf->NumSends = 1;
|
|
}
|
|
|
|
if (dwRemainingBytes > BytesFree)
|
|
{
|
|
DataLenInThisPkt = BytesFree;
|
|
}
|
|
else
|
|
{
|
|
DataLenInThisPkt = (USHORT)dwRemainingBytes;
|
|
}
|
|
|
|
ASSERT(DataLenInThisPkt <= MNP_MAXPKT_SIZE);
|
|
|
|
ASSERT(DataLenInThisPkt <= pMnpSendBuf->BytesFree);
|
|
|
|
RtlCopyMemory(pFrame, pCompressedData, DataLenInThisPkt);
|
|
|
|
dwRemainingBytes -= DataLenInThisPkt;
|
|
|
|
pCompressedData += DataLenInThisPkt;
|
|
|
|
ASSERT(pCompressedData <= pCompressedDataBuffer + CompressedDataLen);
|
|
|
|
pMnpSendBuf->BytesFree -= DataLenInThisPkt;
|
|
|
|
pMnpSendBuf->DataSize += DataLenInThisPkt;
|
|
|
|
ASSERT(pMnpSendBuf->DataSize <= MNP_MAXPKT_SIZE);
|
|
|
|
pFrame += DataLenInThisPkt;
|
|
|
|
// buffer from this point on is free: we could (in a subsequent call)
|
|
// stuff more bytes, starting from this point
|
|
pMnpSendBuf->FreeBuffer = pFrame;
|
|
|
|
//
|
|
// we are either done with copying the entire send, or done with this
|
|
// buffer: in either case, put those stop flag bytes
|
|
//
|
|
*pFrame++ = pArapConn->MnpState.DleByte;
|
|
*pFrame++ = pArapConn->MnpState.EtxByte;
|
|
|
|
ASSERT(pMnpSendBuf->FreeBuffer <=
|
|
(&pMnpSendBuf->Buffer[0] + 20 + MNP_MAXPKT_SIZE));
|
|
|
|
AtalkSetSizeOfBuffDescData(&pMnpSendBuf->sb_BuffDesc,
|
|
(pMnpSendBuf->DataSize + MNP_OVERHD(pArapConn)));
|
|
|
|
fNeedNewBuffer = TRUE;
|
|
}
|
|
|
|
ARAP_DBG_TRACE(pArapConn,21205,pCompressedDataBuffer,CompressedDataLen,
|
|
Priority,DbgStartSeq);
|
|
|
|
return( ARAPERR_NO_ERROR );
|
|
|
|
|
|
ArapQueueSendBytes_ErrExit:
|
|
|
|
//
|
|
// we failed somewhere. Undo whatever we did, to restore the original
|
|
// state and free up whatever resources were allocated.
|
|
//
|
|
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapQueueSendBytes_ErrExit (%lx): taking _ErrExit! %ld\n",
|
|
pArapConn,StatusCode));
|
|
|
|
pArapConn->SendsPending -= CompressedDataLen;
|
|
|
|
// did we fill any bytes in the older buf before allocating new one?
|
|
if (pTailMnpSendBuf)
|
|
{
|
|
pTailMnpSendBuf->DataSize = DataSizeOfOrgTailSend;
|
|
pTailMnpSendBuf->FreeBuffer = pFrame = FreeBufferOfOrgTailSend;
|
|
pTailMnpSendBuf->NumSends = NumSendsOfOrgTailSend;
|
|
|
|
// and don't forget those stop flag bytes we overwrote
|
|
*pFrame++ = pArapConn->MnpState.DleByte;
|
|
*pFrame++ = pArapConn->MnpState.EtxByte;
|
|
}
|
|
|
|
// did we allocate any new buffers? if so, remove and free them
|
|
if (pFirstMnpSendBuf)
|
|
{
|
|
// restore the next-to-send seq num
|
|
pArapConn->MnpState.NextToSend = pFirstMnpSendBuf->SeqNum;
|
|
|
|
while (1)
|
|
{
|
|
// get the next guy first
|
|
pSendList = pFirstMnpSendBuf->Linkage.Flink;
|
|
|
|
// remove this one
|
|
RemoveEntryList(&pFirstMnpSendBuf->Linkage);
|
|
|
|
ArapNdisFreeBuf(pFirstMnpSendBuf);
|
|
|
|
// the guy we thought was next might be the head of list: is he?
|
|
if (pSendList == pSendQHead)
|
|
{
|
|
break;
|
|
}
|
|
|
|
pFirstMnpSendBuf = CONTAINING_RECORD(pSendList, MNPSENDBUF, Linkage);
|
|
}
|
|
}
|
|
|
|
return(StatusCode);
|
|
}
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: ArapGetSendBuf
|
|
// This routine allocates a buffer for MNP send and sets it up
|
|
// sending.
|
|
// The max data in any buffer can only be the negotiated maximum
|
|
// MNP data length (64 or 256 bytes)
|
|
//
|
|
// Parameters: pArapConn - connection element in question
|
|
// Priority - priority of the send
|
|
//
|
|
// Return: Pointer to the newly allocated send buffer
|
|
//
|
|
//
|
|
// NOTES: IMPORTANT: spinlock must be held before calling this routine
|
|
//
|
|
//***$
|
|
|
|
PMNPSENDBUF
|
|
ArapGetSendBuf(
|
|
IN PARAPCONN pArapConn,
|
|
IN DWORD Priority
|
|
)
|
|
{
|
|
|
|
PBYTE pFrame;
|
|
PBYTE pFrameStart;
|
|
BYTE SeqNum;
|
|
PMNPSENDBUF pMnpSendBuf;
|
|
|
|
|
|
DBG_ARAP_CHECK_PAGED_CODE();
|
|
|
|
// allocate an arap send buffer
|
|
pMnpSendBuf = AtalkBPAllocBlock(pArapConn->BlockId);
|
|
if (pMnpSendBuf == NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapGetSendBuf: alloc failed (%lx)\n", pArapConn));
|
|
|
|
ASSERT(0);
|
|
|
|
return( NULL );
|
|
}
|
|
|
|
#if DBG
|
|
pMnpSendBuf->Signature = (pArapConn->BlockId == BLKID_MNP_LGSENDBUF)?
|
|
MNPLGSENDBUF_SIGNATURE : MNPSMSENDBUF_SIGNATURE;
|
|
InitializeListHead(&pMnpSendBuf->Linkage);
|
|
#endif
|
|
|
|
pFrameStart = pFrame = &pMnpSendBuf->Buffer[0];
|
|
|
|
AtalkNdisBuildARAPHdr(pFrame, pArapConn);
|
|
pFrame += WAN_LINKHDR_LEN;
|
|
|
|
|
|
// put the start flag bytes
|
|
*pFrame++ = pArapConn->MnpState.SynByte;
|
|
*pFrame++ = pArapConn->MnpState.DleByte;
|
|
*pFrame++ = pArapConn->MnpState.StxByte;
|
|
|
|
//
|
|
// find out what's going to be the seq num for this send if this is a high
|
|
// priority send.
|
|
//
|
|
//
|
|
if (Priority == ARAP_SEND_PRIORITY_HIGH)
|
|
{
|
|
SeqNum = pArapConn->MnpState.NextToSend;
|
|
ADD_ONE(pArapConn->MnpState.NextToSend);
|
|
}
|
|
|
|
//
|
|
// For the medium and low priority send, we'll put the seq number when we
|
|
// move it to the high-priority queue
|
|
//
|
|
else
|
|
{
|
|
SeqNum = 0;
|
|
}
|
|
|
|
// Optimized? put the header-length, type indication and the seq num
|
|
if (pArapConn->Flags & MNP_OPTIMIZED_DATA)
|
|
{
|
|
*pFrame++ = 2;
|
|
*pFrame++ = pArapConn->MnpState.LTByte;
|
|
*pFrame++ = SeqNum;
|
|
}
|
|
|
|
// ok, non-optimized. put the header-length, type indication, type+len for
|
|
// the variable parm and then the seq num
|
|
else
|
|
{
|
|
*pFrame++ = 4;
|
|
*pFrame++ = pArapConn->MnpState.LTByte;
|
|
*pFrame++ = 1;
|
|
*pFrame++ = 1;
|
|
*pFrame++ = SeqNum;
|
|
}
|
|
|
|
pMnpSendBuf->BytesFree = (pArapConn->BlockId == BLKID_MNP_SMSENDBUF) ?
|
|
MNP_MINPKT_SIZE : MNP_MAXPKT_SIZE;
|
|
|
|
pMnpSendBuf->DataSize = 0;
|
|
pMnpSendBuf->FreeBuffer = pFrame;
|
|
|
|
// store info that's used in retransmission and send completion
|
|
pMnpSendBuf->SeqNum = SeqNum;
|
|
pMnpSendBuf->RetryCount = 0;
|
|
pMnpSendBuf->pArapConn = pArapConn;
|
|
pMnpSendBuf->ComplRoutine = ArapMnpSendComplete;
|
|
pMnpSendBuf->TimeAlloced = AtalkGetCurrentTick();
|
|
pMnpSendBuf->Flags = 0;
|
|
|
|
// MNP refcount: removed when this MNP pkt is acked
|
|
pMnpSendBuf->RefCount = 1;
|
|
|
|
((PBUFFER_HDR)pMnpSendBuf)->bh_NdisPkt = NULL;
|
|
|
|
pArapConn->StatInfo.BytesSent += LT_OVERHEAD(pArapConn);
|
|
|
|
return(pMnpSendBuf);
|
|
}
|
|
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: ArapRefillSendQ
|
|
// This routine removes bytes accumulated in the medium and the
|
|
// low-priority send queues, and puts them on to the high priority
|
|
// queue from where bytes are actually sent out. If sufficient
|
|
// bytes haven't accumulated as yet on either of the queus and we
|
|
// haven't waited long enough as yet, then we skip that queue (to
|
|
// allow more bytes to accumulate)
|
|
// The idea behind this is: there are just too many NBP packets
|
|
// - directed as well as broadcast - going toward the remote client.
|
|
// If we send such a packet as soon as it arrives, we end up sending
|
|
// numerous small sized (like 6 or 8 byte) sends to the client and
|
|
// that really hurts throughput as typically the max size is 256!
|
|
//
|
|
// Parameters: pArapConn - connection element in question
|
|
//
|
|
// Return: TRUE if we moved any data to the higher priority queue
|
|
//
|
|
//***$
|
|
|
|
BOOLEAN
|
|
ArapRefillSendQ(
|
|
IN PARAPCONN pArapConn
|
|
)
|
|
{
|
|
KIRQL OldIrql;
|
|
PMNPSENDBUF pMnpSendBuf=NULL;
|
|
PLIST_ENTRY pSendHead;
|
|
PLIST_ENTRY pSendList;
|
|
LONG TimeWaited;
|
|
BYTE SeqNum;
|
|
BOOLEAN fMovedSomething=FALSE;
|
|
BOOLEAN fWaitLonger=FALSE;
|
|
DWORD SeqOffset;
|
|
|
|
|
|
DBG_ARAP_CHECK_PAGED_CODE();
|
|
|
|
ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
|
|
|
|
pSendHead = &pArapConn->MedPriSendQ;
|
|
|
|
while (1)
|
|
{
|
|
pSendList = pSendHead->Flink;
|
|
|
|
//
|
|
// if the list is not empty, take a look at the first send. If we have
|
|
// accumulated enough bytes, or if we have waited long enough, then it's
|
|
// time has come to be moved to the HighPriSendQ. Otherwise, we let it
|
|
// stay on the queue for some more coalescing
|
|
//
|
|
if (pSendList != pSendHead)
|
|
{
|
|
pMnpSendBuf = CONTAINING_RECORD(pSendList,MNPSENDBUF,Linkage);
|
|
|
|
TimeWaited = AtalkGetCurrentTick() - pMnpSendBuf->TimeAlloced;
|
|
|
|
fWaitLonger =
|
|
((pMnpSendBuf->DataSize < ARAP_SEND_COALESCE_SIZE_LIMIT) &&
|
|
(pMnpSendBuf->NumSends < ARAP_SEND_COALESCE_SRP_LIMIT) &&
|
|
(TimeWaited < ARAP_SEND_COALESCE_TIME_LIMIT) );
|
|
}
|
|
|
|
//
|
|
// if this list is empty or if this send must wait for some more time
|
|
// then we must move to the LOW pri queue. If that's also done, quit
|
|
//
|
|
if ((pSendList == pSendHead) || fWaitLonger )
|
|
{
|
|
// if we were on MedPriSendQ, go to the LowPriSendQ
|
|
if (pSendHead == &pArapConn->MedPriSendQ)
|
|
{
|
|
pSendHead = &pArapConn->LowPriSendQ;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
ASSERT(!fWaitLonger);
|
|
|
|
//
|
|
// time to move this send over to the high pri queue:
|
|
// put that seq number we had postponed putting earlier
|
|
//
|
|
SeqNum = pArapConn->MnpState.NextToSend;
|
|
|
|
ADD_ONE(pArapConn->MnpState.NextToSend);
|
|
|
|
SeqOffset = WAN_LINKHDR_LEN + LT_SEQ_OFFSET(pArapConn);
|
|
|
|
pMnpSendBuf->Buffer[SeqOffset] = SeqNum;
|
|
|
|
pMnpSendBuf->SeqNum = SeqNum;
|
|
|
|
RemoveEntryList(&pMnpSendBuf->Linkage);
|
|
|
|
InsertTailList(&pArapConn->HighPriSendQ, &pMnpSendBuf->Linkage);
|
|
|
|
fMovedSomething = TRUE;
|
|
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapRefill: moved %s seq %lx size = %d wait = %d (%d SRPs)\n",
|
|
(pSendHead == &pArapConn->MedPriSendQ)? "MED":"LOW",
|
|
pMnpSendBuf->SeqNum,pMnpSendBuf->DataSize,TimeWaited,
|
|
pMnpSendBuf->NumSends));
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
|
|
return(fMovedSomething);
|
|
}
|
|
|
|
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: ArapUnblockSelect
|
|
// This function is called when the DLL (ARAP Engine) tells us that
|
|
// it's going away. In ideal world, select irp is the only thing
|
|
// that should get completed here. If any connection was left
|
|
// or any irp wasn't complete yet, this is where we would cleanup!
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Return: result of the operation (ARAPERR_....)
|
|
//
|
|
//***$
|
|
|
|
DWORD
|
|
ArapUnblockSelect(
|
|
IN VOID
|
|
)
|
|
{
|
|
|
|
KIRQL OldIrql;
|
|
PIRP pIrp;
|
|
PIRP pSniffIrp;
|
|
PARAP_SEND_RECV_INFO pSndRcvInfo;
|
|
NTSTATUS ReturnStatus=STATUS_SUCCESS;
|
|
|
|
|
|
|
|
ARAPTRACE(("Entered ArapUnblockSelect\n"));
|
|
|
|
ACQUIRE_SPIN_LOCK(&ArapSpinLock, &OldIrql);
|
|
|
|
pIrp = ArapSelectIrp;
|
|
ArapSelectIrp = NULL;
|
|
|
|
#if DBG
|
|
pSniffIrp = ArapSniffIrp;
|
|
ArapSniffIrp = NULL;
|
|
#endif
|
|
|
|
if (ArapStackState == ARAP_STATE_ACTIVE)
|
|
{
|
|
ArapStackState = ARAP_STATE_ACTIVE_WAITING;
|
|
}
|
|
else if (ArapStackState == ARAP_STATE_INACTIVE)
|
|
{
|
|
ArapStackState = ARAP_STATE_INACTIVE_WAITING;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql);
|
|
|
|
|
|
#if DBG
|
|
//
|
|
// if we had sniffing going, complete the sniff irp since dll is shutting down
|
|
//
|
|
if (pSniffIrp)
|
|
{
|
|
pSndRcvInfo = (PARAP_SEND_RECV_INFO)pSniffIrp->AssociatedIrp.SystemBuffer;
|
|
pSndRcvInfo->StatusCode = ARAPERR_SHUTDOWN_COMPLETE;
|
|
|
|
// complete the irp
|
|
ARAP_COMPLETE_IRP(pSniffIrp, sizeof(ARAP_SEND_RECV_INFO),
|
|
STATUS_SUCCESS, &ReturnStatus);
|
|
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapUnblockSelect: unblocked the sniff irp\n"));
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// complete the select irp, now that the engine tells us that it wants to
|
|
// shutdown
|
|
//
|
|
if (pIrp)
|
|
{
|
|
pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
|
|
pSndRcvInfo->StatusCode = ARAPERR_SHUTDOWN_COMPLETE;
|
|
|
|
// complete the irp
|
|
ARAP_COMPLETE_IRP(pIrp, sizeof(ARAP_SEND_RECV_INFO), STATUS_SUCCESS,
|
|
&ReturnStatus);
|
|
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapUnblockSelect: unblocked the select irp\n"));
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapUnblockSelect: select irp not yet unblocked\n"));
|
|
}
|
|
|
|
return(ARAPERR_NO_ERROR);
|
|
}
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: ArapReleaseResources
|
|
// This routine frees up any global resources we had allocated
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Return: result of the operation (ARAPERR_....)
|
|
//
|
|
//***$
|
|
|
|
DWORD
|
|
ArapReleaseResources(
|
|
IN VOID
|
|
)
|
|
{
|
|
KIRQL OldIrql;
|
|
PLIST_ENTRY pList;
|
|
PADDRMGMT pAddrMgmt;
|
|
PADDRMGMT pNextAddrMgmt;
|
|
PARAPCONN pArapConn;
|
|
|
|
|
|
ARAPTRACE(("Entered ArapReleaseResources\n"));
|
|
|
|
if (RasPortDesc == NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapReleaseResources: arap engine never initialized; returning\n"));
|
|
return(ARAPERR_NO_ERROR);
|
|
}
|
|
|
|
#if ARAP_STATIC_MODE
|
|
//
|
|
// if we were in the static mode of network address allocation, we
|
|
// allocated memory for our network address "bitmap": free that here.
|
|
//
|
|
if (!(ArapGlobs.DynamicMode))
|
|
{
|
|
pAddrMgmt = ArapGlobs.pAddrMgmt;
|
|
|
|
ASSERT(pAddrMgmt);
|
|
|
|
while (pAddrMgmt)
|
|
{
|
|
pNextAddrMgmt = pAddrMgmt->Next;
|
|
AtalkFreeMemory(pAddrMgmt);
|
|
pAddrMgmt = pNextAddrMgmt;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
//
|
|
// By the time this routine is called, all the connections should have been
|
|
// completely closed. If, however, some connection got stuck in some weird
|
|
// state, at least make sure that we don't have a memory leak
|
|
//
|
|
ASSERT(IsListEmpty(&RasPortDesc->pd_ArapConnHead));
|
|
|
|
while (1)
|
|
{
|
|
ACQUIRE_SPIN_LOCK(&RasPortDesc->pd_Lock, &OldIrql);
|
|
|
|
if (IsListEmpty(&RasPortDesc->pd_ArapConnHead))
|
|
{
|
|
RELEASE_SPIN_LOCK(&RasPortDesc->pd_Lock, OldIrql);
|
|
break;
|
|
}
|
|
|
|
pList = RasPortDesc->pd_ArapConnHead.Flink;
|
|
|
|
pArapConn = CONTAINING_RECORD(pList, ARAPCONN, Linkage);
|
|
|
|
ACQUIRE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
|
|
|
|
// protect against it going away while we do this
|
|
pArapConn->RefCount++;
|
|
|
|
RELEASE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
|
|
RELEASE_SPIN_LOCK(&RasPortDesc->pd_Lock, OldIrql);
|
|
|
|
ArapCleanup(pArapConn);
|
|
|
|
ACQUIRE_SPIN_LOCK(&RasPortDesc->pd_Lock, &OldIrql);
|
|
ACQUIRE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
|
|
|
|
RemoveEntryList(&pArapConn->Linkage);
|
|
InitializeListHead(&pArapConn->Linkage);
|
|
|
|
// force this connection to be freed
|
|
pArapConn->RefCount = 1;
|
|
|
|
RELEASE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
|
|
RELEASE_SPIN_LOCK(&RasPortDesc->pd_Lock, OldIrql);
|
|
|
|
DerefArapConn(pArapConn);
|
|
}
|
|
|
|
return(ARAPERR_NO_ERROR);
|
|
}
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: AtalkReferenceRasDefPort
|
|
// This routine puts a refcount on the Default adapter so it doesn't go away
|
|
// with PnP while we are busy doing some ARAP/PPP connection setup
|
|
// It also makes sure that RasPortDesc is indeed present
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Return: TRUE (most cases) if port is all ok, FALSE if PnP in progress or something
|
|
//
|
|
//***$
|
|
|
|
BOOLEAN
|
|
AtalkReferenceRasDefPort(
|
|
IN VOID
|
|
)
|
|
{
|
|
KIRQL OldIrql;
|
|
BOOLEAN fDefPortOk = FALSE;
|
|
|
|
|
|
ACQUIRE_SPIN_LOCK(&AtalkPortLock, &OldIrql);
|
|
|
|
if ((RasPortDesc != NULL) && (!(RasPortDesc->pd_Flags & PD_PNP_RECONFIGURE)))
|
|
{
|
|
if (AtalkDefaultPort)
|
|
{
|
|
ACQUIRE_SPIN_LOCK_DPC(&AtalkDefaultPort->pd_Lock);
|
|
if ((AtalkDefaultPort->pd_Flags &
|
|
(PD_ACTIVE | PD_PNP_RECONFIGURE | PD_CLOSING)) == PD_ACTIVE)
|
|
{
|
|
// put a IrpProcess refcount, so AtalkDefaultPort doesn't go away in PnP
|
|
AtalkDefaultPort->pd_RefCount++;
|
|
fDefPortOk = TRUE;
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
|
|
("AtalkReferenceRasDefPort: port going away, no can do (%lx)\n",
|
|
AtalkDefaultPort->pd_Flags));
|
|
}
|
|
RELEASE_SPIN_LOCK_DPC(&AtalkDefaultPort->pd_Lock);
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
|
|
("AtalkReferenceRasDefPort: no default adapter configured!\n"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
|
|
("AtalkReferenceRasDefPort: RasPortDesc not configured\n"));
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&AtalkPortLock, OldIrql);
|
|
|
|
return(fDefPortOk);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AtalkPnPInformRas(
|
|
IN BOOLEAN fEnableRas
|
|
)
|
|
{
|
|
|
|
PIRP pIrp=NULL;
|
|
PARAP_SEND_RECV_INFO pSndRcvInfo;
|
|
DWORD StatusCode;
|
|
KIRQL OldIrql;
|
|
NTSTATUS ReturnStatus=STATUS_SUCCESS;
|
|
|
|
|
|
//
|
|
// fEnableRas = TRUE: we are asked to inform RAS (aka dll, engine) that the stack
|
|
// is now "active" (i.e. available for RAS connections)
|
|
//
|
|
if (fEnableRas)
|
|
{
|
|
//
|
|
// make sure both the adapters are ready. We don't really need spinlock to
|
|
// check the flag since all PnP operations are guaranteed to be serialized
|
|
//
|
|
if ( (AtalkDefaultPort == NULL) ||
|
|
(AtalkDefaultPort->pd_Flags & PD_PNP_RECONFIGURE) ||
|
|
(RasPortDesc == NULL) ||
|
|
(RasPortDesc->pd_Flags & PD_PNP_RECONFIGURE) )
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("AtalkPnPInformRas: not both adapters are ready %lx %lx, returning\n",
|
|
AtalkDefaultPort,RasPortDesc));
|
|
return;
|
|
}
|
|
|
|
ACQUIRE_SPIN_LOCK(&ArapSpinLock, &OldIrql);
|
|
|
|
//
|
|
// if we are already active, nothing to do!
|
|
//
|
|
if (ArapStackState == ARAP_STATE_ACTIVE)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("AtalkPnPInformRas: stack already active, nothing to do\n"));
|
|
|
|
RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql);
|
|
return;
|
|
}
|
|
|
|
pIrp = ArapSelectIrp;
|
|
ArapSelectIrp = NULL;
|
|
|
|
if (pIrp)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("AtalkPnPInformRas: informing dll that stack is ready\n"));
|
|
|
|
ArapStackState = ARAP_STATE_ACTIVE;
|
|
StatusCode = ARAPERR_STACK_IS_ACTIVE;
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("AtalkPnPInformRas: no select irp. stack ready, but dll not knoweth\n"));
|
|
|
|
ArapStackState = ARAP_STATE_ACTIVE_WAITING;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql);
|
|
}
|
|
|
|
//
|
|
// fEnableRas = FALSE: we are asked to inform RAS (aka dll, engine) that the stack
|
|
// is now "inactive" (i.e. not available for RAS connections)
|
|
//
|
|
else
|
|
{
|
|
ACQUIRE_SPIN_LOCK(&ArapSpinLock, &OldIrql);
|
|
|
|
//
|
|
// if we are already inactive, nothing to do!
|
|
//
|
|
if (ArapStackState == ARAP_STATE_INACTIVE)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("AtalkPnPInformRas: stack already inactive, nothing to do\n"));
|
|
|
|
RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql);
|
|
return;
|
|
}
|
|
|
|
pIrp = ArapSelectIrp;
|
|
ArapSelectIrp = NULL;
|
|
|
|
if (pIrp)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("AtalkPnPInformRas: informing dll that stack is unavailable\n"));
|
|
|
|
ArapStackState = ARAP_STATE_INACTIVE;
|
|
StatusCode = ARAPERR_STACK_IS_NOT_ACTIVE;
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("AtalkPnPInformRas: no select irp. stack unavailable, but dll not knoweth\n"));
|
|
|
|
ArapStackState = ARAP_STATE_INACTIVE_WAITING;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql);
|
|
}
|
|
|
|
if (pIrp)
|
|
{
|
|
pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
|
|
pSndRcvInfo->StatusCode = StatusCode;
|
|
|
|
// complete the irp
|
|
ARAP_COMPLETE_IRP(pIrp, sizeof(ARAP_SEND_RECV_INFO), STATUS_SUCCESS,
|
|
&ReturnStatus);
|
|
}
|
|
}
|
|
|
|
|
|
#if ARAP_STATIC_MODE
|
|
|
|
//***
|
|
//
|
|
// Function: ArapReleaseAddr
|
|
// This routine releases the network address that was being used
|
|
// by the client (corresponding to this connection). In case of
|
|
// dynamic mode, we don't do anything.
|
|
// In case of static mode, we clear the bit corresponding to this
|
|
// particular network address.
|
|
//
|
|
// Parameters: pArapConn - connection element in question
|
|
//
|
|
// Return: none
|
|
//
|
|
//***$
|
|
|
|
VOID
|
|
ArapReleaseAddr(
|
|
IN PARAPCONN pArapConn
|
|
)
|
|
{
|
|
|
|
KIRQL OldIrql;
|
|
PADDRMGMT pAddrMgmt;
|
|
BYTE Node;
|
|
BYTE ByteNum;
|
|
BYTE BitMask;
|
|
DWORD i;
|
|
|
|
|
|
DBG_ARAP_CHECK_PAGED_CODE();
|
|
|
|
//
|
|
// if we are in static mode, we need to "release" the node so that someone
|
|
// else can use it. Find the bit for this node and clear it (i.e. "release")
|
|
//
|
|
if (!(ArapGlobs.DynamicMode))
|
|
{
|
|
ACQUIRE_SPIN_LOCK(&ArapSpinLock, &OldIrql);
|
|
|
|
// first, find the right pAddrMgmt (1st one if we have <255 clients)
|
|
pAddrMgmt = ArapGlobs.pAddrMgmt;
|
|
|
|
ASSERT(pAddrMgmt);
|
|
|
|
while (pAddrMgmt->Network != pArapConn->NetAddr.atn_Network)
|
|
{
|
|
pAddrMgmt = pAddrMgmt->Next;
|
|
|
|
ASSERT(pAddrMgmt);
|
|
}
|
|
|
|
Node = pArapConn->NetAddr.atn_Node;
|
|
|
|
// find out which of the 32 bytes we should be looking at
|
|
ByteNum = Node/8;
|
|
Node -= (ByteNum*8);
|
|
|
|
// generate the bitmask to represent the node
|
|
BitMask = 0x1;
|
|
for (i=0; i<Node; i++ )
|
|
{
|
|
BitMask <<= 1;
|
|
}
|
|
|
|
// now, clear that bit!
|
|
pAddrMgmt->NodeBitMap[ByteNum] &= ~BitMask;
|
|
|
|
RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql);
|
|
}
|
|
|
|
|
|
}
|
|
#endif //ARAP_STATIC_MODE
|
|
|
|
|
|
|
|
//
|
|
// not used anymore: leave them in, in case we need to use them sometime...
|
|
//
|
|
#if 0
|
|
|
|
DWORD
|
|
ArapScheduleWorkerEvent(
|
|
IN DWORD Action,
|
|
IN PVOID Context1,
|
|
IN PVOID Context2
|
|
)
|
|
{
|
|
PARAPQITEM pArapQItem;
|
|
|
|
if ((pArapQItem = AtalkAllocMemory(sizeof(ARAPQITEM))) == NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapScheduleWorkerEvent: mem alloc failed!\n"));
|
|
return(ARAPERR_OUT_OF_RESOURCES);
|
|
}
|
|
|
|
pArapQItem->Action = Action;
|
|
pArapQItem->Context1 = Context1;
|
|
pArapQItem->Context2 = Context2;
|
|
|
|
ExInitializeWorkItem(&pArapQItem->WorkQItem,
|
|
(PWORKER_THREAD_ROUTINE)ArapDelayedEventHandler,
|
|
pArapQItem);
|
|
ExQueueWorkItem(&pArapQItem->WorkQItem, CriticalWorkQueue);
|
|
|
|
return(ARAPERR_NO_ERROR);
|
|
}
|
|
|
|
|
|
VOID
|
|
ArapDelayedEventHandler(
|
|
IN PARAPQITEM pArapQItem
|
|
)
|
|
{
|
|
DWORD Action;
|
|
PIRP pIrp;
|
|
PIO_STACK_LOCATION pIrpSp;
|
|
ULONG IoControlCode;
|
|
PMNPSENDBUF pMnpSendBuf;
|
|
DWORD StatusCode;
|
|
NTSTATUS status;
|
|
KIRQL OldIrq;
|
|
|
|
|
|
Action = pArapQItem->Action;
|
|
switch (Action)
|
|
{
|
|
case ARAPACTION_COMPLETE_IRP:
|
|
|
|
pIrp = (PIRP)pArapQItem->Context1;
|
|
status = (NTSTATUS)pArapQItem->Context2;
|
|
|
|
|
|
ASSERT(pIrp != NULL);
|
|
|
|
#if DBG
|
|
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
|
IoControlCode = pIrpSp->Parameters.DeviceIoControl.IoControlCode;
|
|
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapDelayedEventHandler: completing irp %lx, Ioctl %lx, Status=%lx at irql=%d\n",
|
|
pIrp,IoControlCode,status,KeGetCurrentIrql()));
|
|
#endif
|
|
//TdiCompleteRequest(pIrp, status);
|
|
|
|
pIrp->IoStatus.Status = status;
|
|
|
|
IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
|
|
|
|
break;
|
|
|
|
case ARAPACTION_CALL_COMPLETION:
|
|
|
|
pMnpSendBuf = (PMNPSENDBUF )pArapQItem->Context1;
|
|
StatusCode = (DWORD)pArapQItem->Context2;
|
|
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapDelayedEventHandler: calling compl. %lx with %lx, %ld\n",
|
|
pMnpSendBuf->ComplRoutine,pMnpSendBuf, StatusCode));
|
|
|
|
(pMnpSendBuf->ComplRoutine)(pMnpSendBuf, StatusCode);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapDelayedEventHandler: invalid action %ld\n",Action));
|
|
}
|
|
|
|
AtalkFreeMemory(pArapQItem);
|
|
}
|
|
|
|
#endif // #if 0
|
|
|
|
|