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.
2269 lines
64 KiB
2269 lines
64 KiB
/*++
|
|
|
|
Copyright (c) 1990-1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Protocol.c
|
|
|
|
Abstract:
|
|
|
|
This file contains the procedures that makeup most of the NDIS 4.0/5.0
|
|
Protocol interface. This interface is what NdisWan exposes to the
|
|
WAN Miniports below. NdisWan is not really a protocol and does not
|
|
do TDI, but is a shim that sits between the protocols and the
|
|
WAN Miniport drivers.
|
|
|
|
|
|
Author:
|
|
|
|
Tony Bell (TonyBe) June 06, 1995
|
|
|
|
Environment:
|
|
|
|
Kernel Mode
|
|
|
|
Revision History:
|
|
|
|
TonyBe 06/06/95 Created
|
|
|
|
--*/
|
|
|
|
#include "wan.h"
|
|
|
|
#define __FILE_SIG__ PROTOCOL_FILESIG
|
|
|
|
#ifdef DBG_SENDARRAY
|
|
extern UCHAR SendArray[];
|
|
extern ULONG __si;
|
|
#endif
|
|
|
|
EXPORT
|
|
VOID
|
|
NdisTapiRegisterProvider(
|
|
IN NDIS_HANDLE,
|
|
IN PNDISTAPI_CHARACTERISTICS
|
|
);
|
|
|
|
EXPORT
|
|
VOID
|
|
NdisTapiDeregisterProvider(
|
|
IN NDIS_HANDLE
|
|
);
|
|
|
|
EXPORT
|
|
VOID
|
|
NdisTapiIndicateStatus(
|
|
IN NDIS_HANDLE BindingContext,
|
|
IN PVOID StatusBuffer,
|
|
IN UINT StatusBufferLength
|
|
);
|
|
|
|
//
|
|
// Local functions...
|
|
//
|
|
|
|
VOID
|
|
CompleteSendDesc(
|
|
PSEND_DESC SendDesc,
|
|
NDIS_STATUS Status
|
|
);
|
|
|
|
VOID
|
|
CloseWanAdapterWorker(
|
|
PNDIS_WORK_ITEM WorkItem,
|
|
POPENCB pOpenCB
|
|
);
|
|
|
|
#if 0
|
|
ULONG
|
|
CalcPPPHeaderLength(
|
|
ULONG FramingBits,
|
|
ULONG Flags
|
|
);
|
|
|
|
#endif
|
|
|
|
//
|
|
// Common functions used by both 4.0 and 5.0 miniports
|
|
//
|
|
|
|
NDIS_STATUS
|
|
ProtoOpenWanAdapter(
|
|
IN POPENCB pOpenCB
|
|
)
|
|
/*++
|
|
|
|
Routine Name:
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Values:
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status, OpenErrorStatus;
|
|
ULONG SelectedMediumIndex;
|
|
NDIS_MEDIUM MediumArray[] = {NdisMediumWan, NdisMediumAtm, NdisMediumCoWan};
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoOpenAdapter: Enter - AdapterName %ls", pOpenCB->MiniportName.Buffer));
|
|
|
|
//
|
|
// This is the only initialization of this event
|
|
//
|
|
NdisWanInitializeNotificationEvent(&pOpenCB->NotificationEvent);
|
|
|
|
NdisOpenAdapter(&Status,
|
|
&OpenErrorStatus,
|
|
&(pOpenCB->BindingHandle),
|
|
&SelectedMediumIndex,
|
|
MediumArray,
|
|
sizeof(MediumArray) / sizeof(NDIS_MEDIUM),
|
|
NdisWanCB.ProtocolHandle,
|
|
(NDIS_HANDLE)pOpenCB,
|
|
&(pOpenCB->MiniportName),
|
|
0,
|
|
NULL);
|
|
|
|
if (Status == NDIS_STATUS_PENDING) {
|
|
|
|
NdisWanWaitForNotificationEvent(&pOpenCB->NotificationEvent);
|
|
|
|
Status = pOpenCB->NotificationStatus;
|
|
|
|
NdisWanClearNotificationEvent(&pOpenCB->NotificationEvent);
|
|
}
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS) {
|
|
pOpenCB->MediumType = MediumArray[SelectedMediumIndex];
|
|
}
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoOpenAdapter: Exit"));
|
|
|
|
return (Status);
|
|
}
|
|
|
|
//
|
|
// Enter with the opencb->lock held, exit with the lock released!
|
|
//
|
|
NDIS_STATUS
|
|
ProtoCloseWanAdapter(
|
|
IN POPENCB pOpenCB
|
|
)
|
|
{
|
|
NDIS_STATUS Status;
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoCloseWanAdapter: Enter %p", pOpenCB));
|
|
|
|
pOpenCB->Flags |= OPEN_CLOSING;
|
|
|
|
NdisReleaseSpinLock(&pOpenCB->Lock);
|
|
|
|
//
|
|
// NdisCloseAdapter must be called at IRQL PASSIVE_LEVEL!
|
|
//
|
|
if (KeGetCurrentIrql() > PASSIVE_LEVEL) {
|
|
|
|
NdisAcquireSpinLock(&pOpenCB->Lock);
|
|
|
|
ASSERT(!(pOpenCB->Flags & CLOSE_SCHEDULED));
|
|
|
|
NdisInitializeWorkItem(&pOpenCB->WorkItem,
|
|
CloseWanAdapterWorker,
|
|
pOpenCB);
|
|
|
|
NdisScheduleWorkItem(&pOpenCB->WorkItem);
|
|
|
|
pOpenCB->Flags |= CLOSE_SCHEDULED;
|
|
|
|
NdisReleaseSpinLock(&pOpenCB->Lock);
|
|
|
|
return (NDIS_STATUS_PENDING);
|
|
}
|
|
|
|
|
|
NdisCloseAdapter(&Status,
|
|
pOpenCB->BindingHandle);
|
|
|
|
if (Status != NDIS_STATUS_PENDING) {
|
|
ProtoCloseAdapterComplete(pOpenCB, Status);
|
|
}
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoCloseWanAdapter: Exit"));
|
|
|
|
return(Status);
|
|
}
|
|
|
|
VOID
|
|
CloseWanAdapterWorker(
|
|
PNDIS_WORK_ITEM WorkItem,
|
|
POPENCB pOpenCB
|
|
)
|
|
{
|
|
NDIS_STATUS Status;
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("CloseWanAdapterWorker: Enter %p", pOpenCB));
|
|
|
|
NdisCloseAdapter(&Status,
|
|
pOpenCB->BindingHandle);
|
|
|
|
if (Status != NDIS_STATUS_PENDING) {
|
|
ProtoCloseAdapterComplete(pOpenCB, Status);
|
|
}
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("CloseWanAdapterWorker: Exit"));
|
|
}
|
|
|
|
VOID
|
|
ProtoOpenAdapterComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_STATUS OpenErrorStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Name:
|
|
|
|
ProtoOpenAdapterComplete
|
|
|
|
Routine Description:
|
|
|
|
This function is called upon completion of an open of a miniport.
|
|
The status of the openadapter call is stored and the notification
|
|
event is signalled.
|
|
|
|
Arguments:
|
|
|
|
Return Values:
|
|
|
|
--*/
|
|
{
|
|
POPENCB pOpenCB = (POPENCB)ProtocolBindingContext;
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoOpenAdapterComplete: Enter - OpenCB 0x%p", pOpenCB));
|
|
|
|
pOpenCB->NotificationStatus = Status;
|
|
|
|
NdisWanSetNotificationEvent(&pOpenCB->NotificationEvent);
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoOpenAdapterComplete: Exit"));
|
|
}
|
|
|
|
VOID
|
|
ProtoCloseAdapterComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_STATUS Status
|
|
)
|
|
/*++
|
|
|
|
Routine Name:
|
|
|
|
ProtoCloseAdapterComplete
|
|
|
|
Routine Description:
|
|
|
|
This function is called upon completion of a close of a miniport.
|
|
The status of the closeadapter call is stored and the notification
|
|
event is signalled.
|
|
|
|
Arguments:
|
|
|
|
Return Values:
|
|
|
|
--*/
|
|
{
|
|
POPENCB pOpenCB = (POPENCB)ProtocolBindingContext;
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoCloseAdapterComplete: Enter - OpenCB %p", pOpenCB));
|
|
|
|
if (pOpenCB->UnbindContext != NULL) {
|
|
NdisCompleteUnbindAdapter(pOpenCB->UnbindContext, Status);
|
|
}
|
|
|
|
if (pOpenCB->Flags & OPEN_IN_BIND) {
|
|
//
|
|
// We are attempting to close the adapter from
|
|
// within our bind handler. Per AliD we must wait
|
|
// for the close to finish before we can return
|
|
// from the bind handler thus we have to special case
|
|
// this code and not free the OpenCB here.
|
|
//
|
|
NdisWanSetNotificationEvent(&pOpenCB->NotificationEvent);
|
|
} else {
|
|
NdisWanFreeOpenCB(pOpenCB);
|
|
}
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoCloseAdapterComplete: Exit"));
|
|
}
|
|
|
|
VOID
|
|
ProtoResetComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_STATUS Status
|
|
)
|
|
{
|
|
POPENCB pOpenCB = (POPENCB)ProtocolBindingContext;
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoResetComplete: Enter - OpenCB %p", pOpenCB));
|
|
|
|
pOpenCB->NotificationStatus = Status;
|
|
|
|
NdisWanSetNotificationEvent(&pOpenCB->NotificationEvent);
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoResetComplete: Exit"));
|
|
}
|
|
|
|
VOID
|
|
ProtoReceiveComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext
|
|
)
|
|
{
|
|
POPENCB pOpenCB = (POPENCB)ProtocolBindingContext;
|
|
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ProtoIndicateStatus: Enter - OpenCB %8.x8\n", pOpenCB));
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ProtoIndicateStatus: Exit"));
|
|
}
|
|
|
|
VOID
|
|
ProtoIndicateStatus(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_STATUS GeneralStatus,
|
|
IN PVOID StatusBuffer,
|
|
IN UINT StatusBufferSize
|
|
)
|
|
{
|
|
POPENCB pOpenCB = (POPENCB)ProtocolBindingContext;
|
|
|
|
switch (GeneralStatus) {
|
|
case NDIS_STATUS_WAN_LINE_UP:
|
|
NdisWanLineUpIndication(pOpenCB,
|
|
StatusBuffer,
|
|
StatusBufferSize);
|
|
break;
|
|
|
|
case NDIS_STATUS_WAN_LINE_DOWN:
|
|
NdisWanLineDownIndication(pOpenCB,
|
|
StatusBuffer,
|
|
StatusBufferSize);
|
|
break;
|
|
|
|
case NDIS_STATUS_WAN_FRAGMENT:
|
|
NdisWanFragmentIndication(pOpenCB,
|
|
StatusBuffer,
|
|
StatusBufferSize);
|
|
break;
|
|
|
|
case NDIS_STATUS_TAPI_INDICATION:
|
|
NdisWanTapiIndication(pOpenCB,
|
|
StatusBuffer,
|
|
StatusBufferSize);
|
|
|
|
break;
|
|
|
|
default:
|
|
NdisWanDbgOut(DBG_INFO, DBG_PROTOCOL, ("Unknown Status Indication: 0x%x", GeneralStatus));
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
ProtoIndicateStatusComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext
|
|
)
|
|
{
|
|
POPENCB pOpenCB = (POPENCB)ProtocolBindingContext;
|
|
}
|
|
|
|
VOID
|
|
ProtoWanSendComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN PNDIS_WAN_PACKET WanPacket,
|
|
IN NDIS_STATUS Status
|
|
)
|
|
{
|
|
PSEND_DESC SendDesc;
|
|
PLINKCB LinkCB, RefLinkCB;
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("ProtoWanSendComplete: Enter - WanPacket %p", WanPacket));
|
|
|
|
//
|
|
// Get info from the WanPacket
|
|
//
|
|
SendDesc = (PSEND_DESC)WanPacket->ProtocolReserved1;
|
|
|
|
LinkCB = SendDesc->LinkCB;
|
|
|
|
if (!IsLinkValid(LinkCB->hLinkHandle, FALSE, &RefLinkCB)) {
|
|
|
|
NdisWanDbgOut(DBG_FAILURE, DBG_CL,
|
|
("NDISWAN: SendComplete after link has gone down NdisContext %p\n",
|
|
LinkCB));
|
|
|
|
return;
|
|
}
|
|
|
|
REMOVE_DBG_SEND(PacketTypeWan, LinkCB->OpenCB, WanPacket);
|
|
|
|
ASSERT(RefLinkCB == LinkCB);
|
|
|
|
NdisAcquireSpinLock(&LinkCB->Lock);
|
|
|
|
CompleteSendDesc(SendDesc, Status);
|
|
|
|
//
|
|
// Deref for the ref applied in IsLinkValid
|
|
//
|
|
DEREF_LINKCB(LinkCB);
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("ProtoWanSendComplete: Exit"));
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ProtoWanReceiveIndication(
|
|
IN NDIS_HANDLE NdisLinkHandle,
|
|
IN PUCHAR Packet,
|
|
IN ULONG PacketSize
|
|
)
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
PLINKCB LinkCB = NULL;
|
|
PBUNDLECB BundleCB = NULL;
|
|
PUCHAR DataBuffer;
|
|
ULONG DataBufferSize;
|
|
ULONG BytesCopied;
|
|
PNDIS_PACKET NdisPacket;
|
|
PNDIS_BUFFER NdisBuffer;
|
|
PRECV_DESC RecvDesc;
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ProtoWanReceiveIndication: Enter - Context %x", NdisLinkHandle));
|
|
|
|
do {
|
|
|
|
if (!AreLinkAndBundleValid(NdisLinkHandle,
|
|
TRUE,
|
|
&LinkCB,
|
|
&BundleCB)) {
|
|
#if DBG
|
|
DbgPrint("NDISWAN: Recv after link has gone down LinkContext %x\n",
|
|
NdisLinkHandle);
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
|
|
AcquireBundleLock(BundleCB);
|
|
|
|
//
|
|
// Make sure we don't try to process a receive indication
|
|
// that is larger then our max data buffer size
|
|
// winse 26544
|
|
//
|
|
|
|
if (PacketSize > glMRU) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Build a receive descriptor for this receive. We have
|
|
// to allocate with a large size because this packet might
|
|
// be compressed.
|
|
//
|
|
RecvDesc =
|
|
NdisWanAllocateRecvDesc(glLargeDataBufferSize);
|
|
|
|
if (RecvDesc == NULL) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Update the bandwidth on demand sample array with the latest send.
|
|
// If we need to notify someone of a bandwidth event do it.
|
|
//
|
|
if (BundleCB->Flags & BOND_ENABLED) {
|
|
UpdateBandwidthOnDemand(BundleCB->RUpperBonDInfo, PacketSize);
|
|
CheckUpperThreshold(BundleCB);
|
|
UpdateBandwidthOnDemand(BundleCB->RLowerBonDInfo, PacketSize);
|
|
CheckLowerThreshold(BundleCB);
|
|
}
|
|
|
|
RecvDesc->CopyRequired = TRUE;
|
|
RecvDesc->CurrentBuffer = Packet;
|
|
RecvDesc->CurrentLength = PacketSize;
|
|
RecvDesc->LinkCB = LinkCB;
|
|
RecvDesc->BundleCB = BundleCB;
|
|
|
|
//
|
|
// Indicate to netmon if we are sniffing at
|
|
// the link level
|
|
//
|
|
if (gbSniffLink &&
|
|
(NdisWanCB.PromiscuousAdapter != NULL)) {
|
|
|
|
//
|
|
// Indicate a packet to netmon
|
|
//
|
|
IndicatePromiscuousRecv(BundleCB, RecvDesc, RECV_LINK);
|
|
}
|
|
|
|
//
|
|
// Add up the statistics
|
|
//
|
|
LinkCB->Stats.BytesReceived += RecvDesc->CurrentLength;
|
|
LinkCB->Stats.FramesReceived++;
|
|
BundleCB->Stats.BytesReceived += RecvDesc->CurrentLength;
|
|
|
|
LinkCB->Flags |= LINK_IN_RECV;
|
|
BundleCB->Flags |= BUNDLE_IN_RECV;
|
|
|
|
Status = (*LinkCB->RecvHandler)(LinkCB, RecvDesc);
|
|
|
|
BundleCB->Flags &= ~BUNDLE_IN_RECV;
|
|
LinkCB->Flags &= ~LINK_IN_RECV;
|
|
|
|
if (Status != NDIS_STATUS_PENDING) {
|
|
NdisWanFreeRecvDesc(RecvDesc);
|
|
}
|
|
|
|
} while ( 0 );
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ProtoWanReceiveIndication: Exit"));
|
|
|
|
|
|
//
|
|
// Deref's for the ref's applied in AreLinkAndBundleValid
|
|
//
|
|
DEREF_BUNDLECB_LOCKED(BundleCB);
|
|
DEREF_LINKCB(LinkCB);
|
|
|
|
return (NDIS_STATUS_SUCCESS);
|
|
}
|
|
|
|
VOID
|
|
ProtoRequestComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN PNDIS_REQUEST NdisRequest,
|
|
IN NDIS_STATUS Status
|
|
)
|
|
{
|
|
POPENCB pOpenCB = (POPENCB)ProtocolBindingContext;
|
|
PWAN_REQUEST pWanRequest;
|
|
|
|
pWanRequest = CONTAINING_RECORD(NdisRequest,
|
|
WAN_REQUEST,
|
|
NdisRequest);
|
|
|
|
NdisWanDbgOut(DBG_VERBOSE, DBG_REQUEST, ("ProtoRequestComplete: Enter - pWanRequest: 0x%p", pWanRequest));
|
|
|
|
pWanRequest->NotificationStatus = Status;
|
|
|
|
switch (pWanRequest->Origin) {
|
|
case NDISWAN:
|
|
NdisWanSetNotificationEvent(&pWanRequest->NotificationEvent);
|
|
break;
|
|
|
|
default:
|
|
ASSERT(pWanRequest->Origin == NDISTAPI);
|
|
NdisWanTapiRequestComplete(pOpenCB, pWanRequest);
|
|
break;
|
|
|
|
}
|
|
|
|
NdisWanDbgOut(DBG_VERBOSE, DBG_REQUEST, ("ProtoRequestComplete: Exit"));
|
|
}
|
|
|
|
VOID
|
|
ProtoBindAdapter(
|
|
OUT PNDIS_STATUS Status,
|
|
IN NDIS_HANDLE BindContext,
|
|
IN PNDIS_STRING DeviceName,
|
|
IN PVOID SystemSpecific1,
|
|
IN PVOID SystemSpecific2
|
|
)
|
|
/*++
|
|
|
|
Routine Name:
|
|
|
|
ProtoBindAdapter
|
|
|
|
Routine Description:
|
|
|
|
This function is called by the NDIS wrapper to tell NdisWan
|
|
to bind to an underlying miniport. NdisWan will open the
|
|
miniport and query information on the device.
|
|
|
|
Arguments:
|
|
|
|
Status - Return status
|
|
BindContext - Used in NdisBindAdapterComplete
|
|
DeviceName - Name of device we are opening
|
|
SS1 - Used in NdisOpenProtocolConfig
|
|
SS2 - Reserved
|
|
|
|
Return Values:
|
|
|
|
--*/
|
|
{
|
|
POPENCB pOpenCB;
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoBindAdapter - Enter %ls", DeviceName->Buffer));
|
|
|
|
pOpenCB = NdisWanAllocateOpenCB(DeviceName);
|
|
|
|
if (pOpenCB == NULL) {
|
|
*Status = NDIS_STATUS_RESOURCES;
|
|
return;
|
|
}
|
|
|
|
pOpenCB->Flags |= OPEN_IN_BIND;
|
|
|
|
NdisWanInitializeNotificationEvent(&pOpenCB->InitEvent);
|
|
|
|
*Status = ProtoOpenWanAdapter(pOpenCB);
|
|
|
|
if (*Status != NDIS_STATUS_SUCCESS) {
|
|
|
|
RemoveEntryGlobalList(OpenCBList, &pOpenCB->Linkage);
|
|
|
|
NdisWanDbgOut(DBG_CRITICAL_ERROR, DBG_INIT, ("Failed to bind to %ls! Error 0x%x - %s",
|
|
pOpenCB->MiniportName.Buffer, *Status, NdisWanGetNdisStatus(*Status)));
|
|
|
|
NdisWanFreeOpenCB(pOpenCB);
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Figure out if this is a legacy wan miniport.
|
|
//
|
|
if (pOpenCB->MediumType == NdisMediumWan) {
|
|
pOpenCB->Flags |= OPEN_LEGACY;
|
|
}
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_INIT, ("Successful Binding to %s miniport %ls!",
|
|
(pOpenCB->Flags & OPEN_LEGACY) ? "Legacy" : "NDIS 5.0",
|
|
pOpenCB->MiniportName.Buffer));
|
|
|
|
//
|
|
// Get the wan medium subtype
|
|
//
|
|
{
|
|
WAN_REQUEST WanRequest;
|
|
|
|
NdisZeroMemory(&WanRequest, sizeof(WanRequest));
|
|
WanRequest.Type = SYNC;
|
|
WanRequest.Origin = NDISWAN;
|
|
WanRequest.OpenCB = pOpenCB;
|
|
NdisWanInitializeNotificationEvent(&WanRequest.NotificationEvent);
|
|
|
|
WanRequest.NdisRequest.RequestType =
|
|
NdisRequestQueryInformation;
|
|
|
|
WanRequest.NdisRequest.DATA.QUERY_INFORMATION.Oid =
|
|
OID_WAN_MEDIUM_SUBTYPE;
|
|
|
|
WanRequest.NdisRequest.DATA.QUERY_INFORMATION.InformationBuffer =
|
|
&pOpenCB->MediumSubType;
|
|
|
|
WanRequest.NdisRequest.DATA.QUERY_INFORMATION.InformationBufferLength =
|
|
sizeof(pOpenCB->MediumSubType);
|
|
|
|
*Status = NdisWanSubmitNdisRequest(pOpenCB, &WanRequest);
|
|
|
|
if (*Status != NDIS_STATUS_SUCCESS) {
|
|
NdisWanDbgOut(DBG_FAILURE, DBG_INIT, ("Error returned from OID_WAN_MEDIUM_SUBTYPE! Error 0x%x - %s",
|
|
*Status, NdisWanGetNdisStatus(*Status)));
|
|
pOpenCB->MediumSubType = NdisWanMediumHub;
|
|
*Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
if (pOpenCB->Flags & OPEN_LEGACY) {
|
|
NDIS_WAN_INFO WanInfo;
|
|
WAN_REQUEST WanRequest;
|
|
|
|
//
|
|
// This is a legacy wan miniport
|
|
//
|
|
|
|
NdisZeroMemory(&WanRequest, sizeof(WanRequest));
|
|
WanRequest.Type = SYNC;
|
|
WanRequest.Origin = NDISWAN;
|
|
WanRequest.OpenCB = pOpenCB;
|
|
NdisWanInitializeNotificationEvent(&WanRequest.NotificationEvent);
|
|
|
|
//
|
|
// Get more info...
|
|
//
|
|
NdisZeroMemory(&WanInfo, sizeof(WanInfo));
|
|
|
|
WanRequest.NdisRequest.RequestType =
|
|
NdisRequestQueryInformation;
|
|
|
|
WanRequest.NdisRequest.DATA.QUERY_INFORMATION.Oid =
|
|
OID_WAN_GET_INFO;
|
|
|
|
WanRequest.NdisRequest.DATA.QUERY_INFORMATION.InformationBuffer =
|
|
&WanInfo;
|
|
|
|
WanRequest.NdisRequest.DATA.QUERY_INFORMATION.InformationBufferLength =
|
|
sizeof(WanInfo);
|
|
|
|
*Status = NdisWanSubmitNdisRequest(pOpenCB, &WanRequest);
|
|
|
|
if (*Status != NDIS_STATUS_SUCCESS) {
|
|
NDIS_STATUS CloseStatus;
|
|
|
|
NdisWanDbgOut(DBG_FAILURE, DBG_INIT, ("Error returned from OID_WAN_GET_INFO! Error 0x%x - %s",
|
|
*Status, NdisWanGetNdisStatus(*Status)));
|
|
|
|
NdisAcquireSpinLock(&pOpenCB->Lock);
|
|
|
|
pOpenCB->Flags |= OPEN_CLOSING;
|
|
|
|
NdisWanInitializeNotificationEvent(&pOpenCB->NotificationEvent);
|
|
|
|
NdisReleaseSpinLock(&pOpenCB->Lock);
|
|
|
|
NdisCloseAdapter(&CloseStatus,
|
|
pOpenCB->BindingHandle);
|
|
|
|
if (CloseStatus == NDIS_STATUS_PENDING) {
|
|
|
|
NdisWanWaitForNotificationEvent(&pOpenCB->NotificationEvent);
|
|
}
|
|
|
|
NdisWanFreeOpenCB(pOpenCB);
|
|
|
|
return;
|
|
}
|
|
|
|
NdisMoveMemory(&pOpenCB->WanInfo, &WanInfo, sizeof(NDIS_WAN_INFO));
|
|
|
|
if (pOpenCB->WanInfo.MaxTransmit == 0) {
|
|
pOpenCB->WanInfo.MaxTransmit = 1;
|
|
}
|
|
|
|
if (pOpenCB->WanInfo.Endpoints == 0) {
|
|
pOpenCB->WanInfo.Endpoints = 1000;
|
|
}
|
|
|
|
*Status = NdisWanAllocateSendResources(pOpenCB);
|
|
|
|
if (*Status != NDIS_STATUS_SUCCESS) {
|
|
NDIS_STATUS CloseStatus;
|
|
|
|
NdisWanDbgOut(DBG_FAILURE, DBG_INIT, ("Error returned from AllocateSendResources! Error 0x%x - %s",
|
|
*Status, NdisWanGetNdisStatus(*Status)));
|
|
|
|
NdisAcquireSpinLock(&pOpenCB->Lock);
|
|
|
|
pOpenCB->Flags |= OPEN_CLOSING;
|
|
|
|
NdisWanInitializeNotificationEvent(&pOpenCB->NotificationEvent);
|
|
|
|
NdisReleaseSpinLock(&pOpenCB->Lock);
|
|
|
|
NdisCloseAdapter(&CloseStatus,
|
|
pOpenCB->BindingHandle);
|
|
|
|
if (CloseStatus == NDIS_STATUS_PENDING) {
|
|
|
|
NdisWanWaitForNotificationEvent(&pOpenCB->NotificationEvent);
|
|
}
|
|
|
|
NdisWanFreeOpenCB(pOpenCB);
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Tell tapi about this device
|
|
//
|
|
if (pOpenCB->WanInfo.FramingBits & TAPI_PROVIDER) {
|
|
NDISTAPI_CHARACTERISTICS Chars;
|
|
ULONG NdisTapiKey;
|
|
|
|
NdisMoveMemory(&Chars.Guid,
|
|
&pOpenCB->Guid,
|
|
sizeof(Chars.Guid));
|
|
|
|
Chars.MediaType = pOpenCB->MediumSubType;
|
|
Chars.RequestProc = NdisWanTapiRequestProc;
|
|
|
|
//
|
|
// Note that since there are typically very few
|
|
// (< 10) wan miniports, just having an incrementing
|
|
// counter will do. There is a pathological case where
|
|
// one of the miniports can be added and removed a billion
|
|
// times so that the counter wraps around and clashes with
|
|
// an existing miniport - this is not even a stress scenario.
|
|
//
|
|
|
|
NdisTapiKey = NdisWanInterlockedInc(
|
|
&glNdisTapiKey);
|
|
|
|
pOpenCB->NdisTapiKey = UlongToHandle(NdisTapiKey);
|
|
|
|
NdisTapiRegisterProvider(pOpenCB->NdisTapiKey, &Chars);
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// This is a 5.0 miniport! We will do init work
|
|
// when a call manager registers for this!
|
|
//
|
|
}
|
|
|
|
pOpenCB->Flags &= ~OPEN_IN_BIND;
|
|
|
|
NdisWanSetNotificationEvent(&pOpenCB->InitEvent);
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoBindAdapter - Exit"));
|
|
}
|
|
|
|
VOID
|
|
ProtoUnbindAdapter(
|
|
OUT PNDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_HANDLE UnbindContext
|
|
)
|
|
{
|
|
POPENCB pOpenCB = (POPENCB)ProtocolBindingContext;
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoUnbindAdapter: Enter - OpenCB %p", pOpenCB));
|
|
|
|
NdisAcquireSpinLock(&pOpenCB->Lock);
|
|
|
|
while (pOpenCB->AfRegisteringCount != 0) {
|
|
NdisReleaseSpinLock(&pOpenCB->Lock);
|
|
NdisWanWaitForNotificationEvent(&pOpenCB->AfRegisteringEvent);
|
|
NdisAcquireSpinLock(&pOpenCB->Lock);
|
|
}
|
|
|
|
if (!(pOpenCB->Flags & OPEN_LEGACY)) {
|
|
|
|
while (!IsListEmpty(&pOpenCB->AfSapCBList)) {
|
|
PCL_AFSAPCB AfSapCB;
|
|
NDIS_STATUS RetStatus;
|
|
|
|
AfSapCB =
|
|
(PCL_AFSAPCB)RemoveHeadList(&pOpenCB->AfSapCBList);
|
|
|
|
InsertTailList(&pOpenCB->AfSapCBClosing, &AfSapCB->Linkage);
|
|
|
|
NdisReleaseSpinLock(&pOpenCB->Lock);
|
|
|
|
NdisAcquireSpinLock(&AfSapCB->Lock);
|
|
|
|
AfSapCB->Flags |= AFSAP_REMOVED_UNBIND;
|
|
|
|
DEREF_CLAFSAPCB_LOCKED(AfSapCB);
|
|
|
|
NdisAcquireSpinLock(&pOpenCB->Lock);
|
|
}
|
|
}
|
|
|
|
pOpenCB->UnbindContext = UnbindContext;
|
|
|
|
NdisReleaseSpinLock(&pOpenCB->Lock);
|
|
|
|
if (pOpenCB->WanInfo.FramingBits & TAPI_PROVIDER) {
|
|
NdisTapiDeregisterProvider(pOpenCB->NdisTapiKey);
|
|
}
|
|
|
|
DEREF_OPENCB(pOpenCB);
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoUnbindAdapter: Exit"));
|
|
|
|
*Status = NDIS_STATUS_PENDING;
|
|
}
|
|
|
|
VOID
|
|
ProtoUnload(
|
|
VOID
|
|
)
|
|
{
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoUnload: Enter"));
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoUnload: Exit"));
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ProtoPnPEvent(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN PNET_PNP_EVENT NetPnPEvent
|
|
)
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
POPENCB pOpenCB = (POPENCB)ProtocolBindingContext;
|
|
|
|
if (pOpenCB == NULL) {
|
|
return (NDIS_STATUS_SUCCESS);
|
|
}
|
|
|
|
switch (NetPnPEvent->NetEvent) {
|
|
case NetEventSetPower:
|
|
{
|
|
NET_DEVICE_POWER_STATE PowerState;
|
|
|
|
PowerState = *((NET_DEVICE_POWER_STATE*)NetPnPEvent->Buffer);
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL,
|
|
("ProtoPnPEvent: OpenCB %p %s State %d",
|
|
pOpenCB, "SetPower", PowerState));
|
|
|
|
switch (PowerState) {
|
|
case NetDeviceStateD0:
|
|
break;
|
|
case NetDeviceStateD1:
|
|
case NetDeviceStateD2:
|
|
case NetDeviceStateD3:
|
|
|
|
//
|
|
// If this is the open on asyncmac I do not want it to be closed.
|
|
// I will succeed the set power which should keep ndis from
|
|
// unbinding me. If this is an open on any other miniport
|
|
// I will return not supported so that I will get unbound from
|
|
// the miniport. This is required for correct tapi behavior.
|
|
//
|
|
if (pOpenCB->MediumType == NdisMediumWan &&
|
|
pOpenCB->MediumSubType == NdisWanMediumSerial &&
|
|
!(pOpenCB->WanInfo.FramingBits & TAPI_PROVIDER)) {
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
} else {
|
|
Status = NDIS_STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
//
|
|
// In the case of a Critical Power event we will not
|
|
// receive a Query so we must tear the connection down
|
|
// directly from the Set.
|
|
//
|
|
// If we have any active connections signal rasman to
|
|
// tear them down.
|
|
//
|
|
if (InterlockedCompareExchange(&pOpenCB->ActiveLinkCount, 0, 0)) {
|
|
PIRP Irp;
|
|
|
|
NdisAcquireSpinLock(&NdisWanCB.Lock);
|
|
Irp = NdisWanCB.HibernateEventIrp;
|
|
|
|
if ((Irp != NULL) &&
|
|
IoSetCancelRoutine(Irp, NULL)){
|
|
|
|
NdisWanCB.HibernateEventIrp = NULL;
|
|
|
|
NdisReleaseSpinLock(&NdisWanCB.Lock);
|
|
|
|
//
|
|
// The irp is not being canceled so
|
|
// lets do it!
|
|
//
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
|
|
NdisAcquireSpinLock(&NdisWanCB.Lock);
|
|
}
|
|
|
|
NdisReleaseSpinLock(&NdisWanCB.Lock);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case NetEventQueryPower:
|
|
{
|
|
NET_DEVICE_POWER_STATE PowerState;
|
|
|
|
PowerState = *((NET_DEVICE_POWER_STATE*)NetPnPEvent->Buffer);
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL,
|
|
("ProtoPnPEvent: OpenCB %p %s State %d",
|
|
pOpenCB, "QueryPower", PowerState));
|
|
//
|
|
// If there is an active connection
|
|
// on this binding refuse to go away
|
|
//
|
|
switch (PowerState) {
|
|
case NetDeviceStateD0:
|
|
break;
|
|
case NetDeviceStateD1:
|
|
case NetDeviceStateD2:
|
|
case NetDeviceStateD3:
|
|
|
|
//
|
|
// If we have any active connections signal rasman to
|
|
// tear them down.
|
|
//
|
|
if (InterlockedCompareExchange(&pOpenCB->ActiveLinkCount, 0, 0)) {
|
|
PIRP Irp;
|
|
|
|
NdisAcquireSpinLock(&NdisWanCB.Lock);
|
|
Irp = NdisWanCB.HibernateEventIrp;
|
|
|
|
if ((Irp != NULL) &&
|
|
IoSetCancelRoutine(Irp, NULL)) {
|
|
|
|
NdisWanCB.HibernateEventIrp = NULL;
|
|
NdisReleaseSpinLock(&NdisWanCB.Lock);
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
|
|
NdisAcquireSpinLock(&NdisWanCB.Lock);
|
|
}
|
|
|
|
NdisReleaseSpinLock(&NdisWanCB.Lock);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case NetEventQueryRemoveDevice:
|
|
case NetEventCancelRemoveDevice:
|
|
case NetEventReconfigure:
|
|
case NetEventBindList:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoPnPEvent: Exit"));
|
|
return (Status);
|
|
}
|
|
|
|
VOID
|
|
ProtoCoSendComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolVcContext,
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
{
|
|
PLINKCB LinkCB;
|
|
PBUNDLECB BundleCB;
|
|
PSEND_DESC SendDesc;
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_SEND,
|
|
("ProtoCoSendComplete: Enter - VC %p Packet: %p", ProtocolVcContext, Packet));
|
|
|
|
if (!IsLinkValid(ProtocolVcContext, FALSE, &LinkCB)) {
|
|
|
|
NdisWanDbgOut(DBG_FAILURE, DBG_CL,
|
|
("NDISWAN: SendComplete after link has gone down ProtocolVcContext %p\n",
|
|
LinkCB));
|
|
|
|
return;
|
|
}
|
|
|
|
REMOVE_DBG_SEND(PacketTypeNdis, LinkCB->OpenCB, Packet);
|
|
|
|
//
|
|
// Get Info from the NdisPacket
|
|
//
|
|
SendDesc = PPROTOCOL_RESERVED_FROM_NDIS(Packet)->SendDesc;
|
|
|
|
NdisAcquireSpinLock(&LinkCB->Lock);
|
|
|
|
ASSERT(SendDesc->LinkCB == LinkCB);
|
|
|
|
CompleteSendDesc(SendDesc, Status);
|
|
|
|
NdisAcquireSpinLock(&LinkCB->Lock);
|
|
|
|
//
|
|
// Remove ref that keeps the vc around
|
|
//
|
|
DerefVc(LinkCB);
|
|
|
|
//
|
|
// Deref for the ref applied in IsLinkValid
|
|
//
|
|
DEREF_LINKCB_LOCKED(LinkCB);
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("ProtoCoSendComplete: Exit"));
|
|
}
|
|
|
|
VOID
|
|
ProtoCoIndicateStatus(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_HANDLE ProtocolVcContext OPTIONAL,
|
|
IN NDIS_STATUS GeneralStatus,
|
|
IN PVOID StatusBuffer,
|
|
IN UINT StatusBufferSize
|
|
)
|
|
{
|
|
POPENCB pOpenCB = (POPENCB)ProtocolBindingContext;
|
|
PLINKCB LinkCB;
|
|
PBUNDLECB BundleCB;
|
|
|
|
if (!AreLinkAndBundleValid(ProtocolVcContext,
|
|
TRUE,
|
|
&LinkCB,
|
|
&BundleCB)) {
|
|
|
|
return;
|
|
}
|
|
|
|
switch (GeneralStatus) {
|
|
case NDIS_STATUS_WAN_CO_FRAGMENT:
|
|
NdisCoWanFragmentIndication(LinkCB,
|
|
BundleCB,
|
|
StatusBuffer,
|
|
StatusBufferSize);
|
|
|
|
break;
|
|
|
|
case NDIS_STATUS_WAN_CO_LINKPARAMS:
|
|
NdisCoWanLinkParamChange(LinkCB,
|
|
BundleCB,
|
|
StatusBuffer,
|
|
StatusBufferSize);
|
|
|
|
default:
|
|
NdisWanDbgOut(DBG_INFO, DBG_PROTOCOL,
|
|
("Unknown Status Indication: 0x%x", GeneralStatus));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Deref's for ref's applied in AreLinkAndBundleValid
|
|
//
|
|
DEREF_LINKCB(LinkCB);
|
|
DEREF_BUNDLECB(BundleCB);
|
|
}
|
|
|
|
UINT
|
|
ProtoCoReceivePacket(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_HANDLE ProtocolVcContext,
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
{
|
|
POPENCB pOpenCB = (POPENCB)ProtocolBindingContext;
|
|
PLINKCB LinkCB = NULL;
|
|
PBUNDLECB BundleCB = NULL;
|
|
NDIS_STATUS Status;
|
|
ULONG BufferCount;
|
|
LONG PacketSize;
|
|
PNDIS_BUFFER FirstBuffer;
|
|
PRECV_DESC RecvDesc;
|
|
UINT RefCount = 0;
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE,
|
|
("ProtoCoReceivePacket: Enter - OpenCB %p", pOpenCB));
|
|
|
|
do {
|
|
|
|
if (!AreLinkAndBundleValid(ProtocolVcContext,
|
|
TRUE,
|
|
&LinkCB,
|
|
&BundleCB)) {
|
|
break;
|
|
}
|
|
|
|
#if DBG
|
|
NdisAcquireSpinLock(&LinkCB->Lock);
|
|
|
|
if (LinkCB->ClCallState != CL_CALL_CONNECTED) {
|
|
DbgPrint("NDISWAN: Vc not fully active but indicating data!\n");
|
|
}
|
|
|
|
NdisReleaseSpinLock(&LinkCB->Lock);
|
|
#endif
|
|
|
|
AcquireBundleLock(BundleCB);
|
|
|
|
NdisQueryPacket(Packet,
|
|
NULL,
|
|
&BufferCount,
|
|
&FirstBuffer,
|
|
&PacketSize);
|
|
|
|
if (PacketSize > (LONG)glMRU) {
|
|
break;
|
|
}
|
|
|
|
PRECV_RESERVED_FROM_NDIS(Packet)->MagicNumber = MAGIC_EXTERNAL_RECV;
|
|
|
|
RecvDesc =
|
|
NdisWanAllocateRecvDesc(glLargeDataBufferSize);
|
|
|
|
if (RecvDesc == NULL) {
|
|
break;
|
|
}
|
|
|
|
RecvDesc->LinkCB = LinkCB;
|
|
RecvDesc->BundleCB = BundleCB;
|
|
|
|
//
|
|
// If the packet has only one buffer we are happy, if not
|
|
// we have to allocate our own ndis packet and buffers
|
|
// and copy the data from the miniports packet into our packet
|
|
//
|
|
if (BufferCount > 1 ||
|
|
NDIS_GET_PACKET_STATUS(Packet) == NDIS_STATUS_RESOURCES) {
|
|
|
|
RecvDesc->CurrentBuffer = RecvDesc->StartBuffer +
|
|
MAC_HEADER_LENGTH +
|
|
PROTOCOL_HEADER_LENGTH;
|
|
|
|
//
|
|
// Copy from the miniports packet to my packet
|
|
//
|
|
NdisWanCopyFromPacketToBuffer(Packet,
|
|
0,
|
|
PacketSize,
|
|
RecvDesc->CurrentBuffer,
|
|
&RecvDesc->CurrentLength);
|
|
|
|
ASSERT(PacketSize == RecvDesc->CurrentLength);
|
|
|
|
} else {
|
|
NdisQueryBuffer(FirstBuffer,
|
|
&RecvDesc->CurrentBuffer,
|
|
&RecvDesc->CurrentLength);
|
|
|
|
ASSERT(PacketSize == RecvDesc->CurrentLength);
|
|
|
|
RecvDesc->CopyRequired = TRUE;
|
|
|
|
RecvDesc->OriginalPacket = Packet;
|
|
|
|
RefCount = 1;
|
|
}
|
|
|
|
//
|
|
// Indicate to netmon if we are sniffing at
|
|
// the link level
|
|
//
|
|
if (gbSniffLink &&
|
|
(NdisWanCB.PromiscuousAdapter != NULL)) {
|
|
|
|
//
|
|
// Indicate a packet to netmon
|
|
//
|
|
IndicatePromiscuousRecv(BundleCB, RecvDesc, RECV_LINK);
|
|
}
|
|
|
|
//
|
|
// Update the bandwidth on demand sample array with the latest send.
|
|
// If we need to notify someone of a bandwidth event do it.
|
|
//
|
|
if (BundleCB->Flags & BOND_ENABLED) {
|
|
UpdateBandwidthOnDemand(BundleCB->RUpperBonDInfo, PacketSize);
|
|
CheckUpperThreshold(BundleCB);
|
|
UpdateBandwidthOnDemand(BundleCB->RLowerBonDInfo, PacketSize);
|
|
CheckLowerThreshold(BundleCB);
|
|
}
|
|
|
|
//
|
|
// Add up the statistics
|
|
//
|
|
LinkCB->Stats.BytesReceived += RecvDesc->CurrentLength;
|
|
LinkCB->Stats.FramesReceived++;
|
|
BundleCB->Stats.BytesReceived += RecvDesc->CurrentLength;
|
|
|
|
Status = (*LinkCB->RecvHandler)(LinkCB, RecvDesc);
|
|
|
|
if (Status != NDIS_STATUS_PENDING) {
|
|
RecvDesc->OriginalPacket = NULL;
|
|
NdisWanFreeRecvDesc(RecvDesc);
|
|
RefCount = 0;
|
|
}
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ProtoCoReceivePacket: Exit"));
|
|
|
|
} while (0);
|
|
|
|
//
|
|
// Deref's for ref's applied by AreLinkAndBundleValid
|
|
//
|
|
DEREF_BUNDLECB_LOCKED(BundleCB);
|
|
DEREF_LINKCB(LinkCB);
|
|
|
|
return (RefCount);
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ProtoCoRequest(
|
|
IN NDIS_HANDLE ProtocolAfContext,
|
|
IN NDIS_HANDLE ProtocolVcContext OPTIONAL,
|
|
IN NDIS_HANDLE ProtocolPartyContext OPTIONAL,
|
|
IN OUT PNDIS_REQUEST NdisRequest
|
|
)
|
|
{
|
|
PCL_AFSAPCB AfSapCB = (PCL_AFSAPCB)ProtocolAfContext;
|
|
NDIS_OID Oid;
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_REQUEST, ("ProtoCoRequest: Enter - AfContext %p", ProtocolAfContext));
|
|
|
|
if (NdisRequest->RequestType == NdisRequestQueryInformation) {
|
|
Oid = NdisRequest->DATA.QUERY_INFORMATION.Oid;
|
|
} else {
|
|
Oid = NdisRequest->DATA.SET_INFORMATION.Oid;
|
|
}
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_REQUEST, ("Oid - %x", Oid));
|
|
|
|
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
switch (Oid) {
|
|
case OID_CO_AF_CLOSE:
|
|
{
|
|
POPENCB OpenCB;
|
|
PCL_AFSAPCB tAfSapCB;
|
|
|
|
OpenCB = AfSapCB->OpenCB;
|
|
|
|
NdisAcquireSpinLock(&OpenCB->Lock);
|
|
|
|
while (OpenCB->AfRegisteringCount != 0) {
|
|
NdisReleaseSpinLock(&OpenCB->Lock);
|
|
NdisWanWaitForNotificationEvent(&OpenCB->AfRegisteringEvent);
|
|
NdisAcquireSpinLock(&OpenCB->Lock);
|
|
}
|
|
|
|
for (tAfSapCB = (PCL_AFSAPCB)OpenCB->AfSapCBList.Flink;
|
|
(PVOID)tAfSapCB != (PVOID)&OpenCB->AfSapCBList;
|
|
tAfSapCB = (PCL_AFSAPCB)AfSapCB->Linkage.Flink) {
|
|
|
|
if (tAfSapCB == AfSapCB) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((PVOID)tAfSapCB == (PVOID)&OpenCB->AfSapCBList) {
|
|
NdisWanDbgOut(DBG_FAILURE, DBG_REQUEST, \
|
|
("ProtoCoRequest: Af %p not on OpenCB %p list!", \
|
|
AfSapCB, OpenCB));
|
|
|
|
NdisReleaseSpinLock(&OpenCB->Lock);
|
|
|
|
break;
|
|
}
|
|
|
|
RemoveEntryList(&AfSapCB->Linkage);
|
|
|
|
InsertTailList(&OpenCB->AfSapCBClosing,
|
|
&AfSapCB->Linkage);
|
|
|
|
NdisReleaseSpinLock(&OpenCB->Lock);
|
|
|
|
NdisAcquireSpinLock(&AfSapCB->Lock);
|
|
|
|
ASSERT(!(AfSapCB->Flags & AFSAP_REMOVED_FLAGS));
|
|
ASSERT(AfSapCB->Flags & SAP_REGISTERED);
|
|
|
|
AfSapCB->Flags |= AFSAP_REMOVED_REQUEST;
|
|
|
|
DEREF_CLAFSAPCB_LOCKED(AfSapCB);
|
|
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_REQUEST, ("ProtoCoRequest: Exit"));
|
|
|
|
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
return (NDIS_STATUS_SUCCESS);
|
|
}
|
|
|
|
VOID
|
|
ProtoCoRequestComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolAfContext,
|
|
IN NDIS_HANDLE ProtocolVcContext OPTIONAL,
|
|
IN NDIS_HANDLE ProtocolPartyContext OPTIONAL,
|
|
IN PNDIS_REQUEST NdisRequest
|
|
)
|
|
{
|
|
PCL_AFSAPCB AfSapCB = (PCL_AFSAPCB)ProtocolAfContext;
|
|
PWAN_REQUEST pWanRequest;
|
|
POPENCB pOpenCB;
|
|
|
|
pWanRequest = CONTAINING_RECORD(NdisRequest,
|
|
WAN_REQUEST,
|
|
NdisRequest);
|
|
|
|
pOpenCB = pWanRequest->OpenCB;
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_REQUEST, ("ProtoCoRequestComplete: Enter - WanRequest 0x%p", pWanRequest));
|
|
|
|
pWanRequest->NotificationStatus = Status;
|
|
|
|
switch (pWanRequest->Origin) {
|
|
case NDISWAN:
|
|
NdisWanSetNotificationEvent(&pWanRequest->NotificationEvent);
|
|
break;
|
|
|
|
default:
|
|
ASSERT(pWanRequest->Origin == NDISTAPI);
|
|
NdisWanTapiRequestComplete(pOpenCB, pWanRequest);
|
|
break;
|
|
}
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_REQUEST, ("ProtoCoRequestComplete: Exit"));
|
|
}
|
|
|
|
VOID
|
|
ProtoCoAfRegisterNotify(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN PCO_ADDRESS_FAMILY AddressFamily
|
|
)
|
|
{
|
|
POPENCB OpenCB = (POPENCB)ProtocolBindingContext;
|
|
NDIS_CLIENT_CHARACTERISTICS ClCharacteristics;
|
|
PCL_AFSAPCB AfSapCB;
|
|
NDIS_STATUS Status;
|
|
ULONG GenericUlong;
|
|
NDIS_HANDLE AfHandle;
|
|
WAN_REQUEST WanRequest;
|
|
NDIS_WAN_CO_INFO WanInfo;
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL,
|
|
("ProtoCoAfRegisterNotify: Enter - OpenCB %p AfType: %x", OpenCB, AddressFamily->AddressFamily));
|
|
|
|
//
|
|
// If this is a proxied address family we are interested,
|
|
// so open the address family, register a sap and return success.
|
|
//
|
|
if (AddressFamily->AddressFamily != CO_ADDRESS_FAMILY_TAPI) {
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL,
|
|
("ProtoCoAfRegisterNotify: Af not tapi do not open!"));
|
|
return;
|
|
}
|
|
|
|
NdisAcquireSpinLock(&OpenCB->Lock);
|
|
|
|
for (AfSapCB = (PCL_AFSAPCB)OpenCB->AfSapCBList.Flink;
|
|
(PVOID)AfSapCB != (PVOID)&OpenCB->AfSapCBList;
|
|
AfSapCB = (PCL_AFSAPCB)AfSapCB->Linkage.Flink) {
|
|
|
|
if (AfSapCB->Af.AddressFamily == AddressFamily->AddressFamily) {
|
|
//
|
|
// we already have this addressfamily on this open block.
|
|
//
|
|
NdisReleaseSpinLock(&OpenCB->Lock);
|
|
return;
|
|
}
|
|
}
|
|
|
|
AfSapCB =
|
|
NdisWanAllocateClAfSapCB(OpenCB, AddressFamily);
|
|
|
|
if (AfSapCB == NULL) {
|
|
NdisReleaseSpinLock(&OpenCB->Lock);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Use this crude mechanism to keep us from unbinding while in the
|
|
// middle of af notification. The count is cleaned up either in
|
|
// openafcomplete (if open failed) or in registersapcomplete.
|
|
//
|
|
if (OpenCB->AfRegisteringCount == 0) {
|
|
NdisWanInitializeNotificationEvent(&OpenCB->AfRegisteringEvent);
|
|
}
|
|
|
|
OpenCB->AfRegisteringCount++;
|
|
|
|
NdisReleaseSpinLock(&OpenCB->Lock);
|
|
|
|
//
|
|
// Open the address family
|
|
//
|
|
NdisZeroMemory(&ClCharacteristics, sizeof(NDIS_CLIENT_CHARACTERISTICS));
|
|
|
|
ClCharacteristics.MajorVersion = NDISWAN_MAJOR_VERSION;
|
|
ClCharacteristics.MinorVersion = NDISWAN_MINOR_VERSION;
|
|
ClCharacteristics.ClCreateVcHandler = ClCreateVc;
|
|
ClCharacteristics.ClDeleteVcHandler = ClDeleteVc;
|
|
ClCharacteristics.ClRequestHandler = ProtoCoRequest;
|
|
ClCharacteristics.ClRequestCompleteHandler = ProtoCoRequestComplete;
|
|
ClCharacteristics.ClOpenAfCompleteHandler = ClOpenAfComplete;
|
|
ClCharacteristics.ClCloseAfCompleteHandler = ClCloseAfComplete;
|
|
ClCharacteristics.ClRegisterSapCompleteHandler = ClRegisterSapComplete;
|
|
ClCharacteristics.ClDeregisterSapCompleteHandler = ClDeregisterSapComplete;
|
|
ClCharacteristics.ClMakeCallCompleteHandler = ClMakeCallComplete;
|
|
ClCharacteristics.ClModifyCallQoSCompleteHandler = ClModifyQoSComplete;
|
|
ClCharacteristics.ClCloseCallCompleteHandler = ClCloseCallComplete;
|
|
ClCharacteristics.ClAddPartyCompleteHandler = NULL;
|
|
ClCharacteristics.ClDropPartyCompleteHandler = NULL;
|
|
ClCharacteristics.ClIncomingCallHandler = ClIncomingCall;
|
|
ClCharacteristics.ClIncomingCallQoSChangeHandler = ClIncomingCallQoSChange;
|
|
ClCharacteristics.ClIncomingCloseCallHandler = ClIncomingCloseCall;
|
|
ClCharacteristics.ClIncomingDropPartyHandler = NULL;
|
|
ClCharacteristics.ClCallConnectedHandler = ClCallConnected;
|
|
|
|
Status =
|
|
NdisClOpenAddressFamily(OpenCB->BindingHandle,
|
|
AddressFamily,
|
|
AfSapCB,
|
|
&ClCharacteristics,
|
|
sizeof(NDIS_CLIENT_CHARACTERISTICS),
|
|
&AfHandle);
|
|
|
|
if (Status != NDIS_STATUS_PENDING) {
|
|
ClOpenAfComplete(Status, AfSapCB, AfHandle);
|
|
}
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL,
|
|
("ClOpenAddressFamily AfHandle 0x%x status: 0x%x", AfSapCB->AfHandle, Status));
|
|
|
|
//
|
|
// Do some OID's to the miniport. This is a
|
|
// CoNDIS miniport and are destined for the
|
|
// miniport so AfHandle and VcHandle = NULL!
|
|
//
|
|
NdisZeroMemory(&WanRequest, sizeof(WanRequest));
|
|
|
|
WanRequest.Type = SYNC;
|
|
WanRequest.Origin = NDISWAN;
|
|
WanRequest.OpenCB = OpenCB;
|
|
WanRequest.AfHandle = NULL;
|
|
WanRequest.VcHandle = NULL;
|
|
NdisWanInitializeNotificationEvent(&WanRequest.NotificationEvent);
|
|
|
|
//
|
|
// Get more info...
|
|
//
|
|
WanRequest.NdisRequest.RequestType =
|
|
NdisRequestQueryInformation;
|
|
|
|
WanRequest.NdisRequest.DATA.QUERY_INFORMATION.Oid =
|
|
OID_WAN_CO_GET_INFO;
|
|
|
|
WanRequest.NdisRequest.DATA.QUERY_INFORMATION.InformationBuffer =
|
|
&WanInfo;
|
|
|
|
WanRequest.NdisRequest.DATA.QUERY_INFORMATION.InformationBufferLength =
|
|
sizeof(WanInfo);
|
|
|
|
Status = NdisWanSubmitNdisRequest(OpenCB, &WanRequest);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS) {
|
|
OpenCB->WanInfo.MaxFrameSize = WanInfo.MaxFrameSize;
|
|
OpenCB->WanInfo.MaxTransmit = WanInfo.MaxSendWindow;
|
|
OpenCB->WanInfo.FramingBits = WanInfo.FramingBits;
|
|
OpenCB->WanInfo.DesiredACCM = WanInfo.DesiredACCM;
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL,
|
|
("CO_GET_INFO: FrameSize %d SendWindow %d",
|
|
WanInfo.MaxFrameSize, WanInfo.MaxSendWindow));
|
|
} else {
|
|
|
|
//
|
|
// This guy will get default framing behaviour
|
|
//
|
|
OpenCB->WanInfo.FramingBits = PPP_FRAMING;
|
|
OpenCB->WanInfo.DesiredACCM = 0;
|
|
|
|
//
|
|
// Find the send window
|
|
//
|
|
WanRequest.NdisRequest.RequestType =
|
|
NdisRequestQueryInformation;
|
|
|
|
WanRequest.NdisRequest.DATA.QUERY_INFORMATION.Oid =
|
|
OID_GEN_MAXIMUM_SEND_PACKETS;
|
|
|
|
WanRequest.NdisRequest.DATA.QUERY_INFORMATION.InformationBuffer =
|
|
&GenericUlong;
|
|
|
|
WanRequest.NdisRequest.DATA.QUERY_INFORMATION.InformationBufferLength =
|
|
sizeof(ULONG);
|
|
|
|
Status = NdisWanSubmitNdisRequest(OpenCB, &WanRequest);
|
|
|
|
OpenCB->WanInfo.MaxTransmit = (Status == NDIS_STATUS_SUCCESS &&
|
|
GenericUlong > 0) ? GenericUlong : 10;
|
|
|
|
//
|
|
// Find the max transmit size
|
|
//
|
|
WanRequest.NdisRequest.RequestType =
|
|
NdisRequestQueryInformation;
|
|
|
|
WanRequest.NdisRequest.DATA.QUERY_INFORMATION.Oid =
|
|
OID_GEN_MAXIMUM_TOTAL_SIZE;
|
|
|
|
WanRequest.NdisRequest.DATA.QUERY_INFORMATION.InformationBuffer =
|
|
&GenericUlong;
|
|
|
|
WanRequest.NdisRequest.DATA.QUERY_INFORMATION.InformationBufferLength =
|
|
sizeof(ULONG);
|
|
|
|
Status = NdisWanSubmitNdisRequest(OpenCB, &WanRequest);
|
|
|
|
OpenCB->WanInfo.MaxFrameSize = (Status == NDIS_STATUS_SUCCESS) ?
|
|
GenericUlong : 1500;
|
|
|
|
}
|
|
|
|
OpenCB->WanInfo.Endpoints = 1000;
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoCoAfRegisterNotify: Exit"));
|
|
}
|
|
|
|
NDIS_STATUS
|
|
DoNewLineUpToProtocol(
|
|
PPROTOCOLCB ProtocolCB
|
|
)
|
|
/*++
|
|
|
|
Routine Name:
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Values:
|
|
|
|
--*/
|
|
{
|
|
PMINIPORTCB MiniportCB;
|
|
NDIS_STATUS Status;
|
|
PBUNDLECB BundleCB = ProtocolCB->BundleCB;
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("DoNewLineupToProtocol: Enter"));
|
|
|
|
do {
|
|
|
|
NdisAcquireSpinLock(&MiniportCBList.Lock);
|
|
|
|
//
|
|
// Find the adapter that this lineup is for. Look for the adapter
|
|
// that has the appropriate protocoltype. If it is NBF we need
|
|
// to look for a specific adapter.
|
|
//
|
|
for (MiniportCB = (PMINIPORTCB)MiniportCBList.List.Flink;
|
|
(PVOID)MiniportCB != (PVOID)&MiniportCBList.List;
|
|
MiniportCB = (PMINIPORTCB)MiniportCB->Linkage.Flink) {
|
|
|
|
if (MiniportCB->ProtocolType == ProtocolCB->ProtocolType) {
|
|
|
|
if (ProtocolCB->ProtocolType != PROTOCOL_NBF) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Must be NBF so verify the AdapterName!!!
|
|
//
|
|
if (NdisEqualUnicodeString(&MiniportCB->AdapterName,&ProtocolCB->BindingName, FALSE)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((PVOID)MiniportCB == (PVOID)&MiniportCBList.List) {
|
|
//
|
|
// The adapter was not found...
|
|
//
|
|
NdisWanDbgOut(DBG_FAILURE, DBG_PROTOCOL, ("Adapter not found!"));
|
|
|
|
NdisReleaseSpinLock(&MiniportCBList.Lock);
|
|
|
|
Status = NDISWAN_ERROR_NO_ROUTE;
|
|
|
|
break;
|
|
}
|
|
|
|
ASSERT(MiniportCB->ProtocolType == ProtocolCB->ProtocolType);
|
|
|
|
ETH_COPY_NETWORK_ADDRESS(ProtocolCB->NdisWanAddress, MiniportCB->NetworkAddress);
|
|
|
|
FillNdisWanIndices(ProtocolCB->NdisWanAddress,
|
|
BundleCB->hBundleHandle,
|
|
ProtocolCB->ProtocolHandle);
|
|
|
|
NdisZeroMemory(ProtocolCB->TransportAddress, 6);
|
|
|
|
NdisAcquireSpinLock(&MiniportCB->Lock);
|
|
|
|
InsertTailList(&MiniportCB->ProtocolCBList,
|
|
&ProtocolCB->MiniportLinkage);
|
|
|
|
ProtocolCB->MiniportCB = MiniportCB;
|
|
|
|
REF_MINIPORTCB(MiniportCB);
|
|
|
|
NdisReleaseSpinLock(&MiniportCB->Lock);
|
|
|
|
NdisReleaseSpinLock(&MiniportCBList.Lock);
|
|
|
|
Status = DoLineUpToProtocol(ProtocolCB);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS) {
|
|
|
|
NdisAcquireSpinLock(&MiniportCBList.Lock);
|
|
|
|
NdisAcquireSpinLock(&MiniportCB->Lock);
|
|
|
|
RemoveEntryList(&ProtocolCB->MiniportLinkage);
|
|
|
|
if (MiniportCB->Flags & HALT_IN_PROGRESS) {
|
|
NdisWanSetSyncEvent(&MiniportCB->HaltEvent);
|
|
}
|
|
|
|
NdisReleaseSpinLock(&MiniportCB->Lock);
|
|
|
|
NdisReleaseSpinLock(&MiniportCBList.Lock);
|
|
|
|
DEREF_MINIPORTCB(MiniportCB);
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("DoNewLineupToProtocols: Exit"));
|
|
|
|
return (Status);
|
|
}
|
|
|
|
NDIS_STATUS
|
|
DoLineUpToProtocol(
|
|
IN PPROTOCOLCB ProtocolCB
|
|
)
|
|
/*++
|
|
|
|
Routine Name:
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Values:
|
|
|
|
--*/
|
|
{
|
|
ULONG AllocationSize;
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
PNDIS_WAN_LINE_UP LineUpInfo;
|
|
PMINIPORTCB MiniportCB = ProtocolCB->MiniportCB;
|
|
PBUNDLECB BundleCB = ProtocolCB->BundleCB;
|
|
KIRQL OldIrql;
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("DoLineupToProtocol: Enter"));
|
|
|
|
ASSERT(MiniportCB != NULL);
|
|
|
|
AllocationSize = sizeof(NDIS_WAN_LINE_UP) +
|
|
ProtocolCB->ulLineUpInfoLength +
|
|
(sizeof(WCHAR) * (MAX_NAME_LENGTH + 1) +
|
|
(2 * sizeof(PVOID)));
|
|
|
|
NdisWanAllocateMemory(&LineUpInfo, AllocationSize, LINEUPINFO_TAG);
|
|
|
|
if (LineUpInfo != NULL) {
|
|
ULONG LineUpHandle = ProtocolCB->ulTransportHandle;
|
|
|
|
//
|
|
// Needs to be in 1/100bps, we store in Bps
|
|
//
|
|
LineUpInfo->LinkSpeed = BundleCB->SFlowSpec.PeakBandwidth * 8 / 100;
|
|
|
|
//
|
|
// Set the MTU for this protocol
|
|
//
|
|
{
|
|
POPENCB OpenCB = BundleCB->NextLinkToXmit->OpenCB;
|
|
|
|
//
|
|
// If this connection is running over a VPN we will downsize
|
|
// the MTU
|
|
//
|
|
if ((OpenCB->MediumSubType == NdisWanMediumPPTP ||
|
|
OpenCB->MediumSubType == NdisWanMediumL2TP)) {
|
|
LineUpInfo->MaximumTotalSize = ProtocolCB->TunnelMTU;
|
|
} else {
|
|
LineUpInfo->MaximumTotalSize = ProtocolCB->MTU;
|
|
}
|
|
|
|
if (LineUpInfo->MaximumTotalSize > BundleCB->SFlowSpec.MaxSduSize) {
|
|
LineUpInfo->MaximumTotalSize =
|
|
BundleCB->SFlowSpec.MaxSduSize;
|
|
}
|
|
|
|
#if 0
|
|
//
|
|
// Figure out the size of the ppp header...
|
|
//
|
|
BundleCB->FramingInfo.PPPHeaderLength =
|
|
CalcPPPHeaderLength(BundleCB->FramingInfo.SendFramingBits,
|
|
BundleCB->SendFlags);
|
|
|
|
if (LineUpInfo->MaximumTotalSize > BundleCB->FramingInfo.PPPHeaderLength) {
|
|
LineUpInfo->MaximumTotalSize -= BundleCB->FramingInfo.PPPHeaderLength;
|
|
} else {
|
|
LineUpInfo->MaximumTotalSize = 0;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
LineUpInfo->Quality = NdisWanReliable;
|
|
LineUpInfo->SendWindow = (USHORT)BundleCB->SendWindow;
|
|
LineUpInfo->ProtocolType = ProtocolCB->ProtocolType;
|
|
LineUpInfo->DeviceName.Length = ProtocolCB->InDeviceName.Length;
|
|
LineUpInfo->DeviceName.MaximumLength = MAX_NAME_LENGTH + 1;
|
|
LineUpInfo->DeviceName.Buffer = (PWCHAR)((PUCHAR)LineUpInfo +
|
|
sizeof(NDIS_WAN_LINE_UP) +
|
|
sizeof(PVOID));
|
|
(ULONG_PTR)LineUpInfo->DeviceName.Buffer &= ~((ULONG_PTR)sizeof(PVOID) - 1);
|
|
|
|
if (ProtocolCB->InDeviceName.Length != 0) {
|
|
|
|
NdisMoveMemory(LineUpInfo->DeviceName.Buffer,
|
|
ProtocolCB->InDeviceName.Buffer,
|
|
ProtocolCB->InDeviceName.Length);
|
|
}
|
|
|
|
|
|
LineUpInfo->ProtocolBuffer = (PUCHAR)LineUpInfo +
|
|
sizeof(NDIS_WAN_LINE_UP) +
|
|
(sizeof(WCHAR) * (MAX_NAME_LENGTH + 1) +
|
|
sizeof(PVOID));
|
|
(ULONG_PTR)LineUpInfo->ProtocolBuffer &= ~((ULONG_PTR)sizeof(PVOID) - 1);
|
|
|
|
//
|
|
//
|
|
// The Remote address (DEST address in a send) is what we use to
|
|
// mutilplex sends across our single adapter/binding context.
|
|
// The address has the following format:
|
|
//
|
|
// XX XX XX YY YY ZZ
|
|
//
|
|
// XX = Randomly generated OUI
|
|
// YY = Index into the active bundle connection table to get bundlecb
|
|
// ZZ = Index into the protocol table of a bundle to get protocolcb
|
|
//
|
|
ETH_COPY_NETWORK_ADDRESS(LineUpInfo->RemoteAddress,ProtocolCB->NdisWanAddress);
|
|
ETH_COPY_NETWORK_ADDRESS(LineUpInfo->LocalAddress,ProtocolCB->TransportAddress);
|
|
|
|
//
|
|
// Fill in the protocol specific information
|
|
//
|
|
LineUpInfo->ProtocolBufferLength = ProtocolCB->ulLineUpInfoLength;
|
|
if (ProtocolCB->ulLineUpInfoLength > 0) {
|
|
NdisMoveMemory(LineUpInfo->ProtocolBuffer,
|
|
ProtocolCB->LineUpInfo,
|
|
ProtocolCB->ulLineUpInfoLength);
|
|
}
|
|
|
|
// KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
|
|
|
|
// DbgPrint("LineUp: %x, MTU %d\n",
|
|
// LineUpInfo->ProtocolType, LineUpInfo->MaximumTotalSize);
|
|
|
|
//
|
|
// Do the line up indication
|
|
//
|
|
NdisMIndicateStatus(MiniportCB->MiniportHandle,
|
|
NDIS_STATUS_WAN_LINE_UP,
|
|
LineUpInfo,
|
|
AllocationSize);
|
|
|
|
// KeLowerIrql(OldIrql);
|
|
|
|
//
|
|
// Update protocol queue depth
|
|
//
|
|
{
|
|
PROTOCOL_INFO ProtocolInfo = {0};
|
|
ULONG ByteDepth;
|
|
ULONG i;
|
|
|
|
AcquireBundleLock(BundleCB);
|
|
|
|
ProtocolInfo.ProtocolType = ProtocolCB->ProtocolType;
|
|
GetProtocolInfo(&ProtocolInfo);
|
|
|
|
//
|
|
// Set the send queue byte depth.
|
|
//
|
|
ByteDepth =
|
|
ProtocolInfo.PacketQueueDepth;
|
|
|
|
//
|
|
// If the byte depth is less then 4
|
|
// full packets, then set it to 4 full
|
|
// packets.
|
|
//
|
|
if (ByteDepth < (ProtocolInfo.MTU * 4)) {
|
|
ByteDepth = ProtocolInfo.MTU * 4;
|
|
}
|
|
|
|
for (i = 0; i <= MAX_MCML; i++) {
|
|
ProtocolCB->PacketQueue[i].MaxByteDepth =
|
|
ByteDepth;
|
|
}
|
|
|
|
ReleaseBundleLock(BundleCB);
|
|
}
|
|
|
|
//
|
|
// If this was the first line up for this protocolcb and
|
|
// this lineup was answered we need to collect some info
|
|
//
|
|
if (ProtocolCB->ulTransportHandle == 0) {
|
|
|
|
*((ULONG UNALIGNED *)(&LineUpHandle)) =
|
|
*((ULONG UNALIGNED *)(&LineUpInfo->LocalAddress[2]));
|
|
|
|
if (LineUpHandle != 0) {
|
|
|
|
AcquireBundleLock(BundleCB);
|
|
|
|
ETH_COPY_NETWORK_ADDRESS(ProtocolCB->TransportAddress, LineUpInfo->LocalAddress);
|
|
|
|
ProtocolCB->ulTransportHandle = LineUpHandle;
|
|
|
|
if (LineUpInfo->DeviceName.Length != 0) {
|
|
NdisWanStringToNdisString(&ProtocolCB->OutDeviceName,
|
|
LineUpInfo->DeviceName.Buffer);
|
|
}
|
|
|
|
ReleaseBundleLock(BundleCB);
|
|
|
|
//
|
|
// If this is an nbf adapter
|
|
//
|
|
if (ProtocolCB->ProtocolType == (USHORT)PROTOCOL_NBF) {
|
|
|
|
ASSERT(MiniportCB->ProtocolType == (USHORT)PROTOCOL_NBF);
|
|
|
|
MiniportCB->NbfProtocolCB = ProtocolCB;
|
|
}
|
|
|
|
} else {
|
|
Status = NDISWAN_ERROR_NO_ROUTE;
|
|
}
|
|
}
|
|
|
|
NdisWanFreeMemory(LineUpInfo);
|
|
|
|
} else {
|
|
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("DoLineupToProtocol: Exit"));
|
|
|
|
return (Status);
|
|
}
|
|
|
|
NDIS_STATUS
|
|
DoLineDownToProtocol(
|
|
PPROTOCOLCB ProtocolCB
|
|
)
|
|
{
|
|
NDIS_WAN_LINE_DOWN WanLineDown;
|
|
PNDIS_WAN_LINE_DOWN LineDownInfo = &WanLineDown;
|
|
|
|
PMINIPORTCB MiniportCB = ProtocolCB->MiniportCB;
|
|
PBUNDLECB BundleCB = ProtocolCB->BundleCB;
|
|
|
|
KIRQL OldIrql;
|
|
|
|
//
|
|
// The Remote address (DEST address) is what we use to mutilplex
|
|
// sends across our single adapter/binding context. The address
|
|
// has the following format:
|
|
//
|
|
// XX XX YY YY YY YY
|
|
//
|
|
// XX = Randomly generated OUI
|
|
// YY = ProtocolCB
|
|
//
|
|
ETH_COPY_NETWORK_ADDRESS(LineDownInfo->RemoteAddress, ProtocolCB->NdisWanAddress);
|
|
ETH_COPY_NETWORK_ADDRESS(LineDownInfo->LocalAddress, ProtocolCB->TransportAddress);
|
|
|
|
//
|
|
// If this is an nbf adapter
|
|
//
|
|
if (ProtocolCB->ProtocolType == PROTOCOL_NBF) {
|
|
|
|
MiniportCB->NbfProtocolCB = NULL;
|
|
}
|
|
|
|
ProtocolCB->ulTransportHandle = 0;
|
|
ProtocolCB->State = PROTOCOL_UNROUTED;
|
|
|
|
ReleaseBundleLock(BundleCB);
|
|
|
|
NdisMIndicateStatus(MiniportCB->MiniportHandle,
|
|
NDIS_STATUS_WAN_LINE_DOWN,
|
|
LineDownInfo,
|
|
sizeof(NDIS_WAN_LINE_DOWN));
|
|
|
|
NdisAcquireSpinLock(&MiniportCB->Lock);
|
|
|
|
RemoveEntryList(&ProtocolCB->MiniportLinkage);
|
|
|
|
if (MiniportCB->Flags & HALT_IN_PROGRESS) {
|
|
NdisWanSetSyncEvent(&MiniportCB->HaltEvent);
|
|
}
|
|
|
|
NdisReleaseSpinLock(&MiniportCB->Lock);
|
|
|
|
DEREF_MINIPORTCB(MiniportCB);
|
|
|
|
AcquireBundleLock(BundleCB);
|
|
|
|
return (NDIS_STATUS_SUCCESS);
|
|
}
|
|
|
|
VOID
|
|
CompleteSendDesc(
|
|
PSEND_DESC SendDesc,
|
|
NDIS_STATUS Status
|
|
)
|
|
{
|
|
PLINKCB LinkCB;
|
|
PBUNDLECB BundleCB;
|
|
PPROTOCOLCB ProtocolCB;
|
|
PNDIS_PACKET OriginalPacket;
|
|
BOOLEAN FreeLink = FALSE, FreeBundle = FALSE;
|
|
BOOLEAN LegacyLink;
|
|
PULONG pulRefCount;
|
|
PCM_VCCB CmVcCB;
|
|
INT Class;
|
|
ULONG DescFlags;
|
|
|
|
LinkCB = SendDesc->LinkCB;
|
|
ProtocolCB = SendDesc->ProtocolCB;
|
|
OriginalPacket = SendDesc->OriginalPacket;
|
|
Class = SendDesc->Class;
|
|
DescFlags = SendDesc->Flags;
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_SEND,
|
|
("SendDesc: 0x%p, OriginalPacket: 0x%p, Status: %x",
|
|
SendDesc, OriginalPacket, Status));
|
|
|
|
NdisWanFreeSendDesc(SendDesc);
|
|
|
|
//
|
|
// Bundle that this link is on
|
|
//
|
|
BundleCB = LinkCB->BundleCB;
|
|
|
|
//
|
|
// Deref for the ref applied when a senddesc
|
|
// was retrieved for this link. We don't need to do
|
|
// the full deref here because we are keeping the
|
|
// link from going away with the ref applied when
|
|
// we got the sendcomplete.
|
|
//
|
|
--LinkCB->RefCount;
|
|
|
|
#ifdef DBG_SENDARRAY
|
|
{
|
|
SendArray[__si] = 'c';
|
|
if (++__si == MAX_BYTE_DEPTH) {
|
|
__si = 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
NdisReleaseSpinLock(&LinkCB->Lock);
|
|
|
|
AcquireBundleLock(BundleCB);
|
|
|
|
LegacyLink = (LinkCB->OpenCB->Flags & OPEN_LEGACY) ? 1 : 0;
|
|
|
|
//
|
|
// If the sendwindow is currently full, this completion
|
|
// opens the sendwindow.
|
|
//
|
|
if (LinkCB->OutstandingFrames == LinkCB->SendWindow) {
|
|
LinkCB->SendWindowOpen = TRUE;
|
|
if (LinkCB->LinkActive) {
|
|
BundleCB->SendingLinks++;
|
|
}
|
|
}
|
|
|
|
LinkCB->OutstandingFrames--;
|
|
|
|
if (DescFlags & SEND_DESC_FRAG) {
|
|
InterlockedDecrement(&ProtocolCB->PacketQueue[Class].OutstandingFrags);
|
|
}
|
|
|
|
pulRefCount =
|
|
&(PMINIPORT_RESERVED_FROM_NDIS(OriginalPacket)->RefCount);
|
|
|
|
ASSERT(*pulRefCount > 0);
|
|
|
|
//
|
|
// See if the reference count is zero, if it is not
|
|
// we just return.
|
|
//
|
|
if (InterlockedDecrement(pulRefCount) != 0) {
|
|
|
|
SendPacketOnBundle(BundleCB);
|
|
|
|
return;
|
|
}
|
|
|
|
ReleaseBundleLock(BundleCB);
|
|
|
|
//
|
|
// Complete this NdisPacket back to the transport
|
|
//
|
|
NDIS_SET_PACKET_STATUS(OriginalPacket, Status);
|
|
CompleteNdisPacket(ProtocolCB->MiniportCB,
|
|
ProtocolCB,
|
|
OriginalPacket);
|
|
|
|
AcquireBundleLock(BundleCB);
|
|
|
|
BundleCB->OutstandingFrames--;
|
|
|
|
if ((BundleCB->Flags & FRAMES_PENDING_EVENT) &&
|
|
(BundleCB->OutstandingFrames == 0)) {
|
|
|
|
NdisWanSetSyncEvent(&BundleCB->OutstandingFramesEvent);
|
|
}
|
|
|
|
//
|
|
// Called with bundle lock help but returns with lock released
|
|
//
|
|
SendPacketOnBundle(BundleCB);
|
|
|
|
//
|
|
// Deref for ref applied when sent a packet to be framed.
|
|
//
|
|
DEREF_BUNDLECB(BundleCB);
|
|
}
|
|
|
|
#if 0
|
|
ULONG
|
|
CalcPPPHeaderLength(
|
|
ULONG FramingBits,
|
|
ULONG Flags
|
|
)
|
|
{
|
|
ULONG HeaderLength = 0;
|
|
|
|
if (FramingBits & PPP_FRAMING) {
|
|
|
|
if (!(FramingBits & PPP_COMPRESS_ADDRESS_CONTROL)) {
|
|
//
|
|
// If there is no address/control compression
|
|
// we need a pointer and a length
|
|
//
|
|
|
|
if (FramingBits & LLC_ENCAPSULATION) {
|
|
HeaderLength += 4;
|
|
} else {
|
|
HeaderLength += 2;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If this is not from our private I/O interface we will
|
|
// build the rest of the header.
|
|
//
|
|
if (FramingBits & PPP_MULTILINK_FRAMING) {
|
|
|
|
if (!(FramingBits & PPP_COMPRESS_PROTOCOL_FIELD)) {
|
|
//
|
|
// No protocol compression
|
|
//
|
|
HeaderLength += 1;
|
|
}
|
|
|
|
HeaderLength += 1;
|
|
|
|
if (!(FramingBits & PPP_SHORT_SEQUENCE_HDR_FORMAT)) {
|
|
//
|
|
// We are using long sequence number
|
|
//
|
|
HeaderLength += 2;
|
|
}
|
|
|
|
HeaderLength += 2;
|
|
}
|
|
|
|
if (Flags & (DO_COMPRESSION | DO_ENCRYPTION)) {
|
|
//
|
|
// We are doing compression/encryption so we need
|
|
// a length
|
|
//
|
|
|
|
//
|
|
// It appears that legacy ras (< NT 4.0) requires that
|
|
// the PPP protocol field in a compressed packet not
|
|
// be compressed, ie has to have the leading 0x00
|
|
//
|
|
if (!(FramingBits & PPP_COMPRESS_PROTOCOL_FIELD)) {
|
|
//
|
|
// No protocol compression
|
|
//
|
|
HeaderLength += 1;
|
|
}
|
|
|
|
//
|
|
// Add protocol and coherency bytes
|
|
//
|
|
HeaderLength += 3;
|
|
}
|
|
|
|
|
|
if (!(FramingBits & PPP_COMPRESS_PROTOCOL_FIELD) ||
|
|
(Flags & (DO_COMPRESSION | DO_ENCRYPTION))) {
|
|
HeaderLength += 1;
|
|
}
|
|
|
|
HeaderLength += 1;
|
|
|
|
} else if (FramingBits & RAS_FRAMING) {
|
|
//
|
|
// If this is old ras framing:
|
|
//
|
|
// Alter the framing so that 0xFF 0x03 is not added
|
|
// and that the first byte is 0xFD not 0x00 0xFD
|
|
//
|
|
// So basically, a RAS compression looks like
|
|
// <0xFD> <2 BYTE COHERENCY> <NBF DATA FIELD>
|
|
//
|
|
// Whereas uncompressed looks like
|
|
// <NBF DATA FIELD> which always starts with 0xF0
|
|
//
|
|
// If this is ppp framing:
|
|
//
|
|
// A compressed frame will look like (before address/control
|
|
// - multilink is added)
|
|
// <0x00> <0xFD> <2 Byte Coherency> <Compressed Data>
|
|
//
|
|
if (Flags & (DO_COMPRESSION | DO_ENCRYPTION)) {
|
|
|
|
//
|
|
// Coherency bytes
|
|
//
|
|
HeaderLength += 3;
|
|
}
|
|
}
|
|
|
|
// DbgPrint("PPPHeaderLength %d\n", HeaderLength);
|
|
|
|
return (HeaderLength);
|
|
}
|
|
|
|
#endif
|