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.
4010 lines
88 KiB
4010 lines
88 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
elnkii.c
|
|
|
|
Abstract:
|
|
|
|
This is the main file for the Etherlink II
|
|
Ethernet controller. This driver conforms to the NDIS 3.1 interface.
|
|
|
|
The idea for handling loopback and sends simultaneously is largely
|
|
adapted from the EtherLink II NDIS driver by Adam Barr.
|
|
|
|
Author:
|
|
|
|
Anthony V. Ercolano (Tonye) 20-Jul-1990
|
|
|
|
Environment:
|
|
|
|
Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
|
|
|
|
Revision History:
|
|
|
|
Dec 1991 by Sean Selitrennikoff - Modified Elnkii code by AdamBa to
|
|
fit into the model by TonyE.
|
|
|
|
--*/
|
|
|
|
#include <ndis.h>
|
|
#include <efilter.h>
|
|
#include "elnkhrd.h"
|
|
#include "elnksft.h"
|
|
#include "keywords.h"
|
|
|
|
#if DBG
|
|
#define STATIC
|
|
#else
|
|
#define STATIC static
|
|
#endif
|
|
|
|
|
|
#if DBG
|
|
|
|
extern ULONG ElnkiiSendsCompletedForReset;
|
|
ULONG ElnkiiDebugFlag=ELNKII_DEBUG_LOG;
|
|
extern ULONG ElnkiiSendsCompletedForReset;
|
|
|
|
#endif
|
|
|
|
//
|
|
// This constant is used for places where NdisAllocateMemory
|
|
// needs to be called and the HighestAcceptableAddress does
|
|
// not matter.
|
|
//
|
|
|
|
static const NDIS_PHYSICAL_ADDRESS HighestAcceptableMax =
|
|
NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
|
|
|
|
|
|
//
|
|
// The global MAC block.
|
|
//
|
|
|
|
MAC_BLOCK ElnkiiMacBlock={0};
|
|
|
|
|
|
|
|
//
|
|
// If you add to this, make sure to add the
|
|
// a case in ElnkiiFillInGlobalData() and in
|
|
// ElnkiiQueryGlobalStatistics() if global
|
|
// information only or
|
|
// ElnkiiQueryProtocolStatistics() if it is
|
|
// protocol queriable information.
|
|
//
|
|
STATIC UINT ElnkiiGlobalSupportedOids[] = {
|
|
OID_GEN_SUPPORTED_LIST,
|
|
OID_GEN_HARDWARE_STATUS,
|
|
OID_GEN_MEDIA_SUPPORTED,
|
|
OID_GEN_MEDIA_IN_USE,
|
|
OID_GEN_MAXIMUM_LOOKAHEAD,
|
|
OID_GEN_MAXIMUM_FRAME_SIZE,
|
|
OID_GEN_MAXIMUM_TOTAL_SIZE,
|
|
OID_GEN_MAC_OPTIONS,
|
|
OID_GEN_PROTOCOL_OPTIONS,
|
|
OID_GEN_LINK_SPEED,
|
|
OID_GEN_TRANSMIT_BUFFER_SPACE,
|
|
OID_GEN_RECEIVE_BUFFER_SPACE,
|
|
OID_GEN_TRANSMIT_BLOCK_SIZE,
|
|
OID_GEN_RECEIVE_BLOCK_SIZE,
|
|
OID_GEN_VENDOR_ID,
|
|
OID_GEN_VENDOR_DESCRIPTION,
|
|
OID_GEN_DRIVER_VERSION,
|
|
OID_GEN_CURRENT_PACKET_FILTER,
|
|
OID_GEN_CURRENT_LOOKAHEAD,
|
|
OID_GEN_XMIT_OK,
|
|
OID_GEN_RCV_OK,
|
|
OID_GEN_XMIT_ERROR,
|
|
OID_GEN_RCV_ERROR,
|
|
OID_GEN_RCV_NO_BUFFER,
|
|
OID_802_3_PERMANENT_ADDRESS,
|
|
OID_802_3_CURRENT_ADDRESS,
|
|
OID_802_3_MULTICAST_LIST,
|
|
OID_802_3_MAXIMUM_LIST_SIZE,
|
|
OID_802_3_RCV_ERROR_ALIGNMENT,
|
|
OID_802_3_XMIT_ONE_COLLISION,
|
|
OID_802_3_XMIT_MORE_COLLISIONS
|
|
};
|
|
|
|
//
|
|
// If you add to this, make sure to add the
|
|
// a case in ElnkiiQueryGlobalStatistics() and in
|
|
// ElnkiiQueryProtocolInformation()
|
|
//
|
|
STATIC UINT ElnkiiProtocolSupportedOids[] = {
|
|
OID_GEN_SUPPORTED_LIST,
|
|
OID_GEN_HARDWARE_STATUS,
|
|
OID_GEN_MEDIA_SUPPORTED,
|
|
OID_GEN_MEDIA_IN_USE,
|
|
OID_GEN_MAXIMUM_LOOKAHEAD,
|
|
OID_GEN_MAXIMUM_FRAME_SIZE,
|
|
OID_GEN_MAXIMUM_TOTAL_SIZE,
|
|
OID_GEN_MAC_OPTIONS,
|
|
OID_GEN_PROTOCOL_OPTIONS,
|
|
OID_GEN_LINK_SPEED,
|
|
OID_GEN_TRANSMIT_BUFFER_SPACE,
|
|
OID_GEN_RECEIVE_BUFFER_SPACE,
|
|
OID_GEN_TRANSMIT_BLOCK_SIZE,
|
|
OID_GEN_RECEIVE_BLOCK_SIZE,
|
|
OID_GEN_VENDOR_ID,
|
|
OID_GEN_VENDOR_DESCRIPTION,
|
|
OID_GEN_DRIVER_VERSION,
|
|
OID_GEN_CURRENT_PACKET_FILTER,
|
|
OID_GEN_CURRENT_LOOKAHEAD,
|
|
OID_802_3_PERMANENT_ADDRESS,
|
|
OID_802_3_CURRENT_ADDRESS,
|
|
OID_802_3_MULTICAST_LIST,
|
|
OID_802_3_MAXIMUM_LIST_SIZE
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
// Determines whether failing the initial card test will prevent
|
|
// the adapter from being registered.
|
|
//
|
|
|
|
#ifdef CARD_TEST
|
|
|
|
BOOLEAN InitialCardTest = TRUE;
|
|
|
|
#else // CARD_TEST
|
|
|
|
BOOLEAN InitialCardTest = FALSE;
|
|
|
|
#endif // CARD_TEST
|
|
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
);
|
|
|
|
|
|
#pragma NDIS_INIT_FUNCTION(DriverEntry)
|
|
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the transfer address of the driver. It initializes
|
|
ElnkiiMacBlock and calls NdisInitializeWrapper() and
|
|
NdisRegisterMac().
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Indicates the success or failure of the initialization.
|
|
|
|
--*/
|
|
|
|
{
|
|
NDIS_HANDLE NdisWrapperHandle;
|
|
PMAC_BLOCK NewMacP = &ElnkiiMacBlock;
|
|
NDIS_STATUS Status;
|
|
NDIS_STRING MacName = NDIS_STRING_CONST("Elnkii");
|
|
|
|
//
|
|
// Ensure that the MAC_RESERVED structure will fit in the
|
|
// MacReserved section of a packet.
|
|
//
|
|
|
|
ASSERT(sizeof(MAC_RESERVED) <= sizeof(((PNDIS_PACKET)NULL)->MacReserved));
|
|
|
|
|
|
//
|
|
// Pass the wrapper a pointer to the device object.
|
|
//
|
|
|
|
NdisInitializeWrapper(&NdisWrapperHandle,
|
|
DriverObject,
|
|
RegistryPath,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Set up the driver object.
|
|
//
|
|
|
|
NewMacP->DriverObject = DriverObject;
|
|
|
|
NdisAllocateSpinLock(&NewMacP->SpinLock);
|
|
|
|
NewMacP->NdisWrapperHandle = NdisWrapperHandle;
|
|
NewMacP->Unloading = FALSE;
|
|
NewMacP->AdapterQueue = (PELNKII_ADAPTER)NULL;
|
|
|
|
|
|
//
|
|
// Prepare to call NdisRegisterMac.
|
|
//
|
|
|
|
NewMacP->MacCharacteristics.MajorNdisVersion = ELNKII_NDIS_MAJOR_VERSION;
|
|
NewMacP->MacCharacteristics.MinorNdisVersion = ELNKII_NDIS_MINOR_VERSION;
|
|
NewMacP->MacCharacteristics.OpenAdapterHandler = ElnkiiOpenAdapter;
|
|
NewMacP->MacCharacteristics.CloseAdapterHandler = ElnkiiCloseAdapter;
|
|
NewMacP->MacCharacteristics.SendHandler = ElnkiiSend;
|
|
NewMacP->MacCharacteristics.TransferDataHandler = ElnkiiTransferData;
|
|
NewMacP->MacCharacteristics.ResetHandler = ElnkiiReset;
|
|
NewMacP->MacCharacteristics.RequestHandler = ElnkiiRequest;
|
|
NewMacP->MacCharacteristics.QueryGlobalStatisticsHandler =
|
|
ElnkiiQueryGlobalStatistics;
|
|
NewMacP->MacCharacteristics.UnloadMacHandler = ElnkiiUnload;
|
|
NewMacP->MacCharacteristics.AddAdapterHandler = ElnkiiAddAdapter;
|
|
NewMacP->MacCharacteristics.RemoveAdapterHandler = ElnkiiRemoveAdapter;
|
|
|
|
NewMacP->MacCharacteristics.Name = MacName;
|
|
|
|
NdisRegisterMac(&Status,
|
|
&NewMacP->NdisMacHandle,
|
|
NdisWrapperHandle,
|
|
(NDIS_HANDLE)&ElnkiiMacBlock,
|
|
&NewMacP->MacCharacteristics,
|
|
sizeof(NewMacP->MacCharacteristics));
|
|
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS) {
|
|
|
|
//
|
|
// NdisRegisterMac failed.
|
|
//
|
|
|
|
NdisFreeSpinLock(&NewMacP->SpinLock);
|
|
NdisTerminateWrapper(NdisWrapperHandle,
|
|
(PVOID) NULL
|
|
);
|
|
IF_LOUD( DbgPrint( "NdisRegisterMac failed with code 0x%x\n", Status );)
|
|
return Status;
|
|
}
|
|
|
|
|
|
IF_LOUD( DbgPrint( "NdisRegisterMac succeeded\n" );)
|
|
|
|
IF_LOUD( DbgPrint("Adapter Initialization Complete\n");)
|
|
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
#pragma NDIS_INIT_FUNCTION(ElnkiiAddAdapter)
|
|
|
|
NDIS_STATUS
|
|
ElnkiiAddAdapter(
|
|
IN NDIS_HANDLE MacMacContext,
|
|
IN NDIS_HANDLE ConfigurationHandle,
|
|
IN PNDIS_STRING AdapterName
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
This is the ElinkII MacAddAdapter routine. The system calls this routine
|
|
to add support for a particular ElinkII adapter. This routine extracts
|
|
configuration information from the configuration data base and registers
|
|
the adapter with NDIS.
|
|
|
|
Arguments:
|
|
|
|
See Ndis3.0 spec...
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS - Adapter was successfully added.
|
|
NDIS_STATUS_FAILURE - Adapter was not added, also MAC deregistered.
|
|
|
|
--*/
|
|
{
|
|
PELNKII_ADAPTER NewAdaptP;
|
|
|
|
NDIS_HANDLE ConfigHandle;
|
|
PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
|
|
NDIS_STRING IOAddressStr = IOBASE;
|
|
NDIS_STRING InterruptStr = INTERRUPT;
|
|
NDIS_STRING MaxMulticastListStr = MAXMULTICAST;
|
|
NDIS_STRING NetworkAddressStr = NETWORK_ADDRESS;
|
|
NDIS_STRING MemoryMappedStr = MEMORYMAPPED;
|
|
NDIS_STRING TransceiverStr = TRANSCEIVER;
|
|
|
|
#if NDIS2
|
|
NDIS_STRING EXTERNALStr = NDIS_STRING_CONST("EXTERNAL");
|
|
#endif
|
|
|
|
BOOLEAN ConfigError = FALSE;
|
|
ULONG ConfigErrorValue = 0;
|
|
ULONG Length;
|
|
PVOID NetAddress;
|
|
|
|
NDIS_STATUS Status;
|
|
|
|
|
|
//
|
|
// These are used when calling ElnkiiRegisterAdapter.
|
|
//
|
|
|
|
PVOID IoBaseAddr;
|
|
CCHAR InterruptNumber;
|
|
BOOLEAN ExternalTransceiver;
|
|
BOOLEAN MemMapped;
|
|
UINT MaxMulticastList;
|
|
|
|
//
|
|
// Set default values.
|
|
//
|
|
|
|
IoBaseAddr = DEFAULT_IOBASEADDR;
|
|
InterruptNumber = DEFAULT_INTERRUPTNUMBER;
|
|
ExternalTransceiver = DEFAULT_EXTERNALTRANSCEIVER;
|
|
MemMapped = DEFAULT_MEMMAPPED;
|
|
MaxMulticastList = DEFAULT_MULTICASTLISTMAX;
|
|
|
|
//
|
|
// Allocate memory for the adapter block now.
|
|
//
|
|
|
|
Status = NdisAllocateMemory( (PVOID *)&NewAdaptP, sizeof(ELNKII_ADAPTER), 0, HighestAcceptableMax);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS) {
|
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
NdisZeroMemory (NewAdaptP,
|
|
sizeof(ELNKII_ADAPTER)
|
|
);
|
|
|
|
NdisOpenConfiguration(
|
|
&Status,
|
|
&ConfigHandle,
|
|
ConfigurationHandle
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS) {
|
|
|
|
NdisFreeMemory(NewAdaptP, sizeof(ELNKII_ADAPTER), 0);
|
|
|
|
return NDIS_STATUS_FAILURE;
|
|
|
|
}
|
|
|
|
//
|
|
// Read I/O Address
|
|
//
|
|
|
|
NdisReadConfiguration(
|
|
&Status,
|
|
&ReturnedValue,
|
|
ConfigHandle,
|
|
&IOAddressStr,
|
|
NdisParameterHexInteger
|
|
);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS) {
|
|
|
|
IoBaseAddr = (PVOID)(ReturnedValue->ParameterData.IntegerData);
|
|
|
|
}
|
|
|
|
//
|
|
// Confirm value
|
|
//
|
|
|
|
{
|
|
UCHAR Count;
|
|
|
|
static PVOID IoBases[] = { (PVOID)0x2e0, (PVOID)0x2a0,
|
|
(PVOID)0x280, (PVOID)0x250,
|
|
(PVOID)0x350, (PVOID)0x330,
|
|
(PVOID)0x310, (PVOID)0x300 };
|
|
|
|
for (Count = 0 ; Count < 8; Count++) {
|
|
|
|
if (IoBaseAddr == IoBases[Count]) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (Count == 8) {
|
|
|
|
//
|
|
// Error
|
|
//
|
|
|
|
ConfigError = TRUE;
|
|
ConfigErrorValue = (ULONG)IoBaseAddr;
|
|
|
|
goto RegisterAdapter;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Read interrupt number
|
|
//
|
|
|
|
NdisReadConfiguration(
|
|
&Status,
|
|
&ReturnedValue,
|
|
ConfigHandle,
|
|
&InterruptStr,
|
|
NdisParameterHexInteger
|
|
);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS) {
|
|
|
|
InterruptNumber = (CCHAR)(ReturnedValue->ParameterData.IntegerData);
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Confirm value
|
|
//
|
|
|
|
{
|
|
UCHAR Count;
|
|
|
|
static CCHAR InterruptValues[] = { 2, 3, 4, 5 };
|
|
|
|
for (Count = 0 ; Count < 4; Count++) {
|
|
|
|
if (InterruptNumber == InterruptValues[Count]) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (Count == 4) {
|
|
|
|
//
|
|
// Error
|
|
//
|
|
|
|
ConfigError = TRUE;
|
|
ConfigErrorValue = InterruptNumber;
|
|
|
|
goto RegisterAdapter;
|
|
}
|
|
|
|
}
|
|
|
|
#if !NDIS2
|
|
//
|
|
// Read MaxMulticastList
|
|
//
|
|
|
|
NdisReadConfiguration(
|
|
&Status,
|
|
&ReturnedValue,
|
|
ConfigHandle,
|
|
&MaxMulticastListStr,
|
|
NdisParameterInteger
|
|
);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS) {
|
|
|
|
MaxMulticastList = ReturnedValue->ParameterData.IntegerData;
|
|
|
|
}
|
|
#endif
|
|
|
|
#if NDIS_NT
|
|
//
|
|
// Read Memory Mapped
|
|
//
|
|
|
|
NdisReadConfiguration(
|
|
&Status,
|
|
&ReturnedValue,
|
|
ConfigHandle,
|
|
&MemoryMappedStr,
|
|
NdisParameterHexInteger
|
|
);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS) {
|
|
|
|
MemMapped = (ReturnedValue->ParameterData.IntegerData == 0)?FALSE:TRUE;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#if NDIS2
|
|
//
|
|
// Read Transceiver
|
|
//
|
|
|
|
NdisReadConfiguration(
|
|
&Status,
|
|
&ReturnedValue,
|
|
ConfigHandle,
|
|
&TransceiverStr,
|
|
NdisParameterString
|
|
);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS) {
|
|
|
|
if (NdisEqualString (&ReturnedValue->ParameterData.StringData, &EXTERNALStr, 1 )) {
|
|
ExternalTransceiver = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
#else // NDIS3
|
|
//
|
|
// Read Transceiver
|
|
//
|
|
|
|
NdisReadConfiguration(
|
|
&Status,
|
|
&ReturnedValue,
|
|
ConfigHandle,
|
|
&TransceiverStr,
|
|
NdisParameterInteger
|
|
);
|
|
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS) {
|
|
|
|
ExternalTransceiver = (ReturnedValue->ParameterData.IntegerData == 1)?TRUE:FALSE;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// Read net address
|
|
//
|
|
|
|
NdisReadNetworkAddress(
|
|
&Status,
|
|
&NetAddress,
|
|
&Length,
|
|
ConfigHandle
|
|
);
|
|
|
|
if ((Length == ETH_LENGTH_OF_ADDRESS) && (Status == NDIS_STATUS_SUCCESS)) {
|
|
|
|
ETH_COPY_NETWORK_ADDRESS(
|
|
NewAdaptP->StationAddress,
|
|
NetAddress
|
|
);
|
|
|
|
}
|
|
|
|
RegisterAdapter:
|
|
|
|
NdisCloseConfiguration(ConfigHandle);
|
|
|
|
IF_LOUD( DbgPrint( "Registering adapter # buffers %ld, "
|
|
"I/O base addr 0x%lx, max opens %ld, interrupt number %ld, "
|
|
"external %c, memory mapped %c, max multicast %ld\n",
|
|
DEFAULT_NUMBUFFERS, IoBaseAddr, DEFAULT_MAXOPENS,
|
|
InterruptNumber,
|
|
ExternalTransceiver ? 'Y' : 'N',
|
|
MemMapped ? 'Y' : 'N',
|
|
DEFAULT_MULTICASTLISTMAX );)
|
|
|
|
|
|
|
|
//
|
|
// Set up the parameters.
|
|
//
|
|
|
|
NewAdaptP->NumBuffers = DEFAULT_NUMBUFFERS;
|
|
NewAdaptP->IoBaseAddr = IoBaseAddr;
|
|
NewAdaptP->ExternalTransceiver = ExternalTransceiver;
|
|
NewAdaptP->InterruptNumber = InterruptNumber;
|
|
NewAdaptP->MemMapped = MemMapped;
|
|
NewAdaptP->MaxOpens = DEFAULT_MAXOPENS;
|
|
NewAdaptP->MulticastListMax = MaxMulticastList;
|
|
|
|
if (ElnkiiRegisterAdapter(NewAdaptP,
|
|
ConfigurationHandle,
|
|
AdapterName,
|
|
ConfigError,
|
|
ConfigErrorValue
|
|
) != NDIS_STATUS_SUCCESS) {
|
|
|
|
|
|
|
|
//
|
|
// ElnkiiRegisterAdapter failed.
|
|
//
|
|
|
|
NdisFreeMemory(NewAdaptP, sizeof(ELNKII_ADAPTER), 0);
|
|
return NDIS_STATUS_FAILURE;
|
|
}
|
|
|
|
|
|
|
|
IF_LOUD( DbgPrint( "ElnkiiRegisterAdapter succeeded\n" );)
|
|
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ElnkiiRegisterAdapter(
|
|
IN PELNKII_ADAPTER NewAdaptP,
|
|
IN NDIS_HANDLE ConfigurationHandle,
|
|
IN PNDIS_STRING AdapterName,
|
|
IN BOOLEAN ConfigError,
|
|
IN ULONG ConfigErrorValue
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called when a new adapter should be registered. It allocates space for
|
|
the adapter and open blocks, initializes the adapters block, and
|
|
calls NdisRegisterAdapter().
|
|
|
|
Arguments:
|
|
|
|
NewAdaptP - The adapter structure.
|
|
|
|
ConfigurationHandle - Handle passed to MacAddAdapter.
|
|
|
|
AdapterName - Pointer to the name for this adapter.
|
|
|
|
ConfigError - Was there an error during configuration reading.
|
|
|
|
ConfigErrorValue - Value to log if there is an error.
|
|
|
|
Return Value:
|
|
|
|
Indicates the success or failure of the registration.
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT i;
|
|
BOOLEAN CardPresent, IoBaseCorrect;
|
|
|
|
NDIS_STATUS status; //general purpose return from NDIS calls
|
|
PNDIS_ADAPTER_INFORMATION AdapterInformation; // needed to register adapter
|
|
|
|
//
|
|
// check that NumBuffers <= MAX_XMIT_BUFS
|
|
//
|
|
|
|
if (NewAdaptP->NumBuffers > MAX_XMIT_BUFS) {
|
|
|
|
status = NDIS_STATUS_RESOURCES;
|
|
|
|
goto fail1;
|
|
|
|
}
|
|
|
|
NewAdaptP->OpenQueue = (PELNKII_OPEN)NULL;
|
|
NewAdaptP->CloseQueue = (PELNKII_OPEN)NULL;
|
|
|
|
//
|
|
// The adapter is initialized, register it with NDIS.
|
|
// This must occur before interrupts are enabled since the
|
|
// InitializeInterrupt routine requires the NdisAdapterHandle
|
|
//
|
|
|
|
//
|
|
// Set up the AdapterInformation structure; zero it
|
|
// first in case it is extended later.
|
|
//
|
|
|
|
status = NdisAllocateMemory( (PVOID *)&AdapterInformation,
|
|
sizeof(NDIS_ADAPTER_INFORMATION) +
|
|
sizeof(NDIS_PORT_DESCRIPTOR),
|
|
0,
|
|
HighestAcceptableMax
|
|
);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS) {
|
|
|
|
return(status);
|
|
|
|
}
|
|
|
|
NdisZeroMemory (AdapterInformation,
|
|
sizeof(NDIS_ADAPTER_INFORMATION) +
|
|
sizeof(NDIS_PORT_DESCRIPTOR)
|
|
);
|
|
|
|
AdapterInformation->AdapterType = NdisInterfaceIsa;
|
|
AdapterInformation->NumberOfPortDescriptors = 2;
|
|
AdapterInformation->PortDescriptors[0].InitialPort = (ULONG)NewAdaptP->IoBaseAddr;
|
|
AdapterInformation->PortDescriptors[0].NumberOfPorts = 0x10;
|
|
AdapterInformation->PortDescriptors[0].PortOffset = (PVOID *)(&(NewAdaptP->MappedIoBaseAddr));
|
|
AdapterInformation->PortDescriptors[1].InitialPort = (ULONG)NewAdaptP->IoBaseAddr + 0x400;
|
|
AdapterInformation->PortDescriptors[1].NumberOfPorts = 0x10;
|
|
AdapterInformation->PortDescriptors[1].PortOffset = (PVOID *)(&(NewAdaptP->MappedGaBaseAddr));
|
|
|
|
|
|
if ((status = NdisRegisterAdapter(&NewAdaptP->NdisAdapterHandle,
|
|
ElnkiiMacBlock.NdisMacHandle,
|
|
(NDIS_HANDLE)NewAdaptP,
|
|
ConfigurationHandle,
|
|
AdapterName,
|
|
AdapterInformation))
|
|
!= NDIS_STATUS_SUCCESS) {
|
|
|
|
//
|
|
// NdisRegisterAdapter failed.
|
|
//
|
|
|
|
|
|
NdisFreeMemory(AdapterInformation,
|
|
sizeof(NDIS_ADAPTER_INFORMATION) +
|
|
sizeof(NDIS_PORT_DESCRIPTOR),
|
|
0
|
|
);
|
|
|
|
goto fail2;
|
|
}
|
|
|
|
NdisFreeMemory(AdapterInformation,
|
|
sizeof(NDIS_ADAPTER_INFORMATION) +
|
|
sizeof(NDIS_PORT_DESCRIPTOR),
|
|
0
|
|
);
|
|
|
|
//
|
|
// Allocate the Spin lock.
|
|
//
|
|
NdisAllocateSpinLock(&NewAdaptP->Lock);
|
|
|
|
if (ConfigError) {
|
|
|
|
//
|
|
// Log Error and exit.
|
|
//
|
|
|
|
NdisWriteErrorLogEntry(
|
|
NewAdaptP->NdisAdapterHandle,
|
|
NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
|
|
1,
|
|
ConfigErrorValue
|
|
);
|
|
|
|
goto fail3;
|
|
|
|
}
|
|
|
|
//
|
|
// Initialize Pending information
|
|
//
|
|
NewAdaptP->PendQueue = (PELNKII_PEND_DATA)NULL;
|
|
NewAdaptP->PendQTail = (PELNKII_PEND_DATA)NULL;
|
|
NewAdaptP->PendOp = (PELNKII_PEND_DATA)NULL;
|
|
NewAdaptP->DeferredDpc = (PVOID)HandlePendingOperations;
|
|
|
|
//
|
|
// Initialize References.
|
|
//
|
|
NewAdaptP->References = 0;
|
|
|
|
NdisInitializeTimer(&(NewAdaptP->DeferredTimer),
|
|
NewAdaptP->DeferredDpc,
|
|
NewAdaptP);
|
|
|
|
//
|
|
// Map the memory mapped portion of the card.
|
|
//
|
|
// If NewAdaptP->MemMapped is FALSE, CardGetMemBaseAddr will not
|
|
// return the actual MemBaseAddr, but it will still return
|
|
// CardPresent and IoBaseCorrect.
|
|
//
|
|
//
|
|
|
|
NewAdaptP->MemBaseAddr = CardGetMemBaseAddr(NewAdaptP,
|
|
&CardPresent,
|
|
&IoBaseCorrect
|
|
);
|
|
|
|
if (!CardPresent) {
|
|
|
|
//
|
|
// The card does not seem to be there, fail silently.
|
|
//
|
|
|
|
NdisWriteErrorLogEntry(
|
|
NewAdaptP->NdisAdapterHandle,
|
|
NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
|
|
0
|
|
);
|
|
|
|
status = NDIS_STATUS_ADAPTER_NOT_FOUND;
|
|
|
|
goto fail3;
|
|
|
|
}
|
|
|
|
if (!IoBaseCorrect) {
|
|
|
|
//
|
|
// The card is there, but the I/O base address jumper
|
|
// is not where we expect it to be.
|
|
//
|
|
|
|
|
|
NdisWriteErrorLogEntry(
|
|
NewAdaptP->NdisAdapterHandle,
|
|
NDIS_ERROR_CODE_BAD_IO_BASE_ADDRESS,
|
|
0
|
|
);
|
|
|
|
status = NDIS_STATUS_ADAPTER_NOT_FOUND;
|
|
|
|
goto fail3;
|
|
|
|
}
|
|
|
|
if (NewAdaptP->MemMapped && (NewAdaptP->MemBaseAddr == NULL)) {
|
|
|
|
//
|
|
// The card appears to not be mapped.
|
|
//
|
|
|
|
NewAdaptP->MemMapped = FALSE;
|
|
|
|
}
|
|
|
|
//
|
|
// For memory-mapped operation, map the card's transmit/receive
|
|
// area into memory space. For programmed I/O, we will refer
|
|
// to transmit/receive memory in terms of offsets in the
|
|
// card's 32K address space; for an 8K card this is always
|
|
// the second 8K piece, starting at 0x2000.
|
|
//
|
|
|
|
if (NewAdaptP->MemMapped) {
|
|
|
|
NDIS_PHYSICAL_ADDRESS PhysicalAddress;
|
|
|
|
NdisSetPhysicalAddressHigh(PhysicalAddress, 0);
|
|
NdisSetPhysicalAddressLow(PhysicalAddress, (ULONG)(NewAdaptP->MemBaseAddr));
|
|
|
|
NdisMapIoSpace(
|
|
&status,
|
|
(PVOID *)(&NewAdaptP->XmitStart),
|
|
NewAdaptP->NdisAdapterHandle,
|
|
PhysicalAddress,
|
|
0x2000);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS) {
|
|
|
|
NdisWriteErrorLogEntry(
|
|
NewAdaptP->NdisAdapterHandle,
|
|
NDIS_ERROR_CODE_RESOURCE_CONFLICT,
|
|
0
|
|
);
|
|
|
|
goto fail3;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
NewAdaptP->XmitStart = (PUCHAR)0x2000;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// For the NicXXX fields, always use the addressing system
|
|
// starting at 0x2000 (or 0x20, since they contain the MSB only).
|
|
//
|
|
|
|
NewAdaptP->NicXmitStart = 0x20;
|
|
|
|
|
|
//
|
|
// The start of the receive space.
|
|
//
|
|
|
|
NewAdaptP->PageStart = NewAdaptP->XmitStart +
|
|
(NewAdaptP->NumBuffers * TX_BUF_SIZE);
|
|
|
|
NewAdaptP->NicPageStart = NewAdaptP->NicXmitStart +
|
|
(UCHAR)(NewAdaptP->NumBuffers * BUFS_PER_TX);
|
|
|
|
|
|
//
|
|
// The end of the receive space.
|
|
//
|
|
|
|
NewAdaptP->PageStop = NewAdaptP->XmitStart + 0x2000;
|
|
NewAdaptP->NicPageStop = NewAdaptP->NicXmitStart + (UCHAR)0x20;
|
|
|
|
|
|
|
|
//
|
|
// Initialize the receive variables.
|
|
//
|
|
|
|
NewAdaptP->NicReceiveConfig = RCR_REJECT_ERR;
|
|
NewAdaptP->ReceiveInProgress = FALSE;
|
|
|
|
//
|
|
// Initialize the transmit buffer control.
|
|
//
|
|
|
|
NewAdaptP->CurBufXmitting = -1;
|
|
NewAdaptP->TransmitInterruptPending = FALSE;
|
|
NewAdaptP->BufferOverflow = FALSE;
|
|
NewAdaptP->OverflowRestartXmitDpc = FALSE;
|
|
|
|
for (i=0; i<NewAdaptP->NumBuffers; i++) {
|
|
|
|
NewAdaptP->BufferStatus[i] = EMPTY;
|
|
|
|
}
|
|
|
|
NewAdaptP->ResetInProgress = FALSE;
|
|
NewAdaptP->TransmitInterruptPending = FALSE;
|
|
|
|
NewAdaptP->WakeUpFoundTransmit = FALSE;
|
|
|
|
//
|
|
// Clear Interrupt Information
|
|
//
|
|
|
|
NewAdaptP->ElnkiiHandleXmitCompleteRunning = FALSE;
|
|
|
|
|
|
//
|
|
// The transmit and loopback queues start out empty.
|
|
//
|
|
// Already done since structure is zero'd out.
|
|
//
|
|
|
|
//
|
|
// Clear the tally counters.
|
|
//
|
|
// Already done since structure is zero'd out.
|
|
//
|
|
|
|
//
|
|
// Read the Ethernet address off of the PROM.
|
|
//
|
|
|
|
CardReadEthernetAddress(NewAdaptP);
|
|
|
|
|
|
//
|
|
// Initialize Filter Database
|
|
//
|
|
if (!EthCreateFilter( NewAdaptP->MulticastListMax,
|
|
ElnkiiChangeMulticastAddresses,
|
|
ElnkiiChangeFilterClasses,
|
|
ElnkiiCloseAction,
|
|
NewAdaptP->StationAddress,
|
|
&NewAdaptP->Lock,
|
|
&NewAdaptP->FilterDB
|
|
)) {
|
|
|
|
|
|
NdisWriteErrorLogEntry(
|
|
NewAdaptP->NdisAdapterHandle,
|
|
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
|
|
0
|
|
);
|
|
|
|
status = NDIS_STATUS_FAILURE;
|
|
|
|
goto fail4;
|
|
|
|
}
|
|
|
|
//
|
|
// Now initialize the NIC and Gate Array registers.
|
|
//
|
|
|
|
NewAdaptP->NicInterruptMask =
|
|
IMR_RCV | IMR_XMIT | IMR_XMIT_ERR | IMR_OVERFLOW;
|
|
|
|
|
|
//
|
|
// Link us on to the chain of adapters for this MAC.
|
|
//
|
|
|
|
NewAdaptP->MacBlock = &ElnkiiMacBlock;
|
|
|
|
NdisAcquireSpinLock(&ElnkiiMacBlock.SpinLock);
|
|
|
|
NewAdaptP->NextAdapter = ElnkiiMacBlock.AdapterQueue;
|
|
ElnkiiMacBlock.AdapterQueue = NewAdaptP;
|
|
|
|
NdisReleaseSpinLock(&ElnkiiMacBlock.SpinLock);
|
|
|
|
//
|
|
// Turn Off the card.
|
|
//
|
|
|
|
SyncCardStop(NewAdaptP);
|
|
|
|
//
|
|
// Set flag to ignore interrupts
|
|
//
|
|
|
|
NewAdaptP->InCardTest = TRUE;
|
|
|
|
//
|
|
// Connect to interrupt
|
|
//
|
|
|
|
NdisInitializeInterrupt(&status, // status of call
|
|
&NewAdaptP->NdisInterrupt, // interrupt info str
|
|
NewAdaptP->NdisAdapterHandle, // NDIS adapter handle
|
|
ElnkiiInterruptHandler, // ptr to ISR
|
|
NewAdaptP, // context for ISR, DPC
|
|
ElnkiiInterruptDpc, // ptr to int DPC
|
|
NewAdaptP->InterruptNumber, // vector
|
|
NewAdaptP->InterruptNumber, // level
|
|
FALSE, // NOT shared
|
|
NdisInterruptLatched // InterruptMode
|
|
);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS) {
|
|
|
|
//
|
|
// The NIC could not be written to.
|
|
//
|
|
|
|
NdisWriteErrorLogEntry(
|
|
NewAdaptP->NdisAdapterHandle,
|
|
NDIS_ERROR_CODE_INTERRUPT_CONNECT,
|
|
0
|
|
);
|
|
|
|
goto fail6;
|
|
|
|
}
|
|
|
|
if (!CardSetup(NewAdaptP)) {
|
|
|
|
//
|
|
// The NIC could not be written to.
|
|
//
|
|
|
|
NdisWriteErrorLogEntry(
|
|
NewAdaptP->NdisAdapterHandle,
|
|
NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
|
|
0
|
|
);
|
|
|
|
status = NDIS_STATUS_ADAPTER_NOT_FOUND;
|
|
|
|
goto fail7;
|
|
}
|
|
|
|
|
|
//
|
|
// Perform card tests.
|
|
//
|
|
|
|
if (!CardTest(NewAdaptP)) {
|
|
|
|
//
|
|
// The tests failed, InitialCardTest determines whether
|
|
// this causes the whole initialization to fail.
|
|
//
|
|
|
|
if (InitialCardTest) {
|
|
|
|
NdisWriteErrorLogEntry(
|
|
NewAdaptP->NdisAdapterHandle,
|
|
NDIS_ERROR_CODE_HARDWARE_FAILURE,
|
|
0
|
|
);
|
|
|
|
status = NDIS_STATUS_DEVICE_FAILED;
|
|
|
|
goto fail7;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Normal mode now
|
|
//
|
|
|
|
NewAdaptP->InCardTest = FALSE;
|
|
|
|
NdisInitializeTimer(&NewAdaptP->InterruptTimer,
|
|
(PVOID)ElnkiiInterruptDpc,
|
|
NewAdaptP
|
|
);
|
|
|
|
//
|
|
// Initialize the wake up timer to catch transmits that
|
|
// don't interrupt when complete. It fires continuously
|
|
// every two seconds, and we check if there are any
|
|
// uncompleted sends from the previous two-second
|
|
// period.
|
|
//
|
|
|
|
NewAdaptP->WakeUpDpc = (PVOID)ElnkiiWakeUpDpc;
|
|
|
|
NdisInitializeTimer(&NewAdaptP->WakeUpTimer,
|
|
(PVOID)(NewAdaptP->WakeUpDpc),
|
|
NewAdaptP );
|
|
|
|
NdisSetTimer(
|
|
&NewAdaptP->WakeUpTimer,
|
|
2000
|
|
);
|
|
|
|
NewAdaptP->Removed = FALSE;
|
|
|
|
IF_LOUD( DbgPrint("Interrupt Connected\n");)
|
|
|
|
|
|
//
|
|
// Initialization completed successfully.
|
|
//
|
|
|
|
IF_LOUD( DbgPrint(" [ Elnkii ] : OK");)
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
|
|
|
|
|
|
//
|
|
// Code to unwind what has already been set up when a part of
|
|
// initialization fails, which is jumped into at various
|
|
// points based on where the failure occured. Jumping to
|
|
// a higher-numbered failure point will execute the code
|
|
// for that block and all lower-numbered ones.
|
|
//
|
|
|
|
fail7:
|
|
NdisRemoveInterrupt(&NewAdaptP->NdisInterrupt);
|
|
|
|
fail6:
|
|
NdisAcquireSpinLock(&ElnkiiMacBlock.SpinLock);
|
|
|
|
//
|
|
// Take us out of the AdapterQueue.
|
|
//
|
|
|
|
if (ElnkiiMacBlock.AdapterQueue == NewAdaptP) {
|
|
|
|
ElnkiiMacBlock.AdapterQueue = NewAdaptP->NextAdapter;
|
|
|
|
} else {
|
|
|
|
PELNKII_ADAPTER TmpAdaptP = ElnkiiMacBlock.AdapterQueue;
|
|
|
|
while (TmpAdaptP->NextAdapter != NewAdaptP) {
|
|
|
|
TmpAdaptP = TmpAdaptP->NextAdapter;
|
|
|
|
}
|
|
|
|
TmpAdaptP->NextAdapter = TmpAdaptP->NextAdapter->NextAdapter;
|
|
}
|
|
|
|
NdisReleaseSpinLock(&ElnkiiMacBlock.SpinLock);
|
|
|
|
EthDeleteFilter(NewAdaptP->FilterDB);
|
|
|
|
fail4:
|
|
|
|
//
|
|
// We already enabled the interrupt on the card, so
|
|
// turn it off.
|
|
//
|
|
|
|
NdisRawWritePortUchar(NewAdaptP->MappedGaBaseAddr+GA_INT_DMA_CONFIG, 0x00);
|
|
|
|
if (NewAdaptP->MemMapped) {
|
|
|
|
NdisUnmapIoSpace(
|
|
NewAdaptP->NdisAdapterHandle,
|
|
NewAdaptP->XmitStart,
|
|
0x2000);
|
|
|
|
}
|
|
|
|
fail3:
|
|
NdisDeregisterAdapter(NewAdaptP->NdisAdapterHandle);
|
|
NdisFreeSpinLock(&NewAdaptP->Lock);
|
|
|
|
fail2:
|
|
|
|
fail1:
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
ElnkiiOpenAdapter(
|
|
OUT PNDIS_STATUS OpenErrorStatus,
|
|
OUT NDIS_HANDLE * MacBindingHandle,
|
|
OUT PUINT SelectedMediumIndex,
|
|
IN PNDIS_MEDIUM MediumArray,
|
|
IN UINT MediumArraySize,
|
|
IN NDIS_HANDLE NdisBindingContext,
|
|
IN NDIS_HANDLE MacAdapterContext,
|
|
IN UINT OpenOptions,
|
|
IN PSTRING AddressingInformation OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
NDIS function. It initializes the open block and links it in
|
|
the appropriate lists.
|
|
|
|
Arguments:
|
|
|
|
See NDIS 3.0 spec.
|
|
|
|
--*/
|
|
|
|
{
|
|
PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)MacAdapterContext);
|
|
PELNKII_OPEN NewOpenP;
|
|
NDIS_STATUS Status;
|
|
|
|
//
|
|
// Don't use extended error or OpenOptions for Elnkii
|
|
//
|
|
|
|
UNREFERENCED_PARAMETER(OpenOptions);
|
|
|
|
*OpenErrorStatus=NDIS_STATUS_SUCCESS;
|
|
|
|
IF_LOUD( DbgPrint("In Open Adapter\n");)
|
|
|
|
//
|
|
// Scan the media list for our media type (802.3)
|
|
//
|
|
|
|
*SelectedMediumIndex = (UINT)-1;
|
|
|
|
while (MediumArraySize > 0) {
|
|
|
|
if (MediumArray[--MediumArraySize] == NdisMedium802_3 ) {
|
|
|
|
*SelectedMediumIndex = MediumArraySize;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
if (*SelectedMediumIndex == -1) {
|
|
|
|
return NDIS_STATUS_UNSUPPORTED_MEDIA;
|
|
|
|
}
|
|
|
|
//
|
|
// Allocate memory for the open.
|
|
//
|
|
|
|
|
|
Status = NdisAllocateMemory((PVOID *)&NewOpenP, sizeof(ELNKII_OPEN), 0, HighestAcceptableMax);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS) {
|
|
|
|
NdisWriteErrorLogEntry(
|
|
AdaptP->NdisAdapterHandle,
|
|
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
|
|
0
|
|
);
|
|
|
|
return(NDIS_STATUS_RESOURCES);
|
|
|
|
}
|
|
|
|
NdisZeroMemory(NewOpenP, sizeof(ELNKII_OPEN));
|
|
|
|
//
|
|
// Link this open to the appropriate lists.
|
|
//
|
|
|
|
NdisAcquireSpinLock(&AdaptP->Lock);
|
|
|
|
AdaptP->References++;
|
|
|
|
if ((AdaptP->OpenQueue == NULL) && (AdaptP->CloseQueue == NULL)) {
|
|
|
|
//
|
|
// The first open on this adapter.
|
|
//
|
|
|
|
CardStart(AdaptP);
|
|
|
|
}
|
|
|
|
NewOpenP->NextOpen = AdaptP->OpenQueue;
|
|
AdaptP->OpenQueue = NewOpenP;
|
|
|
|
if (AdaptP->ResetInProgress || !EthNoteFilterOpenAdapter(
|
|
AdaptP->FilterDB,
|
|
NewOpenP,
|
|
NdisBindingContext,
|
|
&NewOpenP->NdisFilterHandle
|
|
)) {
|
|
|
|
AdaptP->References--;
|
|
|
|
AdaptP->OpenQueue = NewOpenP->NextOpen;
|
|
|
|
NdisReleaseSpinLock(&AdaptP->Lock);
|
|
|
|
NdisFreeMemory(NewOpenP, sizeof(ELNKII_OPEN), 0);
|
|
|
|
NdisWriteErrorLogEntry(
|
|
AdaptP->NdisAdapterHandle,
|
|
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
|
|
0
|
|
);
|
|
|
|
return NDIS_STATUS_FAILURE;
|
|
|
|
}
|
|
|
|
//
|
|
// Set up the open block.
|
|
//
|
|
|
|
NewOpenP->Adapter = AdaptP;
|
|
NewOpenP->MacBlock = AdaptP->MacBlock;
|
|
NewOpenP->NdisBindingContext = NdisBindingContext;
|
|
NewOpenP->AddressingInformation = AddressingInformation;
|
|
|
|
//
|
|
// set the Request Queue empty
|
|
//
|
|
|
|
|
|
NewOpenP->Closing = FALSE;
|
|
NewOpenP->LookAhead = ELNKII_MAX_LOOKAHEAD;
|
|
|
|
AdaptP->MaxLookAhead = ELNKII_MAX_LOOKAHEAD;
|
|
|
|
NewOpenP->ReferenceCount = 1;
|
|
|
|
*MacBindingHandle = (NDIS_HANDLE)NewOpenP;
|
|
|
|
ELNKII_DO_DEFERRED(AdaptP);
|
|
|
|
IF_LOUD( DbgPrint("Out Open Adapter\n");)
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
ElnkiiAdjustMaxLookAhead(
|
|
IN PELNKII_ADAPTER Adapter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine finds the open with the maximum lookahead value and
|
|
stores that in the adapter block.
|
|
|
|
Arguments:
|
|
|
|
Adapter - A pointer to the adapter block.
|
|
|
|
Returns:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONG CurrentMax = 0;
|
|
PELNKII_OPEN CurrentOpen;
|
|
|
|
CurrentOpen = Adapter->OpenQueue;
|
|
|
|
while (CurrentOpen != NULL) {
|
|
|
|
if (CurrentOpen->LookAhead > CurrentMax) {
|
|
|
|
CurrentMax = CurrentOpen->LookAhead;
|
|
|
|
}
|
|
|
|
CurrentOpen = CurrentOpen->NextOpen;
|
|
}
|
|
|
|
if (CurrentMax == 0) {
|
|
|
|
CurrentMax = ELNKII_MAX_LOOKAHEAD;
|
|
|
|
}
|
|
|
|
Adapter->MaxLookAhead = CurrentMax;
|
|
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ElnkiiCloseAdapter(
|
|
IN NDIS_HANDLE MacBindingHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
NDIS function. Unlinks the open block and frees it.
|
|
|
|
Arguments:
|
|
|
|
See NDIS 3.0 spec.
|
|
|
|
--*/
|
|
|
|
{
|
|
PELNKII_OPEN OpenP = ((PELNKII_OPEN)MacBindingHandle);
|
|
PELNKII_ADAPTER AdaptP = OpenP->Adapter;
|
|
PELNKII_OPEN TmpOpenP;
|
|
NDIS_STATUS StatusToReturn;
|
|
|
|
NdisAcquireSpinLock(&AdaptP->Lock);
|
|
|
|
if (OpenP->Closing) {
|
|
|
|
//
|
|
// The open is already being closed.
|
|
//
|
|
|
|
NdisReleaseSpinLock(&AdaptP->Lock);
|
|
|
|
return NDIS_STATUS_CLOSING;
|
|
}
|
|
|
|
AdaptP->References++;
|
|
|
|
OpenP->ReferenceCount++;
|
|
|
|
//
|
|
// Remove this open from the list for this adapter.
|
|
//
|
|
|
|
if (OpenP == AdaptP->OpenQueue) {
|
|
|
|
AdaptP->OpenQueue = OpenP->NextOpen;
|
|
|
|
} else {
|
|
|
|
TmpOpenP = AdaptP->OpenQueue;
|
|
|
|
while (TmpOpenP->NextOpen != OpenP) {
|
|
|
|
TmpOpenP = TmpOpenP->NextOpen;
|
|
|
|
}
|
|
|
|
TmpOpenP->NextOpen = OpenP->NextOpen;
|
|
}
|
|
|
|
//
|
|
// Remove from Filter package to block all receives.
|
|
//
|
|
|
|
StatusToReturn = EthDeleteFilterOpenAdapter(
|
|
AdaptP->FilterDB,
|
|
OpenP->NdisFilterHandle,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// If the status is successful that merely implies that
|
|
// we were able to delete the reference to the open binding
|
|
// from the filtering code. If we have a successful status
|
|
// at this point we still need to check whether the reference
|
|
// count to determine whether we can close.
|
|
//
|
|
//
|
|
// The delete filter routine can return a "special" status
|
|
// that indicates that there is a current NdisIndicateReceive
|
|
// on this binding. See below.
|
|
//
|
|
|
|
if (StatusToReturn == NDIS_STATUS_SUCCESS) {
|
|
|
|
//
|
|
// Check whether the reference count is two. If
|
|
// it is then we can get rid of the memory for
|
|
// this open.
|
|
//
|
|
// A count of two indicates one for this routine
|
|
// and one for the filter which we *know* we can
|
|
// get rid of.
|
|
//
|
|
|
|
if (OpenP->ReferenceCount != 2) {
|
|
|
|
//
|
|
// We are not the only reference to the open. Remove
|
|
// it from the open list and delete the memory.
|
|
//
|
|
|
|
|
|
OpenP->Closing = TRUE;
|
|
|
|
//
|
|
// Account for this routines reference to the open
|
|
// as well as reference because of the original open.
|
|
//
|
|
|
|
OpenP->ReferenceCount -= 2;
|
|
|
|
//
|
|
// Change the status to indicate that we will
|
|
// be closing this later.
|
|
//
|
|
|
|
StatusToReturn = NDIS_STATUS_PENDING;
|
|
|
|
} else {
|
|
|
|
OpenP->ReferenceCount -= 2;
|
|
|
|
}
|
|
|
|
} else if (StatusToReturn == NDIS_STATUS_PENDING) {
|
|
|
|
OpenP->Closing = TRUE;
|
|
|
|
//
|
|
// Account for this routines reference to the open
|
|
// as well as reference because of the original open.
|
|
//
|
|
|
|
OpenP->ReferenceCount -= 2;
|
|
|
|
} else if (StatusToReturn == NDIS_STATUS_CLOSING_INDICATING) {
|
|
|
|
//
|
|
// When we have this status it indicates that the filtering
|
|
// code was currently doing an NdisIndicateReceive. It
|
|
// would not be wise to delete the memory for the open at
|
|
// this point. The filtering code will call our close action
|
|
// routine upon return from NdisIndicateReceive and that
|
|
// action routine will decrement the reference count for
|
|
// the open.
|
|
//
|
|
|
|
OpenP->Closing = TRUE;
|
|
|
|
//
|
|
// This status is private to the filtering routine. Just
|
|
// tell the caller the the close is pending.
|
|
//
|
|
|
|
StatusToReturn = NDIS_STATUS_PENDING;
|
|
|
|
//
|
|
// Account for this routines reference to the open.
|
|
//
|
|
|
|
OpenP->ReferenceCount--;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Account for this routines reference to the open.
|
|
//
|
|
|
|
OpenP->ReferenceCount--;
|
|
|
|
}
|
|
|
|
//
|
|
// See if this is the last reference to this open.
|
|
//
|
|
|
|
if (OpenP->ReferenceCount == 0) {
|
|
|
|
//
|
|
// Check if the MaxLookAhead needs adjustment.
|
|
//
|
|
|
|
if (OpenP->LookAhead == AdaptP->MaxLookAhead) {
|
|
|
|
ElnkiiAdjustMaxLookAhead(AdaptP);
|
|
|
|
}
|
|
|
|
//
|
|
// Done, free the open.
|
|
//
|
|
|
|
NdisFreeMemory(OpenP, sizeof(ELNKII_OPEN), 0);
|
|
|
|
if ((AdaptP->OpenQueue == NULL ) && (AdaptP->CloseQueue == NULL)) {
|
|
|
|
//
|
|
// We can disable the card.
|
|
//
|
|
|
|
CardStop(AdaptP);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Add it to the close list
|
|
//
|
|
|
|
OpenP->NextOpen = AdaptP->CloseQueue;
|
|
AdaptP->CloseQueue = OpenP;
|
|
|
|
//
|
|
// Will get removed when count drops to zero.
|
|
//
|
|
|
|
StatusToReturn = NDIS_STATUS_PENDING;
|
|
|
|
}
|
|
|
|
|
|
ELNKII_DO_DEFERRED(AdaptP);
|
|
|
|
return(StatusToReturn);
|
|
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ElnkiiRequest(
|
|
IN NDIS_HANDLE MacBindingHandle,
|
|
IN PNDIS_REQUEST NdisRequest
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine allows a protocol to query and set information
|
|
about the MAC.
|
|
|
|
Arguments:
|
|
|
|
MacBindingHandle - The context value returned by the MAC when the
|
|
adapter was opened. In reality, it is a pointer to PELNKII_OPEN.
|
|
|
|
NdisRequest - A structure which contains the request type (Set or
|
|
Query), an array of operations to perform, and an array for holding
|
|
the results of the operations.
|
|
|
|
Return Value:
|
|
|
|
The function value is the status of the operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
|
|
|
|
PELNKII_OPEN Open = (PELNKII_OPEN)(MacBindingHandle);
|
|
PELNKII_ADAPTER Adapter = (Open->Adapter);
|
|
|
|
IF_LOUD( DbgPrint("In Request\n");)
|
|
|
|
NdisAcquireSpinLock(&Adapter->Lock);
|
|
|
|
//
|
|
// Ensure that the open does not close while in this function.
|
|
//
|
|
|
|
Open->ReferenceCount++;
|
|
|
|
Adapter->References++;
|
|
|
|
//
|
|
// Process request
|
|
//
|
|
|
|
if (Open->Closing) {
|
|
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
|
|
StatusToReturn = NDIS_STATUS_CLOSING;
|
|
|
|
} else if (NdisRequest->RequestType == NdisRequestQueryInformation) {
|
|
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
|
|
StatusToReturn = ElnkiiQueryInformation(Adapter, Open, NdisRequest);
|
|
|
|
} else if (NdisRequest->RequestType == NdisRequestSetInformation) {
|
|
|
|
|
|
//
|
|
// Make sure Adapter is in a valid state.
|
|
//
|
|
|
|
//
|
|
// All requests are rejected during a reset.
|
|
//
|
|
|
|
if (Adapter->ResetInProgress) {
|
|
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
|
|
StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
|
|
|
|
} else {
|
|
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
|
|
StatusToReturn = ElnkiiSetInformation(Adapter,Open,NdisRequest);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
|
|
StatusToReturn = NDIS_STATUS_NOT_RECOGNIZED;
|
|
|
|
}
|
|
|
|
NdisAcquireSpinLock(&Adapter->Lock);
|
|
|
|
--Open->ReferenceCount;
|
|
|
|
ELNKII_DO_DEFERRED(Adapter);
|
|
|
|
IF_LOUD( DbgPrint("Out Request\n");)
|
|
|
|
return(StatusToReturn);
|
|
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ElnkiiQueryProtocolInformation(
|
|
IN PELNKII_ADAPTER Adapter,
|
|
IN PELNKII_OPEN Open,
|
|
IN NDIS_OID Oid,
|
|
IN BOOLEAN GlobalMode,
|
|
IN PVOID InfoBuffer,
|
|
IN UINT BytesLeft,
|
|
OUT PUINT BytesNeeded,
|
|
OUT PUINT BytesWritten
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The ElnkiiQueryProtocolInformation process a Query request for
|
|
NDIS_OIDs that are specific to a binding about the MAC. Note that
|
|
some of the OIDs that are specific to bindings are also queryable
|
|
on a global basis. Rather than recreate this code to handle the
|
|
global queries, I use a flag to indicate if this is a query for the
|
|
global data or the binding specific data.
|
|
|
|
Arguments:
|
|
|
|
Adapter - a pointer to the adapter.
|
|
|
|
Open - a pointer to the open instance.
|
|
|
|
Oid - the NDIS_OID to process.
|
|
|
|
GlobalMode - Some of the binding specific information is also used
|
|
when querying global statistics. This is a flag to specify whether
|
|
to return the global value, or the binding specific value.
|
|
|
|
PlaceInInfoBuffer - a pointer into the NdisRequest->InformationBuffer
|
|
into which store the result of the query.
|
|
|
|
BytesLeft - the number of bytes left in the InformationBuffer.
|
|
|
|
BytesNeeded - If there is not enough room in the information buffer
|
|
then this will contain the number of bytes needed to complete the
|
|
request.
|
|
|
|
BytesWritten - a pointer to the number of bytes written into the
|
|
InformationBuffer.
|
|
|
|
Return Value:
|
|
|
|
The function value is the status of the operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
NDIS_MEDIUM Medium = NdisMedium802_3;
|
|
ULONG GenericULong;
|
|
USHORT GenericUShort;
|
|
UCHAR GenericArray[6];
|
|
|
|
NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
|
|
|
|
//
|
|
// Common variables for pointing to result of query
|
|
//
|
|
|
|
PVOID MoveSource = (PVOID)(&GenericULong);
|
|
ULONG MoveBytes = sizeof(GenericULong);
|
|
UINT Filter;
|
|
|
|
NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady;
|
|
|
|
//
|
|
// General Algorithm:
|
|
//
|
|
// Switch(Request)
|
|
// Get requested information
|
|
// Store results in a common variable.
|
|
// Copy result in common variable to result buffer.
|
|
//
|
|
|
|
//
|
|
// Make sure that ulong is 4 bytes. Else GenericULong must change
|
|
// to something of size 4.
|
|
//
|
|
ASSERT(sizeof(ULONG) == 4);
|
|
|
|
IF_LOUD( DbgPrint("In QueryProtocol\n");)
|
|
|
|
//
|
|
// Make sure no changes occur while processing.
|
|
//
|
|
|
|
NdisAcquireSpinLock(&Adapter->Lock);
|
|
|
|
//
|
|
// Switch on request type
|
|
//
|
|
|
|
switch (Oid) {
|
|
|
|
case OID_GEN_MAC_OPTIONS:
|
|
|
|
GenericULong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
|
|
NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
|
|
NDIS_MAC_OPTION_NO_LOOPBACK
|
|
);
|
|
|
|
if (!Adapter->MemMapped) {
|
|
|
|
GenericULong |= NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case OID_GEN_SUPPORTED_LIST:
|
|
|
|
if (!GlobalMode) {
|
|
|
|
MoveSource = (PVOID)(ElnkiiProtocolSupportedOids);
|
|
MoveBytes = sizeof(ElnkiiProtocolSupportedOids);
|
|
|
|
} else {
|
|
|
|
MoveSource = (PVOID)(ElnkiiGlobalSupportedOids);
|
|
MoveBytes = sizeof(ElnkiiGlobalSupportedOids);
|
|
|
|
}
|
|
break;
|
|
|
|
case OID_GEN_HARDWARE_STATUS:
|
|
|
|
|
|
if (Adapter->ResetInProgress) {
|
|
|
|
HardwareStatus = NdisHardwareStatusReset;
|
|
|
|
} else
|
|
HardwareStatus = NdisHardwareStatusReady;
|
|
|
|
|
|
MoveSource = (PVOID)(&HardwareStatus);
|
|
MoveBytes = sizeof(NDIS_HARDWARE_STATUS);
|
|
|
|
break;
|
|
|
|
case OID_GEN_MEDIA_SUPPORTED:
|
|
case OID_GEN_MEDIA_IN_USE:
|
|
|
|
MoveSource = (PVOID) (&Medium);
|
|
MoveBytes = sizeof(NDIS_MEDIUM);
|
|
break;
|
|
|
|
case OID_GEN_MAXIMUM_LOOKAHEAD:
|
|
|
|
GenericULong = ELNKII_MAX_LOOKAHEAD;
|
|
|
|
break;
|
|
|
|
|
|
case OID_GEN_MAXIMUM_FRAME_SIZE:
|
|
|
|
GenericULong = (ULONG)(1514 - ELNKII_HEADER_SIZE);
|
|
|
|
break;
|
|
|
|
|
|
case OID_GEN_MAXIMUM_TOTAL_SIZE:
|
|
|
|
GenericULong = (ULONG)(1514);
|
|
|
|
break;
|
|
|
|
|
|
case OID_GEN_LINK_SPEED:
|
|
|
|
GenericULong = (ULONG)(100000);
|
|
|
|
break;
|
|
|
|
|
|
case OID_GEN_TRANSMIT_BUFFER_SPACE:
|
|
|
|
GenericULong = (ULONG)(Adapter->NumBuffers * TX_BUF_SIZE);
|
|
|
|
break;
|
|
|
|
case OID_GEN_RECEIVE_BUFFER_SPACE:
|
|
|
|
GenericULong = (ULONG)0x2000;
|
|
GenericULong -= (Adapter->NumBuffers * ((TX_BUF_SIZE / 256) + 1) * 256);
|
|
|
|
//
|
|
// Subtract off receive buffer overhead
|
|
//
|
|
{
|
|
ULONG TmpUlong = GenericULong / 256;
|
|
|
|
TmpUlong *= 4;
|
|
|
|
GenericULong -= TmpUlong;
|
|
|
|
}
|
|
|
|
//
|
|
// Round to nearest 256 bytes
|
|
//
|
|
GenericULong = (GenericULong / 256) * 256;
|
|
|
|
break;
|
|
|
|
case OID_GEN_TRANSMIT_BLOCK_SIZE:
|
|
|
|
GenericULong = (ULONG)(TX_BUF_SIZE);
|
|
|
|
break;
|
|
|
|
case OID_GEN_RECEIVE_BLOCK_SIZE:
|
|
|
|
GenericULong = (ULONG)(256);
|
|
|
|
break;
|
|
|
|
case OID_GEN_VENDOR_ID:
|
|
|
|
NdisMoveMemory(
|
|
(PVOID)(&GenericULong),
|
|
Adapter->PermanentAddress,
|
|
3
|
|
);
|
|
|
|
GenericULong &= 0xFFFFFF00;
|
|
break;
|
|
|
|
case OID_GEN_VENDOR_DESCRIPTION:
|
|
|
|
MoveSource = (PVOID)"Etherlink II Adapter.";
|
|
MoveBytes = 22;
|
|
|
|
break;
|
|
|
|
case OID_GEN_DRIVER_VERSION:
|
|
|
|
GenericUShort = ((USHORT)ELNKII_NDIS_MAJOR_VERSION << 8) |
|
|
ELNKII_NDIS_MINOR_VERSION;
|
|
|
|
MoveSource = (PVOID)(&GenericUShort);
|
|
MoveBytes = sizeof(GenericUShort);
|
|
break;
|
|
|
|
|
|
case OID_GEN_CURRENT_PACKET_FILTER:
|
|
|
|
if (GlobalMode) {
|
|
|
|
Filter = ETH_QUERY_FILTER_CLASSES(Adapter->FilterDB);
|
|
|
|
GenericULong = (ULONG)(Filter);
|
|
|
|
} else {
|
|
|
|
Filter = ETH_QUERY_PACKET_FILTER(Adapter->FilterDB,
|
|
Open->NdisFilterHandle);
|
|
|
|
GenericULong = (ULONG)(Filter);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case OID_GEN_CURRENT_LOOKAHEAD:
|
|
|
|
if ( GlobalMode ) {
|
|
|
|
GenericULong = (ULONG)(Adapter->MaxLookAhead);
|
|
|
|
} else {
|
|
|
|
GenericULong = Open->LookAhead;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case OID_802_3_PERMANENT_ADDRESS:
|
|
ELNKII_MOVE_MEM((PCHAR)GenericArray,
|
|
Adapter->PermanentAddress,
|
|
ETH_LENGTH_OF_ADDRESS);
|
|
|
|
MoveSource = (PVOID)(GenericArray);
|
|
MoveBytes = sizeof(Adapter->PermanentAddress);
|
|
break;
|
|
|
|
|
|
case OID_802_3_CURRENT_ADDRESS:
|
|
|
|
ELNKII_MOVE_MEM((PCHAR)GenericArray,
|
|
Adapter->StationAddress,
|
|
ETH_LENGTH_OF_ADDRESS);
|
|
|
|
MoveSource = (PVOID)(GenericArray);
|
|
MoveBytes = sizeof(Adapter->StationAddress);
|
|
break;
|
|
|
|
case OID_802_3_MULTICAST_LIST:
|
|
|
|
{
|
|
UINT NumAddresses;
|
|
|
|
|
|
if (GlobalMode) {
|
|
|
|
NumAddresses = ETH_NUMBER_OF_GLOBAL_FILTER_ADDRESSES(Adapter->FilterDB);
|
|
|
|
if ((NumAddresses * ETH_LENGTH_OF_ADDRESS) > BytesLeft) {
|
|
|
|
*BytesNeeded = (NumAddresses * ETH_LENGTH_OF_ADDRESS);
|
|
|
|
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
EthQueryGlobalFilterAddresses(
|
|
&StatusToReturn,
|
|
Adapter->FilterDB,
|
|
BytesLeft,
|
|
&NumAddresses,
|
|
InfoBuffer
|
|
);
|
|
|
|
*BytesWritten = NumAddresses * ETH_LENGTH_OF_ADDRESS;
|
|
|
|
//
|
|
// Should not be an error since we held the spinlock
|
|
// nothing should have changed.
|
|
//
|
|
|
|
ASSERT(StatusToReturn == NDIS_STATUS_SUCCESS);
|
|
|
|
} else {
|
|
|
|
NumAddresses = EthNumberOfOpenFilterAddresses(
|
|
Adapter->FilterDB,
|
|
Open->NdisFilterHandle
|
|
);
|
|
|
|
if ((NumAddresses * ETH_LENGTH_OF_ADDRESS) > BytesLeft) {
|
|
|
|
*BytesNeeded = (NumAddresses * ETH_LENGTH_OF_ADDRESS);
|
|
|
|
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
EthQueryOpenFilterAddresses(
|
|
&StatusToReturn,
|
|
Adapter->FilterDB,
|
|
Open->NdisFilterHandle,
|
|
BytesLeft,
|
|
&NumAddresses,
|
|
InfoBuffer
|
|
);
|
|
|
|
//
|
|
// Should not be an error since we held the spinlock
|
|
// nothing should have changed.
|
|
//
|
|
|
|
ASSERT(StatusToReturn == NDIS_STATUS_SUCCESS);
|
|
|
|
*BytesWritten = NumAddresses * ETH_LENGTH_OF_ADDRESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case OID_802_3_MAXIMUM_LIST_SIZE:
|
|
|
|
GenericULong = (ULONG) (Adapter->MulticastListMax);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
if ((StatusToReturn == NDIS_STATUS_SUCCESS) &&
|
|
(Oid != OID_802_3_MULTICAST_LIST)) {
|
|
|
|
if (MoveBytes > BytesLeft) {
|
|
|
|
//
|
|
// Not enough room in InformationBuffer. Punt
|
|
//
|
|
|
|
*BytesNeeded = MoveBytes;
|
|
|
|
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Store result.
|
|
//
|
|
|
|
ELNKII_MOVE_MEM(InfoBuffer, MoveSource, MoveBytes);
|
|
|
|
(*BytesWritten) += MoveBytes;
|
|
|
|
}
|
|
}
|
|
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
|
|
IF_LOUD( DbgPrint("Out QueryProtocol\n");)
|
|
|
|
return(StatusToReturn);
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ElnkiiQueryInformation(
|
|
IN PELNKII_ADAPTER Adapter,
|
|
IN PELNKII_OPEN Open,
|
|
IN PNDIS_REQUEST NdisRequest
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The ElnkiiQueryInformation is used by ElnkiiRequest to query information
|
|
about the MAC.
|
|
|
|
Arguments:
|
|
|
|
Adapter - A pointer to the adapter.
|
|
|
|
Open - A pointer to a particular open instance.
|
|
|
|
NdisRequest - A structure which contains the request type (Query),
|
|
an array of operations to perform, and an array for holding
|
|
the results of the operations.
|
|
|
|
Return Value:
|
|
|
|
The function value is the status of the operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
UINT BytesWritten = 0;
|
|
UINT BytesNeeded = 0;
|
|
UINT BytesLeft = NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength;
|
|
PUCHAR InfoBuffer = (PUCHAR)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer);
|
|
|
|
NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
|
|
|
|
|
|
IF_LOUD( DbgPrint("In QueryInfor\n");)
|
|
|
|
StatusToReturn = ElnkiiQueryProtocolInformation(
|
|
Adapter,
|
|
Open,
|
|
NdisRequest->DATA.QUERY_INFORMATION.Oid,
|
|
FALSE,
|
|
InfoBuffer,
|
|
BytesLeft,
|
|
&BytesNeeded,
|
|
&BytesWritten
|
|
);
|
|
|
|
|
|
NdisRequest->DATA.QUERY_INFORMATION.BytesWritten = BytesWritten;
|
|
|
|
NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = BytesNeeded;
|
|
|
|
IF_LOUD( DbgPrint("Out QueryInfor\n");)
|
|
|
|
return(StatusToReturn);
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ElnkiiSetInformation(
|
|
IN PELNKII_ADAPTER Adapter,
|
|
IN PELNKII_OPEN Open,
|
|
IN PNDIS_REQUEST NdisRequest
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The ElnkiiSetInformation is used by ElnkiiRequest to set information
|
|
about the MAC.
|
|
|
|
Arguments:
|
|
|
|
Adapter - A pointer to the adapter.
|
|
|
|
Open - A pointer to an open instance.
|
|
|
|
NdisRequest - A structure which contains the request type (Set),
|
|
an array of operations to perform, and an array for holding
|
|
the results of the operations.
|
|
|
|
Return Value:
|
|
|
|
The function value is the status of the operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// General Algorithm:
|
|
//
|
|
// Verify length
|
|
// Switch(Request)
|
|
// Process Request
|
|
//
|
|
|
|
UINT BytesRead = 0;
|
|
UINT BytesNeeded = 0;
|
|
UINT BytesLeft = NdisRequest->DATA.SET_INFORMATION.InformationBufferLength;
|
|
PUCHAR InfoBuffer = (PUCHAR)(NdisRequest->DATA.SET_INFORMATION.InformationBuffer);
|
|
|
|
//
|
|
// Variables for a particular request
|
|
//
|
|
|
|
NDIS_OID Oid;
|
|
UINT OidLength;
|
|
|
|
//
|
|
// Variables for holding the new values to be used.
|
|
//
|
|
|
|
ULONG LookAhead;
|
|
ULONG Filter;
|
|
|
|
NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
|
|
|
|
|
|
IF_LOUD( DbgPrint("In SetInfo\n");)
|
|
|
|
//
|
|
// Get Oid and Length of request
|
|
//
|
|
|
|
Oid = NdisRequest->DATA.SET_INFORMATION.Oid;
|
|
|
|
OidLength = BytesLeft;
|
|
|
|
switch (Oid) {
|
|
|
|
|
|
case OID_802_3_MULTICAST_LIST:
|
|
|
|
//
|
|
// Verify length
|
|
//
|
|
|
|
if ((OidLength % ETH_LENGTH_OF_ADDRESS) != 0){
|
|
|
|
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
|
|
|
|
NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
|
|
NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
StatusToReturn = ElnkiiSetMulticastAddresses(
|
|
Adapter,
|
|
Open,
|
|
NdisRequest,
|
|
(UINT)(OidLength / ETH_LENGTH_OF_ADDRESS),
|
|
(PVOID)InfoBuffer
|
|
);
|
|
|
|
break;
|
|
|
|
|
|
case OID_GEN_CURRENT_PACKET_FILTER:
|
|
|
|
//
|
|
// Verify length
|
|
//
|
|
|
|
if (OidLength != 4 ) {
|
|
|
|
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
|
|
|
|
NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
|
|
NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ELNKII_MOVE_MEM(&Filter, InfoBuffer, 4);
|
|
|
|
//
|
|
// Verify bits
|
|
//
|
|
|
|
if (Filter & (NDIS_PACKET_TYPE_SOURCE_ROUTING |
|
|
NDIS_PACKET_TYPE_SMT |
|
|
NDIS_PACKET_TYPE_MAC_FRAME |
|
|
NDIS_PACKET_TYPE_FUNCTIONAL |
|
|
NDIS_PACKET_TYPE_ALL_FUNCTIONAL |
|
|
NDIS_PACKET_TYPE_GROUP
|
|
)) {
|
|
|
|
StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
|
|
|
|
NdisRequest->DATA.SET_INFORMATION.BytesRead = 4;
|
|
NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
StatusToReturn = ElnkiiSetPacketFilter(Adapter,
|
|
Open,
|
|
NdisRequest,
|
|
Filter);
|
|
|
|
|
|
|
|
break;
|
|
|
|
case OID_GEN_CURRENT_LOOKAHEAD:
|
|
|
|
//
|
|
// Verify length
|
|
//
|
|
|
|
if (OidLength != 4) {
|
|
|
|
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
|
|
|
|
NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
|
|
NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ELNKII_MOVE_MEM(&LookAhead, InfoBuffer, 4);
|
|
|
|
if (LookAhead <= ELNKII_MAX_LOOKAHEAD) {
|
|
|
|
if (LookAhead > Adapter->MaxLookAhead) {
|
|
|
|
Adapter->MaxLookAhead = LookAhead;
|
|
|
|
Open->LookAhead = LookAhead;
|
|
|
|
} else {
|
|
|
|
if ((Open->LookAhead == Adapter->MaxLookAhead) &&
|
|
(LookAhead < Open->LookAhead)) {
|
|
|
|
Open->LookAhead = LookAhead;
|
|
|
|
ElnkiiAdjustMaxLookAhead(Adapter);
|
|
|
|
} else {
|
|
|
|
Open->LookAhead = LookAhead;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case OID_GEN_PROTOCOL_OPTIONS:
|
|
|
|
if (OidLength != 4) {
|
|
|
|
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
|
|
|
|
NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
|
|
NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ELNKII_MOVE_MEM(&Open->ProtOptionFlags, InfoBuffer, 4);
|
|
StatusToReturn = NDIS_STATUS_SUCCESS;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
StatusToReturn = NDIS_STATUS_INVALID_OID;
|
|
|
|
NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
|
|
NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
if (StatusToReturn == NDIS_STATUS_SUCCESS) {
|
|
|
|
NdisRequest->DATA.SET_INFORMATION.BytesRead = BytesLeft;
|
|
NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
|
|
|
|
}
|
|
|
|
|
|
IF_LOUD( DbgPrint("Out SetInfo\n");)
|
|
|
|
return(StatusToReturn);
|
|
}
|
|
|
|
|
|
STATIC
|
|
NDIS_STATUS
|
|
ElnkiiSetPacketFilter(
|
|
IN PELNKII_ADAPTER Adapter,
|
|
IN PELNKII_OPEN Open,
|
|
IN PNDIS_REQUEST NdisRequest,
|
|
IN UINT PacketFilter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The ElnkiiSetPacketFilter request allows a protocol to control the types
|
|
of packets that it receives from the MAC.
|
|
|
|
Arguments:
|
|
|
|
Adapter - A pointer to the adapter structure.
|
|
|
|
Open - A pointer to the open block giving the request.
|
|
|
|
NdisRequest - The NDIS_REQUEST with the set packet filter command in it.
|
|
|
|
PacketFilter - A bit mask that contains flags that correspond to specific
|
|
classes of received packets. If a particular bit is set in the mask,
|
|
then packet reception for that class of packet is enabled. If the
|
|
bit is clear, then packets that fall into that class are not received
|
|
by the client. A single exception to this rule is that if the promiscuous
|
|
bit is set, then the client receives all packets on the network, regardless
|
|
of the state of the other flags.
|
|
|
|
Return Value:
|
|
|
|
The function value is the status of the operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Keeps track of the *MAC's* status. The status will only be
|
|
// reset if the filter change action routine is called.
|
|
//
|
|
NDIS_STATUS StatusOfFilterChange = NDIS_STATUS_SUCCESS;
|
|
|
|
NdisAcquireSpinLock(&Adapter->Lock);
|
|
|
|
IF_LOUD( DbgPrint("In SetFilter\n");)
|
|
|
|
if (!Adapter->ResetInProgress) {
|
|
|
|
if (!Open->Closing) {
|
|
|
|
//
|
|
// Increment the open while it is going through the filtering
|
|
// routines.
|
|
//
|
|
|
|
Open->ReferenceCount++;
|
|
|
|
StatusOfFilterChange = EthFilterAdjust(
|
|
Adapter->FilterDB,
|
|
Open->NdisFilterHandle,
|
|
NdisRequest,
|
|
PacketFilter,
|
|
TRUE
|
|
);
|
|
|
|
Open->ReferenceCount--;
|
|
|
|
} else {
|
|
|
|
StatusOfFilterChange = NDIS_STATUS_CLOSING;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
StatusOfFilterChange = NDIS_STATUS_RESET_IN_PROGRESS;
|
|
|
|
}
|
|
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
|
|
IF_LOUD( DbgPrint("Out SetFilter\n");)
|
|
|
|
return StatusOfFilterChange;
|
|
}
|
|
|
|
|
|
|
|
|
|
STATIC
|
|
NDIS_STATUS
|
|
ElnkiiSetMulticastAddresses(
|
|
IN PELNKII_ADAPTER Adapter,
|
|
IN PELNKII_OPEN Open,
|
|
IN PNDIS_REQUEST NdisRequest,
|
|
IN UINT NumAddresses,
|
|
IN CHAR AddressList[][ETH_LENGTH_OF_ADDRESS]
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function calls into the filter package in order to set the
|
|
multicast address list for the card to the specified list.
|
|
|
|
Arguments:
|
|
|
|
Adapter - A pointer to the adapter block.
|
|
|
|
Open - A pointer to the open block submitting the request.
|
|
|
|
NdisRequest - The NDIS_REQUEST with the set multicast address list command
|
|
in it.
|
|
|
|
NumAddresses - A count of the number of addresses in the addressList.
|
|
|
|
AddressList - An array of multicast addresses that this open instance
|
|
wishes to accept.
|
|
|
|
|
|
Return Value:
|
|
|
|
The function value is the status of the operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Keeps track of the *MAC's* status. The status will only be
|
|
// reset if the filter change action routine is called.
|
|
//
|
|
NDIS_STATUS StatusOfFilterChange = NDIS_STATUS_SUCCESS;
|
|
|
|
IF_LOUD( DbgPrint("In SetMulticast\n");)
|
|
|
|
NdisAcquireSpinLock(&Adapter->Lock);
|
|
|
|
if (!Adapter->ResetInProgress) {
|
|
|
|
if (!Open->Closing) {
|
|
|
|
//
|
|
// Increment the open while it is going through the filtering
|
|
// routines.
|
|
//
|
|
|
|
Open->ReferenceCount++;
|
|
|
|
StatusOfFilterChange = EthChangeFilterAddresses(
|
|
Adapter->FilterDB,
|
|
Open->NdisFilterHandle,
|
|
NdisRequest,
|
|
NumAddresses,
|
|
AddressList,
|
|
TRUE
|
|
);
|
|
|
|
Open->ReferenceCount--;
|
|
|
|
} else {
|
|
|
|
StatusOfFilterChange = NDIS_STATUS_CLOSING;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
StatusOfFilterChange = NDIS_STATUS_RESET_IN_PROGRESS;
|
|
|
|
}
|
|
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
|
|
IF_LOUD( DbgPrint("Out SetMulticast\n");)
|
|
|
|
return StatusOfFilterChange;
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
ElnkiiFillInGlobalData(
|
|
IN PELNKII_ADAPTER Adapter,
|
|
IN PNDIS_REQUEST NdisRequest
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine completes a GlobalStatistics request. It is critical that
|
|
if information is needed from the Adapter->* fields, they have been
|
|
updated before this routine is called.
|
|
|
|
Arguments:
|
|
|
|
Adapter - A pointer to the Adapter.
|
|
|
|
NdisRequest - A structure which contains the request type (Global
|
|
Query), an array of operations to perform, and an array for holding
|
|
the results of the operations.
|
|
|
|
Return Value:
|
|
|
|
The function value is the status of the operation.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// General Algorithm:
|
|
//
|
|
// Switch(Request)
|
|
// Get requested information
|
|
// Store results in a common variable.
|
|
// default:
|
|
// Try protocol query information
|
|
// If that fails, fail query.
|
|
//
|
|
// Copy result in common variable to result buffer.
|
|
// Finish processing
|
|
|
|
UINT BytesWritten = 0;
|
|
UINT BytesNeeded = 0;
|
|
UINT BytesLeft = NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength;
|
|
PUCHAR InfoBuffer = (PUCHAR)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer);
|
|
|
|
NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
|
|
|
|
//
|
|
// This variable holds result of query
|
|
//
|
|
|
|
ULONG GenericULong;
|
|
UINT MoveBytes = sizeof(UINT) * 2 + sizeof(NDIS_OID);
|
|
|
|
//
|
|
// Make sure that int is 4 bytes. Else GenericULong must change
|
|
// to something of size 4.
|
|
//
|
|
ASSERT(sizeof(UINT) == 4);
|
|
|
|
|
|
StatusToReturn = ElnkiiQueryProtocolInformation(
|
|
Adapter,
|
|
NULL,
|
|
NdisRequest->DATA.QUERY_INFORMATION.Oid,
|
|
TRUE,
|
|
InfoBuffer,
|
|
BytesLeft,
|
|
&BytesNeeded,
|
|
&BytesWritten
|
|
);
|
|
|
|
if (StatusToReturn == NDIS_STATUS_NOT_SUPPORTED) {
|
|
|
|
StatusToReturn = NDIS_STATUS_SUCCESS;
|
|
|
|
NdisAcquireSpinLock(&Adapter->Lock);
|
|
|
|
//
|
|
// Switch on request type
|
|
//
|
|
|
|
switch (NdisRequest->DATA.QUERY_INFORMATION.Oid) {
|
|
|
|
case OID_GEN_XMIT_OK:
|
|
|
|
GenericULong = (UINT)(Adapter->FramesXmitGood);
|
|
|
|
break;
|
|
|
|
case OID_GEN_RCV_OK:
|
|
|
|
GenericULong = (UINT)(Adapter->FramesRcvGood);
|
|
|
|
break;
|
|
|
|
case OID_GEN_XMIT_ERROR:
|
|
|
|
GenericULong = (UINT)(Adapter->FramesXmitBad);
|
|
|
|
break;
|
|
|
|
case OID_GEN_RCV_ERROR:
|
|
|
|
GenericULong = (UINT)(Adapter->CrcErrors);
|
|
|
|
break;
|
|
|
|
case OID_GEN_RCV_NO_BUFFER:
|
|
|
|
GenericULong = (UINT)(Adapter->MissedPackets);
|
|
|
|
break;
|
|
|
|
case OID_802_3_RCV_ERROR_ALIGNMENT:
|
|
|
|
GenericULong = (UINT)(Adapter->FrameAlignmentErrors);
|
|
|
|
break;
|
|
|
|
case OID_802_3_XMIT_ONE_COLLISION:
|
|
|
|
GenericULong = (UINT)(Adapter->FramesXmitOneCollision);
|
|
|
|
break;
|
|
|
|
case OID_802_3_XMIT_MORE_COLLISIONS:
|
|
|
|
GenericULong = (UINT)(Adapter->FramesXmitManyCollisions);
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
StatusToReturn = NDIS_STATUS_INVALID_OID;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
|
|
//
|
|
// Check to make sure there is enough room in the
|
|
// buffer to store the result.
|
|
//
|
|
|
|
if (BytesLeft >= sizeof(ULONG)) {
|
|
|
|
//
|
|
// Store the result.
|
|
//
|
|
|
|
ELNKII_MOVE_MEM(
|
|
(PVOID)InfoBuffer,
|
|
(PVOID)(&GenericULong),
|
|
sizeof(ULONG)
|
|
);
|
|
|
|
BytesWritten += sizeof(ULONG);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
NdisRequest->DATA.QUERY_INFORMATION.BytesWritten = BytesWritten;
|
|
|
|
NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = BytesNeeded;
|
|
|
|
return(StatusToReturn);
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ElnkiiQueryGlobalStatistics(
|
|
IN NDIS_HANDLE MacAdapterContext,
|
|
IN PNDIS_REQUEST NdisRequest
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The ElnkiiQueryGlobalStatistics is used by the protocol to query
|
|
global information about the MAC.
|
|
|
|
Arguments:
|
|
|
|
MacAdapterContext - The value associated with the adapter that is being
|
|
opened when the MAC registered the adapter with NdisRegisterAdapter.
|
|
|
|
NdisRequest - A structure which contains the request type (Query),
|
|
an array of operations to perform, and an array for holding
|
|
the results of the operations.
|
|
|
|
Return Value:
|
|
|
|
The function value is the status of the operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// General Algorithm:
|
|
//
|
|
//
|
|
// Check if a request is going to pend...
|
|
// If so, pend the entire operation.
|
|
//
|
|
// Else
|
|
// Fill in the request block.
|
|
//
|
|
//
|
|
|
|
PELNKII_ADAPTER Adapter = (PELNKII_ADAPTER)(MacAdapterContext);
|
|
|
|
NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
|
|
|
|
//
|
|
// Check if a request is valid and going to pend...
|
|
// If so, pend the entire operation.
|
|
//
|
|
|
|
|
|
//
|
|
// Switch on request type
|
|
//
|
|
|
|
switch (NdisRequest->DATA.QUERY_INFORMATION.Oid) {
|
|
case OID_GEN_SUPPORTED_LIST:
|
|
case OID_GEN_HARDWARE_STATUS:
|
|
case OID_GEN_MEDIA_SUPPORTED:
|
|
case OID_GEN_MEDIA_IN_USE:
|
|
case OID_GEN_MAXIMUM_LOOKAHEAD:
|
|
case OID_GEN_MAXIMUM_FRAME_SIZE:
|
|
case OID_GEN_MAXIMUM_TOTAL_SIZE:
|
|
case OID_GEN_MAC_OPTIONS:
|
|
case OID_GEN_PROTOCOL_OPTIONS:
|
|
case OID_GEN_LINK_SPEED:
|
|
case OID_GEN_TRANSMIT_BUFFER_SPACE:
|
|
case OID_GEN_RECEIVE_BUFFER_SPACE:
|
|
case OID_GEN_TRANSMIT_BLOCK_SIZE:
|
|
case OID_GEN_RECEIVE_BLOCK_SIZE:
|
|
case OID_GEN_VENDOR_ID:
|
|
case OID_GEN_VENDOR_DESCRIPTION:
|
|
case OID_GEN_DRIVER_VERSION:
|
|
case OID_GEN_CURRENT_PACKET_FILTER:
|
|
case OID_GEN_CURRENT_LOOKAHEAD:
|
|
case OID_802_3_PERMANENT_ADDRESS:
|
|
case OID_802_3_CURRENT_ADDRESS:
|
|
case OID_GEN_XMIT_OK:
|
|
case OID_GEN_RCV_OK:
|
|
case OID_GEN_XMIT_ERROR:
|
|
case OID_GEN_RCV_ERROR:
|
|
case OID_GEN_RCV_NO_BUFFER:
|
|
case OID_802_3_MULTICAST_LIST:
|
|
case OID_802_3_MAXIMUM_LIST_SIZE:
|
|
case OID_802_3_RCV_ERROR_ALIGNMENT:
|
|
case OID_802_3_XMIT_ONE_COLLISION:
|
|
case OID_802_3_XMIT_MORE_COLLISIONS:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
StatusToReturn = NDIS_STATUS_INVALID_OID;
|
|
|
|
break;
|
|
}
|
|
|
|
NdisInterlockedAddUlong(&Adapter->References, 1, &Adapter->Lock);
|
|
|
|
if (StatusToReturn == NDIS_STATUS_SUCCESS) {
|
|
|
|
StatusToReturn = ElnkiiFillInGlobalData(Adapter, NdisRequest);
|
|
|
|
}
|
|
|
|
NdisAcquireSpinLock(&Adapter->Lock);
|
|
|
|
ELNKII_DO_DEFERRED(Adapter);
|
|
|
|
return(StatusToReturn);
|
|
}
|
|
|
|
VOID
|
|
ElnkiiUnload(
|
|
IN NDIS_HANDLE MacMacContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ElnkiiUnload is called when the MAC is to unload itself.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
NDIS_STATUS InitStatus;
|
|
|
|
UNREFERENCED_PARAMETER(MacMacContext);
|
|
|
|
NdisDeregisterMac(
|
|
&InitStatus,
|
|
ElnkiiMacBlock.NdisMacHandle
|
|
);
|
|
|
|
NdisFreeSpinLock(&ElnkiiMacBlock.SpinLock);
|
|
|
|
NdisTerminateWrapper(
|
|
ElnkiiMacBlock.NdisWrapperHandle,
|
|
(PVOID) NULL
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
ElnkiiRemoveAdapter(
|
|
IN PVOID MacAdapterContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ElnkiiRemoveAdapter removes an adapter previously registered
|
|
with NdisRegisterAdapter.
|
|
|
|
Arguments:
|
|
|
|
MacAdapterContext - The context value that the MAC passed
|
|
to NdisRegisterAdapter; actually as pointer to an
|
|
ELNKII_ADAPTER.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PELNKII_ADAPTER Adapter;
|
|
|
|
Adapter = PELNKII_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext);
|
|
|
|
Adapter->Removed = TRUE;
|
|
|
|
ASSERT(Adapter->OpenQueue == (PELNKII_OPEN)NULL);
|
|
|
|
//
|
|
// There are no opens left, so remove ourselves.
|
|
//
|
|
|
|
//
|
|
// Take us out of the AdapterQueue.
|
|
//
|
|
|
|
NdisAcquireSpinLock(&ElnkiiMacBlock.SpinLock);
|
|
|
|
if (ElnkiiMacBlock.AdapterQueue == Adapter) {
|
|
|
|
ElnkiiMacBlock.AdapterQueue = Adapter->NextAdapter;
|
|
|
|
} else {
|
|
|
|
PELNKII_ADAPTER TmpAdaptP = ElnkiiMacBlock.AdapterQueue;
|
|
|
|
while (TmpAdaptP->NextAdapter != Adapter) {
|
|
|
|
TmpAdaptP = TmpAdaptP->NextAdapter;
|
|
|
|
}
|
|
|
|
TmpAdaptP->NextAdapter = TmpAdaptP->NextAdapter->NextAdapter;
|
|
}
|
|
|
|
NdisReleaseSpinLock(&ElnkiiMacBlock.SpinLock);
|
|
|
|
if (Adapter->MemMapped) {
|
|
|
|
NdisUnmapIoSpace(
|
|
Adapter->NdisAdapterHandle,
|
|
Adapter->XmitStart,
|
|
0x2000);
|
|
|
|
}
|
|
|
|
{
|
|
BOOLEAN Canceled;
|
|
NdisCancelTimer(&Adapter->WakeUpTimer, &Canceled);
|
|
|
|
if (!Canceled) {
|
|
NdisStallExecution(500000);
|
|
}
|
|
}
|
|
|
|
EthDeleteFilter(Adapter->FilterDB);
|
|
|
|
NdisRemoveInterrupt(&Adapter->NdisInterrupt);
|
|
|
|
NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
|
|
|
|
NdisFreeSpinLock(&Adapter->Lock);
|
|
|
|
NdisFreeMemory(Adapter, sizeof(ELNKII_ADAPTER), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
ElnkiiReset(
|
|
IN NDIS_HANDLE MacBindingHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
NDIS function.
|
|
|
|
Arguments:
|
|
|
|
See NDIS 3.0 spec.
|
|
|
|
--*/
|
|
|
|
{
|
|
PELNKII_OPEN OpenP = ((PELNKII_OPEN)MacBindingHandle);
|
|
PELNKII_OPEN TmpOpenP;
|
|
PELNKII_ADAPTER AdaptP = OpenP->Adapter;
|
|
NDIS_STATUS Status;
|
|
|
|
|
|
if (OpenP->Closing) {
|
|
|
|
return(NDIS_STATUS_CLOSING);
|
|
|
|
}
|
|
|
|
NdisAcquireSpinLock(&AdaptP->Lock);
|
|
|
|
//
|
|
// Ensure that the open does not close while in this function.
|
|
//
|
|
|
|
OpenP->ReferenceCount++;
|
|
|
|
AdaptP->References++;
|
|
|
|
|
|
//
|
|
// Check that nobody is resetting this adapter, block others.
|
|
//
|
|
|
|
if (AdaptP->ResetInProgress) {
|
|
|
|
--OpenP->ReferenceCount;
|
|
|
|
AdaptP->References--;
|
|
|
|
NdisReleaseSpinLock(&AdaptP->Lock);
|
|
|
|
return NDIS_STATUS_RESET_IN_PROGRESS;
|
|
}
|
|
|
|
//
|
|
// Indicate Reset Start
|
|
//
|
|
|
|
TmpOpenP = AdaptP->OpenQueue;
|
|
|
|
while (TmpOpenP != (PELNKII_OPEN)NULL) {
|
|
|
|
PELNKII_OPEN NextOpen;
|
|
|
|
AddRefWhileHoldingSpinLock(AdaptP, TmpOpenP);
|
|
|
|
NdisReleaseSpinLock(&AdaptP->Lock);
|
|
|
|
NdisIndicateStatus(TmpOpenP->NdisBindingContext,
|
|
NDIS_STATUS_RESET_START,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
NdisAcquireSpinLock(&AdaptP->Lock);
|
|
|
|
NextOpen = TmpOpenP->NextOpen;
|
|
|
|
TmpOpenP->ReferenceCount--;
|
|
|
|
TmpOpenP = NextOpen;
|
|
}
|
|
|
|
//
|
|
// Set Reset Flag
|
|
//
|
|
|
|
AdaptP->ResetInProgress = TRUE;
|
|
AdaptP->NextResetStage = NONE;
|
|
|
|
//
|
|
// Needed in case the reset pends somewhere along the line.
|
|
//
|
|
|
|
AdaptP->ResetOpen = OpenP;
|
|
|
|
NdisReleaseSpinLock(&AdaptP->Lock);
|
|
|
|
//
|
|
// This will take things from here.
|
|
//
|
|
|
|
Status = ElnkiiStage2Reset(AdaptP);
|
|
|
|
NdisAcquireSpinLock(&AdaptP->Lock);
|
|
|
|
--OpenP->ReferenceCount;
|
|
|
|
ELNKII_DO_DEFERRED(AdaptP);
|
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ElnkiiStage2Reset(
|
|
PELNKII_ADAPTER AdaptP
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The second stage of a reset.
|
|
It removes all requests on the pend queue.
|
|
ElnkiiStage3Reset will be called when CurBufXmitting goes to -1.
|
|
|
|
Arguments:
|
|
|
|
AdaptP - The adapter being reset.
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_PENDING if the card is currently transmitting.
|
|
The result of ElnkiiStage3Reset otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
NDIS_STATUS Status;
|
|
PELNKII_PEND_DATA Op;
|
|
PELNKII_OPEN TmpOpen;
|
|
|
|
NdisAcquireSpinLock(&AdaptP->Lock);
|
|
|
|
AdaptP->References++;
|
|
|
|
//
|
|
// kill the pend queue.
|
|
//
|
|
|
|
while (AdaptP->PendQueue != (PELNKII_PEND_DATA)NULL) {
|
|
|
|
Op = AdaptP->PendQueue;
|
|
|
|
AdaptP->PendQueue = Op->Next;
|
|
|
|
TmpOpen = Op->Open;
|
|
|
|
NdisReleaseSpinLock(&AdaptP->Lock);
|
|
|
|
Status = NDIS_STATUS_REQUEST_ABORTED;
|
|
|
|
if ((Op->RequestType != NdisRequestClose) &&
|
|
(Op->RequestType != NdisRequestGeneric1)) { // Not a close Request
|
|
|
|
NdisCompleteRequest(Op->Open->NdisBindingContext,
|
|
PNDIS_REQUEST_FROM_PELNKII_PEND_DATA(Op),
|
|
NDIS_STATUS_REQUEST_ABORTED);
|
|
|
|
}
|
|
|
|
//
|
|
// This will call NdisCompleteClose if necessary.
|
|
//
|
|
|
|
NdisAcquireSpinLock(&AdaptP->Lock);
|
|
|
|
--TmpOpen->ReferenceCount;
|
|
}
|
|
|
|
if (AdaptP->CurBufXmitting != -1) {
|
|
|
|
//
|
|
// ElnkiiHandleXmitComplete will call ElnkiiStage3Reset.
|
|
//
|
|
|
|
AdaptP->NextResetStage = XMIT_STOPPED;
|
|
|
|
AdaptP->References--;
|
|
|
|
NdisReleaseSpinLock(&AdaptP->Lock);
|
|
|
|
return NDIS_STATUS_PENDING;
|
|
|
|
}
|
|
|
|
AdaptP->References--;
|
|
|
|
NdisReleaseSpinLock(&AdaptP->Lock);
|
|
|
|
return ElnkiiStage3Reset(AdaptP);
|
|
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ElnkiiStage3Reset(
|
|
PELNKII_ADAPTER AdaptP
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The third stage of a reset. When called, CurBufXmitting has
|
|
gone to -1. ElnkiiStage4Reset is called when call the
|
|
transmit buffers are emptied (i.e. any threads that were
|
|
filling them have finished).
|
|
|
|
Arguments:
|
|
|
|
AdaptP - The adapter being reset.
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_PENDING if there are still transmit buffers being filled.
|
|
The result of ElnkiiStage4Reset otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT i;
|
|
|
|
NdisAcquireSpinLock(&AdaptP->Lock);
|
|
|
|
AdaptP->References++;
|
|
|
|
//
|
|
// Reset these for afterwards.
|
|
//
|
|
|
|
AdaptP->NextBufToFill = 0;
|
|
|
|
AdaptP->NextBufToXmit = 0;
|
|
|
|
|
|
//
|
|
// Make sure all buffer filling operations are done.
|
|
//
|
|
|
|
for (i=0; i<AdaptP->NumBuffers; i++) {
|
|
|
|
if (AdaptP->BufferStatus[i] != EMPTY) {
|
|
|
|
//
|
|
// ElnkiiSend or ElnkiiCopyAndSend will call ElnkiiStage4Reset.
|
|
//
|
|
|
|
AdaptP->NextResetStage = BUFFERS_EMPTY;
|
|
|
|
AdaptP->References--;
|
|
|
|
NdisReleaseSpinLock(&AdaptP->Lock);
|
|
|
|
return NDIS_STATUS_PENDING;
|
|
}
|
|
}
|
|
|
|
AdaptP->References--;
|
|
|
|
NdisReleaseSpinLock(&AdaptP->Lock);
|
|
|
|
return ElnkiiStage4Reset(AdaptP);
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ElnkiiStage4Reset(
|
|
PELNKII_ADAPTER AdaptP
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The fourth stage of a reset. When called, the last transmit
|
|
buffer has been marked empty. At this point the reset can
|
|
proceed.
|
|
|
|
Arguments:
|
|
|
|
AdaptP - The adapter being reset.
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS if the reset of the card succeeds.
|
|
NDIS_STATUS_FAILURE otherwise.
|
|
|
|
--*/
|
|
{
|
|
UINT i;
|
|
PNDIS_PACKET CurPacket;
|
|
PMAC_RESERVED Reserved;
|
|
PELNKII_OPEN TmpOpenP;
|
|
NDIS_STATUS Status;
|
|
|
|
|
|
//
|
|
// Complete any packets that are waiting in transmit buffers,
|
|
// but are not in the loopback queue.
|
|
//
|
|
|
|
NdisAcquireSpinLock(&AdaptP->Lock);
|
|
|
|
AdaptP->References++;
|
|
|
|
for (i=0; i<AdaptP->NumBuffers; i++) {
|
|
|
|
if (AdaptP->Packets[i] != (PNDIS_PACKET)NULL) {
|
|
|
|
Reserved = RESERVED(AdaptP->Packets[i]);
|
|
|
|
NdisReleaseSpinLock(&AdaptP->Lock);
|
|
|
|
#if DBG
|
|
ElnkiiSendsCompletedForReset++;
|
|
#endif
|
|
|
|
TmpOpenP = Reserved->Open;
|
|
|
|
NdisCompleteSend(Reserved->Open->NdisBindingContext,
|
|
AdaptP->Packets[i],
|
|
NDIS_STATUS_REQUEST_ABORTED);
|
|
|
|
NdisAcquireSpinLock(&AdaptP->Lock);
|
|
|
|
--TmpOpenP->ReferenceCount;
|
|
|
|
AdaptP->Packets[i] = (PNDIS_PACKET)NULL;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Kill any packets waiting in the transmit queue,
|
|
// but are not in the loopback queue.
|
|
//
|
|
|
|
while ((CurPacket = AdaptP->XmitQueue) != (PNDIS_PACKET)NULL) {
|
|
|
|
Reserved = RESERVED(CurPacket);
|
|
|
|
AdaptP->XmitQueue = Reserved->NextPacket;
|
|
|
|
NdisReleaseSpinLock(&AdaptP->Lock);
|
|
|
|
#if DBG
|
|
ElnkiiSendsCompletedForReset++;
|
|
#endif
|
|
|
|
TmpOpenP = Reserved->Open;
|
|
|
|
NdisCompleteSend(Reserved->Open->NdisBindingContext,
|
|
CurPacket,
|
|
NDIS_STATUS_REQUEST_ABORTED);
|
|
|
|
NdisAcquireSpinLock(&AdaptP->Lock);
|
|
|
|
--TmpOpenP->ReferenceCount;
|
|
}
|
|
|
|
|
|
//
|
|
// Now kill everything in the loopback queue.
|
|
//
|
|
|
|
while ((CurPacket = AdaptP->LoopbackQueue) != (PNDIS_PACKET)NULL) {
|
|
|
|
Reserved = RESERVED(CurPacket);
|
|
|
|
AdaptP->LoopbackQueue = Reserved->NextPacket;
|
|
|
|
NdisReleaseSpinLock(&AdaptP->Lock);
|
|
|
|
#if DBG
|
|
ElnkiiSendsCompletedForReset++;
|
|
#endif
|
|
|
|
TmpOpenP = Reserved->Open;
|
|
|
|
NdisCompleteSend(Reserved->Open->NdisBindingContext,
|
|
CurPacket,
|
|
NDIS_STATUS_REQUEST_ABORTED);
|
|
|
|
NdisAcquireSpinLock(&AdaptP->Lock);
|
|
|
|
--TmpOpenP->ReferenceCount;
|
|
}
|
|
|
|
NdisReleaseSpinLock(&AdaptP->Lock);
|
|
|
|
//
|
|
// Wait for packet reception to stop -- this might happen if we
|
|
// really blaze through the reset code before the ReceiveDpc gets
|
|
// a chance to run.
|
|
//
|
|
|
|
while (AdaptP->ReceiveInProgress) {
|
|
|
|
NdisStallExecution(10000);
|
|
}
|
|
|
|
//
|
|
// Physically reset the card.
|
|
//
|
|
|
|
AdaptP->NicInterruptMask =
|
|
IMR_RCV | IMR_XMIT | IMR_XMIT_ERR | IMR_OVERFLOW;
|
|
|
|
Status = CardReset(AdaptP) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE;
|
|
|
|
|
|
//
|
|
// Set the "resetting" flag back to FALSE.
|
|
//
|
|
|
|
NdisAcquireSpinLock(&AdaptP->Lock);
|
|
|
|
AdaptP->ResetInProgress = FALSE;
|
|
|
|
//
|
|
// Indicate the reset complete to all the protocols.
|
|
//
|
|
|
|
|
|
TmpOpenP = AdaptP->OpenQueue;
|
|
|
|
while (TmpOpenP != (PELNKII_OPEN)NULL) {
|
|
|
|
PELNKII_OPEN NextOpen;
|
|
|
|
AddRefWhileHoldingSpinLock(AdaptP, TmpOpenP);
|
|
|
|
NdisReleaseSpinLock(&AdaptP->Lock);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS) {
|
|
|
|
NdisIndicateStatus(TmpOpenP->NdisBindingContext,
|
|
NDIS_STATUS_CLOSED,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
}
|
|
|
|
NdisIndicateStatus(TmpOpenP->NdisBindingContext,
|
|
NDIS_STATUS_RESET_END,
|
|
&Status,
|
|
sizeof(Status)
|
|
);
|
|
|
|
NdisIndicateStatusComplete(TmpOpenP->NdisBindingContext);
|
|
|
|
NdisAcquireSpinLock(&AdaptP->Lock);
|
|
|
|
NextOpen = TmpOpenP->NextOpen;
|
|
|
|
TmpOpenP->ReferenceCount--;
|
|
|
|
TmpOpenP = NextOpen;
|
|
}
|
|
|
|
AdaptP->References--;
|
|
|
|
NdisReleaseSpinLock(&AdaptP->Lock);
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
ElnkiiResetStageDone(
|
|
PELNKII_ADAPTER AdaptP,
|
|
RESET_STAGE StageDone
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Indicates that a stage in the reset is done. Called by
|
|
routines that the reset pended waiting for, to indicate
|
|
that they are done. A central clearing house for determining
|
|
what the next stage is and calling the appropriate routine.
|
|
If a stage completes before it is being pended on, then
|
|
StageDone will not equal AdaptP->NextResetStage and no
|
|
action will be taken.
|
|
|
|
Arguments:
|
|
|
|
AdaptP - The adapter being reset.
|
|
StageDone - The stage that was just completed.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
NDIS_STATUS Status;
|
|
UINT i;
|
|
|
|
|
|
//
|
|
// Make sure this is the stage that was being waited on.
|
|
//
|
|
|
|
if (AdaptP->NextResetStage != StageDone) {
|
|
return;
|
|
}
|
|
|
|
|
|
switch (StageDone) {
|
|
|
|
case MULTICAST_RESET:
|
|
Status = ElnkiiStage2Reset(AdaptP);
|
|
break;
|
|
|
|
case XMIT_STOPPED:
|
|
Status = ElnkiiStage3Reset(AdaptP);
|
|
break;
|
|
|
|
case BUFFERS_EMPTY:
|
|
|
|
//
|
|
// Only continue if this is the last buffer waited for.
|
|
//
|
|
|
|
NdisAcquireSpinLock(&AdaptP->Lock);
|
|
|
|
AdaptP->References++;
|
|
|
|
for (i=0; i<AdaptP->NumBuffers; i++) {
|
|
|
|
if (AdaptP->BufferStatus[i] != EMPTY) {
|
|
|
|
AdaptP->References--;
|
|
|
|
NdisReleaseSpinLock(&AdaptP->Lock);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
AdaptP->References--;
|
|
|
|
NdisReleaseSpinLock(&AdaptP->Lock);
|
|
|
|
Status = ElnkiiStage4Reset(AdaptP);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (Status != NDIS_STATUS_PENDING) {
|
|
|
|
NdisCompleteReset(
|
|
AdaptP->ResetOpen->NdisBindingContext,
|
|
Status);
|
|
|
|
NdisAcquireSpinLock(&AdaptP->Lock);
|
|
|
|
--AdaptP->ResetOpen->ReferenceCount;
|
|
|
|
} else {
|
|
|
|
NdisAcquireSpinLock(&AdaptP->Lock);
|
|
|
|
}
|
|
|
|
ELNKII_DO_DEFERRED(AdaptP);
|
|
}
|
|
|
|
|
|
STATIC
|
|
NDIS_STATUS
|
|
ElnkiiChangeMulticastAddresses(
|
|
IN UINT OldFilterCount,
|
|
IN CHAR OldAddresses[][ETH_LENGTH_OF_ADDRESS],
|
|
IN UINT NewFilterCount,
|
|
IN CHAR NewAddresses[][ETH_LENGTH_OF_ADDRESS],
|
|
IN NDIS_HANDLE MacBindingHandle,
|
|
IN PNDIS_REQUEST NdisRequest,
|
|
IN BOOLEAN Set
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Action routine that will get called when a particular filter
|
|
class is first used or last cleared.
|
|
|
|
NOTE: This routine assumes that it is called with the lock
|
|
acquired.
|
|
|
|
Arguments:
|
|
|
|
|
|
OldFilterCount - The number of addresses that used to be on the card.
|
|
|
|
OldAddresses - A list of all the addresses that used to be on the card.
|
|
|
|
NewFilterCount - The number of addresses that should now be on the card.
|
|
|
|
NewAddresses - A list of addresses that should be put on the card.
|
|
|
|
MacBindingHandle - The context value returned by the MAC when the
|
|
adapter was opened. In reality, it is a pointer to ELNKII_OPEN.
|
|
|
|
NdisRequest - The request which submitted the filter change.
|
|
Must use when completing this request with the NdisCompleteRequest
|
|
service, if the MAC completes this request asynchronously.
|
|
|
|
Set - If true the change resulted from a set, otherwise the
|
|
change resulted from a open closing.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
|
|
PELNKII_ADAPTER Adapter = PELNKII_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
|
|
PELNKII_PEND_DATA PendOp = PELNKII_PEND_DATA_FROM_PNDIS_REQUEST(NdisRequest);
|
|
UINT Filter;
|
|
|
|
//
|
|
// The open that made this request.
|
|
//
|
|
PELNKII_OPEN Open = PELNKII_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
|
|
|
|
//
|
|
// Holds the status that should be returned to the filtering package.
|
|
//
|
|
NDIS_STATUS StatusOfAdd;
|
|
|
|
UNREFERENCED_PARAMETER(OldFilterCount);
|
|
UNREFERENCED_PARAMETER(OldAddresses);
|
|
UNREFERENCED_PARAMETER(NewFilterCount);
|
|
UNREFERENCED_PARAMETER(NewAddresses);
|
|
|
|
if (NdisRequest == NULL) {
|
|
|
|
NdisRequest = &(Open->CloseAddressRequest);
|
|
PendOp = PELNKII_PEND_DATA_FROM_PNDIS_REQUEST(NdisRequest);
|
|
|
|
}
|
|
|
|
//
|
|
// Check to see if the device is already resetting. If it is
|
|
// then reject this add.
|
|
//
|
|
|
|
if (Adapter->ResetInProgress) {
|
|
|
|
StatusOfAdd = NDIS_STATUS_RESET_IN_PROGRESS;
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Verify that the global filter is not all multicast
|
|
// or promiscuous modes. Otherwise adding a multicast
|
|
// address will reset the mode.
|
|
//
|
|
Filter = ETH_QUERY_FILTER_CLASSES(Adapter->FilterDB);
|
|
if ((Filter & NDIS_PACKET_TYPE_ALL_MULTICAST) ||
|
|
(Filter & NDIS_PACKET_TYPE_PROMISCUOUS)
|
|
)
|
|
{
|
|
return(NDIS_STATUS_SUCCESS);
|
|
}
|
|
|
|
PendOp->Open = Open;
|
|
|
|
//
|
|
// We need to add this to the hardware multicast filtering.
|
|
// So pend an operation to do it.
|
|
//
|
|
|
|
//
|
|
// Add one to reference count, to be subtracted when the
|
|
// operation get completed.
|
|
//
|
|
|
|
PendOp->Open->ReferenceCount++;
|
|
PendOp->RequestType = Set ?
|
|
NdisRequestGeneric3 : // Means SetMulticastAddresses
|
|
NdisRequestClose ; // Means CloseMulticast
|
|
PendOp->Next = NULL;
|
|
|
|
|
|
if (Adapter->PendQueue == (PELNKII_PEND_DATA)NULL) {
|
|
|
|
Adapter->PendQueue = Adapter->PendQTail = PendOp;
|
|
|
|
} else {
|
|
|
|
Adapter->PendQTail->Next = PendOp;
|
|
Adapter->PendQTail = PendOp;
|
|
|
|
}
|
|
|
|
|
|
StatusOfAdd = NDIS_STATUS_PENDING;
|
|
|
|
}
|
|
|
|
return StatusOfAdd;
|
|
|
|
}
|
|
|
|
STATIC
|
|
NDIS_STATUS
|
|
ElnkiiChangeFilterClasses(
|
|
IN UINT OldFilterClasses,
|
|
IN UINT NewFilterClasses,
|
|
IN NDIS_HANDLE MacBindingHandle,
|
|
IN PNDIS_REQUEST NdisRequest,
|
|
IN BOOLEAN Set
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Action routine that will get called when an address is added to
|
|
the filter that wasn't referenced by any other open binding.
|
|
|
|
NOTE: This routine assumes that it is called with the lock
|
|
acquired.
|
|
|
|
Arguments:
|
|
|
|
OldFilterClasses - A bit mask that is currently on the card telling
|
|
which packet types to accept.
|
|
|
|
NewFilterClasses - A bit mask that should be put on the card telling
|
|
which packet types to accept.
|
|
|
|
MacBindingHandle - The context value returned by the MAC when the
|
|
adapter was opened. In reality, it is a pointer to ELNKII_OPEN.
|
|
|
|
NdisRequest - The NDIS_REQUEST which submitted the filter change command.
|
|
|
|
Set - A flag telling if the command is a result of a close or not.
|
|
|
|
Return Value:
|
|
|
|
Status of the change (successful or pending).
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PELNKII_ADAPTER Adapter = PELNKII_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
|
|
PELNKII_PEND_DATA PendOp = PELNKII_PEND_DATA_FROM_PNDIS_REQUEST(NdisRequest);
|
|
|
|
//
|
|
// The open that made this request.
|
|
//
|
|
PELNKII_OPEN Open = PELNKII_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
|
|
|
|
//
|
|
// Holds the status that should be returned to the filtering package.
|
|
//
|
|
NDIS_STATUS StatusOfAdd;
|
|
|
|
|
|
UNREFERENCED_PARAMETER(OldFilterClasses);
|
|
UNREFERENCED_PARAMETER(NewFilterClasses);
|
|
|
|
if (NdisRequest == NULL) {
|
|
|
|
NdisRequest = &(Open->CloseFilterRequest);
|
|
PendOp = PELNKII_PEND_DATA_FROM_PNDIS_REQUEST(NdisRequest);
|
|
|
|
}
|
|
|
|
//
|
|
// Check to see if the device is already resetting. If it is
|
|
// then reject this add.
|
|
//
|
|
|
|
if (Adapter->ResetInProgress) {
|
|
|
|
StatusOfAdd = NDIS_STATUS_RESET_IN_PROGRESS;
|
|
|
|
} else {
|
|
|
|
PendOp->Open = Open;
|
|
|
|
//
|
|
// We need to add this to the hardware multicast filtering.
|
|
// So queue a request.
|
|
//
|
|
|
|
PendOp->Open->ReferenceCount++;
|
|
PendOp->RequestType = Set ?
|
|
NdisRequestGeneric2 : // Means SetPacketFilter
|
|
NdisRequestGeneric1 ; // Means CloseFilter
|
|
PendOp->Next = NULL;
|
|
|
|
if (Adapter->PendQueue == (PELNKII_PEND_DATA)NULL) {
|
|
|
|
Adapter->PendQueue = Adapter->PendQTail = PendOp;
|
|
|
|
} else {
|
|
|
|
Adapter->PendQTail->Next = PendOp;
|
|
Adapter->PendQTail = PendOp;
|
|
|
|
}
|
|
|
|
StatusOfAdd = NDIS_STATUS_PENDING;
|
|
|
|
}
|
|
|
|
return StatusOfAdd;
|
|
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
ElnkiiCloseAction(
|
|
IN NDIS_HANDLE MacBindingHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Action routine that will get called when a particular binding
|
|
was closed while it was indicating through NdisIndicateReceive
|
|
|
|
All this routine needs to do is to decrement the reference count
|
|
of the binding.
|
|
|
|
NOTE: This routine assumes that it is called with the lock acquired.
|
|
|
|
Arguments:
|
|
|
|
MacBindingHandle - The context value returned by the MAC when the
|
|
adapter was opened. In reality, it is a pointer to ELNKII_OPEN.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PELNKII_OPEN_FROM_BINDING_HANDLE(MacBindingHandle)->ReferenceCount--;
|
|
|
|
}
|