mirror of https://github.com/lianthony/NT4.0
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.
3259 lines
81 KiB
3259 lines
81 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
atkndis.c
|
|
|
|
Abstract:
|
|
|
|
This module contains code related to ndis-interaction during pre-initialization
|
|
as well as all the code for the protocol/ndis interaction. All in one, to keep
|
|
the globals static.
|
|
|
|
Author:
|
|
|
|
Nikhil Kamkolkar (NikhilK) 8-Jun-1992
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "atalknt.h"
|
|
|
|
//
|
|
// Local routines
|
|
//
|
|
|
|
|
|
NTSTATUS
|
|
AtalkNdisBind(
|
|
PNDIS_PORTDESCRIPTORS NdisPortDesc,
|
|
INT PortNumber);
|
|
|
|
NDIS_STATUS
|
|
AtalkNdisMakeRequest(
|
|
INT Port,
|
|
PATALK_NDIS_REQUEST AtalkRequest);
|
|
|
|
NTSTATUS
|
|
AtalkCreateNdisRequest(
|
|
PATALK_NDIS_REQUEST *Request);
|
|
|
|
UINT
|
|
AtalkNdisGetNoBufferDescriptors(
|
|
PNDIS_PORTDESCRIPTORS NdisPortDesc,
|
|
INT NumberOfPorts);
|
|
|
|
UINT
|
|
AtalkNdisGetNoPacketDescriptors(
|
|
PNDIS_PORTDESCRIPTORS NdisPortDesc,
|
|
INT NumberOfPorts);
|
|
|
|
VOID
|
|
AtalkDerefNdisRequest(
|
|
IN PATALK_NDIS_REQUEST Request);
|
|
|
|
VOID
|
|
AtalkRefNdisRequest(
|
|
IN PATALK_NDIS_REQUEST Request);
|
|
|
|
VOID
|
|
AtalkOpenAdapterComplete(
|
|
IN NDIS_HANDLE NdisBindingContext,
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_STATUS OpenErrorStatus);
|
|
|
|
VOID
|
|
AtalkCloseAdapterComplete(
|
|
IN NDIS_HANDLE NdisBindingContext,
|
|
IN NDIS_STATUS Status);
|
|
|
|
VOID
|
|
AtalkResetComplete(
|
|
IN NDIS_HANDLE NdisBindingContext,
|
|
IN NDIS_STATUS Status);
|
|
|
|
VOID
|
|
AtalkRequestComplete(
|
|
IN NDIS_HANDLE NdisBindingContext,
|
|
IN PNDIS_REQUEST NdisRequest,
|
|
IN NDIS_STATUS Status);
|
|
|
|
VOID
|
|
AtalkStatusIndication (
|
|
IN NDIS_HANDLE NdisBindingContext,
|
|
IN NDIS_STATUS GeneralStatus,
|
|
IN PVOID StatusBuffer,
|
|
IN UINT StatusBufferLength);
|
|
|
|
VOID
|
|
AtalkStatusComplete (
|
|
IN NDIS_HANDLE ProtocolBindingContext);
|
|
|
|
VOID
|
|
AtalkReceiveComplete (
|
|
IN NDIS_HANDLE BindingContext);
|
|
|
|
VOID
|
|
AtalkTransferDataComplete(
|
|
IN NDIS_HANDLE BindingContext,
|
|
IN PNDIS_PACKET NdisPacket,
|
|
IN NDIS_STATUS Status,
|
|
IN UINT BytesTransferred);
|
|
|
|
VOID
|
|
AtalkSendCompletionHandler(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN PNDIS_PACKET NdisPacket,
|
|
IN NDIS_STATUS NdisStatus);
|
|
|
|
NDIS_STATUS
|
|
AtalkReceiveIndication(
|
|
IN NDIS_HANDLE BindingContext,
|
|
IN NDIS_HANDLE ReceiveContext,
|
|
IN PVOID HeaderBuffer,
|
|
IN UINT HeaderBufferSize,
|
|
IN PVOID LookaheadBuffer,
|
|
IN UINT LookaheadBufferSize,
|
|
IN UINT PacketSize);
|
|
|
|
|
|
#if DBG
|
|
VOID
|
|
DumpPacket(
|
|
PUCHAR Packet);
|
|
#endif
|
|
|
|
//
|
|
// Values that are global to all routines in this module only
|
|
//
|
|
// These are the media the stack will support
|
|
//
|
|
|
|
static NDIS_MEDIUM AtalkSupportedMedia[] = {
|
|
NdisMedium802_3,
|
|
NdisMedium802_5,
|
|
NdisMediumLocalTalk };
|
|
|
|
static NDIS_HANDLE AtalkNdisProtocolHandle; // Handle returned by NDIS (RegisterProtocol)
|
|
static NDIS_HANDLE AtalkNdisPacketPoolHandle; // Packet pool handle used for xmit/recv
|
|
static NDIS_HANDLE AtalkNdisBufferPoolHandle; // Buffer pool handle used for xmit/recv
|
|
|
|
|
|
|
|
BOOLEAN
|
|
AtalkNdisRegisterProtocol(
|
|
IN PUNICODE_STRING NameString
|
|
)
|
|
/*++
|
|
|
|
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;
|
|
NDIS_PROTOCOL_CHARACTERISTICS protocolInfo;
|
|
|
|
//
|
|
// Set up the characteristics for the protocol for registering
|
|
// with NDIS
|
|
//
|
|
|
|
protocolInfo.MajorNdisVersion = PROTOCOL_MAJORNDIS_VERSION;
|
|
protocolInfo.MinorNdisVersion = PROTOCOL_MINORNDIS_VERSION;
|
|
|
|
protocolInfo.Name.Length = NameString->Length;
|
|
protocolInfo.Name.Buffer = (PVOID)NameString->Buffer;
|
|
|
|
protocolInfo.OpenAdapterCompleteHandler = AtalkOpenAdapterComplete;
|
|
protocolInfo.CloseAdapterCompleteHandler = AtalkCloseAdapterComplete;
|
|
protocolInfo.ResetCompleteHandler = AtalkResetComplete;
|
|
protocolInfo.RequestCompleteHandler = AtalkRequestComplete;
|
|
|
|
protocolInfo.SendCompleteHandler = AtalkSendCompletionHandler;
|
|
protocolInfo.TransferDataCompleteHandler = AtalkTransferDataComplete;
|
|
|
|
protocolInfo.ReceiveHandler = AtalkReceiveIndication;
|
|
protocolInfo.ReceiveCompleteHandler = AtalkReceiveComplete;
|
|
protocolInfo.StatusHandler = AtalkStatusIndication;
|
|
protocolInfo.StatusCompleteHandler = AtalkStatusComplete;
|
|
|
|
NdisRegisterProtocol(
|
|
&ndisStatus,
|
|
&AtalkNdisProtocolHandle,
|
|
&protocolInfo,
|
|
(UINT)sizeof(NDIS_PROTOCOL_CHARACTERISTICS)+NameString->Length);
|
|
|
|
if (ndisStatus != NDIS_STATUS_SUCCESS) {
|
|
|
|
//
|
|
// BUGBUG: Log error
|
|
//
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISREQ, DEBUG_LEVEL_FATAL,
|
|
("ERROR: AtalkNdisRegisterProtocol - failed %d\n", ndisStatus));
|
|
}
|
|
|
|
return(ndisStatus == NDIS_STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkNdisDeregisterProtocol(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to deregister the protocol
|
|
|
|
Arguments:
|
|
|
|
NONE
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
--*/
|
|
{
|
|
NDIS_STATUS status;
|
|
|
|
NdisDeregisterProtocol(
|
|
&status,
|
|
AtalkNdisProtocolHandle);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS) {
|
|
|
|
//
|
|
// BUGBUG
|
|
// Log error
|
|
//
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISREQ, DEBUG_LEVEL_ERROR,
|
|
("ERROR: AtalkNdisDeregisterProtocol - failed %d\n", status));
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
INT
|
|
AtalkNdisBindToMacs(
|
|
PNDIS_PORTDESCRIPTORS NdisPortDesc,
|
|
INT NumberOfPorts
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called during initialization time to bind to all the macs
|
|
specified
|
|
|
|
Arguments:
|
|
|
|
NdisPortDesc- Pointer to beginning of the array of port descriptors
|
|
NumberOfPorts- Number of elements in this array
|
|
|
|
Return Value:
|
|
|
|
Number of successful bindings
|
|
--*/
|
|
{
|
|
NDIS_STATUS ndisStatus, openStatus;
|
|
UINT selectedMediumIndex;
|
|
INT i, noSuccessfulBinds = 0;
|
|
|
|
|
|
for (i=0; i<NumberOfPorts; i++) {
|
|
if (NdisPortDesc[i].PortState == STATE_ADAPTER_SPECIFIED) {
|
|
|
|
// Initialize the event.
|
|
KeInitializeEvent(
|
|
&NdisPortDesc[i].RequestEvent,
|
|
NotificationEvent,
|
|
FALSE);
|
|
|
|
// We use the event in the Ndis port descriptor to block in case this
|
|
// request pends.
|
|
|
|
// Reset the event before we call open adapter.
|
|
KeResetEvent(
|
|
&NdisPortDesc[i].RequestEvent);
|
|
|
|
NdisOpenAdapter(
|
|
&ndisStatus, // open status
|
|
&openStatus, // more info not used
|
|
&NdisPortDesc[i].NdisBindingHandle,
|
|
&selectedMediumIndex,
|
|
AtalkSupportedMedia,
|
|
sizeof(AtalkSupportedMedia)/sizeof(NDIS_MEDIUM),
|
|
AtalkNdisProtocolHandle,
|
|
(NDIS_HANDLE)&NdisPortDesc[i],
|
|
(PNDIS_STRING)&NdisPortDesc[i].AdapterName,
|
|
0, // Open options
|
|
NULL); // Addressing information
|
|
|
|
|
|
if (ndisStatus == NDIS_STATUS_PENDING) {
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISREQ, DEBUG_LEVEL_INFOCLASS1,
|
|
("INFO1: AtalkNdisBindToMacs - OpenAdapter is pending for %d\n", i));
|
|
|
|
//
|
|
// Make sure we are not at or above dispatch level
|
|
//
|
|
|
|
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
//
|
|
// Wait on event, completion routine will set NdisRequestEvent
|
|
//
|
|
|
|
KeWaitForSingleObject(
|
|
&NdisPortDesc[i].RequestEvent,
|
|
Executive,
|
|
KernelMode,
|
|
TRUE,
|
|
(PLARGE_INTEGER)NULL);
|
|
|
|
ndisStatus = NdisPortDesc[i].RequestStatus;
|
|
}
|
|
|
|
if (ndisStatus == NDIS_STATUS_SUCCESS) {
|
|
|
|
NdisPortDesc[i].PortState = STATE_BOUND;
|
|
NdisPortDesc[i].PortNumber = noSuccessfulBinds;
|
|
NdisPortDesc[i].NdisPortType =
|
|
AtalkSupportedMedia[selectedMediumIndex];
|
|
|
|
noSuccessfulBinds++;
|
|
|
|
|
|
} else {
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISREQ, DEBUG_LEVEL_ERROR,
|
|
("ERROR: NdisOpenAdapter bind to %d failed %lx!\n", i, ndisStatus));
|
|
}
|
|
}
|
|
}
|
|
|
|
return(noSuccessfulBinds);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkNdisUnbindFromMacs(
|
|
PNDIS_PORTDESCRIPTORS NdisPortDesc,
|
|
INT NumberOfPorts
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called during to unbind from all the macs currently bound to
|
|
|
|
Arguments:
|
|
|
|
NdisPortDesc- Pointer to beginning of the array of port descriptors
|
|
NumberOfPorts- Number of elements in this array
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
--*/
|
|
{
|
|
NDIS_STATUS ndisStatus;
|
|
BOOLEAN unbind;
|
|
INT i;
|
|
|
|
for (i = 0; i < NumberOfPorts; i++) {
|
|
|
|
//
|
|
// Grab the perport lock
|
|
//
|
|
|
|
unbind = FALSE;
|
|
ACQUIRE_SPIN_LOCK(&NdisPortDesc[i].PerPortLock);
|
|
if (NdisPortDesc[i].PortState == STATE_BOUND) {
|
|
NdisPortDesc[i].PortState = STATE_UNBINDING;
|
|
unbind = TRUE;
|
|
}
|
|
RELEASE_SPIN_LOCK(&NdisPortDesc[i].PerPortLock);
|
|
|
|
if (unbind) {
|
|
|
|
// Reset the event before we call open adapter.
|
|
KeResetEvent(
|
|
&NdisPortDesc[i].RequestEvent);
|
|
|
|
NdisCloseAdapter(
|
|
&ndisStatus,
|
|
NdisPortDesc[i].NdisBindingHandle);
|
|
|
|
if (ndisStatus == NDIS_STATUS_PENDING) {
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISREQ, DEBUG_LEVEL_INFOCLASS1,
|
|
("INFO1: AtalkNdisUnbindFromMacs - pending for %d!\n", i));
|
|
|
|
//
|
|
// Make sure we are not at or above dispatch level
|
|
//
|
|
|
|
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
//
|
|
// Wait on event, completion routine will set NdisRequestEvent
|
|
//
|
|
|
|
KeWaitForSingleObject(
|
|
&NdisPortDesc[i].RequestEvent,
|
|
Executive,
|
|
KernelMode,
|
|
TRUE,
|
|
(PLARGE_INTEGER)NULL);
|
|
|
|
ndisStatus = NdisPortDesc[i].RequestStatus;
|
|
|
|
} else if (ndisStatus == NDIS_STATUS_SUCCESS) {
|
|
|
|
// Set the state to be unbound.
|
|
// !!! Dont call the completion routine! It will
|
|
// set the event and stuff !!!
|
|
|
|
ACQUIRE_SPIN_LOCK(&NdisPortDesc->PerPortLock);
|
|
NdisPortDesc->PortState == STATE_UNBOUND;
|
|
RELEASE_SPIN_LOCK(&NdisPortDesc->PerPortLock);
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
NTSTATUS
|
|
AtalkNdisBind(
|
|
PNDIS_PORTDESCRIPTORS NdisPortDesc,
|
|
INT PortNumber
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called during initialization time to bind to the mac
|
|
specified by the AdapterName in the passed-in NdisPortDesc
|
|
|
|
DO NOT CALL THIS ROUTINE at dispatch level! Also, it is assumed that
|
|
only *one* thread of execution will be passing through this routine.
|
|
This routine could potentially block and also uses a global event for
|
|
synchronization with the completion routine *and* some static data.
|
|
|
|
Arguments:
|
|
|
|
NdisPortDesc- Pointer to a port descriptor
|
|
|
|
Return Value:
|
|
|
|
Status - STATUS_SUCCESS if the mac was bound to
|
|
STATUS_INSUFFICIENT_RESOURCES otherwise.
|
|
--*/
|
|
{
|
|
NDIS_STATUS ndisStatus, openStatus;
|
|
UINT selectedMediumIndex;
|
|
|
|
//
|
|
// We use the event in the Ndis port descriptor to block in case this
|
|
// request pends.
|
|
//
|
|
// OpenAdapter
|
|
// Wait for completion
|
|
// Set state/media in NdisPortDesc
|
|
//
|
|
|
|
KeInitializeEvent(
|
|
&NdisPortDesc->RequestEvent,
|
|
NotificationEvent,
|
|
FALSE);
|
|
|
|
NdisOpenAdapter(
|
|
&ndisStatus, // open status
|
|
&openStatus, // more info which we don't use
|
|
&NdisPortDesc->NdisBindingHandle,
|
|
&selectedMediumIndex,
|
|
AtalkSupportedMedia,
|
|
sizeof(AtalkSupportedMedia)/sizeof(NDIS_MEDIUM),
|
|
AtalkNdisProtocolHandle,
|
|
(NDIS_HANDLE)NdisPortDesc,
|
|
(PNDIS_STRING)&NdisPortDesc->AdapterName,
|
|
0, // Open options
|
|
NULL); // Addressing information
|
|
|
|
|
|
if (ndisStatus == NDIS_STATUS_PENDING) {
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISREQ, DEBUG_LEVEL_INFOCLASS0, ("INFO: OpenAdapter is pending!\n"));
|
|
|
|
//
|
|
// Make sure we are not at or above dispatch level
|
|
//
|
|
|
|
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
//
|
|
// Wait on event, completion routine will set NdisRequestEvent
|
|
//
|
|
|
|
KeWaitForSingleObject(
|
|
&NdisPortDesc->RequestEvent,
|
|
Executive,
|
|
KernelMode,
|
|
TRUE,
|
|
(PLARGE_INTEGER)NULL);
|
|
|
|
ndisStatus = NdisPortDesc->RequestStatus;
|
|
|
|
KeResetEvent(
|
|
&NdisPortDesc->RequestEvent);
|
|
}
|
|
|
|
if (ndisStatus == NDIS_STATUS_SUCCESS) {
|
|
|
|
NdisPortDesc->PortState = STATE_BOUND;
|
|
NdisPortDesc->PortNumber = PortNumber;
|
|
NdisPortDesc->NdisPortType = AtalkSupportedMedia[selectedMediumIndex];
|
|
|
|
} else {
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISREQ, DEBUG_LEVEL_ERROR, ("ERROR: NdisOpenAdapter failed %lx!\n", ndisStatus));
|
|
}
|
|
|
|
return(((ndisStatus == NDIS_STATUS_SUCCESS) ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES));
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
UINT
|
|
AtalkNdisGetNoPacketDescriptors(
|
|
PNDIS_PORTDESCRIPTORS NdisPortDesc,
|
|
INT NumberOfPorts
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the number of packet descriptors to allocate for this
|
|
protocol globally. It will determine some values based on number of ports
|
|
bound to.
|
|
|
|
Arguments:
|
|
|
|
NdisPortDesc- Pointer to a port descriptor
|
|
NumberOfPorts- Number of ports.
|
|
|
|
Return Value:
|
|
|
|
Number of packet descriptors to allocate
|
|
--*/
|
|
{
|
|
INT i;
|
|
INT noBindings = 0;
|
|
|
|
|
|
for (i = 0; i < NumberOfPorts; i++) {
|
|
if (NdisPortDesc[i].PortState == STATE_BOUND) {
|
|
noBindings++;
|
|
}
|
|
}
|
|
|
|
return(noBindings*PACKETDESCRIPTORS_PERPORT);
|
|
}
|
|
|
|
|
|
|
|
|
|
UINT
|
|
AtalkNdisGetNoBufferDescriptors(
|
|
PNDIS_PORTDESCRIPTORS NdisPortDesc,
|
|
INT NumberOfPorts
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the number of buffer descriptors to allocate for this
|
|
protocol globally. It will determine some values based on number of ports
|
|
bound to.
|
|
|
|
Arguments:
|
|
|
|
NdisPortDesc- Pointer to a port descriptor
|
|
NumberOfPorts- Number of ports.
|
|
|
|
Return Value:
|
|
|
|
Number of buffer descriptors to allocate
|
|
--*/
|
|
{
|
|
INT i;
|
|
INT noBindings = 0;
|
|
|
|
|
|
for (i = 0; i < NumberOfPorts; i++) {
|
|
if (NdisPortDesc[i].PortState == STATE_BOUND) {
|
|
noBindings++;
|
|
}
|
|
}
|
|
|
|
return(noBindings*BUFFERDESCRIPTORS_PERPORT);
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
AtalkNdisInitializeResources(
|
|
PNDIS_PORTDESCRIPTORS NdisPortDesc,
|
|
INT NumberOfPorts
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called during initialization time to initialize any
|
|
Ndis resources for the bound macs. It will be aware enough to use
|
|
all information provided in the port descriptors to allocate proper
|
|
amount and type of resources. It will also allocate the global packet
|
|
and buffer descriptor pools.
|
|
|
|
Arguments:
|
|
|
|
NdisPortDesc- Pointer to a port descriptor
|
|
NumberOfPorts- Number of ports available
|
|
|
|
Return Value:
|
|
|
|
Status - STATUS_SUCCESS if all resources were allocated
|
|
STATUS_INSUFFICIENT_RESOURCES otherwise.
|
|
--*/
|
|
{
|
|
NDIS_STATUS ndisStatus;
|
|
INT portNumber;
|
|
|
|
//
|
|
// Setup the global ndis packet descriptor pools
|
|
//
|
|
|
|
NdisAllocatePacketPool(
|
|
&ndisStatus,
|
|
&AtalkNdisPacketPoolHandle,
|
|
AtalkNdisGetNoPacketDescriptors(NdisPortDesc, NumberOfPorts),
|
|
sizeof(PROTOCOL_RESD));
|
|
|
|
if ((ndisStatus != NDIS_STATUS_SUCCESS) &&
|
|
(ndisStatus != NDIS_STATUS_PENDING)) {
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISREQ, DEBUG_LEVEL_ERROR,
|
|
("ERROR: AtalkNdisInitializeResources - NdisAllocatePool failed %lx!\n",
|
|
ndisStatus));
|
|
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
//
|
|
// Setup the global ndis buffer descriptor pools
|
|
//
|
|
|
|
NdisAllocateBufferPool(
|
|
&ndisStatus,
|
|
&AtalkNdisBufferPoolHandle,
|
|
AtalkNdisGetNoBufferDescriptors(NdisPortDesc, NumberOfPorts));
|
|
|
|
if ((ndisStatus != NDIS_STATUS_SUCCESS) &&
|
|
(ndisStatus != NDIS_STATUS_PENDING)) {
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISREQ, DEBUG_LEVEL_ERROR,
|
|
("ERROR: AtalkNdisInitializeResources - NdisAllocateBuf failed %lx!\n",
|
|
ndisStatus));
|
|
|
|
NdisFreePacketPool(AtalkNdisPacketPoolHandle);
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
for (portNumber = 0; portNumber < NumberOfPorts; portNumber++) {
|
|
if (NdisPortDesc[portNumber].PortState == STATE_BOUND) {
|
|
|
|
//
|
|
// Do all the work
|
|
//
|
|
|
|
NdisAllocateSpinLock(&NdisPortDesc[portNumber].ReceiveLock);
|
|
NdisAllocateSpinLock(&NdisPortDesc[portNumber].PerPortLock);
|
|
|
|
//
|
|
// Initialize the list heads
|
|
//
|
|
|
|
InitializeListHead(&NdisPortDesc[portNumber].ReceiveQueue);
|
|
}
|
|
}
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkNdisReleaseResources(
|
|
PNDIS_PORTDESCRIPTORS NdisPortDesc,
|
|
INT NumberOfPorts
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine releases all resources allocated during NdisAllocateResources.
|
|
|
|
Arguments:
|
|
|
|
NdisPortDesc- Pointer to a port descriptor
|
|
NumberOfPorts- Number of ports available
|
|
|
|
Return Value:
|
|
|
|
None
|
|
--*/
|
|
{
|
|
INT portNumber;
|
|
|
|
NdisFreePacketPool(AtalkNdisPacketPoolHandle);
|
|
NdisFreeBufferPool(AtalkNdisBufferPoolHandle);
|
|
|
|
for (portNumber = 0; portNumber < NumberOfPorts; portNumber++) {
|
|
if (NdisPortDesc[portNumber].PortState == STATE_BOUND) {
|
|
|
|
NdisFreeSpinLock(&NdisPortDesc[portNumber].ReceiveLock);
|
|
NdisFreeSpinLock(&NdisPortDesc[portNumber].PerPortLock);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
// NDIS Request Structure Creation/Reference etc. routines
|
|
//
|
|
|
|
|
|
|
|
NTSTATUS
|
|
AtalkCreateNdisRequest(
|
|
PATALK_NDIS_REQUEST *Request
|
|
)
|
|
{
|
|
PATALK_NDIS_REQUEST request;
|
|
|
|
request = (PATALK_NDIS_REQUEST)AtalkCallocNonPagedMemory(
|
|
sizeof(ATALK_NDIS_REQUEST),
|
|
sizeof(char));
|
|
if (request == NULL) {
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISREQ, DEBUG_LEVEL_SEVERE,
|
|
("SEVERE: AtalkCreateNdisRequest - Malloc failed %lx!\n",
|
|
sizeof(ATALK_NDIS_REQUEST)));
|
|
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
request->Type = ATALK_NDIS_REQUEST_SIGNATURE;
|
|
request->Size = sizeof(ATALK_NDIS_REQUEST);
|
|
|
|
//
|
|
// A reference for creation
|
|
//
|
|
|
|
#if DBG
|
|
request->RefTypes[NREF_CREATE] = 1;
|
|
#endif
|
|
|
|
request->ReferenceCount = 1;
|
|
|
|
*Request = request;
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkDestroyNdisRequest(
|
|
PATALK_NDIS_REQUEST Request
|
|
)
|
|
{
|
|
PCHAR informationBuffer;
|
|
|
|
//
|
|
// Free the information buffer and then the atalkRequest buffer
|
|
//
|
|
|
|
switch (Request->Request.RequestType) {
|
|
case NdisRequestQueryInformation :
|
|
|
|
informationBuffer =
|
|
Request->Request.DATA.QUERY_INFORMATION.InformationBuffer;
|
|
break;
|
|
|
|
case NdisRequestSetInformation :
|
|
|
|
informationBuffer =
|
|
Request->Request.DATA.QUERY_INFORMATION.InformationBuffer;
|
|
break;
|
|
|
|
default:
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISREQ, DEBUG_LEVEL_ERROR,
|
|
("ERROR: AtalkDestroyNdisRequest - unknown type %d\n",
|
|
Request->Request.RequestType));
|
|
|
|
informationBuffer = NULL;
|
|
}
|
|
|
|
if (informationBuffer != NULL) {
|
|
AtalkFreeNonPagedMemory(informationBuffer);
|
|
} else {
|
|
DBGPRINT(ATALK_DEBUG_NDISREQ, DEBUG_LEVEL_ERROR,
|
|
("ERROR: AtalkDestroyNdisRequest - Information buffer was Null! %lx\n",
|
|
Request));
|
|
}
|
|
|
|
//
|
|
// Now free the request buffer itself
|
|
//
|
|
|
|
AtalkFreeNonPagedMemory(Request);
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkRefNdisRequest(
|
|
IN PATALK_NDIS_REQUEST Request
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine increments the reference count on a ndis request structure
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG count;
|
|
|
|
count = NdisInterlockedAddUlong (
|
|
(PULONG)&Request->ReferenceCount,
|
|
(ULONG)1,
|
|
&AtalkGlobalRefLock);
|
|
|
|
ASSERT (count > 0);
|
|
|
|
} /* AtalkRefNdisRequest */
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkDerefNdisRequest(
|
|
IN PATALK_NDIS_REQUEST Request
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine dereferences a transport Request by decrementing the
|
|
reference count contained in the structure. If, after being
|
|
decremented, the reference count is zero, then this routine calls
|
|
AtalkDestroyRequest to remove it from the system.
|
|
|
|
Arguments:
|
|
|
|
Request - Pointer to a transport Request object.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG count;
|
|
|
|
count = NdisInterlockedAddUlong (
|
|
(PULONG)&Request->ReferenceCount,
|
|
(ULONG)-1,
|
|
&AtalkGlobalRefLock);
|
|
|
|
//
|
|
// If we have deleted all references to this Request, then we can
|
|
// destroy the object. It is okay to have already released the spin
|
|
// lock at this point because there is no possible way that another
|
|
// stream of execution has access to the Request any longer.
|
|
//
|
|
|
|
ASSERT (count >= 0);
|
|
|
|
if (count == 1) {
|
|
AtalkDestroyNdisRequest(Request);
|
|
}
|
|
|
|
return;
|
|
|
|
} /* AtalkDerefNdisRequest */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
// NDIS Request Routines
|
|
// NOTE: For all of these request routines, the callers in atkdep.c or the
|
|
// portable code will log errors. No errors will be logged in here.
|
|
// Even for the SetMulticastList, the caller should supply a completion
|
|
// routine for async completion and *that* completion routine should
|
|
// log an error.
|
|
//
|
|
|
|
|
|
BOOLEAN
|
|
AtalkNdisGetCurrentStationAddress(
|
|
int Port,
|
|
PCHAR Address,
|
|
USHORT AddressLength,
|
|
NDIS_MEDIUM Media,
|
|
REQUEST_METHOD RequestMethod,
|
|
PVOID CompletionRoutine,
|
|
PVOID CompletionContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the portable code to get the
|
|
address for the adapter on this port
|
|
|
|
Arguments:
|
|
|
|
Port- The port number associated with the adapter
|
|
Address- A buffer to hold the address
|
|
|
|
Return Value:
|
|
|
|
TRUE- If initialized, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS ndisStatus;
|
|
PCHAR address;
|
|
PATALK_NDIS_REQUEST atalkRequest;
|
|
NDIS_OID ndisOid;
|
|
|
|
ASSERT(RequestMethod == SYNC);
|
|
|
|
//
|
|
// Allocate, as we could potentially pend, called routine will free it up
|
|
//
|
|
|
|
address = (PCHAR)AtalkAllocNonPagedMemory(AddressLength);
|
|
if (address == NULL ) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!NT_SUCCESS(AtalkCreateNdisRequest(&atalkRequest))) {
|
|
|
|
//
|
|
// Free the memory
|
|
//
|
|
|
|
AtalkFreeNonPagedMemory(address);
|
|
return FALSE;
|
|
}
|
|
|
|
switch (Media) {
|
|
case NdisMedium802_3 :
|
|
|
|
ndisOid = OID_802_3_CURRENT_ADDRESS;
|
|
break;
|
|
|
|
case NdisMedium802_5:
|
|
|
|
ndisOid = OID_802_5_CURRENT_ADDRESS;
|
|
break;
|
|
|
|
case NdisMediumLocalTalk :
|
|
|
|
ndisOid = OID_LTALK_CURRENT_NODE_ID;
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Setup request
|
|
//
|
|
|
|
atalkRequest->RequestMethod = RequestMethod;
|
|
atalkRequest->CompletionRoutine = CompletionRoutine;
|
|
atalkRequest->CompletionContext = CompletionContext;
|
|
|
|
atalkRequest->Request.RequestType = NdisRequestQueryInformation;
|
|
atalkRequest->Request.DATA.QUERY_INFORMATION.Oid = ndisOid;
|
|
|
|
atalkRequest->Request.DATA.QUERY_INFORMATION.InformationBuffer =
|
|
address;
|
|
atalkRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength =
|
|
AddressLength;
|
|
|
|
ndisStatus = AtalkNdisMakeRequest(Port, atalkRequest);
|
|
if (ndisStatus != NDIS_STATUS_SUCCESS) {
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISREQ, DEBUG_LEVEL_ERROR,
|
|
("ERROR: AtalkNdisGetEthernetAddress FAILED %lx\n", ndisStatus));
|
|
|
|
} else {
|
|
|
|
//
|
|
// Move address into caller's buffer
|
|
//
|
|
|
|
RtlMoveMemory(Address, address, AddressLength);
|
|
}
|
|
|
|
//
|
|
// Dereference the request structure
|
|
//
|
|
|
|
AtalkDereferenceNdisRequest ("Create", atalkRequest, NREF_CREATE);
|
|
return(ndisStatus == NDIS_STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
AtalkNdisSetLookaheadSize(
|
|
INT Port,
|
|
INT LookaheadSize,
|
|
REQUEST_METHOD RequestMethod,
|
|
PVOID CompletionRoutine,
|
|
PVOID CompletionContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the portable code to set the lookahead data
|
|
size
|
|
|
|
Arguments:
|
|
|
|
Port- The port number associated with the adapter to be initialized
|
|
LookaheadSize- Size to be set as the lookahead size
|
|
|
|
Return Value:
|
|
|
|
TRUE- If initialized, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS ndisStatus;
|
|
PATALK_NDIS_REQUEST atalkRequest;
|
|
PULONG lookaheadSize;
|
|
|
|
ASSERT(RequestMethod == SYNC);
|
|
|
|
//
|
|
// Need to allocate this...
|
|
//
|
|
|
|
lookaheadSize = (PULONG)AtalkAllocNonPagedMemory(sizeof(ULONG));
|
|
if (lookaheadSize == NULL ) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!NT_SUCCESS(AtalkCreateNdisRequest(&atalkRequest))) {
|
|
|
|
//
|
|
// Free the memory
|
|
//
|
|
|
|
AtalkFreeNonPagedMemory(lookaheadSize);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Setup request
|
|
// If this request fails, stack should fail to load...
|
|
// AARP and stuff depends on the lookahead being some minimum...
|
|
//
|
|
|
|
*lookaheadSize = LookaheadSize;
|
|
|
|
atalkRequest->RequestMethod = RequestMethod;
|
|
atalkRequest->CompletionRoutine = CompletionRoutine;
|
|
atalkRequest->CompletionContext = CompletionContext;
|
|
|
|
atalkRequest->Request.RequestType = NdisRequestSetInformation;
|
|
atalkRequest->Request.DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_LOOKAHEAD;
|
|
atalkRequest->Request.DATA.SET_INFORMATION.InformationBuffer = lookaheadSize;
|
|
atalkRequest->Request.DATA.SET_INFORMATION.InformationBufferLength = sizeof(INT);
|
|
|
|
ndisStatus = AtalkNdisMakeRequest(Port, atalkRequest);
|
|
if (ndisStatus != NDIS_STATUS_SUCCESS) {
|
|
DBGPRINT(ATALK_DEBUG_NDISREQ, DEBUG_LEVEL_FATAL,
|
|
("ERROR: AtalkNdisSetLookahead FAILED %lx\n", ndisStatus));
|
|
}
|
|
|
|
AtalkDereferenceNdisRequest ("Create", atalkRequest, NREF_CREATE);
|
|
return(ndisStatus == NDIS_STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
AtalkNdisSetPacketFilter(
|
|
INT Port,
|
|
ULONG PacketFilter,
|
|
REQUEST_METHOD RequestMethod,
|
|
PVOID CompletionRoutine,
|
|
PVOID CompletionContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the portable code to set the packet filter
|
|
|
|
Arguments:
|
|
|
|
Port- The port number associated with the adapter to be initialized
|
|
PacketFilter- Packet filter to be set for adapter on port
|
|
|
|
Return Value:
|
|
|
|
TRUE- If set, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS ndisStatus;
|
|
PATALK_NDIS_REQUEST atalkRequest;
|
|
PULONG packetFilter;
|
|
|
|
|
|
ASSERT(RequestMethod == SYNC);
|
|
|
|
//
|
|
// Need to allocate this...
|
|
//
|
|
|
|
packetFilter = (PULONG)AtalkAllocNonPagedMemory(sizeof(ULONG));
|
|
if (packetFilter == NULL ) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!NT_SUCCESS(AtalkCreateNdisRequest(&atalkRequest))) {
|
|
|
|
//
|
|
// Free the memory
|
|
//
|
|
|
|
AtalkFreeNonPagedMemory(packetFilter);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Setup request
|
|
//
|
|
|
|
*packetFilter = PacketFilter;
|
|
|
|
atalkRequest->RequestMethod = RequestMethod;
|
|
atalkRequest->CompletionRoutine = CompletionRoutine;
|
|
atalkRequest->CompletionContext = CompletionContext;
|
|
|
|
atalkRequest->Request.RequestType = NdisRequestSetInformation;
|
|
atalkRequest->Request.DATA.SET_INFORMATION.Oid =OID_GEN_CURRENT_PACKET_FILTER;
|
|
atalkRequest->Request.DATA.SET_INFORMATION.InformationBuffer = packetFilter;
|
|
|
|
atalkRequest->Request.DATA.SET_INFORMATION.InformationBufferLength =
|
|
sizeof(ULONG);
|
|
|
|
ndisStatus = AtalkNdisMakeRequest(Port, atalkRequest);
|
|
if (ndisStatus != NDIS_STATUS_SUCCESS) {
|
|
DBGPRINT(ATALK_DEBUG_NDISREQ, DEBUG_LEVEL_FATAL,
|
|
("ERROR: AtalkNdisSetpacketfilter FAILED %lx\n", ndisStatus));
|
|
}
|
|
|
|
AtalkDereferenceNdisRequest ("Create", atalkRequest, NREF_CREATE);
|
|
return(ndisStatus == NDIS_STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
AtalkNdisSetMulticastAddressList(
|
|
INT Port,
|
|
PCHAR AddressList,
|
|
ULONG SizeOfList,
|
|
REQUEST_METHOD RequestMethod,
|
|
PVOID CompletionRoutine,
|
|
PVOID CompletionContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the portable code to add the specified
|
|
multicast address to the existing list
|
|
|
|
Arguments:
|
|
|
|
Port- The port number associated with the adapter to be initialized
|
|
AddressList- Buffer containing the address list to be set
|
|
SizeOfList- The size of the address list
|
|
|
|
Return Value:
|
|
|
|
TRUE- If set successfully OR pending, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS ndisStatus;
|
|
PATALK_NDIS_REQUEST atalkRequest;
|
|
PCHAR addressData;
|
|
|
|
|
|
ASSERT(RequestMethod == SYNC_IF_POSSIBLE);
|
|
|
|
//
|
|
// Need to allocate this...
|
|
//
|
|
|
|
addressData = (PCHAR)AtalkAllocNonPagedMemory(SizeOfList);
|
|
if (addressData == NULL ) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!NT_SUCCESS(AtalkCreateNdisRequest(&atalkRequest))) {
|
|
|
|
//
|
|
// Free the allocated memory
|
|
//
|
|
|
|
AtalkFreeNonPagedMemory(addressData);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Setup request
|
|
// Move the list to our buffer
|
|
//
|
|
|
|
RtlMoveMemory(addressData, AddressList, SizeOfList);
|
|
|
|
atalkRequest->RequestMethod = RequestMethod;
|
|
atalkRequest->CompletionRoutine = CompletionRoutine;
|
|
atalkRequest->CompletionContext = CompletionContext;
|
|
|
|
atalkRequest->Request.RequestType = NdisRequestSetInformation;
|
|
atalkRequest->Request.DATA.SET_INFORMATION.Oid = OID_802_3_MULTICAST_LIST;
|
|
atalkRequest->Request.DATA.SET_INFORMATION.InformationBuffer = addressData;
|
|
atalkRequest->Request.DATA.SET_INFORMATION.InformationBufferLength = SizeOfList;
|
|
|
|
ndisStatus = AtalkNdisMakeRequest(Port, atalkRequest);
|
|
ASSERT((ndisStatus == NDIS_STATUS_SUCCESS) || (ndisStatus == NDIS_STATUS_PENDING));
|
|
|
|
AtalkDereferenceNdisRequest ("Create", atalkRequest, NREF_CREATE);
|
|
return(ndisStatus == NDIS_STATUS_SUCCESS || ndisStatus == NDIS_STATUS_PENDING);
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
AtalkNdisSetFunctionalAddress(
|
|
INT Port,
|
|
PCHAR FunctionalAddress,
|
|
ULONG FunctionalAddressLength,
|
|
REQUEST_METHOD RequestMethod,
|
|
PVOID CompletionRoutine,
|
|
PVOID CompletionContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the portable code to add the specified
|
|
multicast address to the existing list
|
|
|
|
Arguments:
|
|
|
|
Port- The port number associated with the adapter to be initialized
|
|
AddressList- Buffer containing the address list to be set
|
|
SizeOfList- The size of the address list
|
|
|
|
Return Value:
|
|
|
|
TRUE- If set successfully OR pending, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS ndisStatus;
|
|
PATALK_NDIS_REQUEST atalkRequest;
|
|
PCHAR addressData;
|
|
|
|
|
|
ASSERT(RequestMethod == SYNC_IF_POSSIBLE);
|
|
|
|
//
|
|
// Need to allocate this...
|
|
//
|
|
|
|
addressData = (PCHAR)AtalkAllocNonPagedMemory(FunctionalAddressLength);
|
|
if (addressData == NULL ) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!NT_SUCCESS(AtalkCreateNdisRequest(&atalkRequest))) {
|
|
|
|
//
|
|
// Free the allocated memory
|
|
//
|
|
|
|
AtalkFreeNonPagedMemory(addressData);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Setup request
|
|
// Move the list to our buffer
|
|
//
|
|
|
|
RtlMoveMemory(addressData, FunctionalAddress, FunctionalAddressLength);
|
|
|
|
atalkRequest->RequestMethod = RequestMethod;
|
|
atalkRequest->CompletionRoutine = CompletionRoutine;
|
|
atalkRequest->CompletionContext = CompletionContext;
|
|
|
|
atalkRequest->Request.RequestType = NdisRequestSetInformation;
|
|
atalkRequest->Request.DATA.SET_INFORMATION.Oid = OID_802_5_CURRENT_FUNCTIONAL;
|
|
atalkRequest->Request.DATA.SET_INFORMATION.InformationBuffer = addressData;
|
|
|
|
atalkRequest->Request.DATA.SET_INFORMATION.InformationBufferLength =
|
|
FunctionalAddressLength;
|
|
|
|
ndisStatus = AtalkNdisMakeRequest(Port, atalkRequest);
|
|
if (ndisStatus != NDIS_STATUS_SUCCESS) {
|
|
DBGPRINT(ATALK_DEBUG_NDISREQ, DEBUG_LEVEL_FATAL,
|
|
("ERROR: AtalkNdisAddMcast FAILED %lx\n", ndisStatus));
|
|
}
|
|
|
|
AtalkDereferenceNdisRequest ("Create", atalkRequest, NREF_CREATE);
|
|
return(ndisStatus == NDIS_STATUS_SUCCESS || ndisStatus == NDIS_STATUS_PENDING);
|
|
}
|
|
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
AtalkNdisMakeRequest(
|
|
INT Port,
|
|
PATALK_NDIS_REQUEST AtalkRequest
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to make a call to NdisRequest. It makes a copy
|
|
of everything passed to it after mallocing the necessary space, as the
|
|
caller could have called it with the parameters on the kernel stack and
|
|
we could potentially block, or need to have the buffers available for
|
|
the completion routine.
|
|
|
|
Arguments:
|
|
|
|
Port- The port number associated with the adapter to be initialized
|
|
AtalkRequest- Pointer to a structure intialized for the request
|
|
NdisRequest- Pointer to status field in which status of request will be returned
|
|
|
|
Return Value:
|
|
|
|
TRUE- If successful, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
KIRQL currentIrql;
|
|
NDIS_STATUS ndisStatus;
|
|
|
|
//
|
|
// Verify consistency of irql level/request method
|
|
//
|
|
|
|
currentIrql = KeGetCurrentIrql();
|
|
if (AtalkRequest->RequestMethod == SYNC_IF_POSSIBLE) {
|
|
if (currentIrql < DISPATCH_LEVEL)
|
|
AtalkRequest->RequestMethod = SYNC;
|
|
else
|
|
AtalkRequest->RequestMethod = ASYNC;
|
|
} else if ((AtalkRequest->RequestMethod == SYNC) &&
|
|
(currentIrql >= DISPATCH_LEVEL)) {
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISREQ, DEBUG_LEVEL_IMPOSSIBLE,
|
|
("IMPOS: AtalkNdisMakeRequest at irql %lx for SYNC\n", currentIrql));
|
|
|
|
return(NDIS_STATUS_FAILURE);
|
|
}
|
|
|
|
//
|
|
// First reference the structure for making this request
|
|
//
|
|
|
|
AtalkReferenceNdisRequest ("MakingRequest", AtalkRequest, NREF_MAKEREQ);
|
|
|
|
//
|
|
// initialize event if we might need to wait
|
|
//
|
|
|
|
if (AtalkRequest->RequestMethod == SYNC) {
|
|
|
|
KeInitializeEvent(
|
|
&AtalkRequest->RequestEvent,
|
|
NotificationEvent,
|
|
FALSE);
|
|
|
|
}
|
|
|
|
NdisRequest(
|
|
&ndisStatus,
|
|
NdisPortDesc[Port].NdisBindingHandle,
|
|
&AtalkRequest->Request);
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISREQ, DEBUG_LEVEL_INFOCLASS0,
|
|
("INFO0: AtalkNdisMakeRequest - status NdisRequest %lx\n", ndisStatus));
|
|
|
|
if (ndisStatus == NDIS_STATUS_PENDING) {
|
|
|
|
//
|
|
// Now depending on whether we are allowed to block or not...
|
|
//
|
|
|
|
if (AtalkRequest->RequestMethod == SYNC) {
|
|
|
|
KeWaitForSingleObject(
|
|
&AtalkRequest->RequestEvent,
|
|
Executive,
|
|
KernelMode,
|
|
TRUE,
|
|
(PLARGE_INTEGER)NULL);
|
|
|
|
ndisStatus = AtalkRequest->RequestStatus;
|
|
|
|
//
|
|
// Jus dereference the request structure
|
|
//
|
|
|
|
AtalkDereferenceNdisRequest ("RequestDone", AtalkRequest, NREF_MAKEREQ);
|
|
}
|
|
}
|
|
|
|
return(ndisStatus);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
// Protocol/NDIS interaction code
|
|
//
|
|
|
|
VOID
|
|
AtalkOpenAdapterComplete(
|
|
IN NDIS_HANDLE NdisBindingContext,
|
|
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:
|
|
|
|
NdisBindingContext- Pointer to a port descriptor for this port
|
|
Status- completion status of open adapter
|
|
OpenErrorStatus- Extra status information
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PNDIS_PORTDESCRIPTORS ndisPortDesc;
|
|
|
|
ndisPortDesc = (PNDIS_PORTDESCRIPTORS) NdisBindingContext;
|
|
ndisPortDesc->RequestStatus = Status;
|
|
|
|
KeSetEvent(
|
|
&ndisPortDesc->RequestEvent,
|
|
0L,
|
|
FALSE);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkCloseAdapterComplete(
|
|
IN NDIS_HANDLE NdisBindingContext,
|
|
IN NDIS_STATUS Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by NDIS to indicate that a close adapter is complete.
|
|
|
|
Arguments:
|
|
|
|
NdisBindingContext- Pointer to a port descriptor for this port
|
|
Status- completion status of close adapter
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PNDIS_PORTDESCRIPTORS ndisPortDesc;
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISREQ, DEBUG_LEVEL_INFOCLASS1,
|
|
("INFO1: AtalkCloseAdapterComplete - Close adapter Completed %lx!\n", Status));
|
|
|
|
ndisPortDesc = (PNDIS_PORTDESCRIPTORS) NdisBindingContext;
|
|
ndisPortDesc->RequestStatus = Status;
|
|
|
|
ACQUIRE_SPIN_LOCK(&ndisPortDesc->PerPortLock);
|
|
ndisPortDesc->PortState == STATE_UNBOUND;
|
|
RELEASE_SPIN_LOCK(&ndisPortDesc->PerPortLock);
|
|
|
|
KeSetEvent(
|
|
&ndisPortDesc->RequestEvent,
|
|
0L,
|
|
FALSE);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkResetComplete(
|
|
IN NDIS_HANDLE NdisBindingContext,
|
|
IN NDIS_STATUS Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by NDIS to indicate that a reset is complete.
|
|
|
|
Arguments:
|
|
|
|
NdisBindingContext- Pointer to a port descriptor for this port
|
|
Status- completion status of close adapter
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
|
|
PNDIS_PORTDESCRIPTORS ndisPortDesc;
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISREQ, DEBUG_LEVEL_ERROR,
|
|
("AtalkResetCOMPLETE called... TO BE IMPLEMENTED\n"));
|
|
|
|
ndisPortDesc = (PNDIS_PORTDESCRIPTORS) NdisBindingContext;
|
|
ndisPortDesc->RequestStatus = Status;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkRequestComplete(
|
|
IN NDIS_HANDLE NdisBindingContext,
|
|
IN PNDIS_REQUEST NdisRequest,
|
|
IN NDIS_STATUS Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by NDIS to indicate that a NdisRequest is complete.
|
|
|
|
Arguments:
|
|
|
|
NdisBindingContext- Pointer to a port descriptor for this port
|
|
NdisRequest- Block identifying the request
|
|
Status- completion status of close adapter
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PNDIS_PORTDESCRIPTORS ndisPortDesc;
|
|
PATALK_NDIS_REQUEST atalkRequest;
|
|
|
|
ndisPortDesc = (PNDIS_PORTDESCRIPTORS) NdisBindingContext;
|
|
|
|
//
|
|
// Get the AtalkRequest block
|
|
//
|
|
|
|
atalkRequest = CONTAINING_RECORD(NdisRequest, ATALK_NDIS_REQUEST, Request);
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISREQ, DEBUG_LEVEL_INFOCLASS0,
|
|
("INFO0: AtalkRequestComplete - %lx status %lx ReqMet %d\n",
|
|
atalkRequest, Status, atalkRequest->RequestMethod));
|
|
|
|
switch (atalkRequest->RequestMethod) {
|
|
case SYNC:
|
|
|
|
//
|
|
// Set status and clear event
|
|
//
|
|
|
|
atalkRequest->RequestStatus = Status;
|
|
KeSetEvent(
|
|
&atalkRequest->RequestEvent,
|
|
0L,
|
|
FALSE);
|
|
|
|
break;
|
|
|
|
case ASYNC :
|
|
|
|
//
|
|
// Call the completion routine if specified
|
|
//
|
|
|
|
if (atalkRequest->CompletionRoutine != NULL) {
|
|
(*atalkRequest->CompletionRoutine)(atalkRequest->CompletionContext);
|
|
}
|
|
|
|
//
|
|
// Dereference the request
|
|
//
|
|
|
|
AtalkDereferenceNdisRequest ("RequestComplete", atalkRequest, NREF_MAKEREQ);
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISREQ, DEBUG_LEVEL_ERROR,
|
|
("IMPOS: AtalkCompleteRequest - Unknown type!!! %lx\n",
|
|
atalkRequest->RequestMethod));
|
|
|
|
KeBugCheck(0);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkStatusIndication (
|
|
IN NDIS_HANDLE NdisBindingContext,
|
|
IN NDIS_STATUS GeneralStatus,
|
|
IN PVOID StatusBuffer,
|
|
IN UINT StatusBufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by NDIS to indicate a status change.
|
|
|
|
Arguments:
|
|
|
|
NdisBindingContext- Pointer to a port descriptor for this port
|
|
GeneralStatus- A general status value
|
|
StatusBuffer - A more specific status value
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
DBGPRINT(ATALK_DEBUG_NDISREQ, DEBUG_LEVEL_IMPOSSIBLE,
|
|
("ERROR: Status indication called %lx\n", GeneralStatus));
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkStatusComplete (
|
|
IN NDIS_HANDLE ProtocolBindingContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by NDIS to allow postprocessing after a status event.
|
|
|
|
Arguments:
|
|
|
|
ProtocolBindingContext- Value associated with the binding with the adapter
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
DBGPRINT(ATALK_DEBUG_NDISREQ, DEBUG_LEVEL_IMPOSSIBLE,
|
|
("ERROR: Status complete called\n"));
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkReceiveComplete (
|
|
IN NDIS_HANDLE BindingContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by NDIS to allow postprocessing after receive indications
|
|
This routine will directly call DdpPacketIn.
|
|
|
|
Arguments:
|
|
|
|
BindingContext- Pointer to a port descriptor for this port
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PNDIS_PORTDESCRIPTORS ndisPortDesc;
|
|
PPROTOCOL_RESD protocolResd;
|
|
PNDIS_PACKET ndisPacket;
|
|
PNDIS_BUFFER ndisBuffer;
|
|
PCHAR packet;
|
|
UINT packetLength, ndisBufferCount;
|
|
|
|
PLIST_ENTRY p;
|
|
|
|
KIRQL oldIrql; // All packets indicated at DPC level
|
|
|
|
ndisPortDesc = (PNDIS_PORTDESCRIPTORS)BindingContext;
|
|
|
|
//
|
|
// Get the stuff off the receive queue for the port and send it up
|
|
//
|
|
|
|
while (TRUE) {
|
|
|
|
PACKET_TYPE packetType;
|
|
|
|
ACQUIRE_SPIN_LOCK(&ndisPortDesc->ReceiveLock);
|
|
|
|
//
|
|
// Check if the first queued receive is done processing. If not,
|
|
// then return, there should be one more ReceiveComplete coming
|
|
// our ways since a pending TransferData is implied by that condition.
|
|
//
|
|
|
|
p = ndisPortDesc->ReceiveQueue.Flink;
|
|
if (p == &ndisPortDesc->ReceiveQueue) {
|
|
|
|
RELEASE_SPIN_LOCK(&ndisPortDesc->ReceiveLock);
|
|
break;
|
|
}
|
|
|
|
ndisPacket = CONTAINING_RECORD(p, NDIS_PACKET, ProtocolReserved);
|
|
protocolResd = (PPROTOCOL_RESD)ndisPacket->ProtocolReserved;
|
|
if (protocolResd->Receive.ReceiveState != RECEIVE_STATE_PROCESSED) {
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISREQ, DEBUG_LEVEL_WARNING,
|
|
("WARNING: AtalkReceiveComplete - First packet processing!\n"));
|
|
|
|
RELEASE_SPIN_LOCK(&ndisPortDesc->ReceiveLock);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Dequeue this received packet and indicate it to the ddp layer
|
|
//
|
|
|
|
p = RemoveHeadList(&ndisPortDesc->ReceiveQueue);
|
|
RELEASE_SPIN_LOCK(&ndisPortDesc->ReceiveLock);
|
|
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
|
|
NdisQueryPacket(
|
|
ndisPacket,
|
|
NULL,
|
|
&ndisBufferCount,
|
|
&ndisBuffer,
|
|
NULL
|
|
);
|
|
|
|
if (ndisBufferCount != 1) {
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISRECEIVE, DEBUG_LEVEL_IMPOSSIBLE,
|
|
("IMPOS: AtalkReceiveComplete - Ndisbuffer count not 1 but %d\n",
|
|
ndisBufferCount));
|
|
|
|
KeBugCheck(0);
|
|
}
|
|
|
|
NdisQueryBuffer(
|
|
ndisBuffer,
|
|
(PVOID *)&packet,
|
|
&packetLength);
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISRECEIVE, DEBUG_LEVEL_TEMP_DEBUG,
|
|
("TDBG: AtalkReceiveComplete - Received Packet %lx Length %lx\n",
|
|
packet, packetLength));
|
|
|
|
//
|
|
// Check the receive status- accept only if ok
|
|
//
|
|
|
|
if (protocolResd->Receive.ReceiveStatus != NDIS_STATUS_SUCCESS) {
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISRECEIVE, DEBUG_LEVEL_ERROR,
|
|
("ERROR: AtalkReceiveComplete - ReceiveStatus FAILURE %lx!\n",
|
|
protocolResd->Receive.ReceiveStatus ));
|
|
|
|
//
|
|
// NOTE: For tokenring the routing info is non-null at this point only
|
|
// for AARP packets. And since those are copied out from the
|
|
// lookahead buffer, there is no way transferData can put a non
|
|
// success status for the packet.
|
|
//
|
|
|
|
#if DBG
|
|
if (ndisPortDesc->NdisPortType == NdisMedium802_5) {
|
|
ASSERT(protocolResd->Receive.RoutingInfo == NULL);
|
|
}
|
|
#endif
|
|
|
|
AtalkDestroyNdisPacket(ndisPacket);
|
|
AtalkFreeNonPagedMemory(packet);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Free up the packet descriptor before indicating the packet to
|
|
// the higher levels
|
|
//
|
|
|
|
packetType = protocolResd->Receive.PacketType;
|
|
|
|
switch (ndisPortDesc->NdisPortType) {
|
|
case NdisMedium802_3 :
|
|
|
|
AtalkDestroyNdisPacket(ndisPacket);
|
|
|
|
if (packetType == APPLETALK_PACKET) {
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISRECEIVE, DEBUG_LEVEL_TEMP_DEBUG,
|
|
("TDBG: AtalkReceiveComplete - Indicating DDP Ethernet "));
|
|
|
|
// RAISE IRQL to DPC level
|
|
KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
|
|
|
|
DdpPacketIn(
|
|
ndisPortDesc->PortNumber,
|
|
packet,
|
|
(INT)packetLength,
|
|
TRUE,
|
|
TRUE,
|
|
0,
|
|
0);
|
|
|
|
// LOWER IRQL to old level
|
|
KeLowerIrql(oldIrql);
|
|
|
|
} else {
|
|
|
|
//
|
|
// AARP Packet
|
|
//
|
|
|
|
UINT aarpDataLength;
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISRECEIVE, DEBUG_LEVEL_TEMP_DEBUG,
|
|
("TDBG: AtalkReceiveComplete - Indicating AARP Ethernet "));
|
|
|
|
//
|
|
// For ethernet, there could be padding included in the packet.
|
|
// Shrink the length if so. Note header length is not included in
|
|
// packetlength.
|
|
//
|
|
|
|
|
|
if (packetLength == (MIN_ETHERNETPACKETLENGTH - ETHERNET_LINKLENGTH)){
|
|
packetLength = IEEE8022_HEADERLENGTH + MAX_AARPDATASIZE;
|
|
}
|
|
|
|
aarpDataLength = packetLength - IEEE8022_HEADERLENGTH;
|
|
if ((aarpDataLength > MAX_AARPDATASIZE) ||
|
|
(aarpDataLength < MIN_AARPDATASIZE))
|
|
{
|
|
ErrorLog("EthernetPacketInAARP", ISevVerbose, __LINE__,
|
|
ndisPortDesc->PortNumber,IErrDependBadAarpSize,
|
|
IMsgDependBadAarpSize, Insert0());
|
|
|
|
//
|
|
// For AARP packets, we free the buffer
|
|
//
|
|
|
|
AtalkFreeNonPagedMemory(packet);
|
|
return;
|
|
}
|
|
|
|
// RAISE IRQL to DPC level
|
|
// KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
|
|
|
|
AarpPacketIn(
|
|
ndisPortDesc->PortNumber,
|
|
NULL,
|
|
0,
|
|
packet,
|
|
packetLength);
|
|
|
|
// LOWER IRQL to old level
|
|
// KeLowerIrql(oldIrql);
|
|
|
|
|
|
//
|
|
// For AARP packets, we free the buffer
|
|
//
|
|
|
|
AtalkFreeNonPagedMemory(packet);
|
|
}
|
|
|
|
break;
|
|
|
|
case NdisMedium802_5 :
|
|
|
|
if (packetType == APPLETALK_PACKET) {
|
|
|
|
AtalkDestroyNdisPacket(ndisPacket);
|
|
|
|
// RAISE IRQL to DPC level
|
|
KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
|
|
|
|
DdpPacketIn(
|
|
ndisPortDesc->PortNumber,
|
|
packet,
|
|
(INT)packetLength,
|
|
TRUE,
|
|
TRUE,
|
|
0,
|
|
0);
|
|
|
|
// LOWER IRQL to old level
|
|
KeLowerIrql(oldIrql);
|
|
|
|
} else {
|
|
|
|
//
|
|
// AARP Packet
|
|
//
|
|
|
|
PCHAR routingInfo = protocolResd->Receive.RoutingInfo;
|
|
USHORT routingInfoLength = protocolResd->Receive.RoutingInfoLength;
|
|
|
|
AtalkDestroyNdisPacket(ndisPacket);
|
|
|
|
// RAISE IRQL to DPC level
|
|
// KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
|
|
|
|
AarpPacketIn(
|
|
ndisPortDesc->PortNumber,
|
|
routingInfo,
|
|
routingInfoLength,
|
|
packet,
|
|
packetLength);
|
|
|
|
// LOWER IRQL to old level
|
|
// KeLowerIrql(oldIrql);
|
|
|
|
//
|
|
// For AARP packets, we free the buffer, and also routing buffer
|
|
//
|
|
|
|
AtalkFreeNonPagedMemory(packet);
|
|
if (routingInfo != NULL) {
|
|
AtalkFreeNonPagedMemory(routingInfo);
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
case NdisMediumLocalTalk :
|
|
|
|
{
|
|
UCHAR destinationNode = protocolResd->Receive.DestinationNode;
|
|
UCHAR sourceNode = protocolResd->Receive.SourceNode;
|
|
UCHAR llapType = protocolResd->Receive.LlapType;
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISRECEIVE, DEBUG_LEVEL_TEMP_DEBUG,
|
|
("TDBG: AtalkReceiveComplete - Localtalk Packet Received!\n"));
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISRECEIVE, DEBUG_LEVEL_TEMP_DEBUG,
|
|
("TDBG: AtalkReceiveComplete - Source %lx Dest %lx LlapType %lx\n",
|
|
sourceNode, destinationNode, llapType));
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISRECEIVE, DEBUG_LEVEL_TEMP_DEBUG,
|
|
("TDBG: AtalkReceiveComplete - Packet %lx Length %lx\n",
|
|
packet, packetLength));
|
|
|
|
AtalkDestroyNdisPacket(ndisPacket);
|
|
|
|
if (packetType == APPLETALK_PACKET) {
|
|
|
|
// RAISE IRQL to DPC level
|
|
KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
|
|
|
|
DdpPacketIn(
|
|
ndisPortDesc->PortNumber,
|
|
packet,
|
|
(INT)packetLength,
|
|
TRUE,
|
|
(BOOLEAN)(llapType == (UCHAR)ALAP_LONGDDPHEADERTYPE),
|
|
(INT)sourceNode,
|
|
(INT)destinationNode);
|
|
|
|
// LOWER IRQL to old level
|
|
KeLowerIrql(oldIrql);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AtalkTransferDataComplete(
|
|
IN NDIS_HANDLE BindingContext,
|
|
IN PNDIS_PACKET NdisPacket,
|
|
IN NDIS_STATUS Status,
|
|
IN UINT BytesTransferred
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by NDIS to indicate completion of a TransferData
|
|
|
|
Arguments:
|
|
|
|
BindingContext- Pointer to a port descriptor for this port
|
|
NdisPacket- Ndis packet into which data was transferred
|
|
Status- Status of request
|
|
bytesTransferred- Actual number of bytes transferred
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PNDIS_PORTDESCRIPTORS ndisPortDesc;
|
|
PPROTOCOL_RESD protocolResd;
|
|
|
|
ndisPortDesc = (PNDIS_PORTDESCRIPTORS)BindingContext;
|
|
protocolResd = (PPROTOCOL_RESD)&NdisPacket->ProtocolReserved;
|
|
|
|
ACQUIRE_SPIN_LOCK(&ndisPortDesc->ReceiveLock);
|
|
protocolResd->Receive.ReceiveState = RECEIVE_STATE_PROCESSED;
|
|
protocolResd->Receive.ReceiveStatus = Status;
|
|
RELEASE_SPIN_LOCK(&ndisPortDesc->ReceiveLock);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
#define RECEIVEIND_PACKETALLOCATED 0x0001
|
|
#define RECEIVEIND_NDISBUFFERALLOCATED 0x0002
|
|
#define RECEIVEIND_ROUTINGINFALLOCATED 0x0004
|
|
|
|
NDIS_STATUS
|
|
AtalkReceiveIndication(
|
|
IN NDIS_HANDLE BindingContext,
|
|
IN NDIS_HANDLE ReceiveContext,
|
|
IN PVOID HeaderBuffer,
|
|
IN UINT HeaderBufferSize,
|
|
IN PVOID LookaheadBuffer,
|
|
IN UINT LookaheadBufferSize,
|
|
IN UINT PacketSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by NDIS to indicate a receive
|
|
|
|
Arguments:
|
|
|
|
BindingContext- Pointer to a port descriptor for this port
|
|
ReceiveContext- To be used in a transfer data if necessary
|
|
LookaheadBuffer- buffer with lookahead data
|
|
LookaheadBufferSize- Size of the above buffer
|
|
PacketSize- Size of whole packet
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS- Packet accepted
|
|
STATUS_NOT_RECOGNIZED- Not our packet
|
|
Other
|
|
|
|
--*/
|
|
{
|
|
PNDIS_PACKET ndisPacket;
|
|
PNDIS_BUFFER ndisBuffer;
|
|
|
|
PCHAR packet; // Where we will copy the packet
|
|
PPROTOCOL_RESD protocolResd; // Protocolresd field in ndisPacket
|
|
|
|
UINT actualPacketSize; // Size of data to copy
|
|
UINT offsetDataStart; // Offset in Lookahead from where to copy
|
|
UINT bytesTransferred; // Number of bytes transferred in XferData
|
|
UINT ddpLength; // Length of packet from ddp header
|
|
|
|
ULONG resources = 0;
|
|
NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS;
|
|
PACKET_TYPE packetType = UNKNOWN_PACKET;
|
|
|
|
PNDIS_PORTDESCRIPTORS ndisPortDesc;
|
|
|
|
PCHAR routingInfo = NULL; // For tokenring only
|
|
UINT routingInfoLength = 0;
|
|
UCHAR llapType; // For localtalk only
|
|
|
|
//
|
|
// Receive algorithm
|
|
//
|
|
// Grab the port spinlock
|
|
// For each port type, verify if packet is to be accepted,
|
|
// if yes, then allocate ndis packet,
|
|
// set state to being processed
|
|
// put in queue
|
|
// if no, release spinlock return;
|
|
// release spin lock
|
|
//
|
|
// Go ahead with allocating the memory etc.,
|
|
// and starting off the transferData call.
|
|
//
|
|
// if status_pending on xfer data, return;
|
|
// else grap port spinlock- set flag in receivestate to done.
|
|
//
|
|
// do actual indication to portable stack in a receivedone routine.
|
|
//
|
|
// IMPORTANT:
|
|
// It is possible that the MAC can make multiple receive indications
|
|
// sequentially for the packets received. To minimize mis-ordering on
|
|
// our part due to blocked indication threads, this routine is shielded
|
|
// by a spinlock. This does not eliminate mis-ordering as the indication
|
|
// thread could block even before the spinlock is acquired. So the higher
|
|
// level protocols will deal with that case
|
|
//
|
|
|
|
ndisPortDesc = (PNDIS_PORTDESCRIPTORS)BindingContext;
|
|
|
|
ACQUIRE_SPIN_LOCK(&ndisPortDesc->ReceiveLock);
|
|
|
|
switch (ndisPortDesc->NdisPortType) {
|
|
case NdisMedium802_3:
|
|
|
|
//
|
|
// Check length for atleast the minimum amount of space
|
|
// Also, Check if the 802.2 header is ok
|
|
//
|
|
|
|
if ( (LookaheadBufferSize <
|
|
(IEEE8022_PROTOCOLOFFSET+IEEE8022_PROTOCOLTYPELENGTH))
|
|
|
|
||
|
|
|
|
((*((PUCHAR)LookaheadBuffer + IEEE8022_DSAPOFFSET) != SNAP_SAP) ||
|
|
(*((PUCHAR)LookaheadBuffer + IEEE8022_SSAPOFFSET) != SNAP_SAP) ||
|
|
(*((PUCHAR)LookaheadBuffer + IEEE8022_CONTROLOFFSET) !=
|
|
UNNUMBEREDINFORMATION)) ) {
|
|
|
|
ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;
|
|
break;
|
|
}
|
|
|
|
if (RtlCompareMemory((PCHAR)LookaheadBuffer+IEEE8022_PROTOCOLOFFSET,
|
|
appleTalkProtocolType,
|
|
IEEE8022_PROTOCOLTYPELENGTH) ==
|
|
IEEE8022_PROTOCOLTYPELENGTH) {
|
|
|
|
//
|
|
// Use GleanAarpInfo to determine whether or not we accept this
|
|
// packet. It will also check the 802.2 headers
|
|
//
|
|
|
|
if (GleanAarpInfo(
|
|
ndisPortDesc->PortNumber,
|
|
(PCHAR)HeaderBuffer + ETHERNET_SOURCE_OFFSET,
|
|
ETHERNET_ADDRESSLENGTH,
|
|
NULL,
|
|
0,
|
|
(PCHAR)LookaheadBuffer,
|
|
LookaheadBufferSize))
|
|
{
|
|
//
|
|
// Our packet- successfully verified
|
|
//
|
|
|
|
packetType = APPLETALK_PACKET;
|
|
actualPacketSize = PacketSize - IEEE8022_HEADERLENGTH;
|
|
offsetDataStart = IEEE8022_HEADERLENGTH;
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (RtlCompareMemory((PCHAR)LookaheadBuffer+IEEE8022_PROTOCOLOFFSET,
|
|
aarpProtocolType,
|
|
IEEE8022_PROTOCOLTYPELENGTH) ==
|
|
IEEE8022_PROTOCOLTYPELENGTH) {
|
|
|
|
packetType = AARP_PACKET;
|
|
actualPacketSize = PacketSize;
|
|
offsetDataStart = 0;
|
|
break;
|
|
|
|
}
|
|
|
|
ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;
|
|
break;
|
|
|
|
case NdisMedium802_5:
|
|
|
|
//
|
|
// The tokenring code changes the source-routing bit in the
|
|
// source address and also tunes the routing info. We need
|
|
// to make copies of these before passing them onto the portable
|
|
// code. Allocate for routingInfo (since it is accessed in receive
|
|
// complete, but use a buffer on the stack for the source address
|
|
//
|
|
|
|
//
|
|
// Check length for atleast the minimum amount of space
|
|
// Also, Check if the 802.2 header is ok
|
|
//
|
|
|
|
if ( (LookaheadBufferSize <
|
|
(IEEE8022_PROTOCOLOFFSET+IEEE8022_PROTOCOLTYPELENGTH))
|
|
|
|
||
|
|
|
|
((*((PUCHAR)LookaheadBuffer + IEEE8022_DSAPOFFSET) != SNAP_SAP) ||
|
|
(*((PUCHAR)LookaheadBuffer + IEEE8022_SSAPOFFSET) != SNAP_SAP) ||
|
|
(*((PUCHAR)LookaheadBuffer + IEEE8022_CONTROLOFFSET) !=
|
|
UNNUMBEREDINFORMATION)) ) {
|
|
|
|
ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Check the packet to see if we are to accept it
|
|
// If so, we'll need to allocate the routing info
|
|
//
|
|
|
|
if (RtlCompareMemory((PCHAR)LookaheadBuffer+IEEE8022_PROTOCOLOFFSET,
|
|
appleTalkProtocolType,IEEE8022_PROTOCOLTYPELENGTH)
|
|
== IEEE8022_PROTOCOLTYPELENGTH) {
|
|
|
|
packetType = APPLETALK_PACKET;
|
|
|
|
//
|
|
// Other two fields will be set after determing routing info etc.
|
|
//
|
|
|
|
} else if (RtlCompareMemory((PCHAR)LookaheadBuffer+IEEE8022_PROTOCOLOFFSET,
|
|
aarpProtocolType, IEEE8022_PROTOCOLTYPELENGTH) ==
|
|
IEEE8022_PROTOCOLTYPELENGTH) {
|
|
|
|
packetType = AARP_PACKET;
|
|
actualPacketSize = PacketSize;
|
|
offsetDataStart = 0;
|
|
|
|
} else {
|
|
|
|
ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Packet is either Appletalk or Aarp.
|
|
// Check for source routing info.
|
|
//
|
|
|
|
if (*((PUCHAR)HeaderBuffer + TOKRING_SOURCEOFFSET) &
|
|
TOKRING_SOURCEROUTINGMASK) {
|
|
|
|
routingInfoLength =
|
|
(*((PUCHAR)HeaderBuffer + TOKRING_ROUTINGINFOOFFSET) &
|
|
TOKRING_ROUTINGINFOSIZEMASK);
|
|
|
|
ASSERT(routingInfoLength != 0);
|
|
|
|
//
|
|
// Routing info must be of reasonable size, and not odd.
|
|
//
|
|
|
|
if ((routingInfoLength & 1) ||
|
|
(routingInfoLength > TOKRING_MAXROUTINGBYTES))
|
|
{
|
|
ErrorLog("TokenRingPacketInAT", ISevVerbose, __LINE__,
|
|
ndisPortDesc->PortNumber, IErrDependBadRoutingInfoSize,
|
|
IMsgDependBadRoutingInfoSize, Insert0());
|
|
|
|
ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;;
|
|
break;
|
|
}
|
|
|
|
routingInfo = (PCHAR)AtalkAllocNonPagedMemory(routingInfoLength);
|
|
if (routingInfo == NULL) {
|
|
ndisStatus = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
resources |= RECEIVEIND_ROUTINGINFALLOCATED;
|
|
|
|
//
|
|
// BUGBUG: Change to NdisMoveMappedMemory
|
|
// Move the routing info to the allocated buffer
|
|
//
|
|
|
|
NdisMoveMappedMemory(
|
|
routingInfo,
|
|
(PCHAR)HeaderBuffer+TOKRING_ROUTINGINFOOFFSET,
|
|
routingInfoLength);
|
|
|
|
}
|
|
|
|
if (packetType == APPLETALK_PACKET) {
|
|
|
|
do {
|
|
|
|
UCHAR localSourceAddress[TOKRING_ADDRESSLENGTH];
|
|
|
|
//
|
|
// Do we at least have a 802.2 and DDP header in the indicated
|
|
// packet?
|
|
//
|
|
|
|
if ((PacketSize < (IEEE8022_HEADERLENGTH + LONGDDP_HEADERLENGTH)) ||
|
|
(PacketSize > (IEEE8022_HEADERLENGTH + MAX_LONGDDPPACKETSIZE)))
|
|
{
|
|
ErrorLog("TokenRingPacketInAT", ISevVerbose, __LINE__,
|
|
ndisPortDesc->PortNumber, IErrDependBadPacketSize,
|
|
IMsgDependBadPacketSize, Insert0());
|
|
|
|
ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// First, glean any AARP information that we can, then handle the DDP
|
|
// packet. This guy also makes sure we have a good 802.2 header...
|
|
//
|
|
// Need to make a localcopy of the source address and then turn
|
|
// the source routing bit off before calling GleanAarpInfo
|
|
//
|
|
// ((PCHAR)HeaderBuffer)[TOKRING_SOURCEOFFSET] =
|
|
// (((PCHAR)HeaderBuffer)[TOKRING_SOURCEOFFSET] &
|
|
// ~TOKRING_SOURCEROUTINGMASK);
|
|
//
|
|
|
|
//
|
|
// BUGBUG: Use NdisMoveMappedMemory
|
|
//
|
|
|
|
NdisMoveMappedMemory(
|
|
localSourceAddress,
|
|
(PCHAR)HeaderBuffer+TOKRING_SOURCEOFFSET,
|
|
TOKRING_ADDRESSLENGTH);
|
|
|
|
//
|
|
// BUGBUG?
|
|
//
|
|
|
|
(*(PUCHAR)localSourceAddress) &= ~TOKRING_SOURCEROUTINGMASK;
|
|
|
|
if (GleanAarpInfo(
|
|
ndisPortDesc->PortNumber,
|
|
localSourceAddress,
|
|
TOKRING_ADDRESSLENGTH,
|
|
routingInfo,
|
|
routingInfoLength,
|
|
LookaheadBuffer,
|
|
LookaheadBufferSize)) {
|
|
|
|
//
|
|
// Pull out the DDP length.
|
|
//
|
|
|
|
ddpLength =
|
|
(LONG)((*((PUCHAR)LookaheadBuffer + IEEE8022_HEADERLENGTH +
|
|
LONGDDP_LENGTHOFFSET) & DDPLENGTH_MASK1)
|
|
<< 8);
|
|
|
|
ddpLength +=
|
|
(LONG)(*((PUCHAR)LookaheadBuffer + IEEE8022_HEADERLENGTH +
|
|
LONGDDP_LENGTHOFFSET + 1) & DDPLENGTH_MASK2);
|
|
|
|
if ((ddpLength < LONGDDP_HEADERLENGTH) ||
|
|
(ddpLength > MAX_LONGDDPPACKETSIZE)) {
|
|
|
|
ErrorLog("TokenRingPacketInAT", ISevVerbose, __LINE__,
|
|
ndisPortDesc->PortNumber, IErrDependBadDdpSize,
|
|
IMsgDependBadDdpSize, Insert0());
|
|
|
|
ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Is the DDP length more than we really got?
|
|
//
|
|
|
|
if (ddpLength + IEEE8022_HEADERLENGTH > PacketSize)
|
|
{
|
|
ErrorLog("TokenRingPacketInAT", ISevVerbose, __LINE__,
|
|
ndisPortDesc->PortNumber,
|
|
IErrDependDataMissing, IMsgDependDataMissing,
|
|
Insert0());
|
|
|
|
ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Remember- routing info is in the header buffer
|
|
//
|
|
|
|
actualPacketSize = PacketSize - IEEE8022_HEADERLENGTH;
|
|
offsetDataStart = IEEE8022_HEADERLENGTH;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// GleanAarpInfo returned FALSE
|
|
//
|
|
|
|
ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;;
|
|
break;
|
|
|
|
} while (FALSE);
|
|
|
|
if (routingInfo != NULL) {
|
|
AtalkFreeNonPagedMemory(routingInfo);
|
|
routingInfoLength = 0;
|
|
routingInfo = NULL;
|
|
resources &= ~(RECEIVEIND_ROUTINGINFALLOCATED);
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
case NdisMediumLocalTalk:
|
|
|
|
//
|
|
// No AARP/802.2 header on localtalk
|
|
//
|
|
|
|
llapType = *((PUCHAR)HeaderBuffer + ALAP_TYPEOFFSET);
|
|
if ((llapType != LLAP_TYPE1) && (llapType != LLAP_TYPE2)) {
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISRECEIVE, DEBUG_LEVEL_WARNING,
|
|
("WARNING: AtalkReceiveIndication - Receveid llap type %d\n", llapType));
|
|
|
|
ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;;
|
|
break;
|
|
}
|
|
|
|
packetType = APPLETALK_PACKET;
|
|
actualPacketSize = PacketSize;
|
|
offsetDataStart = 0;
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
//
|
|
// Should never happen!
|
|
//
|
|
|
|
KeBugCheck(0);
|
|
break;
|
|
}
|
|
|
|
if (ndisStatus != NDIS_STATUS_SUCCESS) {
|
|
RELEASE_SPIN_LOCK(&ndisPortDesc->ReceiveLock);
|
|
return(ndisStatus);
|
|
}
|
|
|
|
//
|
|
// For AARP packets, we expect the whole packet to be in the
|
|
// lookahead data!
|
|
//
|
|
|
|
if ((packetType == AARP_PACKET) &&
|
|
(actualPacketSize != LookaheadBufferSize)) {
|
|
|
|
RELEASE_SPIN_LOCK(&ndisPortDesc->ReceiveLock);
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISRECEIVE, DEBUG_LEVEL_ERROR,
|
|
("ERROR: AtalkReceive - AARP Packet received with size %lx\n",
|
|
actualPacketSize));
|
|
|
|
return (NDIS_STATUS_NOT_RECOGNIZED);
|
|
}
|
|
|
|
//
|
|
// Packet is to be accepted!
|
|
// Allocate an NDIS packet descriptor from the global packet pool
|
|
//
|
|
|
|
NdisAllocatePacket(
|
|
&ndisStatus,
|
|
&ndisPacket,
|
|
AtalkNdisPacketPoolHandle);
|
|
|
|
if (ndisStatus != NDIS_STATUS_SUCCESS) {
|
|
|
|
RELEASE_SPIN_LOCK(&ndisPortDesc->ReceiveLock);
|
|
|
|
// Happens too often on corporate to make it be error level
|
|
DBGPRINT(ATALK_DEBUG_NDISRECEIVE, DEBUG_LEVEL_WARNING,
|
|
("ERROR: AtalkReceiveIndication Failed (NdisAllocatePacket) %lx\n",
|
|
ndisStatus));
|
|
|
|
return(ndisStatus);
|
|
}
|
|
|
|
do {
|
|
|
|
//
|
|
// Store the information needed in the packet descriptor
|
|
//
|
|
|
|
protocolResd = (PPROTOCOL_RESD)&ndisPacket->ProtocolReserved;
|
|
protocolResd->Receive.Port = ndisPortDesc->PortNumber;
|
|
protocolResd->Receive.PacketType = packetType;
|
|
protocolResd->Receive.ReceiveState = RECEIVE_STATE_PROCESSING;
|
|
|
|
//
|
|
// Queue up the packet in the receive queue on this port
|
|
// Release the spinlock
|
|
// Then, go ahead with the transfer data etc.
|
|
//
|
|
// NOTE:
|
|
// NdisAllocatePacket ZEROES out the protocol reserved area. We depend
|
|
// on that and don't initialize ReceiveEntry.
|
|
//
|
|
|
|
InsertTailList(
|
|
&ndisPortDesc->ReceiveQueue,
|
|
&protocolResd->Receive.ReceiveEntry);
|
|
|
|
RELEASE_SPIN_LOCK(&ndisPortDesc->ReceiveLock);
|
|
|
|
|
|
//
|
|
// AT THIS POINT:
|
|
// Spinlock is released, and the packet is to be accepted. We need to
|
|
// Copy/TransferData the packet into our buffer and then leave the
|
|
// major work for the ReceiveComplete indication
|
|
//
|
|
|
|
//
|
|
// For Tokenring we need to copy the routing info and for localtalk
|
|
// we need to remember the destination/source node ids and the lap
|
|
// type
|
|
//
|
|
|
|
|
|
switch (ndisPortDesc->NdisPortType) {
|
|
case NdisMedium802_5:
|
|
|
|
protocolResd->Receive.RoutingInfo = routingInfo;
|
|
protocolResd->Receive.RoutingInfoLength = routingInfoLength;
|
|
break;
|
|
|
|
|
|
case NdisMediumLocalTalk:
|
|
|
|
protocolResd->Receive.DestinationNode =
|
|
*((PUCHAR)HeaderBuffer +ALAP_DESTINATIONOFFSET);
|
|
|
|
protocolResd->Receive.SourceNode =
|
|
*((PUCHAR)HeaderBuffer + ALAP_SOURCEOFFSET);
|
|
|
|
protocolResd->Receive.LlapType = llapType;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Allocate space for the packet excluding the link & 802.2 header
|
|
// If complete packet in lookahead, make a copy and queue else
|
|
// call Transfer data
|
|
//
|
|
|
|
packet = (PCHAR)AtalkAllocNonPagedMemory(actualPacketSize);
|
|
if (packet == NULL) {
|
|
ndisStatus = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
resources |= RECEIVEIND_PACKETALLOCATED;
|
|
|
|
//
|
|
// Make a NDIS buffer descriptor for this data
|
|
//
|
|
|
|
NdisAllocateBuffer(
|
|
&ndisStatus,
|
|
&ndisBuffer,
|
|
AtalkNdisBufferPoolHandle,
|
|
(PVOID)packet,
|
|
(UINT)actualPacketSize);
|
|
|
|
if (ndisStatus != NDIS_STATUS_SUCCESS) {
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISRECEIVE, DEBUG_LEVEL_ERROR,
|
|
("ERROR: AtalkReceiveIndication- NdisAllocate failed! %lx\n",
|
|
ndisStatus));
|
|
|
|
ndisStatus = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
resources |= RECEIVEIND_NDISBUFFERALLOCATED;
|
|
|
|
//
|
|
// Link the buffer descriptor into the packet descriptor
|
|
//
|
|
|
|
NdisChainBufferAtBack(
|
|
ndisPacket,
|
|
ndisBuffer);
|
|
|
|
|
|
if (PacketSize <= LookaheadBufferSize) {
|
|
|
|
//
|
|
// Copy the data into the buffer we allocated, make an ndis
|
|
// buffer descriptor to describe it and then queue the packet
|
|
// into the receive queue for this port
|
|
//
|
|
|
|
NdisMoveMappedMemory(
|
|
packet,
|
|
(PCHAR)LookaheadBuffer+offsetDataStart,
|
|
actualPacketSize);
|
|
|
|
AtalkTransferDataComplete(
|
|
BindingContext,
|
|
ndisPacket,
|
|
NDIS_STATUS_SUCCESS,
|
|
actualPacketSize);
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Need to do TransferData
|
|
//
|
|
|
|
NdisTransferData(
|
|
&ndisStatus,
|
|
ndisPortDesc->NdisBindingHandle,
|
|
ReceiveContext,
|
|
offsetDataStart,
|
|
actualPacketSize,
|
|
ndisPacket,
|
|
&bytesTransferred);
|
|
|
|
|
|
if (ndisStatus == NDIS_STATUS_PENDING) {
|
|
|
|
ndisStatus = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
|
|
} else if (ndisStatus == NDIS_STATUS_SUCCESS) {
|
|
|
|
//
|
|
// Transfer data completed, call the transfer data completion
|
|
// routine to do rest of the work
|
|
//
|
|
|
|
|
|
AtalkTransferDataComplete(
|
|
BindingContext,
|
|
ndisPacket,
|
|
ndisStatus,
|
|
bytesTransferred);
|
|
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISRECEIVE, DEBUG_LEVEL_ERROR,
|
|
("ERROR: AtalkReceiveIndication- TransferData failed %lx\n",
|
|
ndisStatus));
|
|
|
|
ndisStatus = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
//
|
|
// In case of failures, we need to deallocate the resources
|
|
//
|
|
|
|
if (ndisStatus != NDIS_STATUS_SUCCESS) {
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISRECEIVE, DEBUG_LEVEL_ERROR,
|
|
("ERROR: AtalkReceiveIndication- FAILURE %lx\n", ndisStatus));
|
|
|
|
//
|
|
// Free up the allocated resources
|
|
// Dequeue the packet and abort it
|
|
//
|
|
|
|
ACQUIRE_SPIN_LOCK(&ndisPortDesc->ReceiveLock);
|
|
RemoveEntryList(&protocolResd->Receive.ReceiveEntry);
|
|
RELEASE_SPIN_LOCK(&ndisPortDesc->ReceiveLock);
|
|
|
|
if (resources & RECEIVEIND_ROUTINGINFALLOCATED) {
|
|
ASSERT(ndisPortDesc->NdisPortType == NdisMedium802_5);
|
|
ASSERT(routingInfo != NULL);
|
|
|
|
AtalkFreeNonPagedMemory(routingInfo);
|
|
}
|
|
|
|
if (resources & RECEIVEIND_NDISBUFFERALLOCATED) {
|
|
|
|
//
|
|
// Free up ndis buffer and packet- buffer would have been
|
|
// chained in.
|
|
//
|
|
|
|
AtalkDestroyNdisPacket(ndisPacket);
|
|
}
|
|
|
|
if (resources & RECEIVEIND_PACKETALLOCATED) {
|
|
|
|
//
|
|
// Free up the packet
|
|
//
|
|
|
|
AtalkFreeNonPagedMemory(packet);
|
|
}
|
|
}
|
|
|
|
return(ndisStatus);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
AtalkNdisPacketOut(
|
|
int Port,
|
|
BufferDescriptor Chain,
|
|
int Length
|
|
)
|
|
/*++
|
|
|
|
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:
|
|
|
|
Port- The port number associated with the adapter on which to send
|
|
Chain- The portable stacks buffer descriptor chain
|
|
Length- The length to send from chain
|
|
|
|
Return Value:
|
|
|
|
TRUE- If sent/pending, FALSE otherwise
|
|
TransmitComplete is called if this call pended by completion code
|
|
|
|
--*/
|
|
{
|
|
PNDIS_PACKET ndisPacket;
|
|
PNDIS_BUFFER ndisBuffer;
|
|
NDIS_STATUS ndisStatus;
|
|
PPROTOCOL_RESD protocolResd;
|
|
INT currentSizeOfData = 0;
|
|
|
|
BufferDescriptor currentDescriptor;
|
|
|
|
//
|
|
// Allocate an NDIS packet descriptor from the global packet pool
|
|
//
|
|
|
|
NdisAllocatePacket(
|
|
&ndisStatus,
|
|
&ndisPacket,
|
|
AtalkNdisPacketPoolHandle);
|
|
|
|
if (ndisStatus == NDIS_STATUS_SUCCESS) {
|
|
|
|
//
|
|
// Store the information needed in the packet descriptor
|
|
//
|
|
|
|
protocolResd = (PPROTOCOL_RESD)&ndisPacket->ProtocolReserved;
|
|
protocolResd->Send.Port = Port;
|
|
protocolResd->Send.Chain = Chain;
|
|
|
|
for ( currentDescriptor = Chain;
|
|
currentDescriptor != NULL;
|
|
currentDescriptor = currentDescriptor->next) {
|
|
|
|
//
|
|
// First get the onBoard data, as that is always to be prepended to
|
|
// the outBoard data
|
|
//
|
|
|
|
if (currentDescriptor->onBoardDataValid) {
|
|
|
|
//
|
|
// Make a NDIS buffer descriptor for this data
|
|
// This assumes that the buffer descriptor was allocated using
|
|
// one of our allocate routines, and so is in the non-paged pool.
|
|
//
|
|
|
|
currentSizeOfData = MIN(currentDescriptor->onBoardSize, Length);
|
|
|
|
if (currentSizeOfData > 0) {
|
|
|
|
NdisAllocateBuffer(
|
|
&ndisStatus,
|
|
&ndisBuffer,
|
|
AtalkNdisBufferPoolHandle,
|
|
(PVOID)currentDescriptor->onBoardData,
|
|
(UINT)currentSizeOfData);
|
|
|
|
if (ndisStatus != NDIS_STATUS_SUCCESS) {
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISSEND, DEBUG_LEVEL_FATAL,
|
|
("ERROR: AtalkNdisPacketOut - FAILED (NdisBuffer): %lx\n",
|
|
ndisStatus));
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Link the buffer descriptor into the packet descriptor
|
|
//
|
|
|
|
NdisChainBufferAtBack(
|
|
ndisPacket,
|
|
ndisBuffer);
|
|
|
|
Length -= currentSizeOfData;
|
|
if (Length == 0) {
|
|
|
|
//
|
|
// Done with all the data that we need to get
|
|
// Both onBoard and outBoard
|
|
//
|
|
|
|
//
|
|
// Better not be another null buffer descriptor attached
|
|
//
|
|
|
|
ASSERT(currentDescriptor->next == NULL);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check for outboard data- could be char * or an MDL
|
|
//
|
|
|
|
if (currentDescriptor->outBoardDataValid) {
|
|
|
|
currentSizeOfData = MIN(currentDescriptor->outBoardSize, Length);
|
|
if (currentSizeOfData > 0) {
|
|
if (currentDescriptor->opaqueData) {
|
|
|
|
//
|
|
// It is an MDL
|
|
//
|
|
|
|
NdisCopyBuffer(
|
|
&ndisStatus,
|
|
&ndisBuffer,
|
|
AtalkNdisBufferPoolHandle,
|
|
(PVOID)currentDescriptor->outBoardData,
|
|
0, //offset
|
|
(UINT)currentSizeOfData);
|
|
|
|
|
|
if (ndisStatus != NDIS_STATUS_SUCCESS) {
|
|
|
|
//
|
|
// Cleanup
|
|
//
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISSEND, DEBUG_LEVEL_ERROR,
|
|
("ERROR: AtalkNdisPacketOut - FAIL (NdisCopyBuf):%lx\n",
|
|
ndisStatus));
|
|
|
|
break;
|
|
}
|
|
|
|
} else {
|
|
|
|
NdisAllocateBuffer(
|
|
&ndisStatus,
|
|
&ndisBuffer,
|
|
AtalkNdisBufferPoolHandle,
|
|
(PVOID)currentDescriptor->outBoardData,
|
|
(UINT)currentSizeOfData);
|
|
|
|
if (ndisStatus != NDIS_STATUS_SUCCESS) {
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISSEND, DEBUG_LEVEL_ERROR,
|
|
("ERROR: AtalkNdisPacketOut - FAIL (NdisAlloBuf):%lx\n",
|
|
ndisStatus));
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
NdisChainBufferAtBack(
|
|
ndisPacket,
|
|
ndisBuffer);
|
|
}
|
|
|
|
Length -= currentSizeOfData;
|
|
if (Length == 0) {
|
|
|
|
//
|
|
// Done with all the data that we need to get
|
|
//
|
|
//
|
|
// Better not be another null buffer descriptor attached
|
|
//
|
|
|
|
ASSERT(currentDescriptor->next == NULL);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ndisStatus == NDIS_STATUS_SUCCESS) {
|
|
|
|
if (Length > 0) {
|
|
DBGPRINT(ATALK_DEBUG_NDISSEND, DEBUG_LEVEL_IMPOSSIBLE,
|
|
("IMPOS: AtalkNdisSend - Length greater than data available %d\n",
|
|
Length));
|
|
|
|
KeBugCheck(0);
|
|
}
|
|
|
|
//
|
|
// Now send the built packet descriptor
|
|
//
|
|
|
|
|
|
NdisSend(
|
|
&ndisStatus,
|
|
NdisPortDesc[Port].NdisBindingHandle,
|
|
ndisPacket);
|
|
|
|
if (ndisStatus == NDIS_STATUS_PENDING) {
|
|
ndisStatus = NDIS_STATUS_SUCCESS;
|
|
} else if (ndisStatus == NDIS_STATUS_SUCCESS) {
|
|
|
|
//
|
|
// Call the completion handler
|
|
//
|
|
|
|
AtalkSendCompletionHandler(
|
|
NdisPortDesc[Port].NdisBindingHandle,
|
|
ndisPacket,
|
|
NDIS_STATUS_SUCCESS);
|
|
|
|
}
|
|
}
|
|
|
|
if (ndisStatus != NDIS_STATUS_SUCCESS) {
|
|
|
|
DBGPRINT(ATALK_DEBUG_NDISSEND, DEBUG_LEVEL_ERROR,
|
|
("ERROR: AtalkNdisSend - stat %lx ndisPkt %lx Chain %lx Length %lx\n",
|
|
ndisStatus, ndisPacket, Chain, Length));
|
|
|
|
// Always return success after calling the comletion routines.
|
|
ASSERT(protocolResd != NULL);
|
|
NTTransmitComplete(protocolResd->Send.Chain);
|
|
AtalkDestroyNdisPacket(ndisPacket);
|
|
ndisStatus = NDIS_STATUS_SUCCESS;
|
|
}
|
|
} else {
|
|
DBGPRINT(ATALK_DEBUG_NDISSEND, DEBUG_LEVEL_FATAL,
|
|
("AtalkNdisPacketOut FAILED (NdisAllocatePacket): %lx\n",
|
|
ndisStatus));
|
|
|
|
// Always return success after calling the comletion routines.
|
|
NTTransmitComplete(Chain);
|
|
ndisStatus = NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
// We will always return TRUE.
|
|
return(ndisStatus == NDIS_STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkSendCompletionHandler(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN PNDIS_PACKET NdisPacket,
|
|
IN NDIS_STATUS NdisStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called when an aarp packet is received. The whole packet
|
|
must fit in the lookahead buffer
|
|
|
|
Arguments:
|
|
|
|
ProtocolBindingContext- Binding associated with mac
|
|
NdisPacket- Packet which was sent
|
|
NdisStatus- Final status of send
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PPROTOCOL_RESD protocolResd;
|
|
|
|
//
|
|
// Call the completion routine, we don't care about status now
|
|
//
|
|
|
|
protocolResd = (PPROTOCOL_RESD)&(NdisPacket->ProtocolReserved);
|
|
|
|
ASSERT(protocolResd != NULL);
|
|
|
|
NTTransmitComplete(protocolResd->Send.Chain);
|
|
|
|
//
|
|
// Free the packet
|
|
//
|
|
|
|
AtalkDestroyNdisPacket(NdisPacket);
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkDestroyNdisPacket(
|
|
IN PNDIS_PACKET NdisPacket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to release a ndis packet
|
|
|
|
Arguments:
|
|
|
|
NdisPacket- Packet and associated buffer descriptors to be freed
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PNDIS_BUFFER freeBuffer, nextBuffer;
|
|
UINT bufferCount;
|
|
|
|
NdisQueryPacket(
|
|
NdisPacket,
|
|
NULL,
|
|
&bufferCount,
|
|
&freeBuffer,
|
|
NULL);
|
|
|
|
while (freeBuffer != NULL) {
|
|
NdisGetNextBuffer(freeBuffer, &nextBuffer);
|
|
NdisFreeBuffer(freeBuffer);
|
|
freeBuffer = nextBuffer;
|
|
}
|
|
|
|
//
|
|
// Now free the packet itself
|
|
//
|
|
|
|
NdisFreePacket(NdisPacket);
|
|
return;
|
|
}
|
|
|
|
|
|
#if DBG
|
|
|
|
VOID
|
|
DumpPacket(
|
|
PUCHAR Packet
|
|
)
|
|
{
|
|
DbgPrint("\nPACKET DUMP\n");
|
|
DbgPrint("Destination %lx\n", *(ULONG *)&Packet[2]);
|
|
DbgPrint("Source %lx\n", *(ULONG *)&Packet[8]);
|
|
DbgPrint("Protocol Disc %lx\n", *(ULONG *)&Packet[18]);
|
|
|
|
DbgPrint("DDP Source node %d\n", (UCHAR)Packet[32]);
|
|
DbgPrint("DDP Src Socket %d\n", (UCHAR)Packet[34]);
|
|
|
|
DbgPrint("DDP Dest node %d\n", (UCHAR)Packet[31]);
|
|
DbgPrint("DDP Dest Socket %d\n", (UCHAR)Packet[33]);
|
|
|
|
DbgPrint("DDP Type %d\n", (UCHAR)Packet[35]);
|
|
|
|
return;
|
|
|
|
}
|
|
#endif
|