3190 lines
76 KiB
C
3190 lines
76 KiB
C
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
atkndis.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the support code for the stack dealing with
|
|
the NDIS 3.0 interface. The NDIS Init/Deinit and the ndis-protocol
|
|
interface code.
|
|
|
|
Author:
|
|
|
|
Jameel Hyder (jameelh@microsoft.com)
|
|
Nikhil Kamkolkar (nikhilk@microsoft.com)
|
|
|
|
Revision History:
|
|
19 Jun 1992 Initial Version
|
|
|
|
Notes: Tab stop: 4
|
|
--*/
|
|
|
|
#include <atalk.h>
|
|
#pragma hdrstop
|
|
#define FILENUM ATKNDIS
|
|
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(INIT, AtalkNdisInitRegisterProtocol)
|
|
#pragma alloc_text(INIT, atalkNdisInitInitializeResources)
|
|
#pragma alloc_text(PAGEINIT, AtalkNdisInitBind)
|
|
#pragma alloc_text(PAGEINIT, AtalkInitNdisQueryAddrInfo)
|
|
#pragma alloc_text(PAGEINIT, AtalkInitNdisSetLookaheadSize)
|
|
#pragma alloc_text(PAGEINIT, AtalkInitNdisStartPacketReception)
|
|
#pragma alloc_text(PAGEINIT, AtalkBindAdapter)
|
|
#pragma alloc_text(PAGEINIT, AtalkUnbindAdapter)
|
|
#endif
|
|
|
|
|
|
ATALK_ERROR
|
|
AtalkNdisInitRegisterProtocol(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called during initialization time to register the protocol
|
|
with NDIS.
|
|
|
|
Arguments:
|
|
|
|
NameString- The name to be registered for this protocol- human-readable form
|
|
|
|
Return Value:
|
|
|
|
Status - TRUE if register went ok, FALSE otherwise.
|
|
--*/
|
|
{
|
|
NDIS_STATUS ndisStatus;
|
|
UNICODE_STRING RegName;
|
|
NDIS_PROTOCOL_CHARACTERISTICS protocolInfo;
|
|
|
|
RtlZeroMemory(&protocolInfo, sizeof(protocolInfo));
|
|
RtlInitUnicodeString(&RegName, PROTOCOL_REGISTER_NAME);
|
|
|
|
// Set up the characteristics for the protocol for registering with NDIS
|
|
protocolInfo.MajorNdisVersion = PROTOCOL_MAJORNDIS_VERSION;
|
|
protocolInfo.MinorNdisVersion = PROTOCOL_MINORNDIS_VERSION;
|
|
protocolInfo.Name.Length = RegName.Length;
|
|
protocolInfo.Name.Buffer = (PVOID)RegName.Buffer;
|
|
|
|
protocolInfo.OpenAdapterCompleteHandler = AtalkOpenAdapterComplete;
|
|
protocolInfo.CloseAdapterCompleteHandler = AtalkCloseAdapterComplete;
|
|
protocolInfo.ResetCompleteHandler = AtalkResetComplete;
|
|
protocolInfo.RequestCompleteHandler = AtalkRequestComplete;
|
|
|
|
protocolInfo.SendCompleteHandler = AtalkSendComplete;
|
|
protocolInfo.TransferDataCompleteHandler = AtalkTransferDataComplete;
|
|
|
|
protocolInfo.ReceiveHandler = AtalkReceiveIndication;
|
|
protocolInfo.ReceiveCompleteHandler = AtalkReceiveComplete;
|
|
protocolInfo.StatusHandler = AtalkStatusIndication;
|
|
protocolInfo.StatusCompleteHandler = AtalkStatusComplete;
|
|
|
|
protocolInfo.BindAdapterHandler = AtalkBindAdapter;
|
|
protocolInfo.UnbindAdapterHandler = AtalkUnbindAdapter;
|
|
|
|
protocolInfo.PnPEventHandler = AtalkPnPHandler;
|
|
|
|
ndisStatus = atalkNdisInitInitializeResources();
|
|
|
|
if (ndisStatus == NDIS_STATUS_SUCCESS)
|
|
{
|
|
NdisRegisterProtocol(&ndisStatus,
|
|
&AtalkNdisProtocolHandle,
|
|
&protocolInfo,
|
|
(UINT)sizeof(NDIS_PROTOCOL_CHARACTERISTICS)+RegName.Length);
|
|
|
|
if (ndisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
LOG_ERROR(EVENT_ATALK_REGISTERPROTOCOL, ndisStatus, NULL, 0);
|
|
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
|
|
("AtalkNdisRegister: failed %ul\n", ndisStatus));
|
|
}
|
|
}
|
|
|
|
return AtalkNdisToAtalkError(ndisStatus);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AtalkNdisDeregisterProtocol(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to deregister the protocol
|
|
|
|
Arguments:
|
|
|
|
NONE
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
--*/
|
|
{
|
|
NDIS_STATUS ndisStatus;
|
|
|
|
if (AtalkNdisProtocolHandle != (NDIS_HANDLE)NULL)
|
|
{
|
|
NdisDeregisterProtocol(&ndisStatus, AtalkNdisProtocolHandle);
|
|
|
|
AtalkNdisProtocolHandle = (NDIS_HANDLE)NULL;
|
|
if (ndisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
LOG_ERROR(EVENT_ATALK_DEREGISTERPROTOCOL, ndisStatus, NULL, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERTMSG("AtalkNdisDeregisterProtocol: NULL ProtocolHandle\n", FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
LOCAL NDIS_STATUS
|
|
atalkNdisInitInitializeResources(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
Status - STATUS_SUCCESS if all resources were allocated
|
|
STATUS_INSUFFICIENT_RESOURCES otherwise.
|
|
--*/
|
|
{
|
|
NDIS_STATUS ndisStatus;
|
|
LONG numPktDescs, numBufDescs;
|
|
|
|
numPktDescs = NUM_PACKET_DESCRIPTORS;
|
|
if (AtalkRouter)
|
|
{
|
|
numPktDescs *= ROUTING_FACTOR;
|
|
}
|
|
|
|
numBufDescs = NUM_BUFFER_DESCRIPTORS;
|
|
if (AtalkRouter)
|
|
{
|
|
numBufDescs *= ROUTING_FACTOR;
|
|
}
|
|
|
|
do
|
|
{
|
|
// Setup the ndis packet descriptor pools in the Port descriptor
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
|
|
("atalkNdisInitInitializeResources: Allocating %ld Packets\n",
|
|
numPktDescs));
|
|
|
|
AtalkNdisPacketPoolHandle = (PVOID)NDIS_PACKET_POOL_TAG_FOR_APPLETALK;
|
|
|
|
NdisAllocatePacketPoolEx(&ndisStatus,
|
|
&AtalkNdisPacketPoolHandle,
|
|
numPktDescs,
|
|
numPktDescs*200, // Overflow descriptors
|
|
sizeof(PROTOCOL_RESD));
|
|
|
|
if ((ndisStatus != NDIS_STATUS_SUCCESS) && (ndisStatus != NDIS_STATUS_PENDING))
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Setup the ndis buffer descriptor pool
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
|
|
("atalkNdisInitInitializeResources: Allocating %ld buffers\n",
|
|
numBufDescs));
|
|
NdisAllocateBufferPool(&ndisStatus,
|
|
&AtalkNdisBufferPoolHandle,
|
|
numBufDescs);
|
|
|
|
if ((ndisStatus != NDIS_STATUS_SUCCESS) && (ndisStatus != NDIS_STATUS_PENDING))
|
|
{
|
|
NdisFreePacketPool(AtalkNdisPacketPoolHandle);
|
|
AtalkNdisPacketPoolHandle = NULL;
|
|
}
|
|
} while (FALSE);
|
|
|
|
if (ndisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
LOG_ERROR(EVENT_ATALK_NDISRESOURCES, ndisStatus, NULL, 0);
|
|
}
|
|
|
|
return ndisStatus;
|
|
}
|
|
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
AtalkNdisInitBind(
|
|
IN OUT PPORT_DESCRIPTOR pPortDesc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS ndisStatus, openStatus, queryStatus;
|
|
ATALK_ERROR error;
|
|
UINT selectedMediumIndex;
|
|
NDIS_STRING FriendlyName;
|
|
|
|
// reference the port for bind
|
|
AtalkPortReferenceByPtr(pPortDesc, &error);
|
|
if (error != ATALK_NO_ERROR)
|
|
{
|
|
return(STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
// Reset event before possible wait
|
|
KeClearEvent(&pPortDesc->pd_RequestEvent);
|
|
|
|
NdisOpenAdapter(&ndisStatus, // open status
|
|
&openStatus, // more info not used
|
|
&pPortDesc->pd_NdisBindingHandle,
|
|
&selectedMediumIndex,
|
|
AtalkSupportedMedia,
|
|
AtalkSupportedMediaSize,
|
|
AtalkNdisProtocolHandle,
|
|
(NDIS_HANDLE)pPortDesc,
|
|
(PNDIS_STRING)&pPortDesc->pd_AdapterName,
|
|
0, // Open options
|
|
NULL); // Addressing information
|
|
|
|
|
|
if (ndisStatus == NDIS_STATUS_PENDING)
|
|
{
|
|
DBGPRINT(DBG_COMP_NDISREQ, DBG_LEVEL_WARN,
|
|
("AtalkNdisInitBind: OpenAdapter is pending for %Z\n",
|
|
&pPortDesc->pd_AdapterKey));
|
|
|
|
// Make sure we are not at or above dispatch level
|
|
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
// Wait on event, completion routine will set NdisRequestEvent
|
|
// Use wrappers
|
|
KeWaitForSingleObject(&pPortDesc->pd_RequestEvent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
ndisStatus = pPortDesc->pd_RequestStatus;
|
|
}
|
|
|
|
if (ndisStatus == NDIS_STATUS_SUCCESS)
|
|
{
|
|
PPORT_HANDLERS pPortHandler;
|
|
|
|
pPortDesc->pd_Flags |= PD_BOUND;
|
|
pPortDesc->pd_NdisPortType = AtalkSupportedMedia[selectedMediumIndex];
|
|
pPortDesc->pd_PortType = GET_PORT_TYPE(pPortDesc->pd_NdisPortType);
|
|
|
|
if (pPortDesc->pd_PortType != ALAP_PORT)
|
|
{
|
|
pPortDesc->pd_Flags |= PD_EXT_NET;
|
|
}
|
|
else if (pPortDesc->pd_Flags & PD_SEED_ROUTER)
|
|
{
|
|
pPortDesc->pd_InitialNetworkRange.anr_LastNetwork =
|
|
pPortDesc->pd_InitialNetworkRange.anr_FirstNetwork;
|
|
}
|
|
|
|
// is this a RAS port?
|
|
if (pPortDesc->pd_NdisPortType == NdisMediumWan)
|
|
{
|
|
pPortDesc->pd_Flags |= PD_RAS_PORT;
|
|
RasPortDesc = pPortDesc;
|
|
}
|
|
|
|
// Set stuff from the PortHandler structure to the port descriptor
|
|
pPortHandler = &AtalkPortHandlers[pPortDesc->pd_PortType];
|
|
pPortDesc->pd_AddMulticastAddr = pPortHandler->ph_AddMulticastAddr;
|
|
pPortDesc->pd_RemoveMulticastAddr = pPortHandler->ph_RemoveMulticastAddr;
|
|
pPortDesc->pd_AarpProtocolType = pPortHandler->ph_AarpProtocolType;
|
|
pPortDesc->pd_AarpHardwareType = pPortHandler->ph_AarpHardwareType;
|
|
pPortDesc->pd_BroadcastAddrLen = pPortHandler->ph_BroadcastAddrLen;
|
|
RtlCopyMemory(pPortDesc->pd_BroadcastAddr,
|
|
pPortHandler->ph_BroadcastAddr,
|
|
pPortHandler->ph_BroadcastAddrLen);
|
|
|
|
FriendlyName.MaximumLength = FriendlyName.Length = 0;
|
|
FriendlyName.Buffer = NULL;
|
|
|
|
queryStatus = NdisQueryAdapterInstanceName(&FriendlyName,
|
|
pPortDesc->pd_NdisBindingHandle);
|
|
if (queryStatus == NDIS_STATUS_SUCCESS)
|
|
{
|
|
ASSERT((FriendlyName.Buffer != NULL) && (FriendlyName.Length > 0));
|
|
|
|
pPortDesc->pd_FriendlyAdapterName.Buffer =
|
|
AtalkAllocZeroedMemory(FriendlyName.Length + sizeof(WCHAR));
|
|
|
|
if (pPortDesc->pd_FriendlyAdapterName.Buffer != NULL)
|
|
{
|
|
pPortDesc->pd_FriendlyAdapterName.MaximumLength =
|
|
FriendlyName.MaximumLength;
|
|
pPortDesc->pd_FriendlyAdapterName.Length = FriendlyName.Length;
|
|
|
|
RtlCopyMemory(pPortDesc->pd_FriendlyAdapterName.Buffer,
|
|
FriendlyName.Buffer,
|
|
FriendlyName.Length);
|
|
}
|
|
|
|
NdisFreeString(FriendlyName);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOG_ERRORONPORT(pPortDesc,
|
|
EVENT_ATALK_OPENADAPTER,
|
|
ndisStatus,
|
|
NULL,
|
|
0);
|
|
AtalkPortDereference(pPortDesc);
|
|
}
|
|
|
|
return ndisStatus;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkNdisUnbind(
|
|
IN PPORT_DESCRIPTOR pPortDesc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS ndisStatus;
|
|
KIRQL OldIrql;
|
|
|
|
// Reset event before possible wait
|
|
KeClearEvent(&pPortDesc->pd_RequestEvent);
|
|
|
|
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
NdisCloseAdapter(&ndisStatus, pPortDesc->pd_NdisBindingHandle);
|
|
|
|
if (ndisStatus == NDIS_STATUS_PENDING)
|
|
{
|
|
DBGPRINT(DBG_COMP_NDISREQ, DBG_LEVEL_WARN,
|
|
("AtalkNdisUnbind: pending for close!\n"));
|
|
|
|
// Make sure we are not at or above dispatch level
|
|
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
// Wait on event, completion routine will set NdisRequestEvent
|
|
KeWaitForSingleObject(&pPortDesc->pd_RequestEvent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
ndisStatus = pPortDesc->pd_RequestStatus;
|
|
}
|
|
|
|
if (ndisStatus == NDIS_STATUS_SUCCESS)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
|
|
("AtalkNdisUnbind: CloseAdapter on %Z completed successfully\n",
|
|
((pPortDesc->pd_FriendlyAdapterName.Buffer) ?
|
|
(&pPortDesc->pd_FriendlyAdapterName) : (&pPortDesc->pd_AdapterName))
|
|
));
|
|
|
|
|
|
ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
|
|
pPortDesc->pd_Flags &= ~PD_BOUND;
|
|
RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
|
|
|
|
// Remove the reference added at bind time
|
|
AtalkPortDereference(pPortDesc);
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
|
|
("AtalkNdisUnbind: CloseAdapter on %Z failed %lx\n",
|
|
((pPortDesc->pd_FriendlyAdapterName.Buffer) ?
|
|
(&pPortDesc->pd_FriendlyAdapterName) : (&pPortDesc->pd_AdapterName)),
|
|
ndisStatus
|
|
));
|
|
|
|
|
|
LOG_ERRORONPORT(pPortDesc,
|
|
EVENT_ATALK_CLOSEADAPTER,
|
|
ndisStatus,
|
|
NULL,
|
|
0);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AtalkNdisReleaseResources(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
None
|
|
--*/
|
|
{
|
|
if (AtalkNdisPacketPoolHandle != NULL)
|
|
{
|
|
NdisFreePacketPool(AtalkNdisPacketPoolHandle);
|
|
AtalkNdisPacketPoolHandle = NULL;
|
|
}
|
|
if (AtalkNdisBufferPoolHandle)
|
|
{
|
|
NdisFreeBufferPool(AtalkNdisBufferPoolHandle);
|
|
AtalkNdisBufferPoolHandle = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
ATALK_ERROR
|
|
AtalkInitNdisQueryAddrInfo(
|
|
IN PPORT_DESCRIPTOR pPortDesc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
NDIS_OID ndisOid;
|
|
ULONG macOptions;
|
|
PBYTE address;
|
|
UINT addressLength;
|
|
|
|
// We assume a single thread/init time behavior
|
|
NDIS_REQUEST request;
|
|
NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS;
|
|
|
|
do
|
|
{
|
|
// Check to see it we bound successfully to this adapter
|
|
if (!PORT_BOUND(pPortDesc))
|
|
{
|
|
LOG_ERRORONPORT(pPortDesc,
|
|
EVENT_ATALK_NOTBOUNDTOMAC,
|
|
STATUS_INSUFFICIENT_RESOURCES,
|
|
NULL,
|
|
0);
|
|
|
|
ndisStatus = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
switch (pPortDesc->pd_NdisPortType)
|
|
{
|
|
case NdisMedium802_3 :
|
|
ndisOid = OID_802_3_CURRENT_ADDRESS;
|
|
address = &pPortDesc->pd_PortAddr[0];
|
|
addressLength = MAX_HW_ADDR_LEN;
|
|
break;
|
|
|
|
case NdisMediumFddi :
|
|
ndisOid = OID_FDDI_LONG_CURRENT_ADDR;
|
|
address = &pPortDesc->pd_PortAddr[0];
|
|
addressLength = MAX_HW_ADDR_LEN;
|
|
break;
|
|
|
|
case NdisMedium802_5:
|
|
ndisOid = OID_802_5_CURRENT_ADDRESS;
|
|
address = &pPortDesc->pd_PortAddr[0];
|
|
addressLength = MAX_HW_ADDR_LEN;
|
|
break;
|
|
|
|
case NdisMediumLocalTalk :
|
|
ndisOid = OID_LTALK_CURRENT_NODE_ID;
|
|
address = (PBYTE)&pPortDesc->pd_AlapNode;
|
|
addressLength = sizeof(pPortDesc->pd_AlapNode);
|
|
break;
|
|
|
|
case NdisMediumWan:
|
|
ndisOid = OID_WAN_CURRENT_ADDRESS;
|
|
// NOTE: the following two fields not relevant for RAS
|
|
address = &pPortDesc->pd_PortAddr[0];
|
|
addressLength = MAX_HW_ADDR_LEN;
|
|
break;
|
|
|
|
default:
|
|
KeBugCheck(0);
|
|
break;
|
|
}
|
|
|
|
// Setup request
|
|
request.RequestType = NdisRequestQueryInformation;
|
|
request.DATA.QUERY_INFORMATION.Oid = ndisOid;
|
|
request.DATA.QUERY_INFORMATION.InformationBuffer = address;
|
|
request.DATA.QUERY_INFORMATION.InformationBufferLength = addressLength;
|
|
|
|
ndisStatus = AtalkNdisSubmitRequest(pPortDesc,
|
|
&request,
|
|
TRUE,
|
|
NULL,
|
|
NULL);
|
|
|
|
|
|
if (ndisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
LOG_ERRORONPORT(pPortDesc,
|
|
EVENT_ATALK_STATIONADDRESS,
|
|
ndisStatus,
|
|
NULL,
|
|
0);
|
|
}
|
|
|
|
// Setup request to get the mac options information
|
|
request.RequestType = NdisRequestQueryInformation;
|
|
request.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAC_OPTIONS;
|
|
request.DATA.QUERY_INFORMATION.InformationBuffer = &macOptions;
|
|
request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(ULONG);
|
|
|
|
ndisStatus = AtalkNdisSubmitRequest(pPortDesc,
|
|
&request,
|
|
TRUE,
|
|
NULL,
|
|
NULL);
|
|
|
|
|
|
if (ndisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
// No mac options.
|
|
ndisStatus = NDIS_STATUS_SUCCESS;
|
|
macOptions = 0;
|
|
}
|
|
|
|
pPortDesc->pd_MacOptions = macOptions;
|
|
DBGPRINT(DBG_COMP_NDISREQ, DBG_LEVEL_INFO,
|
|
("AtalkNdisQueryAddrInfo: MacOptions %lx\n", macOptions));
|
|
} while (FALSE);
|
|
|
|
return AtalkNdisToAtalkError(ndisStatus);
|
|
}
|
|
|
|
|
|
|
|
|
|
ATALK_ERROR
|
|
AtalkInitNdisSetLookaheadSize(
|
|
IN PPORT_DESCRIPTOR pPortDesc,
|
|
IN INT LookaheadSize // Has to be INT
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
NDIS_REQUEST request;
|
|
NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS;
|
|
|
|
do
|
|
{
|
|
// Check to see it we bound successfully to this adapter
|
|
if (!PORT_BOUND(pPortDesc))
|
|
{
|
|
LOG_ERRORONPORT(pPortDesc,
|
|
EVENT_ATALK_NOTBOUNDTOMAC,
|
|
STATUS_INSUFFICIENT_RESOURCES,
|
|
NULL,
|
|
0);
|
|
|
|
ndisStatus = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
// Setup request
|
|
request.RequestType = NdisRequestSetInformation;
|
|
request.DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_LOOKAHEAD;
|
|
request.DATA.SET_INFORMATION.InformationBuffer = (PBYTE)&LookaheadSize;
|
|
request.DATA.SET_INFORMATION.InformationBufferLength = sizeof(LookaheadSize);
|
|
|
|
ndisStatus = AtalkNdisSubmitRequest(pPortDesc,
|
|
&request,
|
|
TRUE,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (ndisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
LOG_ERRORONPORT(pPortDesc,
|
|
EVENT_ATALK_LOOKAHEADSIZE,
|
|
STATUS_INSUFFICIENT_RESOURCES,
|
|
NULL,
|
|
0);
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
return AtalkNdisToAtalkError(ndisStatus);
|
|
}
|
|
|
|
|
|
|
|
ATALK_ERROR
|
|
AtalkInitNdisStartPacketReception(
|
|
IN PPORT_DESCRIPTOR pPortDesc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
NDIS_REQUEST request;
|
|
ULONG packetFilter;
|
|
NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS;
|
|
KIRQL OldIrql;
|
|
|
|
do
|
|
{
|
|
// Check to see it we bound successfully to this adapter
|
|
if (!PORT_BOUND(pPortDesc))
|
|
{
|
|
LOG_ERRORONPORT(pPortDesc,
|
|
EVENT_ATALK_NOTBOUNDTOMAC,
|
|
STATUS_INSUFFICIENT_RESOURCES,
|
|
NULL,
|
|
0);
|
|
|
|
ndisStatus = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
switch (pPortDesc->pd_NdisPortType)
|
|
{
|
|
case NdisMedium802_3 :
|
|
case NdisMediumFddi :
|
|
packetFilter = NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_MULTICAST;
|
|
break;
|
|
|
|
case NdisMedium802_5:
|
|
packetFilter = NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_FUNCTIONAL;
|
|
break;
|
|
|
|
case NdisMediumLocalTalk :
|
|
packetFilter = NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST;
|
|
break;
|
|
|
|
case NdisMediumWan:
|
|
packetFilter = NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_MULTICAST;
|
|
break;
|
|
|
|
default:
|
|
KeBugCheck(0);
|
|
break;
|
|
}
|
|
|
|
// Setup request
|
|
request.RequestType = NdisRequestSetInformation;
|
|
request.DATA.SET_INFORMATION.Oid =OID_GEN_CURRENT_PACKET_FILTER;
|
|
request.DATA.SET_INFORMATION.InformationBuffer = (PBYTE)&packetFilter;
|
|
request.DATA.SET_INFORMATION.InformationBufferLength = sizeof(packetFilter);
|
|
|
|
ndisStatus = AtalkNdisSubmitRequest(pPortDesc,
|
|
&request,
|
|
TRUE,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (ndisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
LOG_ERRORONPORT(pPortDesc,
|
|
EVENT_ATALK_PACKETFILTER,
|
|
STATUS_INSUFFICIENT_RESOURCES,
|
|
NULL,
|
|
0);
|
|
}
|
|
} while (FALSE);
|
|
|
|
return AtalkNdisToAtalkError(ndisStatus);
|
|
}
|
|
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
AtalkNdisSubmitRequest(
|
|
PPORT_DESCRIPTOR pPortDesc,
|
|
PNDIS_REQUEST Request,
|
|
BOOLEAN ExecuteSync,
|
|
REQ_COMPLETION CompletionRoutine,
|
|
PVOID Ctx
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
None
|
|
--*/
|
|
{
|
|
NDIS_STATUS ndisStatus;
|
|
PATALK_NDIS_REQ atalkNdisRequest;
|
|
|
|
// Allocate an atalk request packet
|
|
if ((atalkNdisRequest = AtalkAllocMemory(sizeof(ATALK_NDIS_REQ))) == NULL)
|
|
{
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
atalkNdisRequest->nr_Request = *Request;
|
|
atalkNdisRequest->nr_Sync = ExecuteSync;
|
|
atalkNdisRequest->nr_RequestCompletion = CompletionRoutine;
|
|
atalkNdisRequest->nr_Ctx = Ctx;
|
|
|
|
if (ExecuteSync)
|
|
{
|
|
// Make sure we are not at or above dispatch level
|
|
// Also assert that the completion routine is NULL
|
|
ASSERT(KeGetCurrentIrql() == LOW_LEVEL);
|
|
ASSERT(CompletionRoutine == NULL);
|
|
|
|
// Initialize event to not signalled before possible wait.
|
|
KeInitializeEvent(&atalkNdisRequest->nr_Event,
|
|
NotificationEvent,
|
|
FALSE);
|
|
}
|
|
|
|
NdisRequest(&ndisStatus,
|
|
pPortDesc->pd_NdisBindingHandle,
|
|
&atalkNdisRequest->nr_Request);
|
|
|
|
DBGPRINT(DBG_COMP_NDISREQ, DBG_LEVEL_INFO,
|
|
("atalkNdisSubmitRequest: status NdisRequest %lx\n", ndisStatus));
|
|
|
|
if (ndisStatus == NDIS_STATUS_PENDING)
|
|
{
|
|
if (ExecuteSync)
|
|
{
|
|
KeWaitForSingleObject(&atalkNdisRequest->nr_Event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
ndisStatus = atalkNdisRequest->nr_RequestStatus;
|
|
AtalkFreeMemory((PVOID)atalkNdisRequest);
|
|
}
|
|
}
|
|
else if (ndisStatus == NDIS_STATUS_SUCCESS)
|
|
{
|
|
// Ndis will not call the completion routine.
|
|
if (!ExecuteSync)
|
|
{
|
|
// Call the users completion routine if specified.
|
|
if (CompletionRoutine != NULL)
|
|
{
|
|
(*CompletionRoutine)(NDIS_STATUS_SUCCESS, Ctx);
|
|
}
|
|
}
|
|
AtalkFreeMemory((PVOID)atalkNdisRequest);
|
|
}
|
|
else
|
|
{
|
|
// There was an error. Just free up the atalk ndis request.
|
|
AtalkFreeMemory((PVOID)atalkNdisRequest);
|
|
}
|
|
|
|
return ndisStatus;
|
|
}
|
|
|
|
|
|
|
|
|
|
// Protocol/NDIS interaction code
|
|
|
|
VOID
|
|
AtalkOpenAdapterComplete(
|
|
IN NDIS_HANDLE NdisBindCtx,
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_STATUS OpenErrorStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called during by NDIS to indicate that an open adapter
|
|
is complete. This happens only during initialization and single-file. Clear
|
|
the event, so the blocked init thread can go on to the next adapter. Set the
|
|
status in the ndis port descriptor for this adapter.
|
|
|
|
Arguments:
|
|
|
|
NdisBindCtx- Pointer to a port descriptor for this port
|
|
Status- completion status of open adapter
|
|
OpenErrorStatus- Extra status information
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PPORT_DESCRIPTOR pPortDesc = (PPORT_DESCRIPTOR)NdisBindCtx;
|
|
|
|
pPortDesc->pd_RequestStatus = Status;
|
|
KeSetEvent(&pPortDesc->pd_RequestEvent, IO_NETWORK_INCREMENT, FALSE);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkCloseAdapterComplete(
|
|
IN NDIS_HANDLE NdisBindCtx,
|
|
IN NDIS_STATUS Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by NDIS to indicate that a close adapter is complete.
|
|
|
|
Arguments:
|
|
|
|
NdisBindCtx- Pointer to a port descriptor for this port
|
|
Status- completion status of close adapter
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PPORT_DESCRIPTOR pPortDesc = (PPORT_DESCRIPTOR)NdisBindCtx;
|
|
|
|
pPortDesc->pd_RequestStatus = Status;
|
|
KeSetEvent(&pPortDesc->pd_RequestEvent, IO_NETWORK_INCREMENT, FALSE);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkResetComplete(
|
|
IN NDIS_HANDLE NdisBindCtx,
|
|
IN NDIS_STATUS Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by NDIS to indicate that a reset is complete.
|
|
|
|
Arguments:
|
|
|
|
NdisBindCtx- Pointer to a port descriptor for this port
|
|
Status- completion status of close adapter
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
UNREFERENCED_PARAMETER(NdisBindCtx);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkRequestComplete(
|
|
IN NDIS_HANDLE NdisBindCtx,
|
|
IN PNDIS_REQUEST NdisRequest,
|
|
IN NDIS_STATUS Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by NDIS to indicate that a NdisRequest is complete.
|
|
|
|
Arguments:
|
|
|
|
NdisBindCtx- Pointer to a port descriptor for this port
|
|
NdisRequest- Block identifying the request
|
|
Status- completion status of close adapter
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATALK_NDIS_REQ atalkRequest;
|
|
|
|
// Get the AtalkRequest block
|
|
atalkRequest = CONTAINING_RECORD(NdisRequest, ATALK_NDIS_REQ, nr_Request);
|
|
|
|
DBGPRINT(DBG_COMP_NDISREQ, DBG_LEVEL_INFO,
|
|
("AtalkRequestComplete: %lx status %lx\n", atalkRequest, Status));
|
|
|
|
if (atalkRequest->nr_Sync)
|
|
{
|
|
// This was a sync request
|
|
// Set status and clear event
|
|
|
|
ASSERT(atalkRequest->nr_RequestCompletion == NULL);
|
|
atalkRequest->nr_RequestStatus = Status;
|
|
KeSetEvent(&atalkRequest->nr_Event, IO_NETWORK_INCREMENT, FALSE);
|
|
}
|
|
|
|
// Call the completion routine if specified
|
|
if (atalkRequest->nr_RequestCompletion != NULL)
|
|
{
|
|
(*atalkRequest->nr_RequestCompletion)(Status, atalkRequest->nr_Ctx);
|
|
}
|
|
|
|
if (!atalkRequest->nr_Sync)
|
|
AtalkFreeMemory(atalkRequest);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkStatusIndication(
|
|
IN NDIS_HANDLE NdisBindCtx,
|
|
IN NDIS_STATUS GeneralStatus,
|
|
IN PVOID StatusBuf,
|
|
IN UINT StatusBufLen
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by NDIS to indicate a status change.
|
|
|
|
Arguments:
|
|
|
|
NdisBindCtx- Pointer to a port descriptor for this port
|
|
GeneralStatus- A general status value
|
|
StatusBuffer - A more specific status value
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
|
|
PPORT_DESCRIPTOR pPortDesc;
|
|
|
|
|
|
pPortDesc = (PPORT_DESCRIPTOR)NdisBindCtx;
|
|
|
|
// line-up, line-down or stat request from ndiswan? deal with it!
|
|
if (pPortDesc == RasPortDesc)
|
|
{
|
|
RasStatusIndication(GeneralStatus, StatusBuf, StatusBufLen);
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_NDISREQ, DBG_LEVEL_ERR,
|
|
("AtalkStatusIndication: Status indication called %lx\n", GeneralStatus));
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkStatusComplete (
|
|
IN NDIS_HANDLE ProtoBindCtx
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by NDIS to allow postprocessing after a status event.
|
|
|
|
Arguments:
|
|
|
|
ProtoBindCtx- Value associated with the binding with the adapter
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
UNREFERENCED_PARAMETER(ProtoBindCtx);
|
|
|
|
DBGPRINT(DBG_COMP_NDISREQ, DBG_LEVEL_WARN,
|
|
("AtalkStatusComplete: Status complete called\n"));
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef struct
|
|
{
|
|
REQ_COMPLETION AddCompletion;
|
|
PVOID AddContext;
|
|
PBYTE Buffer;
|
|
} ADDMC, *PADDMC;
|
|
|
|
LOCAL VOID
|
|
atalkNdisAddMulticastCompletion(
|
|
IN NDIS_STATUS Status,
|
|
IN PADDMC pAmc
|
|
)
|
|
{
|
|
if (pAmc->Buffer != NULL)
|
|
AtalkFreeMemory(pAmc->Buffer);
|
|
if (pAmc->AddCompletion != NULL)
|
|
(*pAmc->AddCompletion)(Status, pAmc->AddContext);
|
|
AtalkFreeMemory(pAmc);
|
|
}
|
|
|
|
|
|
ATALK_ERROR
|
|
AtalkNdisAddMulticast(
|
|
IN PPORT_DESCRIPTOR pPortDesc,
|
|
IN PBYTE Address,
|
|
IN BOOLEAN ExecuteSynchronously,
|
|
IN REQ_COMPLETION AddCompletion,
|
|
IN PVOID AddContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
INT sizeOfList;
|
|
PBYTE addressData, tempList;
|
|
KIRQL OldIrql;
|
|
NDIS_OID ndisOid;
|
|
NDIS_REQUEST request;
|
|
NDIS_STATUS ndisStatus;
|
|
PADDMC pAmc;
|
|
|
|
// Check to see it we bound successfully to this adapter
|
|
if (!PORT_BOUND(pPortDesc))
|
|
{
|
|
LOG_ERRORONPORT(pPortDesc,
|
|
EVENT_ATALK_NOTBOUNDTOMAC,
|
|
STATUS_INSUFFICIENT_RESOURCES,
|
|
NULL,
|
|
0);
|
|
|
|
return ATALK_FAILURE;
|
|
}
|
|
|
|
// Grab the perport spinlock. We need to allocate within a
|
|
// critical section as the size might change. This routine
|
|
// is called very infrequently, during init and when we
|
|
// receive our default zone from zip.
|
|
|
|
ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
|
|
sizeOfList = pPortDesc->pd_MulticastListSize + ELAP_ADDR_LEN;
|
|
|
|
ASSERTMSG("AtalkNdisAddMulticast: Size is not > 0\n", (sizeOfList > 0));
|
|
|
|
// Allocate/reallocate the list for the port descriptor, and also
|
|
// for a copy to be used in the NDIS request function.
|
|
tempList = (PBYTE)AtalkAllocZeroedMemory(sizeOfList);
|
|
addressData = (PBYTE)AtalkAllocZeroedMemory(sizeOfList);
|
|
pAmc = (PADDMC)AtalkAllocZeroedMemory(sizeof(ADDMC));
|
|
|
|
if ((tempList == NULL) || (addressData == NULL) || (pAmc == NULL))
|
|
{
|
|
// Release the spinlock
|
|
RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
|
|
|
|
if (pAmc != NULL)
|
|
AtalkFreeMemory(pAmc);
|
|
if (tempList != NULL)
|
|
AtalkFreeMemory(tempList);
|
|
if (addressData != NULL)
|
|
AtalkFreeMemory(addressData);
|
|
|
|
return ATALK_RESR_MEM;
|
|
}
|
|
|
|
if (pPortDesc->pd_MulticastList == NULL)
|
|
{
|
|
// No old addresses to work with.
|
|
pPortDesc->pd_MulticastListSize = 0;
|
|
}
|
|
else
|
|
{
|
|
// Copy the old list over to the new space
|
|
RtlCopyMemory(tempList,
|
|
pPortDesc->pd_MulticastList,
|
|
pPortDesc->pd_MulticastListSize);
|
|
|
|
// Set the proper values back into PortDesc after freeing the old list
|
|
AtalkFreeMemory(pPortDesc->pd_MulticastList);
|
|
}
|
|
|
|
// Guaranteed space is available to copy the new address
|
|
// Ready to copy our new address here and then do the set!
|
|
RtlCopyMemory(tempList + pPortDesc->pd_MulticastListSize,
|
|
Address,
|
|
ELAP_ADDR_LEN);
|
|
|
|
pPortDesc->pd_MulticastList = tempList;
|
|
pPortDesc->pd_MulticastListSize = sizeOfList;
|
|
|
|
switch (pPortDesc->pd_NdisPortType)
|
|
{
|
|
case NdisMedium802_3 :
|
|
|
|
ndisOid = OID_802_3_MULTICAST_LIST;
|
|
break;
|
|
|
|
case NdisMediumFddi:
|
|
|
|
// FDDI supports 2byte and 6byte multicast addresses. We use the
|
|
// 6byte multicast addresses for appletalk.
|
|
ndisOid = OID_FDDI_LONG_MULTICAST_LIST;
|
|
break;
|
|
|
|
default:
|
|
|
|
KeBugCheck(0);
|
|
break;
|
|
}
|
|
|
|
// Setup request
|
|
// Move the list to our buffer
|
|
|
|
ASSERTMSG("AtalkNdisAddMulticast: Size incorrect!\n",
|
|
((ULONG)sizeOfList == pPortDesc->pd_MulticastListSize));
|
|
|
|
RtlCopyMemory(addressData,
|
|
pPortDesc->pd_MulticastList,
|
|
pPortDesc->pd_MulticastListSize);
|
|
|
|
// Release the spinlock
|
|
RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
|
|
|
|
request.RequestType = NdisRequestSetInformation;
|
|
request.DATA.SET_INFORMATION.Oid = ndisOid;
|
|
request.DATA.SET_INFORMATION.InformationBuffer = addressData;
|
|
request.DATA.SET_INFORMATION.InformationBufferLength = sizeOfList;
|
|
pAmc->AddCompletion = AddCompletion;
|
|
pAmc->AddContext = AddContext;
|
|
pAmc->Buffer = addressData;
|
|
|
|
ndisStatus = AtalkNdisSubmitRequest(pPortDesc,
|
|
&request,
|
|
FALSE,
|
|
atalkNdisAddMulticastCompletion,
|
|
pAmc);
|
|
|
|
// NOTE: Sumbit calls completion if success is being returned.
|
|
if ((ndisStatus != NDIS_STATUS_SUCCESS) &&
|
|
(ndisStatus != NDIS_STATUS_PENDING))
|
|
{
|
|
LOG_ERRORONPORT(pPortDesc,
|
|
EVENT_ATALK_NDISREQUEST,
|
|
ndisStatus,
|
|
NULL,
|
|
0);
|
|
}
|
|
|
|
return AtalkNdisToAtalkError(ndisStatus);
|
|
}
|
|
|
|
|
|
|
|
|
|
ATALK_ERROR
|
|
AtalkNdisRemoveMulticast(
|
|
IN PPORT_DESCRIPTOR pPortDesc,
|
|
IN PBYTE Address,
|
|
IN BOOLEAN ExecuteSynchronously,
|
|
IN REQ_COMPLETION RemoveCompletion,
|
|
IN PVOID RemoveContext
|
|
)
|
|
{
|
|
INT sizeOfList, i, numberInList;
|
|
PBYTE addressData, currentList;
|
|
KIRQL OldIrql;
|
|
NDIS_REQUEST request;
|
|
NDIS_OID ndisOid;
|
|
NDIS_STATUS ndisStatus;
|
|
PADDMC pAmc;
|
|
|
|
do
|
|
{
|
|
// Check to see it we bound successfully to this adapter
|
|
if (!PORT_BOUND(pPortDesc))
|
|
{
|
|
LOG_ERRORONPORT(pPortDesc,
|
|
EVENT_ATALK_NOTBOUNDTOMAC,
|
|
STATUS_INSUFFICIENT_RESOURCES,
|
|
NULL,
|
|
0);
|
|
|
|
ndisStatus = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
// Grab the perport spinlock. Again, a very infrequent operation.
|
|
// Probably just twice in the lifetime of the stack.
|
|
ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
|
|
|
|
ASSERT(pPortDesc->pd_MulticastList != NULL);
|
|
if (pPortDesc->pd_MulticastList == NULL)
|
|
{
|
|
// Nothing to remove!
|
|
ndisStatus = NDIS_STATUS_SUCCESS;
|
|
RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
|
|
break;
|
|
}
|
|
|
|
numberInList = pPortDesc->pd_MulticastListSize/ELAP_ADDR_LEN;
|
|
currentList = pPortDesc->pd_MulticastList;
|
|
for (i = 0; i < numberInList; i++, currentList += ELAP_ADDR_LEN)
|
|
{
|
|
// Search for the address and remember the index if found
|
|
if (RtlCompareMemory(currentList,
|
|
Address,
|
|
ELAP_ADDR_LEN) == ELAP_ADDR_LEN)
|
|
{
|
|
// Move all address following this overwriting this address
|
|
// we ignore wasted space that will never be touched anymore.
|
|
// This could turn out to be a NOP if we are removing the last
|
|
// address in the list.
|
|
RtlMoveMemory(currentList,
|
|
currentList + ELAP_ADDR_LEN,
|
|
pPortDesc->pd_MulticastListSize-((i+1)*ELAP_ADDR_LEN));
|
|
|
|
pPortDesc->pd_MulticastListSize -= ELAP_ADDR_LEN;
|
|
|
|
// Have we removed the last address. If so, reset values.
|
|
if (pPortDesc->pd_MulticastListSize == 0)
|
|
{
|
|
AtalkFreeMemory(pPortDesc->pd_MulticastList);
|
|
pPortDesc->pd_MulticastList = NULL;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
// We assume address was found and the list is changed as expected
|
|
// Set this new list
|
|
switch (pPortDesc->pd_NdisPortType)
|
|
{
|
|
case NdisMedium802_3 :
|
|
|
|
ndisOid = OID_802_3_MULTICAST_LIST;
|
|
break;
|
|
|
|
case NdisMediumFddi:
|
|
|
|
// FDDI supports 2byte and 6byte multicast addresses. We use the
|
|
// 6byte multicast addresses for appletalk.
|
|
ndisOid = OID_FDDI_LONG_MULTICAST_LIST;
|
|
break;
|
|
|
|
default:
|
|
|
|
KeBugCheck(0);
|
|
break;
|
|
}
|
|
|
|
addressData = NULL;
|
|
sizeOfList = pPortDesc->pd_MulticastListSize;
|
|
|
|
pAmc = (PADDMC)AtalkAllocZeroedMemory(sizeof(ADDMC));
|
|
|
|
if (pAmc == NULL)
|
|
{
|
|
RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
|
|
ndisStatus = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
if (sizeOfList > 0)
|
|
{
|
|
// Allocate addressData and copy list to it
|
|
addressData = (PBYTE)AtalkAllocMemory(sizeOfList);
|
|
if (addressData == NULL)
|
|
{
|
|
// Release the spinlock
|
|
RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
|
|
AtalkFreeMemory(pAmc);
|
|
ndisStatus = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
// Move the list to our buffer
|
|
RtlCopyMemory(addressData,
|
|
pPortDesc->pd_MulticastList,
|
|
pPortDesc->pd_MulticastListSize);
|
|
}
|
|
|
|
// Release the spinlock
|
|
RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
|
|
|
|
request.RequestType = NdisRequestSetInformation;
|
|
request.DATA.SET_INFORMATION.Oid = ndisOid;
|
|
request.DATA.SET_INFORMATION.InformationBuffer = addressData;
|
|
request.DATA.SET_INFORMATION.InformationBufferLength = sizeOfList;
|
|
pAmc->AddCompletion = RemoveCompletion;
|
|
pAmc->AddContext = RemoveContext;
|
|
pAmc->Buffer = addressData;
|
|
|
|
ndisStatus = AtalkNdisSubmitRequest(pPortDesc,
|
|
&request,
|
|
FALSE,
|
|
atalkNdisAddMulticastCompletion,
|
|
pAmc);
|
|
|
|
if ((ndisStatus != NDIS_STATUS_SUCCESS) &&
|
|
(ndisStatus != NDIS_STATUS_PENDING))
|
|
{
|
|
LOG_ERRORONPORT(pPortDesc,
|
|
EVENT_ATALK_NDISREQUEST,
|
|
ndisStatus,
|
|
NULL,
|
|
0);
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
return AtalkNdisToAtalkError(ndisStatus);
|
|
}
|
|
|
|
|
|
|
|
ATALK_ERROR
|
|
AtalkNdisSendPacket(
|
|
IN PPORT_DESCRIPTOR pPortDesc,
|
|
IN PBUFFER_DESC BufferChain,
|
|
IN SEND_COMPLETION SendCompletion OPTIONAL,
|
|
IN PSEND_COMPL_INFO pSendInfo OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the portable code to send a packet out on
|
|
ethernet. It will build the NDIS packet descriptor for the passed in
|
|
chain and then send the packet on the specified port.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE- If sent/pending, FALSE otherwise
|
|
TransmitComplete is called if this call pended by completion code
|
|
|
|
--*/
|
|
{
|
|
PNDIS_PACKET ndisPacket;
|
|
PNDIS_BUFFER ndisBuffer;
|
|
PPROTOCOL_RESD protocolResd;
|
|
ATALK_ERROR error;
|
|
PSENDBUF pSendBuf;
|
|
NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS;
|
|
PMDL pMdl;
|
|
PMDL pFirstMdl=NULL;
|
|
|
|
if (PORT_CLOSING(pPortDesc))
|
|
{
|
|
// If we are not active, return!
|
|
return ATALK_PORT_CLOSING;
|
|
}
|
|
|
|
do
|
|
{
|
|
pSendBuf = (PSENDBUF)((PBYTE)BufferChain - sizeof(BUFFER_HDR));
|
|
ndisPacket = pSendBuf->sb_BuffHdr.bh_NdisPkt;
|
|
|
|
// Store the information needed in the packet descriptor
|
|
protocolResd = (PPROTOCOL_RESD)&ndisPacket->ProtocolReserved;
|
|
protocolResd->Send.pr_Port = pPortDesc;
|
|
protocolResd->Send.pr_BufferDesc = BufferChain;
|
|
protocolResd->Send.pr_SendCompletion = SendCompletion;
|
|
if (pSendInfo != NULL)
|
|
protocolResd->Send.pr_SendInfo = *pSendInfo;
|
|
else RtlZeroMemory(&protocolResd->Send.pr_SendInfo, sizeof(SEND_COMPL_INFO));
|
|
|
|
// For the first buffer, set up the length of the NDIS buffer to be
|
|
// the same as in indicated in the descriptor.
|
|
NdisAdjustBufferLength(pSendBuf->sb_BuffHdr.bh_NdisBuffer,
|
|
BufferChain->bd_Length);
|
|
|
|
// NOTE: There is either a PBYTE being pointed to, or a PAMDL
|
|
// being pointed to by the buffer descriptor. Also, the
|
|
// size of the data will be the size that is to be
|
|
// used. At the end, just assert that the total length
|
|
// equals length passed in.
|
|
if (BufferChain->bd_Next != NULL)
|
|
{
|
|
if (BufferChain->bd_Next->bd_Flags & BD_CHAR_BUFFER)
|
|
{
|
|
NdisAllocateBuffer(&ndisStatus,
|
|
&ndisBuffer,
|
|
AtalkNdisBufferPoolHandle,
|
|
(PVOID)BufferChain->bd_Next->bd_CharBuffer,
|
|
(UINT)BufferChain->bd_Next->bd_Length);
|
|
|
|
if (ndisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DBGPRINT(DBG_COMP_NDISSEND, DBG_LEVEL_ERR,
|
|
("AtalkNdisSendPacket: NdisAllocateBuffer %lx\n", ndisStatus));
|
|
// LOG_ERROR(EVENT_ATALK_NDISRESOURCES, ndisStatus, NULL, 0);
|
|
break;
|
|
}
|
|
|
|
ATALK_DBG_INC_COUNT(AtalkDbgMdlsAlloced);
|
|
|
|
NdisChainBufferAtBack(ndisPacket, ndisBuffer);
|
|
}
|
|
else
|
|
{
|
|
// It is an MDL
|
|
pMdl = (PMDL)BufferChain->bd_Next->bd_OpaqueBuffer;
|
|
|
|
ASSERT(AtalkSizeMdlChain(pMdl) == BufferChain->bd_Next->bd_Length);
|
|
while (pMdl)
|
|
{
|
|
NdisCopyBuffer(&ndisStatus,
|
|
&ndisBuffer,
|
|
AtalkNdisBufferPoolHandle,
|
|
(PVOID)pMdl,
|
|
0, //Offset
|
|
(UINT)MmGetMdlByteCount(pMdl));
|
|
|
|
if (ndisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
if (pFirstMdl)
|
|
{
|
|
AtalkNdisFreeBuffer(pFirstMdl);
|
|
}
|
|
break;
|
|
}
|
|
|
|
ATALK_DBG_INC_COUNT(AtalkDbgMdlsAlloced);
|
|
|
|
if (!pFirstMdl)
|
|
{
|
|
pFirstMdl = pMdl;
|
|
}
|
|
|
|
NdisChainBufferAtBack(ndisPacket, ndisBuffer);
|
|
|
|
pMdl = pMdl->Next;
|
|
}
|
|
|
|
if (ndisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DBGPRINT(DBG_COMP_NDISSEND, DBG_LEVEL_ERR,
|
|
("AtalkNdisSendPacket: NdisCopyBuffer %lx\n", ndisStatus));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef PROFILING
|
|
INTERLOCKED_INCREMENT_LONG_DPC(
|
|
&pPortDesc->pd_PortStats.prtst_CurSendsOutstanding,
|
|
&AtalkStatsLock.SpinLock);
|
|
#endif
|
|
INTERLOCKED_INCREMENT_LONG_DPC(
|
|
&pPortDesc->pd_PortStats.prtst_NumPacketsOut,
|
|
&AtalkStatsLock.SpinLock);
|
|
|
|
// Now send the built packet descriptor
|
|
NdisSend(&ndisStatus,
|
|
pPortDesc->pd_NdisBindingHandle,
|
|
ndisPacket);
|
|
|
|
// Completion will dereference the port!
|
|
if (ndisStatus != NDIS_STATUS_PENDING)
|
|
{
|
|
// Call the completion handler
|
|
AtalkSendComplete(pPortDesc->pd_NdisBindingHandle,
|
|
ndisPacket,
|
|
ndisStatus);
|
|
ndisStatus = NDIS_STATUS_PENDING;
|
|
}
|
|
} while (FALSE);
|
|
|
|
return AtalkNdisToAtalkError(ndisStatus);
|
|
}
|
|
|
|
|
|
|
|
ATALK_ERROR
|
|
AtalkNdisAddFunctional(
|
|
IN PPORT_DESCRIPTOR pPortDesc,
|
|
IN PBYTE Address,
|
|
IN BOOLEAN ExecuteSynchronously,
|
|
IN REQ_COMPLETION AddCompletion,
|
|
IN PVOID AddContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
NDIS_REQUEST request;
|
|
NDIS_STATUS ndisStatus;
|
|
KIRQL OldIrql;
|
|
|
|
DBGPRINT(DBG_COMP_NDISREQ, DBG_LEVEL_INFO,
|
|
("Current %02x%02x%02x%02x, Adding %02x%02x%02x%02x\n",
|
|
pPortDesc->pd_FunctionalAddr[0], pPortDesc->pd_FunctionalAddr[1],
|
|
pPortDesc->pd_FunctionalAddr[2], pPortDesc->pd_FunctionalAddr[3],
|
|
Address[2], Address[3], Address[4], Address[5]));
|
|
|
|
// Grab the perport spinlock
|
|
ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
|
|
|
|
// We only need the last four bytes of the address assuming that the
|
|
// first two bytes always remain the same (C000) and that the MAC assumes
|
|
// the same- NDIS 3.0 OID length = 4
|
|
for (i = 0;
|
|
i < sizeof(ULONG);
|
|
i++)
|
|
pPortDesc->pd_FunctionalAddr[i] |= Address[2+i];
|
|
|
|
// Release the spinlock
|
|
RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
|
|
|
|
DBGPRINT(DBG_COMP_NDISREQ, DBG_LEVEL_INFO,
|
|
("After Add %02x%02x%02x%02x\n",
|
|
pPortDesc->pd_FunctionalAddr[0], pPortDesc->pd_FunctionalAddr[1],
|
|
pPortDesc->pd_FunctionalAddr[2], pPortDesc->pd_FunctionalAddr[3]));
|
|
|
|
request.RequestType = NdisRequestSetInformation;
|
|
request.DATA.SET_INFORMATION.Oid = OID_802_5_CURRENT_FUNCTIONAL;
|
|
request.DATA.SET_INFORMATION.InformationBuffer = pPortDesc->pd_FunctionalAddr;
|
|
request.DATA.SET_INFORMATION.InformationBufferLength = TLAP_ADDR_LEN - TLAP_MCAST_HDR_LEN;
|
|
|
|
ndisStatus = AtalkNdisSubmitRequest(pPortDesc,
|
|
&request,
|
|
ExecuteSynchronously,
|
|
AddCompletion,
|
|
AddContext);
|
|
|
|
if (ndisStatus == NDIS_STATUS_PENDING)
|
|
{
|
|
ASSERT(ExecuteSynchronously != TRUE);
|
|
}
|
|
else if (ndisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
LOG_ERRORONPORT(pPortDesc,
|
|
EVENT_ATALK_NDISREQUEST,
|
|
ndisStatus,
|
|
NULL,
|
|
0);
|
|
}
|
|
|
|
return AtalkNdisToAtalkError(ndisStatus);
|
|
}
|
|
|
|
|
|
|
|
|
|
ATALK_ERROR
|
|
AtalkNdisRemoveFunctional(
|
|
IN PPORT_DESCRIPTOR pPortDesc,
|
|
IN PBYTE Address,
|
|
IN BOOLEAN ExecuteSynchronously,
|
|
IN REQ_COMPLETION RemoveCompletion,
|
|
IN PVOID RemoveContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
KIRQL OldIrql;
|
|
NDIS_REQUEST request;
|
|
NDIS_STATUS ndisStatus;
|
|
|
|
DBGPRINT(DBG_COMP_NDISREQ, DBG_LEVEL_INFO,
|
|
("Current %02x%02x%02x%02x, Removing %02x%02x%02x%02x\n",
|
|
pPortDesc->pd_FunctionalAddr[0], pPortDesc->pd_FunctionalAddr[1],
|
|
pPortDesc->pd_FunctionalAddr[2], pPortDesc->pd_FunctionalAddr[3],
|
|
Address[2], Address[3], Address[4], Address[5]));
|
|
|
|
// Grab the perport spinlock
|
|
ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
|
|
|
|
// We only need the last four bytes of the address assuming that the
|
|
// first two bytes always remain the same (C000) and that the MAC assumes
|
|
// the same- NDIS 3.0 OID length = 4
|
|
for (i = 0; i < sizeof(ULONG); i++)
|
|
pPortDesc->pd_FunctionalAddr[i] &= ~Address[2+i];
|
|
|
|
// Release the spinlock
|
|
RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
|
|
|
|
DBGPRINT(DBG_COMP_NDISREQ, DBG_LEVEL_INFO,
|
|
("After Remove %02x%02x%02x%02x\n",
|
|
pPortDesc->pd_FunctionalAddr[0], pPortDesc->pd_FunctionalAddr[1],
|
|
pPortDesc->pd_FunctionalAddr[2], pPortDesc->pd_FunctionalAddr[3]));
|
|
|
|
request.RequestType = NdisRequestSetInformation;
|
|
request.DATA.SET_INFORMATION.Oid = OID_802_5_CURRENT_FUNCTIONAL;
|
|
request.DATA.SET_INFORMATION.InformationBuffer = pPortDesc->pd_FunctionalAddr;
|
|
request.DATA.SET_INFORMATION.InformationBufferLength = TLAP_ADDR_LEN - TLAP_MCAST_HDR_LEN;
|
|
|
|
ndisStatus = AtalkNdisSubmitRequest(pPortDesc,
|
|
&request,
|
|
ExecuteSynchronously,
|
|
RemoveCompletion,
|
|
RemoveContext);
|
|
|
|
if (ndisStatus == NDIS_STATUS_PENDING)
|
|
{
|
|
ASSERT(ExecuteSynchronously != TRUE);
|
|
}
|
|
else if (ndisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
LOG_ERRORONPORT(pPortDesc,
|
|
EVENT_ATALK_NDISREQUEST,
|
|
ndisStatus,
|
|
NULL,
|
|
0);
|
|
}
|
|
|
|
return AtalkNdisToAtalkError(ndisStatus);
|
|
}
|
|
|
|
|
|
|
|
|
|
USHORT
|
|
AtalkNdisBuildEthHdr(
|
|
IN PUCHAR PortAddr, // 802 address of port
|
|
IN PBYTE pLinkHdr, // Start of link header
|
|
IN PBYTE pDestHwOrMcastAddr, // Destination or multicast addr
|
|
IN LOGICAL_PROTOCOL Protocol, // Logical protocol
|
|
IN USHORT ActualDataLen // Length for ethernet packets
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
USHORT len;
|
|
|
|
// Set destination address.
|
|
if (pDestHwOrMcastAddr == NULL)
|
|
pDestHwOrMcastAddr = AtalkElapBroadcastAddr;
|
|
|
|
RtlCopyMemory(pLinkHdr,
|
|
pDestHwOrMcastAddr,
|
|
ELAP_ADDR_LEN);
|
|
|
|
// Set source address.
|
|
RtlCopyMemory(pLinkHdr += ELAP_ADDR_LEN,
|
|
PortAddr,
|
|
ELAP_ADDR_LEN);
|
|
|
|
// Set length, excluding Ethernet hardware header.
|
|
len = ActualDataLen + IEEE8022_HDR_LEN;
|
|
pLinkHdr += ELAP_ADDR_LEN;
|
|
PUTSHORT2SHORT(pLinkHdr, len);
|
|
pLinkHdr += sizeof(USHORT);
|
|
|
|
ATALK_BUILD8022_HDR(pLinkHdr, Protocol);
|
|
|
|
// Return the link header length.
|
|
return (ELAP_LINKHDR_LEN + IEEE8022_HDR_LEN);
|
|
}
|
|
|
|
|
|
|
|
|
|
USHORT
|
|
AtalkNdisBuildTRHdr(
|
|
IN PUCHAR PortAddr, // 802 address of port
|
|
IN PBYTE pLinkHdr, // Start of link header
|
|
IN PBYTE pDestHwOrMcastAddr, // Destination or multicast addr
|
|
IN LOGICAL_PROTOCOL Protocol, // Logical protocol
|
|
IN PBYTE pRouteInfo, // Routing info for tokenring
|
|
IN USHORT RouteInfoLen // Length of above
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
USHORT linkLen;
|
|
|
|
// Here we need to worry about the routing info.
|
|
// If we currently do not have any, set the values
|
|
if (pDestHwOrMcastAddr == NULL)
|
|
{
|
|
// Broadcast?
|
|
pRouteInfo = AtalkBroadcastRouteInfo;
|
|
RouteInfoLen = TLAP_MIN_ROUTING_BYTES;
|
|
|
|
}
|
|
else if (RouteInfoLen != 0)
|
|
{
|
|
// We are all set
|
|
}
|
|
else if (AtalkFixedCompareCaseSensitive(pDestHwOrMcastAddr,
|
|
TLAP_BROADCAST_DEST_LEN,
|
|
AtalkBroadcastDestHdr,
|
|
TLAP_BROADCAST_DEST_LEN))
|
|
{
|
|
// Multicast?
|
|
pRouteInfo = AtalkBroadcastRouteInfo;
|
|
RouteInfoLen = TLAP_MIN_ROUTING_BYTES;
|
|
}
|
|
else
|
|
{
|
|
// No routing know; use simple non-broadcast
|
|
pRouteInfo = AtalkSimpleRouteInfo;
|
|
RouteInfoLen = TLAP_MIN_ROUTING_BYTES;
|
|
}
|
|
|
|
linkLen = TLAP_MIN_LINKHDR_LEN + RouteInfoLen + IEEE8022_HDR_LEN;
|
|
|
|
// Set the first two bytes in the header
|
|
*pLinkHdr++ = TLAP_ACCESS_CTRL_VALUE;
|
|
*pLinkHdr++ = TLAP_FRAME_CTRL_VALUE ;
|
|
|
|
// Set detination address.
|
|
if (pDestHwOrMcastAddr == NULL)
|
|
pDestHwOrMcastAddr = AtalkTlapBroadcastAddr;
|
|
|
|
RtlCopyMemory(pLinkHdr,
|
|
pDestHwOrMcastAddr ,
|
|
TLAP_ADDR_LEN);
|
|
|
|
// Set source address.
|
|
RtlCopyMemory(pLinkHdr += TLAP_ADDR_LEN,
|
|
PortAddr,
|
|
TLAP_ADDR_LEN);
|
|
|
|
ASSERTMSG("AtalkNdisBuildTRHdr: Routing Info is 0!\n", (RouteInfoLen > 0));
|
|
*pLinkHdr |= TLAP_SRC_ROUTING_MASK;
|
|
|
|
// Move in routing info.
|
|
RtlCopyMemory(pLinkHdr += TLAP_ADDR_LEN,
|
|
pRouteInfo,
|
|
RouteInfoLen);
|
|
|
|
pLinkHdr += RouteInfoLen;
|
|
ATALK_BUILD8022_HDR(pLinkHdr, Protocol);
|
|
|
|
// Return the link header length.
|
|
return linkLen;
|
|
}
|
|
|
|
|
|
|
|
|
|
USHORT
|
|
AtalkNdisBuildFDDIHdr(
|
|
IN PUCHAR PortAddr, // 802 address of port
|
|
IN PBYTE pLinkHdr, // Start of link header
|
|
IN PBYTE pDestHwOrMcastAddr, // Destination or multicast addr
|
|
IN LOGICAL_PROTOCOL Protocol // Logical protocol
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
*pLinkHdr++ = FDDI_HEADER_BYTE;
|
|
|
|
// Set destination address.
|
|
if (pDestHwOrMcastAddr == NULL)
|
|
pDestHwOrMcastAddr = AtalkElapBroadcastAddr;
|
|
|
|
// Set destination address.
|
|
RtlCopyMemory(pLinkHdr,
|
|
pDestHwOrMcastAddr,
|
|
FDDI_ADDR_LEN);
|
|
|
|
// Set source address.
|
|
RtlCopyMemory(pLinkHdr += FDDI_ADDR_LEN,
|
|
PortAddr,
|
|
FDDI_ADDR_LEN);
|
|
|
|
pLinkHdr += FDDI_ADDR_LEN;
|
|
|
|
// NOTE: No Length field for FDDI, unlike Ethernet.
|
|
ATALK_BUILD8022_HDR(pLinkHdr, Protocol);
|
|
|
|
// Return the link header length.
|
|
return (FDDI_LINKHDR_LEN + IEEE8022_HDR_LEN);
|
|
}
|
|
|
|
|
|
|
|
|
|
USHORT
|
|
AtalkNdisBuildLTHdr(
|
|
IN PBYTE pLinkHdr, // Start of link header
|
|
IN PBYTE pDestHwOrMcastAddr, // Destination or multicast addr
|
|
IN BYTE AlapSrc, // Localtalk source node
|
|
IN BYTE AlapType // Localtalk ddp header type
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
// Fill in LAP header.
|
|
if (pDestHwOrMcastAddr == NULL)
|
|
pLinkHdr = AtalkAlapBroadcastAddr;
|
|
|
|
*pLinkHdr++ = *pDestHwOrMcastAddr;
|
|
|
|
*pLinkHdr++ = AlapSrc;
|
|
*pLinkHdr = AlapType;
|
|
|
|
// Return the link header length.
|
|
return ALAP_LINKHDR_LEN;
|
|
}
|
|
|
|
VOID
|
|
AtalkNdisSendTokRingTestResp(
|
|
IN PPORT_DESCRIPTOR pPortDesc,
|
|
IN PBYTE HdrBuf,
|
|
IN UINT HdrBufSize,
|
|
IN PBYTE LkBuf,
|
|
IN UINT LkBufSize,
|
|
IN UINT PktSize
|
|
)
|
|
{
|
|
PBUFFER_DESC pBufDesc, pHdrDesc;
|
|
PBYTE pResp;
|
|
UINT routeInfoLen = 0;
|
|
|
|
// Allocate a buffer to hold the response and call NdisSend
|
|
// providing a completion routine which will free up the buffer.
|
|
ASSERT(PktSize == LkBufSize);
|
|
|
|
// make sure there are at least 14 bytes!
|
|
if (HdrBufSize < TLAP_ROUTE_INFO_OFFSET)
|
|
{
|
|
ASSERT(0);
|
|
return;
|
|
}
|
|
|
|
// First allocate a buffer to hold the link header.
|
|
AtalkNdisAllocBuf(&pHdrDesc);
|
|
if (pHdrDesc == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ((pBufDesc = AtalkAllocBuffDesc(NULL,
|
|
(USHORT)LkBufSize,
|
|
BD_CHAR_BUFFER | BD_FREE_BUFFER)) == NULL)
|
|
|
|
{
|
|
AtalkNdisFreeBuf(pHdrDesc);
|
|
|
|
RES_LOG_ERROR();
|
|
return;
|
|
}
|
|
|
|
pResp = pHdrDesc->bd_CharBuffer;
|
|
*pResp++ = TLAP_ACCESS_CTRL_VALUE;
|
|
*pResp++ = TLAP_FRAME_CTRL_VALUE;
|
|
|
|
// Set destination address to be the incoming src addr.
|
|
ATALK_RECV_INDICATION_COPY(pPortDesc,
|
|
pResp,
|
|
HdrBuf+TLAP_SRC_OFFSET,
|
|
TLAP_ADDR_LEN);
|
|
|
|
// Make sure we do not have the routing bit set.
|
|
*pResp &= ~TLAP_SRC_ROUTING_MASK;
|
|
pResp += TLAP_ADDR_LEN;
|
|
|
|
// Set source address to be the incoming destination address.
|
|
ATALK_RECV_INDICATION_COPY(pPortDesc,
|
|
pResp,
|
|
HdrBuf+TLAP_DEST_OFFSET,
|
|
TLAP_ADDR_LEN);
|
|
|
|
// Is there routing info present?
|
|
if (HdrBuf[TLAP_SRC_OFFSET] & TLAP_SRC_ROUTING_MASK)
|
|
{
|
|
routeInfoLen = (HdrBuf[TLAP_ROUTE_INFO_OFFSET] & TLAP_ROUTE_INFO_SIZE_MASK);
|
|
ASSERT(routeInfoLen != 0);
|
|
ASSERTMSG("RouteInfo incorrect!\n",
|
|
(routeInfoLen <= TLAP_MAX_ROUTING_BYTES));
|
|
|
|
if (HdrBufSize < (TLAP_ROUTE_INFO_OFFSET+routeInfoLen))
|
|
{
|
|
ASSERT(0);
|
|
AtalkNdisFreeBuf(pHdrDesc);
|
|
AtalkFreeBuffDesc(pBufDesc);
|
|
return;
|
|
}
|
|
|
|
// Copy it in the response packet and then tune it.
|
|
ATALK_RECV_INDICATION_COPY(pPortDesc,
|
|
pResp + TLAP_ADDR_LEN,
|
|
HdrBuf+TLAP_ROUTE_INFO_OFFSET,
|
|
routeInfoLen);
|
|
|
|
// Set to "non-broadcast" and invert "direction".
|
|
*(pResp+TLAP_ADDR_LEN) &= TLAP_NON_BROADCAST_MASK;
|
|
*(pResp+TLAP_ADDR_LEN+1) ^= TLAP_DIRECTION_MASK;
|
|
|
|
// Set the routing info bit in the source address
|
|
*pResp |= TLAP_SRC_ROUTING_MASK;
|
|
}
|
|
|
|
// Set the length for this buffer descriptor.
|
|
AtalkSetSizeOfBuffDescData(pHdrDesc, TLAP_ROUTE_INFO_OFFSET + routeInfoLen);
|
|
|
|
// Copy the remaining data
|
|
ATALK_RECV_INDICATION_COPY(pPortDesc,
|
|
pBufDesc->bd_CharBuffer,
|
|
LkBuf,
|
|
LkBufSize);
|
|
|
|
// Set the source SAP to indicate FINAL (0xAB instead of 0xAA)
|
|
pBufDesc->bd_CharBuffer[IEEE8022_SSAP_OFFSET] = SNAP_SAP_FINAL;
|
|
|
|
// Chain the passed in buffer desc onto the tail of the one
|
|
// returned above.
|
|
AtalkPrependBuffDesc(pHdrDesc, pBufDesc);
|
|
|
|
// Call send at this point
|
|
if (!ATALK_SUCCESS(AtalkNdisSendPacket(pPortDesc,
|
|
pHdrDesc,
|
|
AtalkNdisSendTokRingTestRespComplete,
|
|
NULL)))
|
|
{
|
|
AtalkNdisSendTokRingTestRespComplete(NDIS_STATUS_RESOURCES,
|
|
pHdrDesc,
|
|
NULL);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkNdisSendTokRingTestRespComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN PBUFFER_DESC pBufDesc,
|
|
IN PSEND_COMPL_INFO pInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
// Free up the buffer descriptor
|
|
ASSERT((pBufDesc != NULL) && (pBufDesc->bd_Next != NULL));
|
|
ASSERT(pBufDesc->bd_Flags & BD_CHAR_BUFFER);
|
|
AtalkFreeBuffDesc(pBufDesc->bd_Next);
|
|
AtalkNdisFreeBuf(pBufDesc);
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
AtalkReceiveIndication(
|
|
IN NDIS_HANDLE BindingCtx,
|
|
IN NDIS_HANDLE ReceiveCtx,
|
|
IN PVOID HdrBuf,
|
|
IN UINT HdrBufSize,
|
|
IN PVOID LkBuf,
|
|
IN UINT LkBufSize,
|
|
IN UINT PktSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by NDIS to indicate a receive
|
|
|
|
Arguments:
|
|
|
|
BindingCtx- Pointer to a port descriptor for this port
|
|
ReceiveCtx- To be used in a transfer data if necessary
|
|
LkBuf- buffer with lookahead data
|
|
LkBufSize- Size of the above buffer
|
|
PktSize- Size of whole packet
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS- Packet accepted
|
|
STATUS_NOT_RECOGNIZED- Not our packet
|
|
Other
|
|
|
|
--*/
|
|
{
|
|
PPORT_DESCRIPTOR pPortDesc = (PPORT_DESCRIPTOR)BindingCtx;
|
|
PNDIS_PACKET ndisPkt;
|
|
PBUFFER_HDR pBufferHdr = NULL;
|
|
PPROTOCOL_RESD protocolResd; // Protocolresd field in ndisPkt
|
|
UINT actualPktSize; // Size of data to copy
|
|
UINT bytesTransferred; // Number of bytes transferred in XferData
|
|
BOOLEAN result;
|
|
UINT xferOffset;
|
|
PBYTE lkBufOrig = (PBYTE)LkBuf;
|
|
ATALK_ERROR error = ATALK_NO_ERROR;
|
|
BOOLEAN shortDdpHdr = FALSE;
|
|
BYTE indicate = 0,
|
|
subType = 0;
|
|
NDIS_MEDIUM Media;
|
|
PBYTE packet = NULL; // Where we will copy the packet
|
|
NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS;
|
|
LOGICAL_PROTOCOL protocol = UNKNOWN_PROTOCOL;
|
|
PARAPCONN pArapConn;
|
|
PATCPCONN pAtcpConn;
|
|
ATALK_NODEADDR ClientNode;
|
|
#ifdef PROFILING
|
|
TIME TimeS, TimeE, TimeD;
|
|
|
|
TimeS = KeQueryPerformanceCounter(NULL);
|
|
#endif
|
|
|
|
do
|
|
{
|
|
if ((pPortDesc->pd_Flags & (PD_ACTIVE | PD_CLOSING)) != PD_ACTIVE)
|
|
{
|
|
// If we are not active, return!
|
|
ndisStatus = ATALK_PORT_CLOSING;
|
|
break;
|
|
}
|
|
|
|
ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
|
|
ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
|
|
|
Media = pPortDesc->pd_NdisPortType;
|
|
|
|
// Reduce 802.2 code, avoid making it a routine. First 802.2.
|
|
switch (Media)
|
|
{
|
|
case NdisMedium802_3:
|
|
case NdisMediumFddi:
|
|
case NdisMedium802_5:
|
|
ATALK_VERIFY8022_HDR((PBYTE)LkBuf, LkBufSize, protocol, result);
|
|
|
|
if (!result)
|
|
{
|
|
ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;
|
|
|
|
if (LkBufSize < IEEE8022_CONTROL_OFFSET+1)
|
|
{
|
|
ASSERT(0);
|
|
break;
|
|
}
|
|
|
|
if (Media == NdisMedium802_5)
|
|
{
|
|
// BUG #16002
|
|
// On tokenring the macs also send out a Unnumbered format
|
|
// TEST frame to which we need to respond. Check for that
|
|
// here.
|
|
|
|
if ((((PBYTE)LkBuf)[IEEE8022_DSAP_OFFSET] == SNAP_SAP) &&
|
|
(((PBYTE)LkBuf)[IEEE8022_SSAP_OFFSET] == SNAP_SAP) &&
|
|
(((PBYTE)LkBuf)[IEEE8022_CONTROL_OFFSET] == UNNUMBERED_FORMAT))
|
|
{
|
|
DBGPRINT(DBG_COMP_NDISRECV, DBG_LEVEL_INFO,
|
|
("atalkNdisAcceptTlapPacket: LLC TEST FRAME RECD!\n"));
|
|
|
|
RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
|
|
|
// Due to the aarp lookahead size setting, we are guaranteed
|
|
// the entire frame is contained in the lookahead data.
|
|
AtalkNdisSendTokRingTestResp(pPortDesc,
|
|
(PBYTE)HdrBuf,
|
|
HdrBufSize,
|
|
(PBYTE)LkBuf,
|
|
LkBufSize,
|
|
PktSize);
|
|
|
|
ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (protocol == APPLETALK_PROTOCOL)
|
|
{
|
|
// Do we at least have a 802.2 and DDP header in the indicated packet?
|
|
if ((PktSize < (IEEE8022_HDR_LEN + LDDP_HDR_LEN)) ||
|
|
(PktSize > (IEEE8022_HDR_LEN + MAX_LDDP_PKT_SIZE)))
|
|
{
|
|
ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;
|
|
break;
|
|
}
|
|
}
|
|
else // AARP
|
|
{
|
|
UINT routeInfoLen = 0; // length of routing info if present (802.5)
|
|
|
|
switch (Media)
|
|
{
|
|
case NdisMediumFddi:
|
|
// For fddi, there could be padding included in the packet. Shrink
|
|
// the length if so. Note header length is not included in packetlength.
|
|
//
|
|
if (PktSize >= (MIN_FDDI_PKT_LEN - FDDI_LINKHDR_LEN))
|
|
{
|
|
PktSize = (IEEE8022_HDR_LEN + AARP_MIN_DATA_SIZE);
|
|
}
|
|
break;
|
|
|
|
case NdisMedium802_5:
|
|
|
|
// Remember- routing info is in the header buffer
|
|
if (((PBYTE)HdrBuf)[TLAP_SRC_OFFSET] & TLAP_SRC_ROUTING_MASK)
|
|
{
|
|
routeInfoLen = (((PBYTE)HdrBuf)[TLAP_ROUTE_INFO_OFFSET] &
|
|
TLAP_ROUTE_INFO_SIZE_MASK);
|
|
ASSERTMSG("RouteInfo incorrect!\n",
|
|
((routeInfoLen > 0) && (routeInfoLen <= TLAP_MAX_ROUTING_BYTES)));
|
|
|
|
// Routing info must be of reasonable size, and not odd.
|
|
if ((routeInfoLen & 1) ||
|
|
(routeInfoLen > TLAP_MAX_ROUTING_BYTES))
|
|
{
|
|
ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;
|
|
break;
|
|
}
|
|
}
|
|
// Fall through to 802.3 case
|
|
|
|
case NdisMedium802_3:
|
|
if (PktSize >= (ELAP_MIN_PKT_LEN - ELAP_LINKHDR_LEN))
|
|
{
|
|
PktSize = (IEEE8022_HDR_LEN + AARP_MIN_DATA_SIZE);
|
|
}
|
|
}
|
|
|
|
if (((PktSize - IEEE8022_HDR_LEN) > AARP_MAX_DATA_SIZE) ||
|
|
((PktSize - IEEE8022_HDR_LEN) < AARP_MIN_DATA_SIZE))
|
|
{
|
|
ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;
|
|
break;
|
|
}
|
|
}
|
|
actualPktSize = (PktSize + HdrBufSize - IEEE8022_HDR_LEN);
|
|
(PBYTE)LkBuf += IEEE8022_HDR_LEN;
|
|
xferOffset = IEEE8022_HDR_LEN;
|
|
|
|
break;
|
|
|
|
case NdisMediumLocalTalk:
|
|
|
|
// No AARP/802.2 header on localtalk
|
|
protocol = APPLETALK_PROTOCOL;
|
|
|
|
// we should have enough bytes to have at least the short-header
|
|
if (LkBufSize < SDDP_PROTO_TYPE_OFFSET+1)
|
|
{
|
|
ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;
|
|
ASSERT(0);
|
|
break;
|
|
}
|
|
|
|
if (((PBYTE)HdrBuf)[ALAP_TYPE_OFFSET] == ALAP_SDDP_HDR_TYPE)
|
|
{
|
|
shortDdpHdr = TRUE;
|
|
}
|
|
else if (((PBYTE)HdrBuf)[ALAP_TYPE_OFFSET] != ALAP_LDDP_HDR_TYPE)
|
|
{
|
|
ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;
|
|
break;
|
|
}
|
|
actualPktSize = PktSize + HdrBufSize;
|
|
xferOffset = 0;
|
|
break;
|
|
|
|
case NdisMediumWan:
|
|
|
|
if (pPortDesc->pd_Flags & PD_RAS_PORT)
|
|
{
|
|
//
|
|
// 1st byte 0x01 tells us it's a PPP connection
|
|
//
|
|
if ((((PBYTE)HdrBuf)[0] == PPP_ID_BYTE1) &&
|
|
(((PBYTE)HdrBuf)[1] == PPP_ID_BYTE2))
|
|
{
|
|
RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
|
|
|
DBGDUMPBYTES("Packet from PPP client:", (PBYTE)LkBuf,LkBufSize,4);
|
|
|
|
if (AtalkReferenceDefaultPort())
|
|
{
|
|
AtalkDdpPacketIn(AtalkDefaultPort, // came on which port
|
|
NULL, // Link Hdr
|
|
(PBYTE)LkBuf, // packet
|
|
(USHORT)LkBufSize, // how big is the pkt
|
|
TRUE); // did this come on WAN?
|
|
|
|
AtalkPortDereference(AtalkDefaultPort);
|
|
}
|
|
}
|
|
|
|
//
|
|
// this is ARAP connection: lot of stuff to be done before pkt
|
|
// can be given to the right destination...
|
|
//
|
|
else
|
|
{
|
|
ASSERT ((((PBYTE)HdrBuf)[0] == ARAP_ID_BYTE1) &&
|
|
(((PBYTE)HdrBuf)[1] == ARAP_ID_BYTE2));
|
|
|
|
*((ULONG UNALIGNED *)(&pArapConn)) =
|
|
*((ULONG UNALIGNED *)(&((PBYTE)HdrBuf)[2]));
|
|
|
|
RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
|
|
|
ASSERT(pArapConn->Signature == ARAPCONN_SIGNATURE);
|
|
|
|
//
|
|
// NDISWAN guarantees that all the data is in the LookAhead buffer
|
|
//
|
|
ArapRcvIndication( pArapConn,
|
|
LkBuf,
|
|
LkBufSize );
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
// Should never happen!
|
|
DBGPRINT(DBG_COMP_DDP, DBG_LEVEL_FATAL,
|
|
("AtalkReceiveIndication: Unknown media\n"));
|
|
ASSERT(0);
|
|
ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;
|
|
break;
|
|
}
|
|
|
|
// we have already taken care of the Wan case: quit here
|
|
if (Media == NdisMediumWan)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// if pkt not interesting, quit., if this is ras adapter, quit
|
|
//
|
|
if (ndisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
|
break;
|
|
}
|
|
|
|
INTERLOCKED_INCREMENT_LONG_DPC(
|
|
&pPortDesc->pd_PortStats.prtst_NumPacketsIn,
|
|
&AtalkStatsLock.SpinLock);
|
|
|
|
INTERLOCKED_ADD_STATISTICS(&pPortDesc->pd_PortStats.prtst_DataIn,
|
|
(LONG)actualPktSize,
|
|
&AtalkStatsLock.SpinLock);
|
|
|
|
ASSERT ((protocol == APPLETALK_PROTOCOL) || (protocol == AARP_PROTOCOL));
|
|
|
|
// At this point, the IEEE802.2 header has been skipped in the lookahead
|
|
// buffer.
|
|
// Packet is to be accepted! Get an appropriate buffer and set the
|
|
// fields.
|
|
switch (protocol)
|
|
{
|
|
case APPLETALK_PROTOCOL:
|
|
// We either need to receive this packet on the default port, or
|
|
// we must be a router.
|
|
if ((pPortDesc == AtalkDefaultPort) || AtalkRouter)
|
|
{
|
|
if (shortDdpHdr)
|
|
{
|
|
// Check to see if we can indicate this to ATP/ADSP.
|
|
if ((((PBYTE)LkBuf)[SDDP_PROTO_TYPE_OFFSET] == DDPPROTO_ATP) &&
|
|
((USHORT)(LkBufSize - xferOffset) >= (SDDP_HDR_LEN + ATP_HEADER_SIZE)))
|
|
{
|
|
indicate = INDICATE_ATP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Check to see if we can indicate this to ATP/ADSP.
|
|
if ((((PBYTE)LkBuf)[LDDP_PROTO_TYPE_OFFSET] == DDPPROTO_ATP) &&
|
|
((USHORT)(LkBufSize - xferOffset) >= (LDDP_HDR_LEN + ATP_HEADER_SIZE)))
|
|
{
|
|
indicate = INDICATE_ATP;
|
|
}
|
|
}
|
|
}
|
|
|
|
// First check for optimizing ATP/ADSP packets.
|
|
if (indicate == INDICATE_ATP)
|
|
{
|
|
error = AtalkIndAtpPkt(pPortDesc,
|
|
(PBYTE)LkBuf,
|
|
(USHORT)(PktSize - xferOffset),
|
|
&xferOffset, // IN/OUT parameter
|
|
HdrBuf,
|
|
shortDdpHdr,
|
|
&subType,
|
|
&packet,
|
|
&ndisPkt);
|
|
|
|
if (ATALK_SUCCESS(error))
|
|
{
|
|
break;
|
|
}
|
|
else if (error == ATALK_INVALID_PKT)
|
|
{
|
|
// This indicates that the indication code has figured out that
|
|
// the packet is bad.
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// This is the case where the indication code cannot figure out
|
|
// if this packet qualifies.
|
|
indicate = 0;
|
|
error = ATALK_NO_ERROR;
|
|
}
|
|
}
|
|
|
|
if (actualPktSize > (sizeof(DDP_SMBUFFER) - sizeof(BUFFER_HDR)))
|
|
{
|
|
pBufferHdr = (PBUFFER_HDR)AtalkBPAllocBlock(BLKID_DDPLG);
|
|
}
|
|
else
|
|
{
|
|
pBufferHdr = (PBUFFER_HDR)AtalkBPAllocBlock(BLKID_DDPSM);
|
|
}
|
|
break;
|
|
|
|
case AARP_PROTOCOL:
|
|
pBufferHdr = (PBUFFER_HDR)AtalkBPAllocBlock(BLKID_AARP);
|
|
break;
|
|
|
|
default:
|
|
KeBugCheck(0);
|
|
break;
|
|
}
|
|
|
|
if (!ATALK_SUCCESS(error) || ((pBufferHdr == NULL) && (indicate == 0)))
|
|
{
|
|
#if DBG
|
|
UINT i;
|
|
|
|
DBGPRINT(DBG_COMP_NDISRECV, DBG_LEVEL_ERR,
|
|
("AtalkReceiveIndication: Dropping packet (2) %ld\n", error));
|
|
for (i = 0; i < HdrBufSize; i++)
|
|
DBGPRINTSKIPHDR(DBG_COMP_NDISRECV, DBG_LEVEL_ERR,
|
|
("%02x ", ((PUCHAR)HdrBuf)[i]));
|
|
for (i = 0; i < LkBufSize; i++)
|
|
DBGPRINTSKIPHDR(DBG_COMP_NDISRECV, DBG_LEVEL_ERR,
|
|
("%02x ", ((PUCHAR)LkBuf)[i]));
|
|
|
|
#endif
|
|
// No logging in this critical path.
|
|
// LOG_ERRORONPORT(pPortDesc,
|
|
// EVENT_ATALK_AARPPACKET,
|
|
// actualPktSize,
|
|
// HdrBuf,
|
|
// HdrBufSize);
|
|
|
|
RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
|
|
|
if (error != ATALK_DUP_PKT)
|
|
{
|
|
INTERLOCKED_INCREMENT_LONG_DPC(
|
|
&pPortDesc->pd_PortStats.prtst_NumPktDropped,
|
|
&AtalkStatsLock.SpinLock);
|
|
}
|
|
|
|
ndisStatus = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
if (indicate == 0)
|
|
{
|
|
packet = (PBYTE)pBufferHdr + sizeof(BUFFER_HDR);
|
|
|
|
// Get a pointer to the NDIS packet descriptor from the buffer header.
|
|
ndisPkt = pBufferHdr->bh_NdisPkt;
|
|
}
|
|
|
|
protocolResd = (PPROTOCOL_RESD)(ndisPkt->ProtocolReserved);
|
|
|
|
// Store the information needed in the packet descriptor
|
|
protocolResd->Receive.pr_Port = pPortDesc;
|
|
protocolResd->Receive.pr_Protocol = protocol;
|
|
protocolResd->Receive.pr_Processed = FALSE;
|
|
|
|
// Queue up the packet in the receive queue on this port
|
|
// Then, go ahead with the transfer data etc. For Atp response
|
|
// case when SubType == ATP_USER_BUFX, we do not want any
|
|
// Recv. completion processing, do not queue. In this case
|
|
// TransferData completion frees up the Ndis resources.
|
|
if ((indicate != INDICATE_ATP) ||
|
|
(protocolResd->Receive.pr_OptimizeSubType != ATP_USER_BUFX))
|
|
{
|
|
ATALK_RECV_INDICATION_COPY(pPortDesc,
|
|
protocolResd->Receive.pr_LinkHdr,
|
|
(PBYTE)HdrBuf,
|
|
HdrBufSize);
|
|
InsertTailList(&pPortDesc->pd_ReceiveQueue,
|
|
&protocolResd->Receive.pr_Linkage);
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_NDISRECV, DBG_LEVEL_ERR,
|
|
("AtalkReceiveIndication: Skipping link hdr !!!\n"));
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
|
#ifdef PROFILING
|
|
INTERLOCKED_INCREMENT_LONG_DPC(
|
|
&pPortDesc->pd_PortStats.prtst_CurReceiveQueue,
|
|
&AtalkStatsLock.SpinLock);
|
|
#endif
|
|
|
|
// Adjust for the link header size. Set size in protocol reserved. We want
|
|
// to avoid changing the size described by the NDIS buffer descriptor.
|
|
if (indicate == 0)
|
|
{
|
|
actualPktSize -= HdrBufSize;
|
|
protocolResd->Receive.pr_DataLength = (USHORT)actualPktSize;
|
|
}
|
|
else
|
|
{
|
|
actualPktSize = protocolResd->Receive.pr_DataLength;
|
|
}
|
|
|
|
ASSERT(ndisStatus == NDIS_STATUS_SUCCESS);
|
|
|
|
if ((PktSize <= LkBufSize) &&
|
|
((indicate != INDICATE_ATP) || (subType != ATP_RESPONSE)))
|
|
{
|
|
// LkBuf has already been advanced to skip the ieee 802.2 header.
|
|
// We may need to skip more. Use the original lkbuf and xfer offset.
|
|
ATALK_RECV_INDICATION_COPY(pPortDesc,
|
|
packet,
|
|
(PBYTE)lkBufOrig + xferOffset,
|
|
actualPktSize);
|
|
bytesTransferred = actualPktSize;
|
|
}
|
|
else
|
|
{
|
|
// Skip 802.2 header (both AARP and Appletalk), localtalk doesnt have one!
|
|
if (actualPktSize > 0)
|
|
{
|
|
NdisTransferData(&ndisStatus,
|
|
pPortDesc->pd_NdisBindingHandle,
|
|
ReceiveCtx,
|
|
xferOffset,
|
|
actualPktSize,
|
|
ndisPkt,
|
|
&bytesTransferred);
|
|
ASSERT(bytesTransferred == actualPktSize);
|
|
}
|
|
}
|
|
|
|
if (ndisStatus == NDIS_STATUS_PENDING)
|
|
{
|
|
ndisStatus = NDIS_STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
// Transfer data completed, call the transfer data completion
|
|
// routine to do rest of the work. If an error happened, ReceiveCompletion
|
|
// will drop the packet.
|
|
protocolResd->Receive.pr_ReceiveStatus = ndisStatus;
|
|
protocolResd->Receive.pr_Processed = TRUE;
|
|
|
|
// In case of intermediate Atp response, the packet is not actually linked
|
|
// into the receive queue, just free it.
|
|
if ((protocolResd->Receive.pr_OptimizeType == INDICATE_ATP) &&
|
|
(protocolResd->Receive.pr_OptimizeSubType == ATP_USER_BUFX))
|
|
{
|
|
PNDIS_BUFFER ndisBuffer;
|
|
|
|
// Free NDIS buffers if any are present.
|
|
NdisUnchainBufferAtFront(ndisPkt, &ndisBuffer);
|
|
|
|
if (ndisBuffer != NULL)
|
|
{
|
|
AtalkNdisFreeBuffer(ndisBuffer);
|
|
}
|
|
NdisDprFreePacket(ndisPkt);
|
|
}
|
|
}
|
|
} while (FALSE);
|
|
|
|
#ifdef PROFILING
|
|
TimeE = KeQueryPerformanceCounter(NULL);
|
|
TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
|
|
|
|
INTERLOCKED_ADD_LARGE_INTGR_DPC(&pPortDesc->pd_PortStats.prtst_RcvIndProcessTime,
|
|
TimeD,
|
|
&AtalkStatsLock.SpinLock);
|
|
|
|
INTERLOCKED_INCREMENT_LONG_DPC( &pPortDesc->pd_PortStats.prtst_RcvIndCount,
|
|
&AtalkStatsLock.SpinLock);
|
|
#endif
|
|
|
|
return ndisStatus;
|
|
}
|
|
|
|
|
|
VOID
|
|
AtalkTransferDataComplete(
|
|
IN NDIS_HANDLE BindingCtx,
|
|
IN PNDIS_PACKET NdisPkt,
|
|
IN NDIS_STATUS Status,
|
|
IN UINT BytesTransferred
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by NDIS to indicate completion of a TransferData
|
|
|
|
Arguments:
|
|
|
|
BindingCtx- Pointer to a port descriptor for this port
|
|
NdisPkt- Ndis packet into which data was transferred
|
|
Status- Status of request
|
|
bytesTransferred- Actual number of bytes transferred
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PPROTOCOL_RESD protocolResd;
|
|
PNDIS_BUFFER ndisBuffer;
|
|
|
|
protocolResd = (PPROTOCOL_RESD)(NdisPkt->ProtocolReserved);
|
|
|
|
protocolResd->Receive.pr_ReceiveStatus = Status;
|
|
protocolResd->Receive.pr_Processed = TRUE;
|
|
|
|
// In case of intermediate Atp response, the packet is not actually linked
|
|
// into the receive queue, just free it.
|
|
if (protocolResd->Receive.pr_OptimizeSubType == ATP_USER_BUFX)
|
|
{
|
|
// Free NDIS buffers if any are present.
|
|
NdisUnchainBufferAtFront(NdisPkt, &ndisBuffer);
|
|
|
|
if (ndisBuffer != NULL)
|
|
{
|
|
AtalkNdisFreeBuffer(ndisBuffer);
|
|
}
|
|
NdisDprFreePacket(NdisPkt);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkReceiveComplete(
|
|
IN NDIS_HANDLE BindingCtx
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We experimented with queueing up a work item for receive completion. It really
|
|
KILLED performance with multiple clients as apparently the receive completion
|
|
kept getting interrupted with receive indications. AS the optimization was
|
|
put in for slow cards like the ELNKII which do not have adequate buffering,
|
|
we decided to take it out. The retry values (or timeout trimming) should be
|
|
enough for the slow cards. They will inevitably drop packets.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PPORT_DESCRIPTOR pPortDesc = (PPORT_DESCRIPTOR)BindingCtx;
|
|
PPROTOCOL_RESD protocolResd;
|
|
PNDIS_PACKET ndisPkt;
|
|
PNDIS_BUFFER ndisBuffer;
|
|
PBUFFER_HDR pBufHdr;
|
|
NDIS_MEDIUM Media;
|
|
PLIST_ENTRY p;
|
|
PBYTE packet;
|
|
LOGICAL_PROTOCOL protocol;
|
|
UINT packetLength;
|
|
BOOLEAN fDerefDefPort=FALSE;
|
|
#ifdef PROFILING
|
|
TIME TimeS, TimeE, TimeD;
|
|
#endif
|
|
|
|
|
|
if (pPortDesc->pd_Flags & PD_RAS_PORT)
|
|
{
|
|
// give ARAP guys a chance
|
|
ArapRcvComplete();
|
|
|
|
if (!AtalkReferenceDefaultPort())
|
|
{
|
|
return;
|
|
}
|
|
|
|
fDerefDefPort = TRUE;
|
|
|
|
// give PPP guys a chance
|
|
pPortDesc = AtalkDefaultPort;
|
|
}
|
|
|
|
// Get the stuff off the receive queue for the port and send it up. Do not
|
|
// enter if the queue is initially empty.
|
|
if (IsListEmpty(&pPortDesc->pd_ReceiveQueue))
|
|
{
|
|
if (fDerefDefPort)
|
|
{
|
|
AtalkPortDereference(AtalkDefaultPort);
|
|
}
|
|
return;
|
|
}
|
|
|
|
#ifdef PROFILING
|
|
TimeS = KeQueryPerformanceCounter(NULL);
|
|
#endif
|
|
|
|
while (TRUE)
|
|
{
|
|
ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
|
p = pPortDesc->pd_ReceiveQueue.Flink;
|
|
if (p == &pPortDesc->pd_ReceiveQueue)
|
|
{
|
|
// Queue is empty
|
|
RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
|
break;
|
|
}
|
|
|
|
ndisPkt = CONTAINING_RECORD(p, NDIS_PACKET, ProtocolReserved[0]);
|
|
protocolResd = (PPROTOCOL_RESD)(ndisPkt->ProtocolReserved);
|
|
|
|
// Check if the queued receive is done processing. Since we are looping
|
|
// through the queue and since receive complete only checks if the first
|
|
// is done, we need this check here for subsequent queued up receives.
|
|
if (!protocolResd->Receive.pr_Processed)
|
|
{
|
|
// Queue is empty
|
|
RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
|
break;
|
|
}
|
|
|
|
// Dequeue and indicate this packet to the ddp/atp layer
|
|
p = RemoveHeadList(&pPortDesc->pd_ReceiveQueue);
|
|
pBufHdr = protocolResd->Receive.pr_BufHdr;
|
|
|
|
RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
|
|
|
#ifdef PROFILING
|
|
INTERLOCKED_DECREMENT_LONG_DPC(
|
|
&pPortDesc->pd_PortStats.prtst_CurReceiveQueue,
|
|
&AtalkStatsLock.SpinLock);
|
|
#endif
|
|
Media = pPortDesc->pd_NdisPortType;
|
|
protocol = protocolResd->Receive.pr_Protocol;
|
|
|
|
if ((protocol == APPLETALK_PROTOCOL) &&
|
|
(protocolResd->Receive.pr_OptimizeType == INDICATE_ATP))
|
|
{
|
|
protocolResd->Receive.pr_OptimizeType = 0;
|
|
ASSERT(protocolResd->Receive.pr_OptimizeSubType != ATP_USER_BUFX);
|
|
|
|
// Check the receive status- accept only if ok
|
|
if (protocolResd->Receive.pr_ReceiveStatus == NDIS_STATUS_SUCCESS)
|
|
{
|
|
// Glean information. Check for route info if tokenring network.
|
|
if (Media != NdisMediumLocalTalk)
|
|
{
|
|
AtalkAarpOptGleanInfo(pPortDesc,
|
|
protocolResd->Receive.pr_LinkHdr,
|
|
&protocolResd->Receive.pr_SrcAddr,
|
|
&protocolResd->Receive.pr_DestAddr,
|
|
protocolResd->Receive.pr_OffCablePkt);
|
|
}
|
|
|
|
// Different calls for response & non-response packets.
|
|
if (protocolResd->Receive.pr_OptimizeSubType == ATP_USER_BUF)
|
|
{
|
|
AtalkAtpPacketIn(AtalkDefaultPort,
|
|
protocolResd->Receive.pr_AtpAddrObj->atpao_DdpAddr,
|
|
protocolResd->Receive.pr_AtpHdr,
|
|
(USHORT)(protocolResd->Receive.pr_DataLength + 8),
|
|
&protocolResd->Receive.pr_SrcAddr,
|
|
&protocolResd->Receive.pr_DestAddr,
|
|
ATALK_NO_ERROR,
|
|
DDPPROTO_ATP,
|
|
protocolResd->Receive.pr_AtpAddrObj,
|
|
TRUE,
|
|
protocolResd->Receive.pr_OptimizeCtx);
|
|
}
|
|
else
|
|
{
|
|
ASSERT (protocolResd->Receive.pr_OptimizeSubType == ATP_ALLOC_BUF);
|
|
|
|
packet = (PBYTE)pBufHdr + sizeof(BUFFER_HDR);
|
|
ASSERT(packet != NULL);
|
|
|
|
AtalkAtpPacketIn(AtalkDefaultPort,
|
|
protocolResd->Receive.pr_AtpAddrObj->atpao_DdpAddr,
|
|
packet,
|
|
(USHORT)protocolResd->Receive.pr_DataLength,
|
|
&protocolResd->Receive.pr_SrcAddr,
|
|
&protocolResd->Receive.pr_DestAddr,
|
|
ATALK_NO_ERROR,
|
|
DDPPROTO_ATP,
|
|
protocolResd->Receive.pr_AtpAddrObj,
|
|
TRUE,
|
|
protocolResd->Receive.pr_OptimizeCtx);
|
|
}
|
|
}
|
|
|
|
// Different calls for user buffer/allocated packets
|
|
if (protocolResd->Receive.pr_OptimizeSubType == ATP_USER_BUF)
|
|
{
|
|
// Free NDIS buffers if any are present.
|
|
NdisUnchainBufferAtFront(ndisPkt, &ndisBuffer);
|
|
|
|
if (ndisBuffer != NULL)
|
|
{
|
|
AtalkNdisFreeBuffer(ndisBuffer);
|
|
}
|
|
NdisDprFreePacket(ndisPkt);
|
|
}
|
|
else
|
|
{
|
|
AtalkBPFreeBlock(packet-sizeof(BUFFER_HDR));
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// IMPORTANT:
|
|
// We know that the buffer is virtually contiguous since we allocated
|
|
// it. And we also know that only one buffer is allocated. So we use
|
|
// that knowledge to get the actual address and pass that onto the
|
|
// higher level routines.
|
|
// !!!!
|
|
// Although, the allocated buffer contains the link header tagged on at
|
|
// the end, we do not have the packet descriptor describing that. As
|
|
// far as we are concerned here, that tagged entity does not exist and
|
|
// is independently pointed to by protocolResd->pr_LinkHdr.
|
|
// !!!!
|
|
packet = (PBYTE)pBufHdr + sizeof(BUFFER_HDR);
|
|
ASSERT(packet != NULL);
|
|
|
|
packetLength = protocolResd->Receive.pr_DataLength;
|
|
|
|
// Check the receive status- accept only if ok
|
|
if (protocolResd->Receive.pr_ReceiveStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DBGPRINT(DBG_COMP_NDISRECV, DBG_LEVEL_ERR,
|
|
("AtalkReceiveComplete: ReceiveStatus FAILURE %lx!\n",
|
|
protocolResd->Receive.pr_ReceiveStatus));
|
|
|
|
AtalkBPFreeBlock(packet-sizeof(BUFFER_HDR));
|
|
continue;
|
|
}
|
|
|
|
// The packet descriptor is now associate with the buffer, and we cant
|
|
// release the buffer (and hence the descriptor) until after we indicate to
|
|
// the higher levels
|
|
|
|
switch (Media)
|
|
{
|
|
case NdisMedium802_3 :
|
|
case NdisMediumFddi :
|
|
case NdisMedium802_5 :
|
|
case NdisMediumLocalTalk :
|
|
|
|
if (protocol == APPLETALK_PROTOCOL)
|
|
{
|
|
DBGPRINT(DBG_COMP_NDISRECV, DBG_LEVEL_INFO,
|
|
("AtalkReceiveComplete: Indicating DDP Ethernet\n"));
|
|
|
|
AtalkDdpPacketIn(pPortDesc,
|
|
protocolResd->Receive.pr_LinkHdr,
|
|
packet,
|
|
(USHORT)packetLength,
|
|
FALSE);
|
|
}
|
|
else
|
|
{
|
|
// AARP Packet
|
|
DBGPRINT(DBG_COMP_NDISRECV, DBG_LEVEL_INFO,
|
|
("AtalkReceiveComplete: Indicating AARP Ethernet\n"));
|
|
|
|
ASSERT(Media != NdisMediumLocalTalk);
|
|
AtalkAarpPacketIn(pPortDesc,
|
|
protocolResd->Receive.pr_LinkHdr,
|
|
packet,
|
|
(USHORT)packetLength);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
KeBugCheck(0);
|
|
break;
|
|
}
|
|
|
|
// !!!!
|
|
// We dont have to free the link header. This follows the packet
|
|
// buffer (and was allocated along with it) and will be freed when
|
|
// the packet is freed.
|
|
AtalkBPFreeBlock(packet-sizeof(BUFFER_HDR));
|
|
}
|
|
|
|
if (fDerefDefPort)
|
|
{
|
|
AtalkPortDereference(AtalkDefaultPort);
|
|
}
|
|
|
|
#ifdef PROFILING
|
|
TimeE = KeQueryPerformanceCounter(NULL);
|
|
TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
|
|
|
|
INTERLOCKED_ADD_LARGE_INTGR_DPC(
|
|
&pPortDesc->pd_PortStats.prtst_RcvCompProcessTime,
|
|
TimeD,
|
|
&AtalkStatsLock.SpinLock);
|
|
|
|
INTERLOCKED_INCREMENT_LONG_DPC( &pPortDesc->pd_PortStats.prtst_RcvCompCount,
|
|
&AtalkStatsLock.SpinLock);
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AtalkSendComplete(
|
|
IN NDIS_HANDLE ProtoBindCtx,
|
|
IN PNDIS_PACKET NdisPkt,
|
|
IN NDIS_STATUS NdisStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
ProtoBindCtx- Binding associated with mac
|
|
NdisPkt- Packet which was sent
|
|
NdisStatus- Final status of send
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PPROTOCOL_RESD pProtocolResd;
|
|
PNDIS_BUFFER pNdisBuffer=NULL, pNdisFirstBuffer=NULL;
|
|
PPORT_DESCRIPTOR pPortDesc;
|
|
PBUFFER_DESC pBufferDesc;
|
|
SEND_COMPLETION pSendComp;
|
|
SEND_COMPL_INFO sendInfo;
|
|
|
|
// Call the completion routine, we don't care about status now
|
|
pProtocolResd = (PPROTOCOL_RESD)(NdisPkt->ProtocolReserved);
|
|
ASSERT(pProtocolResd != NULL);
|
|
|
|
pPortDesc = pProtocolResd->Send.pr_Port;
|
|
sendInfo = pProtocolResd->Send.pr_SendInfo;
|
|
pBufferDesc = pProtocolResd->Send.pr_BufferDesc;
|
|
pSendComp = pProtocolResd->Send.pr_SendCompletion;
|
|
|
|
// We free up all the ndis buffer descriptors except the first one.
|
|
// NOTE: The presence of a second buffer descriptor indicates that more
|
|
// than one NdisBuffer is present. But not necessarily just two. If
|
|
// the client had passed in a MDL chain, we would create a corresponding
|
|
// NDIS buffer descriptor chain. Therefore, remove the first, free up
|
|
// all remaining ones, then queue back the first.
|
|
|
|
NdisUnchainBufferAtFront(NdisPkt, &pNdisFirstBuffer);
|
|
|
|
if (pProtocolResd->Send.pr_BufferDesc->bd_Next != NULL)
|
|
{
|
|
while (TRUE)
|
|
{
|
|
NdisUnchainBufferAtBack(NdisPkt,
|
|
&pNdisBuffer);
|
|
|
|
if (pNdisBuffer == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Free up the ndis buffer descriptor.
|
|
AtalkNdisFreeBuffer(pNdisBuffer);
|
|
}
|
|
}
|
|
|
|
// Reintialize the packet descriptor.
|
|
NdisReinitializePacket(NdisPkt);
|
|
|
|
// Put first buffer back in.
|
|
if (pNdisFirstBuffer != NULL)
|
|
{
|
|
NdisChainBufferAtFront(NdisPkt, pNdisFirstBuffer);
|
|
}
|
|
|
|
// Call the completion routine for the transmit. This invalidates NdisPkt.
|
|
if (pSendComp)
|
|
{
|
|
(*pSendComp)(NdisStatus, pBufferDesc, &sendInfo);
|
|
}
|
|
|
|
// Dereference the port
|
|
ASSERT(pPortDesc != NULL);
|
|
|
|
#ifdef PROFILING
|
|
INTERLOCKED_DECREMENT_LONG(
|
|
&pPortDesc->pd_PortStats.prtst_CurSendsOutstanding,
|
|
&AtalkStatsLock.SpinLock);
|
|
#endif
|
|
}
|
|
|
|
|
|
VOID
|
|
AtalkBindAdapter(
|
|
OUT PNDIS_STATUS Status,
|
|
IN NDIS_HANDLE BindContext,
|
|
IN PNDIS_STRING DeviceName,
|
|
IN PVOID SystemSpecific1,
|
|
IN PVOID SystemSpecific2
|
|
)
|
|
{
|
|
// are we unloading? if so, just return
|
|
if (AtalkBindnUnloadStates & ATALK_UNLOADING)
|
|
{
|
|
DBGPRINT(DBG_COMP_NDISRECV, DBG_LEVEL_ERR,
|
|
("AtalkBindAdapter: nothing to do: driver unloading\n"));
|
|
return;
|
|
}
|
|
|
|
AtalkBindnUnloadStates |= ATALK_BINDING;
|
|
|
|
AtalkLockInitIfNecessary();
|
|
*Status = AtalkInitAdapter(DeviceName, NULL);
|
|
|
|
ASSERT(*Status != NDIS_STATUS_PENDING);
|
|
AtalkUnlockInitIfNecessary();
|
|
|
|
AtalkBindnUnloadStates &= ~ATALK_BINDING;
|
|
}
|
|
|
|
|
|
VOID
|
|
AtalkUnbindAdapter(
|
|
OUT PNDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_HANDLE UnbindContext
|
|
)
|
|
{
|
|
PPORT_DESCRIPTOR pPortDesc = (PPORT_DESCRIPTOR)ProtocolBindingContext;
|
|
|
|
|
|
DBGPRINT(DBG_COMP_ACTION, DBG_LEVEL_ERR,
|
|
("AtalkUnbindAdapter on %lx\n",ProtocolBindingContext));
|
|
|
|
ASSERT( VALID_PORT(pPortDesc) );
|
|
|
|
AtalkLockInitIfNecessary();
|
|
|
|
// First and foremost: tell guys above so they can cleanup
|
|
if ((pPortDesc->pd_Flags & PD_DEF_PORT) ||
|
|
(pPortDesc->pd_Flags & PD_RAS_PORT))
|
|
{
|
|
if (pPortDesc->pd_Flags & PD_DEF_PORT)
|
|
{
|
|
ASSERT(pPortDesc == AtalkDefaultPort);
|
|
|
|
if (TdiAddressChangeRegHandle)
|
|
{
|
|
TdiDeregisterNetAddress(TdiAddressChangeRegHandle);
|
|
TdiAddressChangeRegHandle = NULL;
|
|
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
|
|
("AtalkUnbindAdapter: TdiDeregisterNetAddress on %Z done\n",
|
|
&pPortDesc->pd_AdapterName));
|
|
|
|
}
|
|
|
|
// this will tell AFP
|
|
if (TdiRegistrationHandle)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
|
|
("AtalkUnbindAdapter: default adapter unbound, telling AFP, RAS\n"));
|
|
|
|
TdiDeregisterDeviceObject(TdiRegistrationHandle);
|
|
TdiRegistrationHandle = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
|
|
("AtalkUnbindAdapter: RAS adapter unbound! telling AFP, RAS\n"));
|
|
}
|
|
|
|
// this will take care of informing ARAP and PPP engine above
|
|
AtalkPnPInformRas(FALSE);
|
|
}
|
|
|
|
|
|
*Status = AtalkDeinitAdapter(pPortDesc);
|
|
|
|
ASSERT(*Status != NDIS_STATUS_PENDING);
|
|
AtalkUnlockInitIfNecessary();
|
|
}
|
|
|
|
|