Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

723 lines
16 KiB

/*++
Copyright (c) 1990-1995 Microsoft Corporation
Module Name:
Protocol.c
Abstract:
This file contains the procedures that makeup most of the NDIS 3.1
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"
EXPORT
VOID
NdisTapiIndicateStatus(
IN NDIS_HANDLE BindingContext,
IN PVOID StatusBuffer,
IN UINT StatusBufferLength
);
NDIS_STATUS
DoLineUpWork(
IN PPROTOCOLCB ProtocolCB
);
NDIS_STATUS
DoLineDownWork(
PPROTOCOLCB ProtocolCB
);
NDIS_STATUS
NdisWanOpenWanAdapter(
IN PWAN_ADAPTERCB pWanAdapterCB
)
/*++
Routine Name:
Routine Description:
Arguments:
Return Values:
--*/
{
NDIS_STATUS Status, OpenErrorStatus;
ULONG SelectedMediumIndex;
NDIS_MEDIUM MediumArray[] = {NdisMediumWan};
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanOpenAdapter: Enter - AdapterName %ls", pWanAdapterCB->MiniportName.Buffer));
//
// This is the only initialization of this event
//
NdisWanInitializeNotificationEvent(&pWanAdapterCB->NotificationEvent);
NdisOpenAdapter(&Status,
&OpenErrorStatus,
&(pWanAdapterCB->hNdisBindingHandle),
&SelectedMediumIndex,
MediumArray,
sizeof(MediumArray) / sizeof(NDIS_MEDIUM),
NdisWanCB.hProtocolHandle,
(NDIS_HANDLE)pWanAdapterCB,
&(pWanAdapterCB->MiniportName),
0,
NULL);
if (Status == NDIS_STATUS_PENDING) {
NdisWanWaitForNotificationEvent(&pWanAdapterCB->NotificationEvent);
Status = pWanAdapterCB->NotificationStatus;
NdisWanClearNotificationEvent(&pWanAdapterCB->NotificationEvent);
}
//
// Medium type must be WAN!
//
pWanAdapterCB->MediumType = NdisMediumWan;
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanOpenAdapter: Exit"));
return (Status);
}
VOID
NdisWanOpenAdapterComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status,
IN NDIS_STATUS OpenErrorStatus
)
/*++
Routine Name:
Routine Description:
Arguments:
Return Values:
--*/
{
PWAN_ADAPTERCB pWanAdapterCB = (PWAN_ADAPTERCB)ProtocolBindingContext;
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanOpenAdapterComplete: Enter - WanAdapterCB 0x%4.4x", pWanAdapterCB));
pWanAdapterCB->NotificationStatus = Status;
NdisWanSetNotificationEvent(&pWanAdapterCB->NotificationEvent);
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanOpenAdapterComplete: Exit"));
}
VOID
NdisWanCloseAdapterComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status
)
/*++
Routine Name:
Routine Description:
Arguments:
Return Values:
--*/
{
PWAN_ADAPTERCB pWanAdapterCB = (PWAN_ADAPTERCB)ProtocolBindingContext;
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanCloseAdapterComplete: Enter"));
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("WanAdapterCB 0x%4.4x", pWanAdapterCB));
pWanAdapterCB->NotificationStatus = Status;
NdisWanSetNotificationEvent(&pWanAdapterCB->NotificationEvent);
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanCloseAdapterComplete: Exit"));
}
VOID
NdisWanResetComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status
)
/*++
Routine Name:
Routine Description:
Arguments:
Return Values:
--*/
{
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanResetComplete: Enter"));
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanResetComplete: Exit"));
}
VOID
NdisWanTransferDataComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET pNdisPacket,
IN NDIS_STATUS Status,
IN UINT BytesTransferred
)
/*++
Routine Name:
Routine Description:
Arguments:
Return Values:
--*/
{
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanTransferDataComplete: Enter"));
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanTransferDataComplete: Exit"));
}
VOID
NdisWanRequestComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_REQUEST NdisRequest,
IN NDIS_STATUS Status
)
/*++
Routine Name:
Routine Description:
Arguments:
Return Values:
--*/
{
PWAN_ADAPTERCB pWanAdapterCB = (PWAN_ADAPTERCB)ProtocolBindingContext;
PWAN_REQUEST pWanRequest = GetWanRequest(pWanAdapterCB, NdisRequest);
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanRequestComplete: Enter - pWanRequest: 0x%8.8x", pWanRequest));
pWanRequest->NotificationStatus = Status;
switch (pWanRequest->Origin) {
case NDISTAPI:
NdisWanTapiRequestComplete(pWanAdapterCB, pWanRequest);
break;
default:
NdisWanSetNotificationEvent(&pWanRequest->NotificationEvent);
break;
}
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanRequestComplete: Exit"));
}
VOID
NdisWanIndicateStatus(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS GeneralStatus,
IN PVOID StatusBuffer,
IN UINT StatusBufferSize
)
/*++
Routine Name:
Routine Description:
Arguments:
Return Values:
--*/
{
PWAN_ADAPTERCB pWanAdapterCB = (PWAN_ADAPTERCB)ProtocolBindingContext;
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanIndicateStatus: Enter"));
switch (GeneralStatus) {
case NDIS_STATUS_WAN_LINE_UP:
NdisWanLineUpIndication(pWanAdapterCB,
StatusBuffer,
StatusBufferSize);
break;
case NDIS_STATUS_WAN_LINE_DOWN:
NdisWanLineDownIndication(pWanAdapterCB,
StatusBuffer,
StatusBufferSize);
break;
case NDIS_STATUS_WAN_FRAGMENT:
NdisWanFragmentIndication(pWanAdapterCB,
StatusBuffer,
StatusBufferSize);
break;
case NDIS_STATUS_TAPI_INDICATION:
NdisWanTapiIndication(pWanAdapterCB,
StatusBuffer,
StatusBufferSize);
break;
default:
NdisWanDbgOut(DBG_INFO, DBG_PROTOCOL, ("Unknown Status Indication: 0x%8.8x", GeneralStatus));
break;
}
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanIndicateStatus: Exit"));
}
VOID
NdisWanIndicateStatusComplete(
IN NDIS_HANDLE BindingContext
)
/*++
Routine Name:
Routine Description:
Arguments:
Return Values:
--*/
{
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanIndicateStatusComplete: Enter"));
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("NdisWanIndicateStatusComplete: Exit"));
}
NDIS_STATUS
DoNewLineUpToProtocol(
PPROTOCOLCB ProtocolCB
)
/*++
Routine Name:
Routine Description:
Arguments:
Return Values:
--*/
{
PADAPTERCB AdapterCB;
NDIS_STATUS Status = STATUS_SUCCESS;
PBUNDLECB BundleCB = ProtocolCB->BundleCB;
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("DoNewLineupToProtocol: Enter"));
//
// Find the adapter that this lineup is for
//
NdisAcquireSpinLock(&AdapterCBList.Lock);
for (AdapterCB = (PADAPTERCB)AdapterCBList.List.Flink;
(PVOID)AdapterCB != (PVOID)&AdapterCBList.List;
AdapterCB = (PADAPTERCB)AdapterCB->Linkage.Flink) {
if (NdisWanCompareNdisString(&AdapterCB->AdapterName,
&ProtocolCB->BindingName)) {
break;
}
}
NdisReleaseSpinLock(&AdapterCBList.Lock);
if ((PVOID)AdapterCB != (PVOID)&AdapterCBList.List) {
ASSERT(AdapterCB->ProtocolType == ProtocolCB->usProtocolType);
ETH_COPY_NETWORK_ADDRESS(ProtocolCB->NdisWanAddress, AdapterCB->NetworkAddress);
//
// Put the protocol index in place
//
FillNdisWanProtocolIndex(ProtocolCB->NdisWanAddress, ProtocolCB->hProtocolHandle);
//
// Put the bundle index in place
//
FillNdisWanBundleIndex(ProtocolCB->NdisWanAddress, BundleCB->hBundleHandle);
NdisZeroMemory(ProtocolCB->TransportAddress, 6);
FillTransportBundleIndex(ProtocolCB->TransportAddress, BundleCB->hBundleHandle);
ProtocolCB->AdapterCB = AdapterCB;
Status = DoLineUpToProtocol(ProtocolCB);
} else {
Status = NDISWAN_ERROR_NO_ROUTE;
NdisWanDbgOut(DBG_FAILURE, DBG_PROTOCOL, ("Adapter not found!"));
}
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("DoNewLineupToProtocols: Exit"));
return (Status);
}
NDIS_STATUS
DoLineUpToProtocol(
IN PPROTOCOLCB ProtocolCB
)
/*++
Routine Name:
Routine Description:
Arguments:
Return Values:
--*/
{
NDIS_STATUS Status;
PDEFERRED_DESC DeferredDesc;
PADAPTERCB AdapterCB = ProtocolCB->AdapterCB;
#if TRY_IMMEDIATE_LINEUP
if (NdisWanAcquireMiniportLock(AdapterCB)) {
NdisAcquireSpinLock(&AdapterCB->Lock);
if (IsDeferredQueueEmpty(&AdapterCB->DeferredQueue[StatusIndication])) {
NdisReleaseSpinLock(&AdapterCB->Lock);
Status = DoLineUpWork(ProtocolCB);
NdisWanReleaseMiniportLock(AdapterCB);
return (Status);
}
NdisReleaseSpinLock(&AdapterCB->Lock);
NdisWanReleaseMiniportLock(AdapterCB);
}
#endif
NdisAcquireSpinLock(&AdapterCB->Lock);
//
// Queue up a deferred work item
//
NdisWanGetDeferredDesc(AdapterCB, &DeferredDesc);
DeferredDesc->Context = ProtocolCB;
DeferredDesc->Type = LineUp;
InsertTailDeferredQueue(&AdapterCB->DeferredQueue[StatusIndication],
DeferredDesc);
NdisWanSetDeferred(AdapterCB);
NdisReleaseSpinLock(&AdapterCB->Lock);
Status = NDIS_STATUS_PENDING;
return (Status);
}
NDIS_STATUS
DoLineUpWork(
PPROTOCOLCB ProtocolCB
)
{
ULONG i, AllocationSize;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PNDIS_WAN_LINE_UP LineUpInfo;
PADAPTERCB AdapterCB = ProtocolCB->AdapterCB;
PBUNDLECB BundleCB = ProtocolCB->BundleCB;
PBUNDLE_LINE_UP BundleLineUpInfo = &BundleCB->LineUpInfo;
NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("DoLineupToProtocol: Enter"));
ASSERT(AdapterCB != NULL);
AllocationSize = sizeof(NDIS_WAN_LINE_UP) +
ProtocolCB->ulLineUpInfoLength +
(sizeof(WCHAR) * (MAX_NAME_LENGTH + 1) +
(2 * sizeof(PVOID)));
NdisWanAllocateMemory(&LineUpInfo, AllocationSize);
if (LineUpInfo != NULL) {
NDIS_HANDLE LineUpHandle = ProtocolCB->hTransportHandle;
//
// Fill values that are common to all protocols on this bundle
//
LineUpInfo->LinkSpeed = BundleLineUpInfo->BundleSpeed;
LineUpInfo->MaximumTotalSize = BundleLineUpInfo->ulMaximumTotalSize;
LineUpInfo->Quality = BundleLineUpInfo->Quality;
LineUpInfo->SendWindow = BundleLineUpInfo->usSendWindow;
LineUpInfo->ProtocolType = ProtocolCB->usProtocolType;
LineUpInfo->DeviceName.Length = 0;
LineUpInfo->DeviceName.MaximumLength = MAX_NAME_LENGTH + 1;
LineUpInfo->DeviceName.Buffer = (PWCHAR)((PUCHAR)LineUpInfo +
sizeof(NDIS_WAN_LINE_UP));
(ULONG)LineUpInfo->DeviceName.Buffer &= (ULONG)~(sizeof(PVOID) - 1);
LineUpInfo->ProtocolBuffer = (PUCHAR)LineUpInfo +
sizeof(NDIS_WAN_LINE_UP) +
(sizeof(WCHAR) * (MAX_NAME_LENGTH + 1) +
sizeof(PVOID));
(ULONG)LineUpInfo->ProtocolBuffer &= (ULONG)~(sizeof(PVOID) - 1);
//
// The Local address(SRC address in a send), is used
// to figure out what bundle to send across if the
// DEST address is a multicast. We use the two high
// order bytes of the address. The transport uses the
// other four bytes for a context on receive.
//
//
// 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;
NdisMoveMemory(LineUpInfo->ProtocolBuffer,
ProtocolCB->LineUpInfo,
ProtocolCB->ulLineUpInfoLength);
//
// Do the line up indication
//
NdisMIndicateStatus(AdapterCB->hMiniportHandle,
NDIS_STATUS_WAN_LINE_UP,
LineUpInfo,
AllocationSize);
*((ULONG UNALIGNED *)(&LineUpHandle)) = *((ULONG UNALIGNED *)(&LineUpInfo->LocalAddress[2]));
//
// If this was the first line up for this protocolcb and
// this lineup was answered we need to collect some info
//
if (ProtocolCB->hTransportHandle == NULL) {
if (LineUpHandle != NULL) {
NdisAcquireSpinLock(&BundleCB->Lock);
ETH_COPY_NETWORK_ADDRESS(ProtocolCB->TransportAddress, LineUpInfo->LocalAddress);
ProtocolCB->hTransportHandle = LineUpHandle;
if (LineUpInfo->DeviceName.Length != 0) {
NdisWanStringToNdisString(&ProtocolCB->DeviceName,
LineUpInfo->DeviceName.Buffer);
}
NdisReleaseSpinLock(&BundleCB->Lock);
//
// If this is an nbf adapter
//
if (ProtocolCB->usProtocolType == PROTOCOL_NBF) {
ASSERT(AdapterCB->ProtocolType == PROTOCOL_NBF);
AdapterCB->NbfBundleCB = BundleCB;
AdapterCB->NbfProtocolHandle = ProtocolCB->hProtocolHandle;
}
} 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
)
{
PADAPTERCB AdapterCB = ProtocolCB->AdapterCB;
PDEFERRED_DESC DeferredDesc;
//
// We are always going to defer the line down. This will
// allow us to complete all sends and process all loopbacks
// before doing the linedown.
//
NdisAcquireSpinLock(&AdapterCB->Lock);
//
// Queue up a deferred work item
//
NdisWanGetDeferredDesc(AdapterCB, &DeferredDesc);
DeferredDesc->Context = ProtocolCB;
DeferredDesc->Type = LineDown;
InsertTailDeferredQueue(&AdapterCB->DeferredQueue[StatusIndication],
DeferredDesc);
NdisWanSetDeferred(AdapterCB);
NdisReleaseSpinLock(&AdapterCB->Lock);
return (NDIS_STATUS_PENDING);
}
NDIS_STATUS
DoLineDownWork(
PPROTOCOLCB ProtocolCB
)
{
NDIS_WAN_LINE_DOWN WanLineDown;
PNDIS_WAN_LINE_DOWN LineDownInfo = &WanLineDown;
PADAPTERCB AdapterCB = ProtocolCB->AdapterCB;
//
// 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 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(LineDownInfo->RemoteAddress, ProtocolCB->NdisWanAddress);
ETH_COPY_NETWORK_ADDRESS(LineDownInfo->LocalAddress, ProtocolCB->TransportAddress);
//
// If this is an nbf adapter
//
if (ProtocolCB->usProtocolType == PROTOCOL_NBF) {
ASSERT(AdapterCB->ProtocolType == PROTOCOL_NBF);
AdapterCB->NbfBundleCB = NULL;
(ULONG)AdapterCB->NbfProtocolHandle = MAX_PROTOCOLS + 1;
}
ProtocolCB->hTransportHandle = NULL;
NdisMIndicateStatus(AdapterCB->hMiniportHandle,
NDIS_STATUS_WAN_LINE_DOWN,
LineDownInfo,
sizeof(NDIS_WAN_LINE_DOWN));
return (NDIS_STATUS_SUCCESS);
}
VOID
NdisWanProcessStatusIndications(
PADAPTERCB AdapterCB
)
{
NDIS_STATUS Status;
while (!IsDeferredQueueEmpty(&AdapterCB->DeferredQueue[StatusIndication])) {
PPROTOCOLCB ProtocolCB;
PBUNDLECB BundleCB;
ULONG DescType;
PDEFERRED_DESC ReturnDesc;
ReturnDesc = RemoveHeadDeferredQueue(&AdapterCB->DeferredQueue[StatusIndication]);
NdisReleaseSpinLock(&AdapterCB->Lock);
ProtocolCB = ReturnDesc->Context;
BundleCB= ProtocolCB->BundleCB;
DescType = ReturnDesc->Type;
ASSERT((DescType == LineUp) || (DescType == LineDown));
if (DescType == LineUp) {
Status = DoLineUpWork(ProtocolCB);
}else {
Status = DoLineDownWork(ProtocolCB);
}
NdisAcquireSpinLock(&AdapterCB->Lock);
InsertHeadDeferredQueue(&AdapterCB->FreeDeferredQueue, ReturnDesc);
NdisAcquireSpinLock(&BundleCB->Lock);
BundleCB->IndicationStatus = Status;
NdisWanSetSyncEvent(&BundleCB->IndicationEvent);
NdisReleaseSpinLock(&BundleCB->Lock);
}
}