You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2904 lines
82 KiB
2904 lines
82 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
arap.c
|
|
|
|
Abstract:
|
|
|
|
This module implements routines specific to ARAP
|
|
|
|
Author:
|
|
|
|
Shirish Koti
|
|
|
|
Revision History:
|
|
15 Nov 1996 Initial Version
|
|
|
|
--*/
|
|
|
|
|
|
#include <atalk.h>
|
|
#pragma hdrstop
|
|
|
|
|
|
#define FILENUM ARAP
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, ArapProcessIoctl)
|
|
#pragma alloc_text(PAGE_ARAP, ArapMarkConnectionUp)
|
|
#pragma alloc_text(PAGE_ARAP, ArapIoctlRecv)
|
|
#pragma alloc_text(PAGE_ARAP, ArapExchangeParms)
|
|
#pragma alloc_text(PAGE_ARAP, ArapConnect)
|
|
#pragma alloc_text(PAGE_ARAP, ArapConnectComplete)
|
|
#pragma alloc_text(PAGE_ARAP, ArapDisconnect)
|
|
#pragma alloc_text(PAGE_ARAP, ArapGetAddr)
|
|
#pragma alloc_text(PAGE_ARAP, ArapGetStats)
|
|
#pragma alloc_text(PAGE_ARAP, ArapIoctlSend)
|
|
#pragma alloc_text(PAGE_ARAP, ArapSendPrepare)
|
|
#pragma alloc_text(PAGE_ARAP, ArapMnpSendComplete)
|
|
#pragma alloc_text(PAGE_ARAP, ArapIoctlSendComplete)
|
|
#pragma alloc_text(PAGE_ARAP, ArapDataToDll)
|
|
#pragma alloc_text(PAGE_ARAP, MnpSendAckIfReqd)
|
|
#pragma alloc_text(PAGE_ARAP, MnpSendLNAck)
|
|
#pragma alloc_text(PAGE_ARAP, ArapSendLDPacket)
|
|
#pragma alloc_text(PAGE_ARAP, ArapRetryTimer)
|
|
#endif
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: ArapProcessIoctl
|
|
// Process all ioctls coming from the Ras-ARAP module
|
|
//
|
|
// Parameters: pIrp - the irp to process
|
|
//
|
|
// Return: result of the operation
|
|
//
|
|
//***$
|
|
|
|
NTSTATUS
|
|
ArapProcessIoctl(
|
|
IN PIRP pIrp
|
|
)
|
|
{
|
|
NTSTATUS status=STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION pIrpSp;
|
|
ULONG IoControlCode;
|
|
PARAP_SEND_RECV_INFO pSndRcvInfo=NULL;
|
|
PATCPCONN pAtcpConn=NULL;
|
|
PARAPCONN pArapConn=NULL;
|
|
ATALK_NODEADDR ClientNode;
|
|
DWORD dwBytesToDll;
|
|
DWORD dwOrgIrql;
|
|
DWORD dwFlags;
|
|
DWORD dwInputBufLen;
|
|
DWORD dwOutputBufLen;
|
|
BOOLEAN fDerefDefPort=FALSE;
|
|
NTSTATUS ReturnStatus=STATUS_SUCCESS;
|
|
|
|
|
|
PAGED_CODE ();
|
|
|
|
dwOrgIrql = KeGetCurrentIrql();
|
|
|
|
ASSERT(dwOrgIrql < DISPATCH_LEVEL);
|
|
|
|
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
|
|
|
IoControlCode = pIrpSp->Parameters.DeviceIoControl.IoControlCode;
|
|
|
|
dwInputBufLen = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
|
|
|
dwOutputBufLen = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
|
|
ARAPTRACE(("Entered ArapProcessIoctl (%lx %lx)\n",pIrp, IoControlCode));
|
|
|
|
pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
if (!pSndRcvInfo)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapProcessIoctl: SystemBuffer is NULL!! (ioctl = %lx,pIrp = %lx)\n",
|
|
pIrp,IoControlCode));
|
|
|
|
ARAP_COMPLETE_IRP(pIrp, 0, STATUS_INVALID_PARAMETER, &ReturnStatus);
|
|
return( ReturnStatus );
|
|
}
|
|
|
|
if (dwInputBufLen < sizeof(ARAP_SEND_RECV_INFO))
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapProcessIoctl: irp %lx, too small input buffer (%d bytes)!\n",
|
|
pIrp,dwInputBufLen));
|
|
|
|
ARAP_COMPLETE_IRP(pIrp, 0, STATUS_INVALID_PARAMETER, &ReturnStatus);
|
|
return( ReturnStatus );
|
|
}
|
|
|
|
if (dwOutputBufLen < sizeof(ARAP_SEND_RECV_INFO))
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapProcessIoctl: irp %lx, too small output buffer (%d bytes)!\n",
|
|
pIrp,dwOutputBufLen));
|
|
|
|
ARAP_COMPLETE_IRP(pIrp, 0, STATUS_INVALID_PARAMETER, &ReturnStatus);
|
|
return( ReturnStatus );
|
|
}
|
|
|
|
//
|
|
// handle PPP (ATCP) ioctls separately
|
|
//
|
|
if ((IoControlCode == IOCTL_ATCP_SETUP_CONNECTION) ||
|
|
(IoControlCode == IOCTL_ATCP_SUPPRESS_BCAST) ||
|
|
(IoControlCode == IOCTL_ATCP_CLOSE_CONNECTION))
|
|
{
|
|
if (IoControlCode == IOCTL_ATCP_SETUP_CONNECTION)
|
|
{
|
|
AtalkLockPPPIfNecessary();
|
|
ReturnStatus = PPPProcessIoctl(pIrp, pSndRcvInfo, IoControlCode, NULL);
|
|
return (ReturnStatus);
|
|
}
|
|
else
|
|
{
|
|
ClientNode.atn_Network = pSndRcvInfo->ClientAddr.ata_Network;
|
|
ClientNode.atn_Node = (BYTE)pSndRcvInfo->ClientAddr.ata_Node;
|
|
|
|
if (ClientNode.atn_Node != 0)
|
|
{
|
|
// find the right connection
|
|
pAtcpConn = FindAndRefPPPConnByAddr(ClientNode, &dwFlags);
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapProcessIoctl: excuse me? Node is 0! Irp=%lx\n",pIrp));
|
|
ASSERT(0);
|
|
}
|
|
|
|
if (pAtcpConn)
|
|
{
|
|
PPPProcessIoctl(pIrp, pSndRcvInfo, IoControlCode, pAtcpConn);
|
|
|
|
// remove the refcount put in by FindAndRefPPPConnByAddr
|
|
DerefPPPConn(pAtcpConn);
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapProcessIoctl: PPP Ioctl %lx but can't find conn %x.%x\n",
|
|
IoControlCode,pSndRcvInfo->ClientAddr.ata_Network,
|
|
pSndRcvInfo->ClientAddr.ata_Node));
|
|
|
|
pSndRcvInfo->StatusCode = ARAPERR_NO_SUCH_CONNECTION;
|
|
ARAP_COMPLETE_IRP(pIrp, sizeof(ARAP_SEND_RECV_INFO),
|
|
STATUS_SUCCESS, &ReturnStatus);
|
|
return (ReturnStatus);
|
|
}
|
|
}
|
|
|
|
return( STATUS_SUCCESS);
|
|
}
|
|
|
|
//
|
|
// NOTE: ALL THE ARAP CODE IS NOW DEFUNCT. To minimize code-churn, only small changes
|
|
// are done to disable ARAP. At some point in time, all the code needs to be cleaned up
|
|
// so ARAP-specific stuff is completely removed
|
|
//
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapProcessIoctl: ARAP not supported anymore!!\n"));
|
|
ASSERT(0);
|
|
|
|
ARAP_COMPLETE_IRP(pIrp, 0, STATUS_INVALID_PARAMETER, &ReturnStatus);
|
|
return( ReturnStatus );
|
|
}
|
|
|
|
|
|
if (!ArapAcceptIrp(pIrp, IoControlCode, &fDerefDefPort))
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapProcessIoctl: irp %lx not accepted (%lx)\n", pIrp,IoControlCode));
|
|
|
|
ARAP_COMPLETE_IRP(pIrp, sizeof(ARAP_SEND_RECV_INFO), STATUS_SUCCESS, &ReturnStatus);
|
|
|
|
// remove that IrpProcess refcount
|
|
if (fDerefDefPort)
|
|
{
|
|
AtalkPortDereference(AtalkDefaultPort);
|
|
}
|
|
|
|
return( ReturnStatus);
|
|
}
|
|
|
|
if ((IoControlCode != IOCTL_ARAP_EXCHANGE_PARMS) &&
|
|
(IoControlCode != IOCTL_ARAP_GET_ZONE_LIST))
|
|
{
|
|
pArapConn = pSndRcvInfo->AtalkContext;
|
|
}
|
|
|
|
//
|
|
// if ths irp is for a specific connection, validate the connection first!
|
|
//
|
|
if ((pArapConn != NULL) && (!ArapConnIsValid(pArapConn)))
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapProcessIoctl: conn %lx is gone! (ioctl = %lx)\n",
|
|
pArapConn,IoControlCode));
|
|
|
|
pSndRcvInfo->StatusCode = ARAPERR_NO_SUCH_CONNECTION;
|
|
|
|
ARAP_COMPLETE_IRP(pIrp, sizeof(ARAP_SEND_RECV_INFO), STATUS_SUCCESS, &ReturnStatus);
|
|
|
|
// remove that IrpProcess refcount
|
|
if (fDerefDefPort)
|
|
{
|
|
AtalkPortDereference(AtalkDefaultPort);
|
|
}
|
|
|
|
return( ReturnStatus);
|
|
}
|
|
|
|
dwBytesToDll = sizeof(ARAP_SEND_RECV_INFO);
|
|
|
|
// in most likelihood, we're going to return pending: mark it so
|
|
IoMarkIrpPending(pIrp);
|
|
|
|
switch (IoControlCode)
|
|
{
|
|
//
|
|
// receive parameters from the user-level, and return some of our own
|
|
//
|
|
case IOCTL_ARAP_EXCHANGE_PARMS:
|
|
|
|
// exchange of parms: if not already done, lock arap pages
|
|
AtalkLockArapIfNecessary();
|
|
|
|
status = ArapExchangeParms( pIrp );
|
|
dwBytesToDll = sizeof(EXCHGPARMS);
|
|
|
|
// exchange of parms done: unlock if possible
|
|
AtalkUnlockArapIfNecessary();
|
|
break;
|
|
|
|
case IOCTL_ARAP_SETUP_CONNECTION:
|
|
|
|
// new connection being established: if not already done, lock arap pages
|
|
AtalkLockArapIfNecessary();
|
|
pSndRcvInfo->StatusCode = ARAPERR_NO_ERROR;
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
//
|
|
// setup the low level arap connection link (aka Point-to-Point Link)
|
|
// (first time client dials in, we respond. At callback, we initiate;
|
|
// at callback time, we initiate the connection here)
|
|
//
|
|
case IOCTL_ARAP_MNP_CONN_RESPOND:
|
|
case IOCTL_ARAP_MNP_CONN_INITIATE:
|
|
|
|
status = ArapConnect( pIrp, IoControlCode );
|
|
break;
|
|
|
|
//
|
|
// obtain (or make up) an appletalk address for the client and return it
|
|
//
|
|
case IOCTL_ARAP_GET_ADDR:
|
|
|
|
status = ArapGetAddr( pIrp );
|
|
break;
|
|
|
|
//
|
|
// just mark the Arap connection as being established
|
|
//
|
|
case IOCTL_ARAP_CONNECTION_UP:
|
|
|
|
status = ArapMarkConnectionUp( pIrp );
|
|
break;
|
|
|
|
//
|
|
// dll wants the connection blown away: disconnect it
|
|
//
|
|
case IOCTL_ARAP_DISCONNECT:
|
|
|
|
status = ArapDisconnect( pIrp );
|
|
break;
|
|
|
|
//
|
|
// send the buffer given by the dll
|
|
//
|
|
case IOCTL_ARAP_SEND:
|
|
|
|
status = ArapIoctlSend( pIrp );
|
|
break;
|
|
|
|
//
|
|
// "direct irp": get data for the connection specified
|
|
//
|
|
case IOCTL_ARAP_RECV:
|
|
|
|
status = ArapIoctlRecv( pIrp );
|
|
break;
|
|
|
|
//
|
|
// "select irp": get data if there is for any connection
|
|
//
|
|
case IOCTL_ARAP_SELECT:
|
|
|
|
status = ArapProcessSelect( pIrp );
|
|
break;
|
|
|
|
#if DBG
|
|
//
|
|
// "sniff irp": return all the sniff info
|
|
//
|
|
case IOCTL_ARAP_SNIFF_PKTS:
|
|
|
|
status = ArapProcessSniff( pIrp );
|
|
break;
|
|
#endif
|
|
|
|
//
|
|
// engine wants the select irp unblocked (either because it's shutting
|
|
// down or because we want to shutdown)
|
|
//
|
|
case IOCTL_ARAP_CONTINUE_SHUTDOWN:
|
|
|
|
ArapUnblockSelect();
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
//
|
|
// get names of all the zones in the entire network
|
|
//
|
|
case IOCTL_ARAP_GET_ZONE_LIST:
|
|
|
|
ArapZipGetZoneStat( (PZONESTAT)pSndRcvInfo );
|
|
|
|
// (-4 to avoid 4 bytes from ZoneNames[1] field)
|
|
dwBytesToDll = ((PZONESTAT)pSndRcvInfo)->BufLen + sizeof(ZONESTAT) - 4;
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapProcessIoctl: Invalid Request %lx\n", IoControlCode));
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
|
|
if( status != STATUS_PENDING )
|
|
{
|
|
pIrpSp->Control &= ~SL_PENDING_RETURNED;
|
|
|
|
ARAP_COMPLETE_IRP(pIrp, dwBytesToDll, STATUS_SUCCESS, &ReturnStatus);
|
|
status = ReturnStatus;
|
|
}
|
|
|
|
//
|
|
// if this irp was for a specific connection, validation refcount was put
|
|
// on it: take that away
|
|
//
|
|
if (pArapConn)
|
|
{
|
|
DerefArapConn(pArapConn);
|
|
}
|
|
|
|
// remove that IrpProcess refcount
|
|
if (fDerefDefPort)
|
|
{
|
|
AtalkPortDereference(AtalkDefaultPort);
|
|
}
|
|
|
|
ASSERT(KeGetCurrentIrql() == dwOrgIrql);
|
|
|
|
return( status );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: ArapMarkConnectionUp
|
|
// Set the flags in our connection to mark that Arap connection
|
|
// has been established (by the dll) (we don't route until this
|
|
// happens)
|
|
//
|
|
// Parameters: pIrp - the irp to process
|
|
//
|
|
// Return: result of the operation
|
|
//
|
|
//***$
|
|
|
|
NTSTATUS
|
|
ArapMarkConnectionUp(
|
|
IN PIRP pIrp
|
|
)
|
|
{
|
|
|
|
PARAPCONN pArapConn;
|
|
PARAP_SEND_RECV_INFO pSndRcvInfo;
|
|
KIRQL OldIrql;
|
|
|
|
|
|
DBG_ARAP_CHECK_PAGED_CODE();
|
|
|
|
pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
pArapConn = (PARAPCONN)pSndRcvInfo->AtalkContext;
|
|
|
|
if (pArapConn == NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapMarkConnectionUp: null conn\n"));
|
|
|
|
pSndRcvInfo->StatusCode = ARAPERR_NO_SUCH_CONNECTION;
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
(" Yippeee! %s connection is up! (%x.%x @%lx)\n",
|
|
(pArapConn->Flags & ARAP_V20_CONNECTION)? "ARAP v2.0":"ARAP v1.0",
|
|
pArapConn->NetAddr.atn_Network,pArapConn->NetAddr.atn_Node,pArapConn));
|
|
|
|
ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
|
|
|
|
pArapConn->Flags |= ARAP_CONNECTION_UP;
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
|
|
pSndRcvInfo->StatusCode = ARAPERR_NO_ERROR;
|
|
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: ArapIoctlRecv
|
|
// Try to get data for the specified connection. If there is no
|
|
// data available, irp is just "queued"
|
|
//
|
|
// Parameters: pIrp - the irp to process
|
|
//
|
|
// Return: result of the operation
|
|
//
|
|
//***$
|
|
|
|
NTSTATUS
|
|
ArapIoctlRecv(
|
|
IN PIRP pIrp
|
|
)
|
|
{
|
|
|
|
PARAPCONN pArapConn;
|
|
PARAP_SEND_RECV_INFO pSndRcvInfo;
|
|
KIRQL OldIrql;
|
|
|
|
|
|
|
|
DBG_ARAP_CHECK_PAGED_CODE();
|
|
|
|
pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
pArapConn = (PARAPCONN)pSndRcvInfo->AtalkContext;
|
|
|
|
if (pArapConn == NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapIoctlRecv: null conn\n"));
|
|
|
|
pSndRcvInfo->StatusCode = ARAPERR_NO_SUCH_CONNECTION;
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
ARAPTRACE(("Entered ArapIoctlRecv (%lx %lx)\n",pIrp,pArapConn));
|
|
|
|
ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
|
|
|
|
if (pArapConn->State >= MNP_LDISCONNECTING)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapIoctlRecv: rejecting recv ioctl recvd during disconnect %lx\n", pArapConn));
|
|
|
|
pSndRcvInfo->StatusCode = ARAPERR_DISCONNECT_IN_PROGRESS;
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
// we only allow one irp to be in progress at a time
|
|
if (pArapConn->pRecvIoctlIrp != NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("ArapIoctlRecv: rejecting recv \
|
|
(irp already in progress) %lx\n", pArapConn));
|
|
|
|
pSndRcvInfo->StatusCode = ARAPERR_IRP_IN_PROGRESS;
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
pArapConn->pRecvIoctlIrp = pIrp;
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
|
|
// see if we can satisfy this request
|
|
ArapDataToDll( pArapConn );
|
|
|
|
return( STATUS_PENDING );
|
|
}
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: ArapExchangeParms
|
|
// Get configuration parameters from the dll, and return some info
|
|
//
|
|
// Parameters: pIrp - the irp to process
|
|
//
|
|
// Return: result of the operation
|
|
//
|
|
//***$
|
|
|
|
NTSTATUS
|
|
ArapExchangeParms(
|
|
IN PIRP pIrp
|
|
)
|
|
{
|
|
ZONESTAT ZoneStat;
|
|
KIRQL OldIrql;
|
|
PADDRMGMT pAddrMgmt;
|
|
PEXCHGPARMS pExchgParms;
|
|
|
|
|
|
DBG_ARAP_CHECK_PAGED_CODE();
|
|
|
|
ARAPTRACE(("Entered ArapExchangeParms (%lx)\n",pIrp));
|
|
|
|
pExchgParms = (PEXCHGPARMS)pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
// we enter this routine only if AtalkDefaultPort is referenced
|
|
|
|
ACQUIRE_SPIN_LOCK(&ArapSpinLock, &OldIrql);
|
|
|
|
ArapGlobs.LowVersion = pExchgParms->Parms.LowVersion;
|
|
ArapGlobs.HighVersion = pExchgParms->Parms.HighVersion;
|
|
ArapGlobs.MnpInactiveTime = pExchgParms->Parms.MnpInactiveTime;
|
|
ArapGlobs.V42bisEnabled = pExchgParms->Parms.V42bisEnabled;
|
|
ArapGlobs.SmartBuffEnabled = pExchgParms->Parms.SmartBuffEnabled;
|
|
ArapGlobs.NetworkAccess = pExchgParms->Parms.NetworkAccess;
|
|
ArapGlobs.DynamicMode = pExchgParms->Parms.DynamicMode;
|
|
ArapGlobs.NetRange.LowEnd = pExchgParms->Parms.NetRange.LowEnd;
|
|
ArapGlobs.NetRange.HighEnd = pExchgParms->Parms.NetRange.HighEnd;
|
|
ArapGlobs.MaxLTFrames = (BYTE)pExchgParms->Parms.MaxLTFrames;
|
|
ArapGlobs.SniffMode = pExchgParms->Parms.SniffMode;
|
|
|
|
ArapGlobs.pAddrMgmt = NULL;
|
|
|
|
// we only support dynamic mode
|
|
ASSERT(ArapGlobs.DynamicMode);
|
|
|
|
#if ARAP_STATIC_MODE
|
|
//
|
|
// allocate and initialize the bitmap for node allocation
|
|
//
|
|
if (!(ArapGlobs.DynamicMode))
|
|
{
|
|
RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql);
|
|
|
|
if (!ArapValidNetrange(ArapGlobs.NetRange))
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapExchangeParms: Netrange %lx - %lx is invalid\n",
|
|
ArapGlobs.NetRange.LowEnd,ArapGlobs.NetRange.HighEnd));
|
|
|
|
pExchgParms->StatusCode = ARAPERR_BAD_NETWORK_RANGE;
|
|
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
|
|
ACQUIRE_SPIN_LOCK(&ArapSpinLock, &OldIrql);
|
|
|
|
if ( (pAddrMgmt = AtalkAllocZeroedMemory(sizeof(ADDRMGMT))) == NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapExchangeParms: alloc for pAddrMgmt failed\n"));
|
|
|
|
RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql);
|
|
pExchgParms->StatusCode = ARAPERR_OUT_OF_RESOURCES;
|
|
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
|
|
//
|
|
// node numbers 0 and 255 are reserved, so mark them as occupied.
|
|
//
|
|
pAddrMgmt->NodeBitMap[0] |= 0x1;
|
|
pAddrMgmt->NodeBitMap[31] |= 0x80;
|
|
|
|
pAddrMgmt->Network = ArapGlobs.NetRange.LowEnd;
|
|
|
|
ArapGlobs.pAddrMgmt = pAddrMgmt;
|
|
}
|
|
#endif //ARAP_STATIC_MODE
|
|
|
|
|
|
RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql);
|
|
|
|
//
|
|
// now, time to return some stack info to the dll.
|
|
//
|
|
|
|
// just an initial guess: dll will figure out the real number when an
|
|
// actual connection comes in
|
|
//
|
|
pExchgParms->Parms.NumZones = 50;
|
|
|
|
pExchgParms->Parms.ServerAddr.ata_Network =
|
|
AtalkDefaultPort->pd_Nodes->an_NodeAddr.atn_Network;
|
|
|
|
pExchgParms->Parms.ServerAddr.ata_Node =
|
|
AtalkDefaultPort->pd_Nodes->an_NodeAddr.atn_Node;
|
|
|
|
// copy the server zone in Pascal string format
|
|
if (AtalkDesiredZone)
|
|
{
|
|
pExchgParms->Parms.ServerZone[0] = AtalkDesiredZone->zn_ZoneLen;
|
|
|
|
RtlCopyMemory( &pExchgParms->Parms.ServerZone[1],
|
|
&AtalkDesiredZone->zn_Zone[0],
|
|
AtalkDesiredZone->zn_ZoneLen );
|
|
}
|
|
else if (AtalkDefaultPort->pd_DefaultZone)
|
|
{
|
|
pExchgParms->Parms.ServerZone[0] = AtalkDefaultPort->pd_DefaultZone->zn_ZoneLen;
|
|
|
|
RtlCopyMemory( &pExchgParms->Parms.ServerZone[1],
|
|
&AtalkDefaultPort->pd_DefaultZone->zn_Zone[0],
|
|
AtalkDefaultPort->pd_DefaultZone->zn_ZoneLen );
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("Arap: Server not in any zone?? Client won't see any zones!!\n"));
|
|
|
|
pExchgParms->Parms.ServerZone[0] = 0;
|
|
}
|
|
|
|
ArapGlobs.OurNetwkNum =
|
|
AtalkDefaultPort->pd_Nodes->an_NodeAddr.atn_Network;
|
|
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("Arap: ready to accept connections (Router net=%x node=%x)\n",
|
|
AtalkDefaultPort->pd_Nodes->an_NodeAddr.atn_Network,
|
|
AtalkDefaultPort->pd_Nodes->an_NodeAddr.atn_Node));
|
|
|
|
pExchgParms->StatusCode = ARAPERR_NO_ERROR;
|
|
|
|
// complete the irp successfully
|
|
return (STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: ArapConnect
|
|
// Setup the MNP level connection with the client
|
|
//
|
|
// Parameters: pIrp - the irp to process
|
|
//
|
|
// Return: result of the operation
|
|
//
|
|
//***$
|
|
|
|
NTSTATUS
|
|
ArapConnect(
|
|
IN PIRP pIrp,
|
|
IN ULONG IoControlCode
|
|
)
|
|
{
|
|
KIRQL OldIrql;
|
|
PBYTE pFrame;
|
|
SHORT MnpLen;
|
|
SHORT FrameLen;
|
|
DWORD StatusCode=ARAPERR_NO_ERROR;
|
|
PMNPSENDBUF pMnpSendBuf=NULL;
|
|
PARAP_SEND_RECV_INFO pSndRcvInfo;
|
|
PARAPCONN pArapConn;
|
|
PNDIS_PACKET ndisPacket;
|
|
NDIS_STATUS ndisStatus;
|
|
|
|
|
|
DBG_ARAP_CHECK_PAGED_CODE();
|
|
|
|
ARAPTRACE(("Entered ArapConnect (%lx)\n",pIrp));
|
|
|
|
pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
pArapConn = FindArapConnByContx(pSndRcvInfo->pDllContext);
|
|
|
|
if (pArapConn == NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapConnect: couldn't find pArapConn!\n"));
|
|
ASSERT(0);
|
|
pSndRcvInfo->StatusCode = ARAPERR_NO_SUCH_CONNECTION;
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
ACQUIRE_SPIN_LOCK(&ArapSpinLock, &OldIrql);
|
|
ArapConnections++;
|
|
RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql);
|
|
|
|
#if ARAP_STATIC_MODE
|
|
// This will add a route (one-time only) for the ARAP network range
|
|
ArapAddArapRoute();
|
|
#endif //ARAP_STATIC_MODE
|
|
|
|
|
|
// first, write stack's context for dll's future use
|
|
pSndRcvInfo->AtalkContext = (PVOID)pArapConn;
|
|
|
|
//
|
|
// put a refcount for the connection (deref only when the connection gets
|
|
// disconnected *and* the dll is told about it).
|
|
// Also, initialize the v42bis stuff for this connection
|
|
//
|
|
ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
|
|
|
|
if (pArapConn->pIoctlIrp != NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("ArapConnect: rejecting connect \
|
|
(irp already in progress) %lx\n", pArapConn));
|
|
|
|
pSndRcvInfo->StatusCode = ARAPERR_IRP_IN_PROGRESS;
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
ASSERT(pArapConn->State == MNP_IDLE);
|
|
|
|
if (IoControlCode == IOCTL_ARAP_MNP_CONN_RESPOND)
|
|
{
|
|
pArapConn->State = MNP_RESPONSE;
|
|
}
|
|
|
|
//
|
|
// we're doing callback: do some fixing up
|
|
//
|
|
else
|
|
{
|
|
pArapConn->State = MNP_REQUEST;
|
|
pArapConn->Flags |= ARAP_CALLBACK_MODE;
|
|
pArapConn->MnpState.SendCredit = 8;
|
|
}
|
|
|
|
|
|
// Connect refcount: remove only after we tell dll that connection died
|
|
pArapConn->RefCount++;
|
|
|
|
// put MNPSend refcount
|
|
pArapConn->RefCount++;
|
|
|
|
pArapConn->pIoctlIrp = pIrp;
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
|
|
KeInitializeEvent(&pArapConn->NodeAcquireEvent, NotificationEvent, FALSE);
|
|
|
|
|
|
StatusCode = ARAPERR_NO_ERROR;
|
|
|
|
//
|
|
// allocate buf to send out the connection response/request
|
|
//
|
|
if ((pMnpSendBuf = AtalkBPAllocBlock(BLKID_MNP_SMSENDBUF)) != NULL)
|
|
{
|
|
// get an ndis packet for this puppy
|
|
StatusCode = ArapGetNdisPacket(pMnpSendBuf);
|
|
}
|
|
|
|
if ((pMnpSendBuf == NULL) || (StatusCode != ARAPERR_NO_ERROR))
|
|
{
|
|
if (pMnpSendBuf)
|
|
{
|
|
ArapNdisFreeBuf(pMnpSendBuf);
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapConnect: AtalkBPAllocBlock failed on %lx\n", pArapConn));
|
|
}
|
|
|
|
ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
|
|
pArapConn->State = MNP_IDLE;
|
|
pSndRcvInfo->StatusCode = ARAPERR_OUT_OF_RESOURCES;
|
|
pSndRcvInfo->AtalkContext = ARAP_INVALID_CONTEXT;
|
|
pArapConn->pIoctlIrp = NULL;
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
|
|
// didn't succeed: remove that connection refcount
|
|
DerefArapConn(pArapConn);
|
|
|
|
// and the MNPSend refcount
|
|
DerefArapConn(pArapConn);
|
|
|
|
// return success: we have already set our StatusCode to the right thing
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
#if DBG
|
|
pMnpSendBuf->Signature = MNPSMSENDBUF_SIGNATURE;
|
|
#endif
|
|
|
|
// yes, we need this, in case we bail out
|
|
InitializeListHead(&pMnpSendBuf->Linkage);
|
|
|
|
pMnpSendBuf->SeqNum = 0; // Indication code expects this to be 0
|
|
pMnpSendBuf->RetryCount = 1;
|
|
pMnpSendBuf->RefCount = 1; // 1 MNP refcount
|
|
pMnpSendBuf->pArapConn = pArapConn;
|
|
pMnpSendBuf->ComplRoutine = ArapConnectComplete;
|
|
pMnpSendBuf->Flags = 1;
|
|
|
|
// when should we retransmit this pkt?
|
|
pMnpSendBuf->RetryTime = pArapConn->SendRetryTime + AtalkGetCurrentTick();
|
|
|
|
pFrame = &pMnpSendBuf->Buffer[0];
|
|
|
|
AtalkNdisBuildARAPHdr(pFrame, pArapConn);
|
|
|
|
pFrame += WAN_LINKHDR_LEN;
|
|
|
|
FrameLen = WAN_LINKHDR_LEN;
|
|
|
|
//
|
|
// are we just responding to a connection request?
|
|
//
|
|
if (IoControlCode == IOCTL_ARAP_MNP_CONN_RESPOND)
|
|
{
|
|
//
|
|
// pSndRcvInfo contains the client's connect request. Parse it and
|
|
// prepare a response as appropriate
|
|
//
|
|
|
|
ACQUIRE_SPIN_LOCK(&ArapSpinLock, &OldIrql);
|
|
|
|
StatusCode = PrepareConnectionResponse( pArapConn,
|
|
&pSndRcvInfo->Data[0],
|
|
pSndRcvInfo->DataLen,
|
|
pFrame,
|
|
&MnpLen);
|
|
|
|
RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql);
|
|
|
|
if (StatusCode != ARAPERR_NO_ERROR)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapConnect: (%lx) response prep failed %ld\n", pArapConn,StatusCode));
|
|
|
|
ArapConnectComplete(pMnpSendBuf, StatusCode);
|
|
|
|
return( STATUS_PENDING );
|
|
}
|
|
|
|
FrameLen += MnpLen;
|
|
}
|
|
|
|
//
|
|
// no, actually we are initiating a connection (callback time)
|
|
// copy the frame we used in earlier setup (that dll kindly saved for us)
|
|
//
|
|
else
|
|
{
|
|
RtlCopyMemory(pFrame, (PBYTE)&pSndRcvInfo->Data[0], pSndRcvInfo->DataLen);
|
|
|
|
FrameLen += (USHORT)pSndRcvInfo->DataLen;
|
|
|
|
#if DBG
|
|
pArapConn->MnpState.SynByte = pSndRcvInfo->Data[0];
|
|
pArapConn->MnpState.DleByte = pSndRcvInfo->Data[1];
|
|
pArapConn->MnpState.StxByte = pSndRcvInfo->Data[2];
|
|
pArapConn->MnpState.EtxByte = MNP_ETX;
|
|
#endif
|
|
|
|
}
|
|
|
|
AtalkSetSizeOfBuffDescData(&pMnpSendBuf->sb_BuffDesc, FrameLen);
|
|
|
|
pMnpSendBuf->RefCount++; // 1 ndis count, since we'll send now
|
|
pMnpSendBuf->DataSize = FrameLen;
|
|
|
|
NdisAdjustBufferLength(pMnpSendBuf->sb_BuffHdr.bh_NdisBuffer,
|
|
pMnpSendBuf->DataSize);
|
|
|
|
// put this connection response on the retransmission queue
|
|
ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
|
|
|
|
InsertTailList(&pArapConn->RetransmitQ, &pMnpSendBuf->Linkage);
|
|
|
|
pArapConn->SendsPending += pMnpSendBuf->DataSize;
|
|
|
|
pArapConn->MnpState.UnAckedSends++;
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
|
|
ndisPacket = pMnpSendBuf->sb_BuffHdr.bh_NdisPkt;
|
|
|
|
NdisSend(&ndisStatus, RasPortDesc->pd_NdisBindingHandle, ndisPacket);
|
|
|
|
// if there was a problem sending, call the completion routine here
|
|
// retransmit logic will send it again
|
|
//
|
|
if (ndisStatus != NDIS_STATUS_PENDING)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("MnpSendAck: NdisSend failed %lx\n",ndisStatus));
|
|
|
|
ArapNdisSendComplete(ARAPERR_SEND_FAILED, (PBUFFER_DESC)pMnpSendBuf, NULL);
|
|
}
|
|
|
|
//
|
|
// done. we'll complete the irp when the client responds (acks or response)
|
|
//
|
|
return( STATUS_PENDING );
|
|
}
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: ArapConnectComplete
|
|
// Completion routine for the ArapConnect routine. This routine
|
|
// is called by the ArapRcvComplete routine when we get an ack
|
|
// for our Connection response (LR) frame
|
|
//
|
|
// Parameters: pMnpSendBuf - the send buff that contained the LR response
|
|
// StatusCode - how did it go?
|
|
//
|
|
// Return: none
|
|
//
|
|
//***$
|
|
|
|
VOID
|
|
ArapConnectComplete(
|
|
IN PMNPSENDBUF pMnpSendBuf,
|
|
IN DWORD StatusCode
|
|
)
|
|
{
|
|
KIRQL OldIrql;
|
|
PIRP pIrp;
|
|
PARAPCONN pArapConn;
|
|
PARAP_SEND_RECV_INFO pSndRcvInfo;
|
|
NTSTATUS ReturnStatus=STATUS_SUCCESS;
|
|
|
|
|
|
|
|
DBG_ARAP_CHECK_PAGED_CODE();
|
|
|
|
pArapConn = pMnpSendBuf->pArapConn;
|
|
|
|
if (StatusCode != ARAPERR_NO_ERROR)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapConnectComplete: (%x): conn setup failed (%d)!\n",
|
|
pArapConn,StatusCode));
|
|
//
|
|
// BUGBUG: change ArapCleanup to accept StatusCode as a parm (currently,
|
|
// the real reason behind disconnect is lost, so dll doesn't get it)
|
|
//
|
|
ArapCleanup(pArapConn);
|
|
|
|
DerefMnpSendBuf(pMnpSendBuf, FALSE);
|
|
|
|
return;
|
|
}
|
|
|
|
ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
|
|
|
|
pIrp = pArapConn->pIoctlIrp;
|
|
|
|
pArapConn->pIoctlIrp = NULL;
|
|
|
|
pArapConn->SendsPending -= pMnpSendBuf->DataSize;
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
|
|
ARAPTRACE(("Entered ArapConnectComplete (%lx %lx)\n",pIrp,pArapConn));
|
|
|
|
// if there is an irp (under normal conditions, should be), complete it
|
|
if (pIrp)
|
|
{
|
|
pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
pSndRcvInfo->StatusCode = StatusCode;
|
|
|
|
if (StatusCode != ARAPERR_NO_ERROR)
|
|
{
|
|
pSndRcvInfo->StatusCode = ARAPERR_DISCONNECT_IN_PROGRESS;
|
|
}
|
|
|
|
//
|
|
// copy the frame we used to establish the connection. In case of
|
|
// callback, dll will pass this back to initiate the connection
|
|
//
|
|
if (pSndRcvInfo->IoctlCode == IOCTL_ARAP_MNP_CONN_RESPOND)
|
|
{
|
|
pSndRcvInfo->DataLen = (DWORD)pMnpSendBuf->DataSize;
|
|
|
|
RtlCopyMemory((PBYTE)&pSndRcvInfo->Data[0],
|
|
(PBYTE)&pMnpSendBuf->Buffer[0],
|
|
(DWORD)pMnpSendBuf->DataSize);
|
|
}
|
|
|
|
ARAP_COMPLETE_IRP(pIrp,
|
|
pSndRcvInfo->DataLen + sizeof(ARAP_SEND_RECV_INFO),
|
|
STATUS_SUCCESS, &ReturnStatus);
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapConnectComplete: (%x): no irp available!\n",pArapConn));
|
|
}
|
|
|
|
DerefMnpSendBuf(pMnpSendBuf, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: ArapDisconnect
|
|
// Disconnect the connection
|
|
//
|
|
// Parameters: pIrp - the irp to process
|
|
//
|
|
// Return: result of the operation
|
|
//
|
|
//***$
|
|
|
|
NTSTATUS
|
|
ArapDisconnect(
|
|
IN PIRP pIrp
|
|
)
|
|
{
|
|
PARAPCONN pArapConn;
|
|
PARAP_SEND_RECV_INFO pSndRcvInfo;
|
|
|
|
|
|
DBG_ARAP_CHECK_PAGED_CODE();
|
|
|
|
pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
pArapConn = (PARAPCONN)pSndRcvInfo->AtalkContext;
|
|
|
|
if ((pArapConn == NULL) || (pArapConn == ARAP_INVALID_CONTEXT))
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapDisconnect: null conn\n"));
|
|
|
|
pSndRcvInfo->StatusCode = ARAPERR_NO_SUCH_CONNECTION;
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapDisconnect: rcvd DISCONNECT on %lx (irp=%lx)\n",pArapConn,pIrp));
|
|
|
|
// UserCode = 0xFF
|
|
pSndRcvInfo->StatusCode = ArapSendLDPacket(pArapConn, 0xFF);
|
|
|
|
ArapCleanup(pArapConn);
|
|
|
|
//
|
|
// done. let this irp complete: we'll notify the dll of
|
|
// 'disconnect-complete' (via select irp) when our cleanup completes
|
|
//
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: ArapGetAddr
|
|
// Get a network address for the remote client
|
|
// (if doing dynamic addressing, go to the net; otherwise, get one
|
|
// from the table we maintain)
|
|
//
|
|
// Parameters: pIrp - the irp to process
|
|
//
|
|
// Return: result of the operation
|
|
//
|
|
//***$
|
|
|
|
NTSTATUS
|
|
ArapGetAddr(
|
|
IN PIRP pIrp
|
|
)
|
|
{
|
|
PARAPCONN pArapConn;
|
|
PARAP_SEND_RECV_INFO pSndRcvInfo;
|
|
DWORD StatusCode = ARAPERR_NO_NETWORK_ADDR;
|
|
|
|
|
|
DBG_ARAP_CHECK_PAGED_CODE();
|
|
|
|
pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
pArapConn = (PARAPCONN)pSndRcvInfo->AtalkContext;
|
|
|
|
ARAPTRACE(("Entered ArapGetAddr (%lx %lx)\n",pIrp,pArapConn));
|
|
|
|
if (pArapConn == NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapGetAddr: null conn\n"));
|
|
|
|
pSndRcvInfo->StatusCode = ARAPERR_NO_SUCH_CONNECTION;
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
if (ArapGlobs.DynamicMode)
|
|
{
|
|
StatusCode = ArapGetDynamicAddr(pArapConn);
|
|
}
|
|
|
|
#if ARAP_STATIC_MODE
|
|
else
|
|
{
|
|
StatusCode = ArapGetStaticAddr(pArapConn);
|
|
}
|
|
#endif //ARAP_STATIC_MODE
|
|
|
|
pSndRcvInfo->StatusCode = StatusCode;
|
|
|
|
if (StatusCode == ARAPERR_NO_ERROR)
|
|
{
|
|
pSndRcvInfo->ClientAddr.ata_Network = pArapConn->NetAddr.atn_Network;
|
|
pSndRcvInfo->ClientAddr.ata_Node = pArapConn->NetAddr.atn_Node;
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapGetAddr: returning %d\n", StatusCode));
|
|
}
|
|
|
|
return( STATUS_SUCCESS );
|
|
|
|
}
|
|
|
|
|
|
// we don't really support this: why have the code!
|
|
#if 0
|
|
|
|
//***
|
|
//
|
|
// Function: ArapGetStats
|
|
// Return statistics (bytes in, bytes out, compressed etc.) about
|
|
// the specified connection
|
|
//
|
|
// Parameters: pIrp - the irp to process
|
|
//
|
|
// Return: result of the operation
|
|
//
|
|
//***$
|
|
|
|
NTSTATUS
|
|
ArapGetStats(
|
|
IN PIRP pIrp
|
|
)
|
|
{
|
|
|
|
PARAPCONN pArapConn;
|
|
PARAP_SEND_RECV_INFO pSndRcvInfo;
|
|
KIRQL OldIrql;
|
|
PSTAT_INFO pStatInfo;
|
|
|
|
|
|
DBG_ARAP_CHECK_PAGED_CODE();
|
|
|
|
pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
pArapConn = (PARAPCONN)pSndRcvInfo->AtalkContext;
|
|
|
|
if (pArapConn == NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapGetStats: null conn\n"));
|
|
|
|
pSndRcvInfo->StatusCode = ARAPERR_NO_SUCH_CONNECTION;
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapGetStats: returning stats for (%lx)\n",pArapConn));
|
|
|
|
pStatInfo = (PSTAT_INFO)&pSndRcvInfo->Data[0];
|
|
|
|
ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
|
|
|
|
*pStatInfo = pArapConn->StatInfo;
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
|
|
pSndRcvInfo->StatusCode = ARAPERR_NO_ERROR;
|
|
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
#endif // #if 0 around ArapGetStats
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: ArapIoctlSend
|
|
// Send the buffer given by the dll to the remote client.
|
|
// This routine calls the routine to prepare the send (v42bis
|
|
// compression and MNP bookkeeping) and then sends it out
|
|
//
|
|
// Parameters: pIrp - the irp to process
|
|
//
|
|
// Return: result of the operation
|
|
//
|
|
//***$
|
|
|
|
NTSTATUS
|
|
ArapIoctlSend(
|
|
IN PIRP pIrp
|
|
)
|
|
{
|
|
KIRQL OldIrql;
|
|
BUFFER_DESC OrgBuffDesc;
|
|
PARAPCONN pArapConn;
|
|
PARAP_SEND_RECV_INFO pSndRcvInfo;
|
|
DWORD StatusCode=ARAPERR_NO_ERROR;
|
|
|
|
|
|
DBG_ARAP_CHECK_PAGED_CODE();
|
|
|
|
pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
pArapConn = (PARAPCONN)pSndRcvInfo->AtalkContext;
|
|
|
|
if (pArapConn == NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapIoctlSend: null conn\n"));
|
|
|
|
pSndRcvInfo->StatusCode = ARAPERR_NO_SUCH_CONNECTION;
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
ARAPTRACE(("Entered ArapIoctlSend (%lx %lx)\n",pIrp,pArapConn));
|
|
|
|
// save the irp so we can complete it in the completion routine
|
|
ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
|
|
|
|
// we only allow one irp to be in progress at a time
|
|
if (pArapConn->pIoctlIrp != NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("ArapIoctlSend: rejecting send \
|
|
(irp already in progress) %lx\n", pArapConn));
|
|
|
|
pSndRcvInfo->StatusCode = ARAPERR_IRP_IN_PROGRESS;
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
pArapConn->pIoctlIrp = pIrp;
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
|
|
ASSERT(pSndRcvInfo->DataLen <= 618);
|
|
|
|
DBGDUMPBYTES("Dll send:", &pSndRcvInfo->Data[0],pSndRcvInfo->DataLen,1);
|
|
|
|
//
|
|
// get the send ready (compression, MNP bookkeeping etc.)
|
|
//
|
|
OrgBuffDesc.bd_Next = NULL;
|
|
OrgBuffDesc.bd_Length = (SHORT)pSndRcvInfo->DataLen;
|
|
OrgBuffDesc.bd_CharBuffer = &pSndRcvInfo->Data[0];
|
|
OrgBuffDesc.bd_Flags = BD_CHAR_BUFFER;
|
|
|
|
StatusCode = ArapSendPrepare( pArapConn,
|
|
&OrgBuffDesc,
|
|
ARAP_SEND_PRIORITY_HIGH );
|
|
|
|
if (StatusCode == ARAPERR_NO_ERROR)
|
|
{
|
|
//
|
|
// now, send that send over. Note that we don't care about the return
|
|
// code here: if this particular send fails, we still tell the dll that
|
|
// the send succeeded because our retransmission logic will take care
|
|
// of ensuring that the send gets there.
|
|
//
|
|
ArapNdisSend( pArapConn, &pArapConn->HighPriSendQ );
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapIoctlSend (%lx): ArapSendPrepare failed (%ld)\n",
|
|
pArapConn,StatusCode));
|
|
}
|
|
|
|
ArapIoctlSendComplete(StatusCode, pArapConn);
|
|
|
|
return( STATUS_PENDING );
|
|
}
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: ArapProcessSelect
|
|
// Process the select irp issued by the dll
|
|
// This routine saves the select irp so that any connection that
|
|
// needs it can take it. Also, it sees if any of the connections
|
|
// is waiting for an irp to indicate a disconnect-complete or
|
|
// data to the dll. If so, that is completed here.
|
|
//
|
|
// Parameters: pIrp - the select irp to process
|
|
//
|
|
// Return: result of the operation
|
|
//
|
|
//***$
|
|
|
|
NTSTATUS
|
|
ArapProcessSelect(
|
|
IN PIRP pIrp
|
|
)
|
|
{
|
|
KIRQL OldIrql;
|
|
KIRQL OldIrql2;
|
|
PARAPCONN pDiscArapConn=NULL;
|
|
PARAPCONN pRcvArapConn=NULL;
|
|
PARAP_SEND_RECV_INFO pSndRcvInfo;
|
|
PLIST_ENTRY pList;
|
|
DWORD dwBytesToDll;
|
|
DWORD StatusCode;
|
|
NTSTATUS ReturnStatus;
|
|
|
|
|
|
|
|
ARAPTRACE(("Entered ArapProcessSelect (%lx)\n",pIrp));
|
|
|
|
pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
|
|
pDiscArapConn = NULL;
|
|
pRcvArapConn = NULL;
|
|
|
|
//
|
|
// it's possible that between the time the last select irp completed and
|
|
// this select came down, some activity that needs a select irp occured
|
|
// (e.g. a disconnect). See if we have hit such a condition
|
|
//
|
|
|
|
ArapDelayedNotify(&pDiscArapConn, &pRcvArapConn);
|
|
|
|
//
|
|
// if we found an arapconn that was waiting for a select irp to notify the
|
|
// dll of disconnect, do the good deed!
|
|
//
|
|
if (pDiscArapConn)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapProcessSelect: completing delayed disconnect on %lx!\n", pDiscArapConn));
|
|
|
|
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 (pDiscArapConn->pDbgTraceBuffer && pDiscArapConn->SniffedBytes > 0)
|
|
{
|
|
dwBytesToDll = ArapFillIrpWithSniffInfo(pDiscArapConn,pIrp);
|
|
}
|
|
#endif
|
|
|
|
dwBytesToDll += sizeof(ARAP_SEND_RECV_INFO);
|
|
|
|
//
|
|
// no need for spinlock here
|
|
//
|
|
if (pDiscArapConn->Flags & ARAP_REMOTE_DISCONN)
|
|
{
|
|
StatusCode = ARAPERR_RDISCONNECT_COMPLETE;
|
|
}
|
|
else
|
|
{
|
|
StatusCode = ARAPERR_LDISCONNECT_COMPLETE;
|
|
}
|
|
|
|
pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
|
|
pSndRcvInfo->pDllContext = pDiscArapConn->pDllContext;
|
|
|
|
pSndRcvInfo->StatusCode = StatusCode;
|
|
|
|
pSndRcvInfo->DataLen = dwBytesToDll;
|
|
|
|
// we told (rather, will very shortly tell) dll: remove this link
|
|
pDiscArapConn->pDllContext = NULL;
|
|
|
|
// now that we told dll, remove 1 refcount
|
|
DerefArapConn( pDiscArapConn );
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
|
|
if (pIrp->Cancel)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapProcessSelect: select irp %lx already cancelled!\n", pIrp));
|
|
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
ARAP_COMPLETE_IRP(pIrp, 0, STATUS_CANCELLED, &ReturnStatus);
|
|
return(ReturnStatus);
|
|
}
|
|
|
|
ACQUIRE_SPIN_LOCK(&ArapSpinLock, &OldIrql2);
|
|
|
|
if (ArapSelectIrp != NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapProcessSelect: select irp %lx already in progress!\n", ArapSelectIrp));
|
|
ASSERT(0);
|
|
|
|
pSndRcvInfo->StatusCode = ARAPERR_IRP_IN_PROGRESS;
|
|
RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql2);
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
//
|
|
// does arap engine need to be told about some change?
|
|
//
|
|
if ( (ArapStackState == ARAP_STATE_ACTIVE_WAITING) ||
|
|
(ArapStackState == ARAP_STATE_INACTIVE_WAITING) )
|
|
{
|
|
if (ArapStackState == ARAP_STATE_ACTIVE_WAITING)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapProcessSelect: delayed notify: stack is now active!\n"));
|
|
|
|
ArapStackState = ARAP_STATE_ACTIVE;
|
|
pSndRcvInfo->StatusCode = ARAPERR_STACK_IS_ACTIVE;
|
|
}
|
|
else if (ArapStackState == ARAP_STATE_INACTIVE_WAITING)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapProcessSelect: delayed notify: stack is now inactive!\n"));
|
|
|
|
ArapStackState = ARAP_STATE_INACTIVE;
|
|
pSndRcvInfo->StatusCode = ARAPERR_STACK_IS_NOT_ACTIVE;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql2);
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
//
|
|
// ok, most common case: we just need to stash this select irp!
|
|
//
|
|
ArapSelectIrp = pIrp;
|
|
|
|
RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql2);
|
|
|
|
IoSetCancelRoutine(pIrp, (PDRIVER_CANCEL)AtalkTdiCancel);
|
|
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
|
|
|
|
//
|
|
// if there was an arapconn waiting for a select irp, pass on the data!
|
|
//
|
|
if (pRcvArapConn)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_INFO,
|
|
("ArapProcessSelect: getting delayed data on %lx at %ld\n",
|
|
pRcvArapConn,AtalkGetCurrentTick()));
|
|
|
|
ARAP_DBG_TRACE(pRcvArapConn,11105,0,0,0,0);
|
|
|
|
ArapDataToDll( pRcvArapConn );
|
|
}
|
|
|
|
return(STATUS_PENDING);
|
|
}
|
|
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: ArapDelayedNotify
|
|
// This routine checks to see if any of the arap connections was
|
|
// waiting for a select irp to come down to notify the dll that
|
|
// either the connection went away, or if there was any data waiting on a
|
|
// connection.
|
|
//
|
|
// Parameters: ppDiscArapConn - if a "disconnected" connection exists, it's returned
|
|
// in this pointer. If many exist, the first one lucks out.
|
|
// If none exists, null is returned here
|
|
// ppRecvArapConn - same as above except that the connection returned is
|
|
// the one where some data is waiting
|
|
//
|
|
// Return: none
|
|
//
|
|
//***$
|
|
VOID
|
|
ArapDelayedNotify(
|
|
OUT PARAPCONN *ppDiscArapConn,
|
|
OUT PARAPCONN *ppRecvArapConn
|
|
)
|
|
{
|
|
|
|
KIRQL OldIrql;
|
|
PARAPCONN pArapConn=NULL;
|
|
PLIST_ENTRY pList;
|
|
PARAPCONN pDiscArapConn=NULL;
|
|
PARAPCONN pRecvArapConn=NULL;
|
|
|
|
|
|
*ppDiscArapConn = NULL;
|
|
*ppRecvArapConn = NULL;
|
|
|
|
if (!RasPortDesc)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapDelayedNotify: RasPortDesc is NULL!\n"));
|
|
ASSERT(0);
|
|
|
|
return;
|
|
}
|
|
|
|
ACQUIRE_SPIN_LOCK(&RasPortDesc->pd_Lock, &OldIrql);
|
|
|
|
pList = RasPortDesc->pd_ArapConnHead.Flink;
|
|
|
|
while (pList != &RasPortDesc->pd_ArapConnHead)
|
|
{
|
|
pArapConn = CONTAINING_RECORD(pList, ARAPCONN, Linkage);
|
|
pList = pArapConn->Linkage.Flink;
|
|
|
|
ACQUIRE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
|
|
|
|
//
|
|
// if a connection has been disconnected and is waiting for a select
|
|
// irp to show up, find out who that is and let the caller know
|
|
//
|
|
if ((pArapConn->State == MNP_DISCONNECTED) &&
|
|
(pArapConn->Flags & DISCONNECT_NO_IRP))
|
|
{
|
|
pArapConn->Flags &= ~DISCONNECT_NO_IRP;
|
|
pDiscArapConn = pArapConn;
|
|
|
|
RELEASE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// if a connection has some data come in on it while select irp wasn't
|
|
// down yet, note down this connection
|
|
//
|
|
if ((pArapConn->State == MNP_UP) &&
|
|
(pArapConn->Flags & ARAP_CONNECTION_UP) &&
|
|
(!IsListEmpty(&pArapConn->ArapDataQ)))
|
|
{
|
|
pRecvArapConn = pArapConn;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&RasPortDesc->pd_Lock,OldIrql);
|
|
|
|
if (pDiscArapConn)
|
|
{
|
|
*ppDiscArapConn = pDiscArapConn;
|
|
}
|
|
else if (pRecvArapConn)
|
|
{
|
|
*ppRecvArapConn = pRecvArapConn;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: ArapSendPrepare
|
|
// This routine takes an incoming buffer descriptor, compresses
|
|
// each of the buffers in it and passes the compressed data on to
|
|
// another routine which splits (or stuffs) the compressed bytes
|
|
// into MNP-level packets.
|
|
//
|
|
// Parameters: pArapConn - the connection in question
|
|
// pOrgBuffDesc - the buffer descriptor containing data buffer(s)
|
|
// Priority - how important is the data (highest priority = 1)
|
|
// 1 - directed DDP dgrams (all except NBP)
|
|
// 2 - directed DDP dgrams (NBP)
|
|
// 3 - all DDP-level broadcast (NBP only)
|
|
//
|
|
// Return: ARAPERR_NO_ERROR if things go well, otherwise errorcode
|
|
//
|
|
//***$
|
|
|
|
DWORD
|
|
ArapSendPrepare(
|
|
IN PARAPCONN pArapConn,
|
|
IN PBUFFER_DESC pOrgBuffDesc,
|
|
IN DWORD Priority
|
|
)
|
|
{
|
|
|
|
KIRQL OldIrql;
|
|
DWORD StatusCode=ARAPERR_NO_ERROR;
|
|
SHORT EthLen, MnpLen;
|
|
PBYTE pCurrBuff;
|
|
DWORD CurrBuffLen;
|
|
DWORD UncompressedDataLen;
|
|
PBYTE pCompressedData;
|
|
PBYTE pCompressedDataBuffer;
|
|
DWORD CompressedDataLen;
|
|
DWORD CDataLen;
|
|
PBUFFER_DESC pBuffDesc;
|
|
DWORD CompBufDataSize;
|
|
|
|
|
|
|
|
DBG_ARAP_CHECK_PAGED_CODE();
|
|
|
|
// BUGBUG: this line put in for now: remove it and make sure priority queue stuff works
|
|
Priority = ARAP_SEND_PRIORITY_HIGH;
|
|
|
|
|
|
ARAPTRACE(("Entered ArapSendPrepare (%lx %lx)\n",pArapConn,pOrgBuffDesc));
|
|
|
|
//
|
|
// it's essential to hold this lock until the entire send is compressed and
|
|
// put on the queue (Otherwise, we risk mixing up different sends!)
|
|
//
|
|
ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
|
|
|
|
// are we disconnecting (or not up yet)? if so, don't accept this send
|
|
if (pArapConn->State != MNP_UP)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapSendPrepare: (%lx) state=%d, rejecting send\n",
|
|
pArapConn,pArapConn->State));
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
return( ARAPERR_DISCONNECT_IN_PROGRESS );
|
|
}
|
|
|
|
// do we have too many sends queued up? if so, just drop this send
|
|
if (pArapConn->SendsPending > ARAP_SENDQ_UPPER_LIMIT)
|
|
{
|
|
// make sure it's not gone negative..
|
|
ASSERT(pArapConn->SendsPending < 0x100000);
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
return( ARAPERR_OUT_OF_RESOURCES );
|
|
}
|
|
|
|
//
|
|
// allocate memory to store the compressed data
|
|
//
|
|
|
|
pCompressedDataBuffer = AtalkBPAllocBlock(BLKID_ARAP_SNDPKT);
|
|
|
|
if (pCompressedDataBuffer == NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapSendPrepare: alloc for compressing data failed (%lx)\n", pArapConn));
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
return( ARAPERR_OUT_OF_RESOURCES );
|
|
}
|
|
|
|
|
|
pBuffDesc = pOrgBuffDesc; // first buffer
|
|
CompressedDataLen = 0; // length of compressed data
|
|
CompBufDataSize = ARAP_SENDBUF_SIZE; // size of buffer in which to compress
|
|
pCompressedData = pCompressedDataBuffer; // ptr to buffer in which to compress
|
|
UncompressedDataLen = 0; // size of uncompressed data
|
|
|
|
#if DBG
|
|
//
|
|
// put in a guard signature to catch buffer overrun
|
|
//
|
|
*((DWORD *)&(pCompressedDataBuffer[ARAP_SENDBUF_SIZE-4])) = 0xdeadbeef;
|
|
#endif
|
|
|
|
|
|
//
|
|
// first, walk through the buffer descriptor chain and compress all the
|
|
// buffers.
|
|
//
|
|
while (pBuffDesc)
|
|
{
|
|
//
|
|
// is this a buffer?
|
|
//
|
|
if (pBuffDesc->bd_Flags & BD_CHAR_BUFFER)
|
|
{
|
|
pCurrBuff = pBuffDesc->bd_CharBuffer;
|
|
CurrBuffLen = pBuffDesc->bd_Length;
|
|
}
|
|
|
|
//
|
|
// nope, it's an mdl!
|
|
//
|
|
else
|
|
{
|
|
pCurrBuff = MmGetSystemAddressForMdlSafe(
|
|
pBuffDesc->bd_OpaqueBuffer,
|
|
NormalPagePriority);
|
|
|
|
if (pCurrBuff == NULL)
|
|
{
|
|
ASSERT(0);
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
AtalkBPFreeBlock(pCompressedDataBuffer);
|
|
return( ARAPERR_OUT_OF_RESOURCES );
|
|
}
|
|
|
|
CurrBuffLen = MmGetMdlByteCount(pBuffDesc->bd_OpaqueBuffer);
|
|
}
|
|
|
|
DBGDUMPBYTES("ArapSendPrepare (current buffer): ",pCurrBuff,CurrBuffLen,2);
|
|
|
|
UncompressedDataLen += CurrBuffLen;
|
|
|
|
ASSERT(UncompressedDataLen <= ARAP_LGPKT_SIZE);
|
|
|
|
// exclude the 2 srp length bytes
|
|
if (UncompressedDataLen > ARAP_MAXPKT_SIZE_OUTGOING+2)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapSendPrepare (%lx): send pkt exceeds limit\n",pArapConn));
|
|
|
|
ASSERT(0);
|
|
}
|
|
|
|
//
|
|
// compress the packet (if v42bis is on, that is)
|
|
//
|
|
if (pArapConn->Flags & MNP_V42BIS_NEGOTIATED)
|
|
{
|
|
StatusCode = v42bisCompress(pArapConn,
|
|
pCurrBuff,
|
|
CurrBuffLen,
|
|
pCompressedData,
|
|
CompBufDataSize,
|
|
&CDataLen);
|
|
|
|
}
|
|
|
|
//
|
|
// hmmm, no v42bis! just copy it as is and skip compression!
|
|
//
|
|
else
|
|
{
|
|
ASSERT(CompBufDataSize >= CurrBuffLen);
|
|
|
|
RtlCopyMemory(pCompressedData,
|
|
pCurrBuff,
|
|
CurrBuffLen);
|
|
|
|
CDataLen = CurrBuffLen;
|
|
|
|
StatusCode = ARAPERR_NO_ERROR;
|
|
}
|
|
|
|
|
|
#if DBG
|
|
// ... and, check our guard signature
|
|
ASSERT (*((DWORD *)&(pCompressedDataBuffer[ARAP_SENDBUF_SIZE-4])) == 0xdeadbeef);
|
|
#endif
|
|
|
|
if (StatusCode != ARAPERR_NO_ERROR)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("ArapSendPrepare (%lx):\
|
|
v42bisCompress returned %ld\n", pArapConn,StatusCode));
|
|
|
|
ASSERT(0);
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
|
|
AtalkBPFreeBlock(pCompressedDataBuffer);
|
|
return(StatusCode);
|
|
}
|
|
|
|
pCompressedData += CDataLen;
|
|
CompressedDataLen += CDataLen;
|
|
CompBufDataSize -= CDataLen;
|
|
|
|
pBuffDesc = pBuffDesc->bd_Next;
|
|
}
|
|
|
|
|
|
// we are about to send so many uncompressed bytes: update stats
|
|
pArapConn->StatInfo.BytesTransmittedUncompressed += UncompressedDataLen;
|
|
|
|
// this is how many bytes will go out on the wire: update stats
|
|
pArapConn->StatInfo.BytesTransmittedCompressed += CompressedDataLen;
|
|
|
|
//
|
|
// this is how many bytes will go out on the wire: update stats
|
|
// Note that we will be adding the start/stop etc. bytes to this count somewhere else
|
|
//
|
|
pArapConn->StatInfo.BytesSent += CompressedDataLen;
|
|
|
|
#if DBG
|
|
ArapStatistics.SendPreCompMax =
|
|
(UncompressedDataLen > ArapStatistics.SendPreCompMax)?
|
|
UncompressedDataLen : ArapStatistics.SendPreCompMax;
|
|
|
|
ArapStatistics.SendPostCompMax =
|
|
(CompressedDataLen > ArapStatistics.SendPostCompMax)?
|
|
CompressedDataLen : ArapStatistics.SendPostCompMax;
|
|
|
|
ArapStatistics.SendPreCompMin =
|
|
(UncompressedDataLen < ArapStatistics.SendPreCompMin)?
|
|
UncompressedDataLen : ArapStatistics.SendPreCompMin;
|
|
|
|
ArapStatistics.SendPostCompMin =
|
|
(CompressedDataLen < ArapStatistics.SendPostCompMin)?
|
|
CompressedDataLen : ArapStatistics.SendPostCompMin;
|
|
#endif
|
|
|
|
|
|
ARAP_DBG_TRACE(pArapConn,11205,pOrgBuffDesc,Priority,0,0);
|
|
|
|
// now go put the send on the queue (And yes: hold that lock)
|
|
StatusCode = ArapQueueSendBytes(pArapConn,
|
|
pCompressedDataBuffer,
|
|
CompressedDataLen,
|
|
Priority);
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
|
|
AtalkBPFreeBlock(pCompressedDataBuffer);
|
|
|
|
return(StatusCode);
|
|
}
|
|
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: ArapMnpSendComplete
|
|
// Free up the buffer used for the MNP send. If the send failed
|
|
// then kill the connection (remember, it's not just one send
|
|
// failing but a failure after all the retransmission jing-bang)
|
|
//
|
|
// Parameters: pMnpSendBuf - the send buff that contained the LR response
|
|
// StatusCode - how did it go?
|
|
//
|
|
// Return: none
|
|
//
|
|
//***$
|
|
|
|
VOID ArapMnpSendComplete(
|
|
IN PMNPSENDBUF pMnpSendBuf,
|
|
IN DWORD StatusCode
|
|
)
|
|
{
|
|
PARAPCONN pArapConn;
|
|
DWORD State;
|
|
KIRQL OldIrql;
|
|
|
|
|
|
DBG_ARAP_CHECK_PAGED_CODE();
|
|
|
|
pArapConn = pMnpSendBuf->pArapConn;
|
|
|
|
ARAPTRACE(("Entered ArapMnpSendComplete (%lx %lx %lx)\n",
|
|
pMnpSendBuf,StatusCode,pArapConn));
|
|
|
|
// the send buffer is getting freed up: update the counter
|
|
ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
|
|
|
|
State = pArapConn->State;
|
|
|
|
pArapConn->SendsPending -= pMnpSendBuf->DataSize;
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
|
|
if ((StatusCode != ARAPERR_NO_ERROR) && (State < MNP_LDISCONNECTING))
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapMnpSendComplete (%lx %lx): bad link? Tearing down connection\n",
|
|
StatusCode,pArapConn));
|
|
|
|
// link must have gone down: kill the connection!
|
|
ArapCleanup(pArapConn);
|
|
}
|
|
|
|
// mark that compl. routine has run
|
|
#if DBG
|
|
pMnpSendBuf->Signature -= 0x100;
|
|
#endif
|
|
|
|
// the send has been acked: take away the MNP refcount on the send
|
|
DerefMnpSendBuf(pMnpSendBuf, FALSE);
|
|
}
|
|
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: ArapIoctlSendComplete
|
|
// This routine is called right after the send is done in
|
|
// ArapIoctlSend, to let the dll know what happened to the send.
|
|
//
|
|
// Parameters: Status - did the send actually succeed
|
|
// pArapConn - the connection in quesion
|
|
//
|
|
// Return: none
|
|
//
|
|
//***$
|
|
|
|
VOID
|
|
ArapIoctlSendComplete(
|
|
DWORD StatusCode,
|
|
PARAPCONN pArapConn
|
|
)
|
|
{
|
|
|
|
PIRP pIrp;
|
|
KIRQL OldIrql;
|
|
PARAP_SEND_RECV_INFO pSndRcvInfo;
|
|
NTSTATUS ReturnStatus=STATUS_SUCCESS;
|
|
|
|
|
|
DBG_ARAP_CHECK_PAGED_CODE();
|
|
|
|
ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
|
|
|
|
pIrp = pArapConn->pIoctlIrp;
|
|
pArapConn->pIoctlIrp = NULL;
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
|
|
ARAPTRACE(("Entered ArapIoctlSendComplete (%lx %lx)\n",pArapConn,pIrp));
|
|
|
|
//
|
|
// if there is a user-level irp pending, complete it here
|
|
//
|
|
if (pIrp)
|
|
{
|
|
pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
pSndRcvInfo->StatusCode = StatusCode;
|
|
|
|
// complete the irp (irp always completes successfully!)
|
|
ARAP_COMPLETE_IRP(pIrp, sizeof(ARAP_SEND_RECV_INFO), STATUS_SUCCESS, &ReturnStatus);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: ArapDataToDll
|
|
// This routine tries to complete a receive posted on a connection.
|
|
// When data arrives, if the Arap connection is established then
|
|
// this routine tries to complete a receive via the "select" irp.
|
|
// If the Arap connection is not yet established, then a receive
|
|
// is completed via a "direct" irp.
|
|
//
|
|
// Parameters: pArapConn - connection element in question
|
|
//
|
|
// Return: Number of bytes transferred to the dll
|
|
//
|
|
//***$
|
|
|
|
DWORD
|
|
ArapDataToDll(
|
|
IN PARAPCONN pArapConn
|
|
)
|
|
{
|
|
|
|
KIRQL OldIrql;
|
|
PLIST_ENTRY pRcvList;
|
|
PARAPBUF pArapBuf;
|
|
PARAP_SEND_RECV_INFO pSndRcvInfo=NULL;
|
|
PIRP pIrp;
|
|
USHORT SrpModLen;
|
|
DWORD dwBytesToDll;
|
|
DWORD StatusCode;
|
|
NTSTATUS ReturnStatus=STATUS_SUCCESS;
|
|
|
|
|
|
DBG_ARAP_CHECK_PAGED_CODE();
|
|
|
|
ARAPTRACE(("Entered ArapDataToDll (%lx)\n",pArapConn));
|
|
|
|
ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
|
|
|
|
if (IsListEmpty(&pArapConn->ArapDataQ))
|
|
{
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
return( 0 );
|
|
}
|
|
|
|
pRcvList = pArapConn->ArapDataQ.Flink;
|
|
|
|
pArapBuf = CONTAINING_RECORD(pRcvList, ARAPBUF, Linkage);
|
|
|
|
//
|
|
// if the ARAP connection is established, we can hand the data only
|
|
// to a select irp (dll won't post direct rcv's anymore)
|
|
//
|
|
if ( pArapConn->Flags & ARAP_CONNECTION_UP )
|
|
{
|
|
ArapGetSelectIrp(&pIrp);
|
|
StatusCode = ARAPERR_DATA;
|
|
}
|
|
|
|
//
|
|
// if the ARAP connection is not established yet, we must guarantee that
|
|
// we hand the data only to a direct rcv irp for this connection
|
|
//
|
|
else
|
|
{
|
|
pIrp = pArapConn->pRecvIoctlIrp;
|
|
pArapConn->pRecvIoctlIrp = NULL;
|
|
StatusCode = ARAPERR_NO_ERROR;
|
|
}
|
|
|
|
// no irp? just have to wait then
|
|
if (!pIrp)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_INFO,
|
|
("ArapDataToDll: no select irp, data waiting %lx at %ld\n", pArapConn,AtalkGetCurrentTick()));
|
|
|
|
ARAP_DBG_TRACE(pArapConn,11505,0,0,0,0);
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
return( 0 );
|
|
}
|
|
|
|
//
|
|
// now that we have irp, fill in the info, after unlinking the recv buf
|
|
//
|
|
RemoveEntryList(&pArapBuf->Linkage);
|
|
|
|
ASSERT(pArapConn->RecvsPending >= pArapBuf->DataSize);
|
|
pArapConn->RecvsPending -= pArapBuf->DataSize;
|
|
|
|
ARAP_ADJUST_RECVCREDIT(pArapConn);
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
|
|
pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
ASSERT(pSndRcvInfo->DataLen >= pArapBuf->DataSize);
|
|
|
|
SrpModLen = pArapBuf->DataSize;
|
|
|
|
// ok, copy the data in
|
|
RtlCopyMemory( &pSndRcvInfo->Data[0],
|
|
pArapBuf->CurrentBuffer,
|
|
pArapBuf->DataSize );
|
|
|
|
|
|
// set the info (contexts need to be set each time in case of select)
|
|
pSndRcvInfo->AtalkContext = pArapConn;
|
|
pSndRcvInfo->pDllContext = pArapConn->pDllContext;
|
|
pSndRcvInfo->DataLen = SrpModLen;
|
|
pSndRcvInfo->StatusCode = StatusCode;
|
|
|
|
dwBytesToDll = SrpModLen + sizeof(ARAP_SEND_RECV_INFO);
|
|
|
|
DBGDUMPBYTES("Dll recv:", &pSndRcvInfo->Data[0],pSndRcvInfo->DataLen,1);
|
|
|
|
// ok, complete that irp now!
|
|
ARAP_COMPLETE_IRP(pIrp, dwBytesToDll, STATUS_SUCCESS, &ReturnStatus);
|
|
|
|
// done with that buffer: free it here
|
|
ARAP_FREE_RCVBUF(pArapBuf);
|
|
|
|
return(SrpModLen);
|
|
}
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: MnpSendAckIfReqd
|
|
// This routine sends an ack to the remote client after making
|
|
// sure that condition(s) do exist warranting sending of an Ack.
|
|
//
|
|
// Parameters: pArapConn - connection element in question
|
|
//
|
|
// Return: none
|
|
//
|
|
//***$
|
|
|
|
VOID
|
|
MnpSendAckIfReqd(
|
|
IN PARAPCONN pArapConn,
|
|
IN BOOLEAN fForceAck
|
|
)
|
|
{
|
|
KIRQL OldIrql;
|
|
BYTE SeqToAck;
|
|
BYTE RecvCredit;
|
|
PMNPSENDBUF pMnpSendBuf;
|
|
PBYTE pFrame, pFrameStart;
|
|
BOOLEAN fOptimized=TRUE;
|
|
USHORT FrameLen;
|
|
PNDIS_PACKET ndisPacket;
|
|
NDIS_STATUS ndisStatus;
|
|
DWORD StatusCode;
|
|
BOOLEAN fMustSend;
|
|
|
|
|
|
|
|
DBG_ARAP_CHECK_PAGED_CODE();
|
|
|
|
ARAPTRACE(("Entered MnpSendAckIfReqd (%lx)\n",pArapConn));
|
|
|
|
ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
|
|
|
|
//
|
|
// if we are not up yet (or are disconnecting), forget about this ack
|
|
//
|
|
if (pArapConn->State != MNP_UP)
|
|
{
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
return;
|
|
}
|
|
|
|
fMustSend = FALSE;
|
|
|
|
//
|
|
// first, find out if we need to send an ack at all
|
|
//
|
|
|
|
|
|
//
|
|
// if we are told to send, just send it: don't question the decision!
|
|
//
|
|
if (fForceAck)
|
|
{
|
|
fMustSend = TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// spec says if we have one or more unacked pkts and there is no user data
|
|
// to send, then send it (what's user data got to do with this??)
|
|
//
|
|
// BUGBUG: for now, don't check for IsListEmpty(&pArapConn->HighPriSendQ)
|
|
#if 0
|
|
else if ( (pArapConn->MnpState.UnAckedRecvs > 0) &&
|
|
(IsListEmpty(&pArapConn->HighPriSendQ)) )
|
|
{
|
|
fMustSend = TRUE;
|
|
}
|
|
#endif
|
|
else if (pArapConn->MnpState.UnAckedRecvs > 0)
|
|
{
|
|
fMustSend = TRUE;
|
|
}
|
|
|
|
//
|
|
// if we haven't acked for a while (i.e. have received more than the
|
|
// acceptable number of unacked packets) then send it
|
|
//
|
|
else if (pArapConn->MnpState.UnAckedRecvs >= pArapConn->MnpState.UnAckedLimit)
|
|
{
|
|
fMustSend = TRUE;
|
|
}
|
|
|
|
if (!fMustSend)
|
|
{
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
return;
|
|
}
|
|
|
|
|
|
StatusCode = ARAPERR_NO_ERROR;
|
|
|
|
// first, allocate a buff descriptor (before we change the state variables)
|
|
if ((pMnpSendBuf = AtalkBPAllocBlock(BLKID_MNP_SMSENDBUF)) != NULL)
|
|
{
|
|
StatusCode = ArapGetNdisPacket(pMnpSendBuf);
|
|
}
|
|
|
|
if ((pMnpSendBuf == NULL) || (StatusCode != ARAPERR_NO_ERROR))
|
|
{
|
|
if (pMnpSendBuf)
|
|
{
|
|
ArapNdisFreeBuf(pMnpSendBuf);
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("MnpSendAckIfReqd: AtalkBPAllocBlock failed on %lx\n", pArapConn))
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
return;
|
|
}
|
|
|
|
|
|
// BUGBUG: for now, always send full size
|
|
//RecvCredit = pArapConn->MnpState.RecvCredit;
|
|
RecvCredit = pArapConn->MnpState.WindowSize;
|
|
|
|
// tell the client which is the last packet we got successfully
|
|
SeqToAck = pArapConn->MnpState.LastSeqRcvd;
|
|
|
|
#if DBG
|
|
if ((SeqToAck == pArapConn->MnpState.LastAckSent) && (pArapConn->MnpState.HoleInSeq++ > 1))
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_INFO,
|
|
("MnpSendAckIfReqd: ack %x already sent earlier\n",SeqToAck));
|
|
}
|
|
#endif
|
|
|
|
pArapConn->MnpState.LastAckSent = pArapConn->MnpState.LastSeqRcvd;
|
|
|
|
// with this ack, we will be acking all the outstanding recv's
|
|
pArapConn->MnpState.UnAckedRecvs = 0;
|
|
|
|
// "stop" the 402 timer
|
|
pArapConn->LATimer = 0;
|
|
|
|
// reset the flow-control timer
|
|
pArapConn->FlowControlTimer = AtalkGetCurrentTick() +
|
|
pArapConn->T404Duration;
|
|
|
|
if (!(pArapConn->Flags & MNP_OPTIMIZED_DATA))
|
|
{
|
|
fOptimized = FALSE;
|
|
}
|
|
|
|
ARAP_DBG_TRACE(pArapConn,11605,0,SeqToAck,RecvCredit,0);
|
|
|
|
MNP_DBG_TRACE(pArapConn,SeqToAck,MNP_LA);
|
|
|
|
// put MNPSend refcount
|
|
pArapConn->RefCount++;
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
|
|
#if DBG
|
|
pMnpSendBuf->Signature = MNPSMSENDBUF_SIGNATURE;
|
|
InitializeListHead(&pMnpSendBuf->Linkage);
|
|
#endif
|
|
|
|
pMnpSendBuf->RetryCount = 0; // not relevant here
|
|
pMnpSendBuf->RefCount = 1; // remove when send completes
|
|
pMnpSendBuf->pArapConn = pArapConn;
|
|
pMnpSendBuf->ComplRoutine = NULL;
|
|
pMnpSendBuf->Flags = 1;
|
|
|
|
pFrame = pFrameStart = &pMnpSendBuf->Buffer[0];
|
|
|
|
AtalkNdisBuildARAPHdr(pFrame, pArapConn);
|
|
|
|
pFrame += WAN_LINKHDR_LEN;
|
|
|
|
//
|
|
// put the start flags
|
|
//
|
|
*pFrame++ = pArapConn->MnpState.SynByte;
|
|
*pFrame++ = pArapConn->MnpState.DleByte;
|
|
*pFrame++ = pArapConn->MnpState.StxByte;
|
|
|
|
//
|
|
// now, put the body of the Ack frame
|
|
//
|
|
if (fOptimized)
|
|
{
|
|
*pFrame++ = 3; // length indication
|
|
*pFrame++ = 5; // type indication
|
|
*pFrame++ = SeqToAck; // Receive seq number ( N(R) )
|
|
*pFrame++ = RecvCredit; // receive credit ( N(k) )
|
|
}
|
|
else
|
|
{
|
|
*pFrame++ = 7; // length indication
|
|
*pFrame++ = 5; // type indication
|
|
*pFrame++ = 1; // var type
|
|
*pFrame++ = 1; // var len
|
|
*pFrame++ = SeqToAck; // receive seq number ( N(R) )
|
|
*pFrame++ = 2; // var type
|
|
*pFrame++ = 1; // var len
|
|
*pFrame++ = RecvCredit; // receive credit ( N(k) )
|
|
}
|
|
|
|
//
|
|
// now finally, put the stop flags (no need for spinlock: this won't change!)
|
|
//
|
|
*pFrame++ = pArapConn->MnpState.DleByte;
|
|
*pFrame++ = pArapConn->MnpState.EtxByte;
|
|
|
|
FrameLen = (USHORT)(pFrame - pFrameStart);
|
|
|
|
AtalkSetSizeOfBuffDescData(&pMnpSendBuf->sb_BuffDesc, FrameLen);
|
|
|
|
NdisAdjustBufferLength(pMnpSendBuf->sb_BuffHdr.bh_NdisBuffer,FrameLen);
|
|
|
|
//
|
|
// send the packet over. We need to go directly, and not via ArapNdisSend
|
|
// because this packet needs to be delivered just once, regardless of
|
|
// whether send window is open
|
|
//
|
|
|
|
ndisPacket = pMnpSendBuf->sb_BuffHdr.bh_NdisPkt;
|
|
|
|
NdisSend(&ndisStatus, RasPortDesc->pd_NdisBindingHandle, ndisPacket);
|
|
|
|
// if there was a problem sending, call the completion routine here
|
|
if (ndisStatus != NDIS_STATUS_PENDING)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("MnpSendAckIfReqd: NdisSend failed %lx\n",ndisStatus));
|
|
|
|
ArapNdisSendComplete(ARAPERR_SEND_FAILED, (PBUFFER_DESC)pMnpSendBuf, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: MnpSendLNAck
|
|
// This routine sends an LN ack to the remote client, acknowleding
|
|
// receipt of an LN frame
|
|
//
|
|
// Parameters: pArapConn - connection element in question
|
|
//
|
|
// Return: none
|
|
//
|
|
//***$
|
|
|
|
VOID
|
|
MnpSendLNAck(
|
|
IN PARAPCONN pArapConn,
|
|
IN BYTE LnSeqToAck
|
|
)
|
|
{
|
|
KIRQL OldIrql;
|
|
PMNPSENDBUF pMnpSendBuf;
|
|
PBYTE pFrame, pFrameStart;
|
|
USHORT FrameLen;
|
|
PNDIS_PACKET ndisPacket;
|
|
NDIS_STATUS ndisStatus;
|
|
DWORD StatusCode;
|
|
|
|
|
|
|
|
DBG_ARAP_CHECK_PAGED_CODE();
|
|
|
|
ARAPTRACE(("Entered MnpSendLNAck (%lx), %d\n",pArapConn,LnSeqToAck));
|
|
|
|
StatusCode = ARAPERR_NO_ERROR;
|
|
|
|
// first, allocate a buff descriptor
|
|
if ((pMnpSendBuf = AtalkBPAllocBlock(BLKID_MNP_SMSENDBUF)) != NULL)
|
|
{
|
|
StatusCode = ArapGetNdisPacket(pMnpSendBuf);
|
|
}
|
|
|
|
|
|
if (pMnpSendBuf == NULL || (StatusCode != ARAPERR_NO_ERROR))
|
|
{
|
|
if (pMnpSendBuf)
|
|
{
|
|
ArapNdisFreeBuf(pMnpSendBuf);
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("MnpSendLNAck: AtalkBPAllocBlock failed on %lx\n", pArapConn))
|
|
}
|
|
return;
|
|
}
|
|
|
|
#if DBG
|
|
pMnpSendBuf->Signature = MNPSMSENDBUF_SIGNATURE;
|
|
InitializeListHead(&pMnpSendBuf->Linkage);
|
|
#endif
|
|
|
|
pMnpSendBuf->RetryCount = 0; // not relevant here
|
|
pMnpSendBuf->RefCount = 1; // remove when send completes
|
|
pMnpSendBuf->pArapConn = pArapConn;
|
|
pMnpSendBuf->ComplRoutine = NULL;
|
|
pMnpSendBuf->Flags = 1;
|
|
|
|
pFrame = pFrameStart = &pMnpSendBuf->Buffer[0];
|
|
|
|
ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
|
|
|
|
// if we are disconnecting, forget about sending this ack
|
|
if (pArapConn->State >= MNP_LDISCONNECTING)
|
|
{
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
ArapNdisFreeBuf(pMnpSendBuf);
|
|
return;
|
|
}
|
|
|
|
// put MNPSend refcount
|
|
pArapConn->RefCount++;
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
|
|
AtalkNdisBuildARAPHdr(pFrame, pArapConn);
|
|
|
|
pFrame += WAN_LINKHDR_LEN;
|
|
|
|
//
|
|
// put the start flags
|
|
//
|
|
*pFrame++ = pArapConn->MnpState.SynByte;
|
|
*pFrame++ = pArapConn->MnpState.DleByte;
|
|
*pFrame++ = pArapConn->MnpState.StxByte;
|
|
|
|
//
|
|
// now, put the body of the Ack frame
|
|
//
|
|
*pFrame++ = 4; // length indication
|
|
*pFrame++ = 7; // type indication
|
|
*pFrame++ = 1; // var type
|
|
*pFrame++ = 1; // var len
|
|
*pFrame++ = LnSeqToAck; //
|
|
|
|
//
|
|
// now finally, put the stop flags
|
|
//
|
|
*pFrame++ = pArapConn->MnpState.DleByte;
|
|
*pFrame++ = pArapConn->MnpState.EtxByte;
|
|
|
|
FrameLen = (USHORT)(pFrame - pFrameStart);
|
|
|
|
AtalkSetSizeOfBuffDescData(&pMnpSendBuf->sb_BuffDesc, FrameLen);
|
|
|
|
NdisAdjustBufferLength(pMnpSendBuf->sb_BuffHdr.bh_NdisBuffer,FrameLen);
|
|
|
|
//
|
|
// send the packet over. We need to go directly, and not via ArapNdisSend
|
|
// because this packet needs to be delivered just once, regardless of
|
|
// whether send window is open
|
|
//
|
|
|
|
ndisPacket = pMnpSendBuf->sb_BuffHdr.bh_NdisPkt;
|
|
|
|
NdisSend(&ndisStatus, RasPortDesc->pd_NdisBindingHandle, ndisPacket);
|
|
|
|
// if there was a problem sending, call the completion routine here
|
|
if (ndisStatus != NDIS_STATUS_PENDING)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("MnpSendLNAck: NdisSend failed %lx\n",ndisStatus));
|
|
|
|
ArapNdisSendComplete(ARAPERR_SEND_FAILED, (PBUFFER_DESC)pMnpSendBuf, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: ArapSendLDPacket
|
|
// This routine sends a Disconnect (LD) packet to the client
|
|
//
|
|
// Parameters: pArapConn - the connection
|
|
//
|
|
// Return: result of the operation
|
|
//
|
|
//***$
|
|
|
|
DWORD
|
|
ArapSendLDPacket(
|
|
IN PARAPCONN pArapConn,
|
|
IN BYTE UserCode
|
|
)
|
|
{
|
|
PBYTE pFrame, pFrameStart;
|
|
USHORT FrameLen;
|
|
PNDIS_PACKET ndisPacket;
|
|
NDIS_STATUS ndisStatus;
|
|
PMNPSENDBUF pMnpSendBuf;
|
|
KIRQL OldIrql;
|
|
DWORD StatusCode;
|
|
|
|
|
|
DBG_ARAP_CHECK_PAGED_CODE();
|
|
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapSendLDPacket: sending DISCONNECT on %lx\n",pArapConn));
|
|
|
|
StatusCode = ARAPERR_NO_ERROR;
|
|
|
|
//
|
|
// allocate buf to send out the disconnection request
|
|
//
|
|
if ((pMnpSendBuf = AtalkBPAllocBlock(BLKID_MNP_SMSENDBUF)) != NULL)
|
|
{
|
|
StatusCode = ArapGetNdisPacket(pMnpSendBuf);
|
|
}
|
|
|
|
if ((pMnpSendBuf == NULL) || (StatusCode != ARAPERR_NO_ERROR))
|
|
{
|
|
if (pMnpSendBuf)
|
|
{
|
|
ArapNdisFreeBuf(pMnpSendBuf);
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapSendLDPacket: AtalkBPAllocBlock failed on %lx\n", pArapConn));
|
|
}
|
|
|
|
return(ARAPERR_OUT_OF_RESOURCES);
|
|
}
|
|
|
|
#if DBG
|
|
pMnpSendBuf->Signature = MNPSMSENDBUF_SIGNATURE;
|
|
InitializeListHead(&pMnpSendBuf->Linkage);
|
|
#endif
|
|
pMnpSendBuf->RetryCount = 0; // not relevant here
|
|
pMnpSendBuf->RefCount = 1; // remove when send completes
|
|
pMnpSendBuf->pArapConn = pArapConn;
|
|
pMnpSendBuf->ComplRoutine = NULL;
|
|
pMnpSendBuf->Flags = 1;
|
|
|
|
ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
|
|
|
|
//
|
|
// if we are already disconnecting (say remote disconnected), just say ok
|
|
//
|
|
if (pArapConn->State >= MNP_LDISCONNECTING)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("ArapSendLDPacket: silently \
|
|
discarding disconnect (already in progress) %lx\n", pArapConn));
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
ArapNdisFreeBuf(pMnpSendBuf);
|
|
return(ARAPERR_DISCONNECT_IN_PROGRESS);
|
|
}
|
|
|
|
// Disconnect refcount: protect pArapConn until disconnect is complete
|
|
pArapConn->RefCount++;
|
|
|
|
// put MNPSend refcount
|
|
pArapConn->RefCount++;
|
|
|
|
pArapConn->State = MNP_LDISCONNECTING;
|
|
|
|
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
|
|
|
pFrame = pFrameStart = &pMnpSendBuf->Buffer[0];
|
|
|
|
AtalkNdisBuildARAPHdr(pFrame, pArapConn);
|
|
|
|
pFrame += WAN_LINKHDR_LEN;
|
|
|
|
//
|
|
// put the start flags
|
|
//
|
|
*pFrame++ = pArapConn->MnpState.SynByte;
|
|
*pFrame++ = pArapConn->MnpState.DleByte;
|
|
*pFrame++ = pArapConn->MnpState.StxByte;
|
|
|
|
//
|
|
// now, put the body of the LD frame
|
|
//
|
|
*pFrame++ = 7; // length indication
|
|
*pFrame++ = 2; // type indication for LD
|
|
*pFrame++ = 1; // var type
|
|
*pFrame++ = 1; // var len
|
|
*pFrame++ = 0xFF; // User-initiated disconnect
|
|
|
|
*pFrame++ = 2; // var type
|
|
*pFrame++ = 1; // var len
|
|
*pFrame++ = UserCode;
|
|
|
|
//
|
|
// now finally, put the stop flags
|
|
//
|
|
*pFrame++ = pArapConn->MnpState.DleByte;
|
|
*pFrame++ = pArapConn->MnpState.EtxByte;
|
|
|
|
FrameLen = (USHORT)(pFrame - pFrameStart);
|
|
|
|
AtalkSetSizeOfBuffDescData(&pMnpSendBuf->sb_BuffDesc, FrameLen);
|
|
|
|
NdisAdjustBufferLength(pMnpSendBuf->sb_BuffHdr.bh_NdisBuffer,FrameLen);
|
|
|
|
ARAP_SET_NDIS_CONTEXT(pMnpSendBuf, NULL);
|
|
|
|
ndisPacket = pMnpSendBuf->sb_BuffHdr.bh_NdisPkt;
|
|
|
|
// send the packet over (and don't bother checking return code!)
|
|
NdisSend(&ndisStatus, RasPortDesc->pd_NdisBindingHandle, ndisPacket);
|
|
|
|
// if there was a problem sending, call the completion routine here
|
|
if (ndisStatus != NDIS_STATUS_PENDING)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapSendLDPacket: NdisSend failed %lx\n",ndisStatus));
|
|
|
|
ArapNdisSendComplete(ARAPERR_SEND_FAILED, (PBUFFER_DESC)pMnpSendBuf, NULL);
|
|
}
|
|
|
|
// remove the disconnect refcount
|
|
DerefArapConn(pArapConn);
|
|
|
|
return(ARAPERR_NO_ERROR);
|
|
}
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: ArapRetryTimer
|
|
// This is the general purpose timer routine for ARAP.
|
|
// It checks
|
|
// if the ack timer (LATimer) has expired (if yes, send ack)
|
|
// if the flowcontrol timer has expired (if yes, send ack)
|
|
// if the inactivity timer has expired (if yes, send ack)
|
|
// if the retransmit timer has expired (if yes, retransmit)
|
|
//
|
|
// Parameters: pTimer - the context for the timer that just fired
|
|
// TimerShuttingDown - this is TRUE if timer is shutting down
|
|
//
|
|
// Return: none
|
|
//
|
|
//***$
|
|
|
|
LONG FASTCALL
|
|
ArapRetryTimer(
|
|
IN PTIMERLIST pTimer,
|
|
IN BOOLEAN TimerShuttingDown
|
|
)
|
|
{
|
|
|
|
PARAPCONN pArapConn;
|
|
PLIST_ENTRY pList;
|
|
PMNPSENDBUF pMnpSendBuf;
|
|
BOOLEAN fRetransmit=FALSE;
|
|
BOOLEAN fMustSendAck = FALSE;
|
|
BOOLEAN fKill=FALSE;
|
|
BOOLEAN fMustFlowControl=FALSE;
|
|
BOOLEAN fInactiveClient=FALSE;
|
|
LONG CurrentTime;
|
|
PIRP pIrp=NULL;
|
|
NTSTATUS ReturnStatus=STATUS_SUCCESS;
|
|
|
|
|
|
DBG_ARAP_CHECK_PAGED_CODE();
|
|
|
|
pArapConn = CONTAINING_RECORD(pTimer, ARAPCONN, RetryTimer);
|
|
|
|
ARAPTRACE(("Entered ArapRetryTimer (%lx)\n",pArapConn));
|
|
|
|
ACQUIRE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
|
|
|
|
//
|
|
// if the global timer is shutting down, or if the connection isn't in the
|
|
// right state (e.g. it is disconnecting), then don't requeue the timer
|
|
//
|
|
if ( TimerShuttingDown ||
|
|
(pArapConn->State <= MNP_IDLE) || (pArapConn->State > MNP_UP) )
|
|
{
|
|
pArapConn->Flags &= ~RETRANSMIT_TIMER_ON;
|
|
|
|
RELEASE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
|
|
|
|
if (TimerShuttingDown)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapRetryTimer: timer shut down, killing conn (%lx)\n",pArapConn));
|
|
|
|
ArapCleanup(pArapConn);
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapRetryTimer: (%lx) invalid state (%d), not requeing timer\n",
|
|
pArapConn,pArapConn->State));
|
|
}
|
|
|
|
// remove the timer refcount
|
|
DerefArapConn(pArapConn);
|
|
|
|
return ATALK_TIMER_NO_REQUEUE;
|
|
}
|
|
|
|
CurrentTime = AtalkGetCurrentTick();
|
|
|
|
//
|
|
// has the 402 timer expired? if yes, we must send an ack
|
|
// (a value of 0 signifies that the 402 timer is not "running")
|
|
//
|
|
if ( (pArapConn->LATimer != 0) && (CurrentTime >= pArapConn->LATimer) )
|
|
{
|
|
//
|
|
// make sure there is a receive that needs to be acked (if sent the ack
|
|
// just before this timer fired, don't send the ack again)
|
|
//
|
|
if (pArapConn->MnpState.UnAckedRecvs)
|
|
{
|
|
fMustSendAck = TRUE;
|
|
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapRetryTimer: 402 timer fired, forcing ack out (%d, now %d)\n",
|
|
pArapConn->LATimer,CurrentTime));
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapRetryTimer: saved on on ack (UnAckedRecvs = 0)\n",pArapConn));
|
|
}
|
|
}
|
|
|
|
//
|
|
// has the flow control timer "expired"? If so, we must send an ack and
|
|
// reset the timer
|
|
// (a value of 0 signifies that the flow control timer is not "running")
|
|
//
|
|
else if ( (pArapConn->FlowControlTimer != 0) &&
|
|
(CurrentTime >= pArapConn->FlowControlTimer) )
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_INFO,
|
|
("ArapRetryTimer: flow-control timer, forcing ack (%d, now %d)\n",
|
|
pArapConn->FlowControlTimer,CurrentTime));
|
|
|
|
fMustFlowControl = TRUE;
|
|
|
|
pArapConn->FlowControlTimer = CurrentTime + pArapConn->T404Duration;
|
|
}
|
|
|
|
//
|
|
// if the client been inactive for a long time, we must tell dll
|
|
//
|
|
else if (CurrentTime >= pArapConn->InactivityTimer)
|
|
{
|
|
// first make sure we can get the select irp
|
|
ArapGetSelectIrp(&pIrp);
|
|
|
|
// if we managed to get a select irp, reset the timer so we don't keep
|
|
// informing the dll after every tick after this point!
|
|
//
|
|
if (pIrp)
|
|
{
|
|
pArapConn->InactivityTimer = pArapConn->T403Duration + CurrentTime;
|
|
|
|
fInactiveClient = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Has the retransmit timer expired? If so, we need to retransmit
|
|
//
|
|
else
|
|
{
|
|
//
|
|
// look at the first entry of the retransmit queue. If it's time is up, do
|
|
// the retransmit thing. Otherwise, we are done. (All others in the queue
|
|
// will be retransmitted after this first one is acked, so ignore for now)
|
|
//
|
|
pList = pArapConn->RetransmitQ.Flink;
|
|
|
|
// no entries on the retransmit queue? we're done!
|
|
if (pList == &pArapConn->RetransmitQ)
|
|
{
|
|
RELEASE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
|
|
return ATALK_TIMER_REQUEUE;
|
|
}
|
|
|
|
pMnpSendBuf = CONTAINING_RECORD(pList, MNPSENDBUF, Linkage);
|
|
|
|
// is it time to retransmit yet?
|
|
if (CurrentTime >= pMnpSendBuf->RetryTime)
|
|
{
|
|
if (pMnpSendBuf->RetryCount >= ARAP_MAX_RETRANSMITS)
|
|
{
|
|
fKill = TRUE;
|
|
RemoveEntryList(&pMnpSendBuf->Linkage);
|
|
|
|
ASSERT(pArapConn->MnpState.UnAckedSends >= 1);
|
|
|
|
// not really important, since we're about to disconnect!
|
|
pArapConn->MnpState.UnAckedSends--;
|
|
|
|
ASSERT(pArapConn->SendsPending >= pMnpSendBuf->DataSize);
|
|
|
|
InitializeListHead(&pMnpSendBuf->Linkage);
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_INFO,
|
|
("ArapRetryTimer: timer fired, retransmitting....%x (%ld now %ld)\n",
|
|
pMnpSendBuf->SeqNum,pMnpSendBuf->RetryTime,CurrentTime));
|
|
|
|
if (pMnpSendBuf->RetryCount > 8)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapRetryTimer: buf %lx of %lx retransmitted %d times!\n",
|
|
pMnpSendBuf,pArapConn,pMnpSendBuf->RetryCount));
|
|
}
|
|
|
|
pArapConn->MnpState.RetransmitMode = TRUE;
|
|
pArapConn->MnpState.MustRetransmit = TRUE;
|
|
|
|
fRetransmit = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
|
|
|
|
// force an ack out (that's what TRUE does)
|
|
if (fMustSendAck || fMustFlowControl)
|
|
{
|
|
MnpSendAckIfReqd(pArapConn, TRUE);
|
|
}
|
|
|
|
// if we must retransmit, go for it.
|
|
//
|
|
else if (fRetransmit)
|
|
{
|
|
ArapNdisSend(pArapConn, &pArapConn->RetransmitQ);
|
|
}
|
|
|
|
//
|
|
// if we retransmitted too many times, let the completion routine know.
|
|
// (it will probably kill the connection)
|
|
//
|
|
else if (fKill)
|
|
{
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapRetryTimer: too many retransmits (%lx), disconnecting %lx\n",
|
|
pMnpSendBuf,pArapConn));
|
|
|
|
(pMnpSendBuf->ComplRoutine)(pMnpSendBuf, ARAPERR_SEND_FAILED);
|
|
}
|
|
|
|
//
|
|
// if the connection has been inactive for longer than the limit (given to
|
|
// us by the dll), then tell dll about it
|
|
//
|
|
else if (fInactiveClient)
|
|
{
|
|
PARAP_SEND_RECV_INFO pSndRcvInfo;
|
|
|
|
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
|
("ArapRetryTimer: (%lx) inactive, telling dll (%lx)\n",pArapConn, pIrp));
|
|
|
|
ASSERT(pIrp != NULL);
|
|
|
|
pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
pSndRcvInfo->pDllContext = pArapConn->pDllContext;
|
|
pSndRcvInfo->AtalkContext = pArapConn;
|
|
pSndRcvInfo->StatusCode = ARAPERR_CONN_INACTIVE;
|
|
|
|
ARAP_COMPLETE_IRP(pIrp, sizeof(ARAP_SEND_RECV_INFO), STATUS_SUCCESS, &ReturnStatus);
|
|
return ReturnStatus;
|
|
}
|
|
|
|
return ATALK_TIMER_REQUEUE;
|
|
}
|
|
|
|
|