summaryrefslogtreecommitdiffstats
path: root/private/ntos/ndis/ndis30
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/ndis/ndis30')
-rw-r--r--private/ntos/ndis/ndis30/afilter.c2083
-rw-r--r--private/ntos/ndis/ndis30/afilter.h339
-rw-r--r--private/ntos/ndis/ndis30/efilter.c2252
-rw-r--r--private/ntos/ndis/ndis30/efilter.h605
-rw-r--r--private/ntos/ndis/ndis30/ffilter.c3193
-rw-r--r--private/ntos/ndis/ndis30/ffilter.h692
-rw-r--r--private/ntos/ndis/ndis30/makefile6
-rw-r--r--private/ntos/ndis/ndis30/makefile.inc2
-rw-r--r--private/ntos/ndis/ndis30/miniport.c10214
-rw-r--r--private/ntos/ndis/ndis30/minisub.c280
-rw-r--r--private/ntos/ndis/ndis30/ndis.prf102
-rw-r--r--private/ntos/ndis/ndis30/ndis.rc39
-rw-r--r--private/ntos/ndis/ndis30/ndis.src185
-rw-r--r--private/ntos/ndis/ndis30/ndismac.h1218
-rw-r--r--private/ntos/ndis/ndis30/ndismain.h1976
-rw-r--r--private/ntos/ndis/ndis30/ndismini.h1216
-rw-r--r--private/ntos/ndis/ndis30/precomp.h6
-rw-r--r--private/ntos/ndis/ndis30/sources59
-rw-r--r--private/ntos/ndis/ndis30/tfilter.c2119
-rw-r--r--private/ntos/ndis/ndis30/tfilter.h558
-rw-r--r--private/ntos/ndis/ndis30/wrapper.c17480
-rw-r--r--private/ntos/ndis/ndis30/wrapper.h473
-rw-r--r--private/ntos/ndis/ndis30/wrapper.txt120
23 files changed, 45217 insertions, 0 deletions
diff --git a/private/ntos/ndis/ndis30/afilter.c b/private/ntos/ndis/ndis30/afilter.c
new file mode 100644
index 000000000..9d50eedc9
--- /dev/null
+++ b/private/ntos/ndis/ndis30/afilter.c
@@ -0,0 +1,2083 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ afilter.c
+
+Abstract:
+
+ This module implements a set of library routines to handle packet
+ filtering for NDIS MAC drivers. It also provides routines for collecting fragmented packets and
+ breaking up a packet into fragmented packets
+
+Author:
+
+ Alireza Dabagh 3-22-1993, (partially borrowed from EFILTER.C)
+
+
+Revision History:
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+#if DBG
+UINT AfilterDebugFlag = 0;
+#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);
+
+//
+// A set of macros to manipulate bitmasks.
+//
+
+//VOID
+//CLEAR_BIT_IN_MASK(
+// IN UINT Offset,
+// IN OUT PMASK MaskToClear
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Clear a bit in the bitmask pointed to by the parameter.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to altered.
+//
+// MaskToClear - Pointer to the mask to be adjusted.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+//
+#define CLEAR_BIT_IN_MASK(Offset,MaskToClear) *MaskToClear &= (~(1 << Offset))
+
+//VOID
+//SET_BIT_IN_MASK(
+// IN UINT Offset,
+// IN OUT PMASK MaskToSet
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Set a bit in the bitmask pointed to by the parameter.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to altered.
+//
+// MaskToSet - Pointer to the mask to be adjusted.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+#define SET_BIT_IN_MASK(Offset,MaskToSet) *MaskToSet |= (1 << Offset)
+
+//BOOLEAN
+//IS_BIT_SET_IN_MASK(
+// IN UINT Offset,
+// IN MASK MaskToTest
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Tests if a particular bit in the bitmask pointed to by the parameter is
+// set.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to test.
+//
+// MaskToTest - The mask to be tested.
+//
+//Return Value:
+//
+// Returns TRUE if the bit is set.
+//
+//--*/
+#define IS_BIT_SET_IN_MASK(Offset,MaskToTest) \
+((MaskToTest & (1 << Offset))?(TRUE):(FALSE))
+
+//BOOLEAN
+//IS_MASK_CLEAR(
+// IN MASK MaskToTest
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Tests whether there are *any* bits enabled in the mask.
+//
+//Arguments:
+//
+// MaskToTest - The bit mask to test for all clear.
+//
+//Return Value:
+//
+// Will return TRUE if no bits are set in the mask.
+//
+//--*/
+#define IS_MASK_CLEAR(MaskToTest) ((!MaskToTest)?(TRUE):(FALSE))
+
+//VOID
+//CLEAR_MASK(
+// IN OUT PMASK MaskToClear
+// );
+//
+///*++
+//
+//Routine Description:
+//
+// Clears a mask.
+//
+//Arguments:
+//
+// MaskToClear - The bit mask to adjust.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+#define CLEAR_MASK(MaskToClear) *MaskToClear = 0
+
+//
+// VOID
+// ARC_FILTER_ALLOC_OPEN(
+// IN PETH_FILTER Filter,
+// OUT PUINT FilterIndex
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Allocates an open block. This only allocate the index, not memory for
+// the open block.
+//
+//Arguments:
+//
+// Filter - DB from which to allocate the space
+//
+// FilterIndex - pointer to place to store the index.
+//
+//Return Value:
+//
+// FilterIndex of the new open
+//
+//--*/
+#define ARC_FILTER_ALLOC_OPEN(Filter, FilterIndex)\
+{\
+ UINT i; \
+ for (i=0; i < ARC_FILTER_MAX_OPENS; i++) { \
+ if (IS_BIT_SET_IN_MASK(i,(Filter)->FreeBindingMask)) { \
+ *(FilterIndex) = i; \
+ CLEAR_BIT_IN_MASK(i, &((Filter)->FreeBindingMask)); \
+ break; \
+ } \
+ } \
+}
+
+//
+// VOID
+// ARC_FILTER_FREE_OPEN(
+// IN PETH_FILTER Filter,
+// IN PARC_BINDING_INFO LocalOpen
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Frees an open block. Also frees the memory associated with the open.
+//
+//Arguments:
+//
+// Filter - DB from which to allocate the space
+//
+// FilterIndex - Index to free
+//
+//Return Value:
+//
+// FilterIndex of the new open
+//
+//--*/
+#define ARC_FILTER_FREE_OPEN(Filter, LocalOpen)\
+{\
+ SET_BIT_IN_MASK(((LocalOpen)->FilterIndex), &((Filter)->FreeBindingMask)); \
+ NdisFreeMemory((LocalOpen), sizeof(ARC_BINDING_INFO), 0);\
+}
+
+
+
+NDIS_SPIN_LOCK ArcReferenceLock = {0};
+KEVENT ArcPagedInEvent = {0};
+ULONG ArcReferenceCount = 0;
+PVOID ArcImageHandle = {0};
+
+VOID
+ArcInitializePackage(VOID)
+{
+ NdisAllocateSpinLock(&ArcReferenceLock);
+ KeInitializeEvent(
+ &ArcPagedInEvent,
+ NotificationEvent,
+ FALSE
+ );
+}
+
+VOID
+ArcReferencePackage(VOID)
+{
+ ACQUIRE_SPIN_LOCK(&ArcReferenceLock);
+
+ ArcReferenceCount++;
+
+ if (ArcReferenceCount == 1) {
+
+ KeResetEvent(
+ &ArcPagedInEvent
+ );
+
+ RELEASE_SPIN_LOCK(&ArcReferenceLock);
+
+ //
+ // Page in all the functions
+ //
+ ArcImageHandle = MmLockPagableCodeSection(ArcCreateFilter);
+
+ //
+ // Signal to everyone to go
+ //
+ KeSetEvent(
+ &ArcPagedInEvent,
+ 0L,
+ FALSE
+ );
+
+ } else {
+
+ RELEASE_SPIN_LOCK(&ArcReferenceLock);
+
+ //
+ // Wait for everything to be paged in
+ //
+ KeWaitForSingleObject(
+ &ArcPagedInEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ NULL
+ );
+
+ }
+
+}
+
+VOID
+ArcDereferencePackage(VOID)
+{
+ ACQUIRE_SPIN_LOCK(&ArcReferenceLock);
+
+ ArcReferenceCount--;
+
+ if (ArcReferenceCount == 0) {
+
+ RELEASE_SPIN_LOCK(&ArcReferenceLock);
+
+ //
+ // Page out all the functions
+ //
+ MmUnlockPagableImageSection(ArcImageHandle);
+
+ } else {
+
+ RELEASE_SPIN_LOCK(&ArcReferenceLock);
+
+ }
+
+}
+
+
+//
+// Defines for resource growth
+//
+#define ARC_BUFFER_SIZE 1024
+#define ARC_BUFFER_ALLOCATION_UNIT 8
+#define ARC_PACKET_ALLOCATION_UNIT 2
+
+
+//
+// Forward declarations
+//
+NDIS_STATUS
+ArcAllocateBuffers(
+ IN PARC_FILTER Filter
+ );
+
+NDIS_STATUS
+ArcAllocatePackets(
+ IN PARC_FILTER Filter
+ );
+
+VOID
+ArcDiscardPacketBuffers(
+ IN PARC_FILTER Filter,
+ IN PARC_PACKET Packet
+ );
+
+VOID
+ArcDestroyPacket(
+ IN PARC_FILTER Filter,
+ IN PARC_PACKET Packet
+ );
+
+BOOLEAN
+ArcConvertToNdisPacket(
+ IN PARC_FILTER Filter,
+ IN PARC_PACKET Packet,
+ IN BOOLEAN ConvertWholePacket
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGENDSA, ArcFilterTransferData)
+#pragma alloc_text(PAGENDSA, ArcFilterDprIndicateReceiveComplete)
+#pragma alloc_text(PAGENDSA, ArcFilterDoIndication)
+#pragma alloc_text(PAGENDSA, ArcFilterAdjust)
+#pragma alloc_text(PAGENDSA, ArcDeleteFilterOpenAdapter)
+#pragma alloc_text(PAGENDSA, ArcNoteFilterOpenAdapter)
+#pragma alloc_text(PAGENDSA, ArcCreateFilter)
+#pragma alloc_text(PAGENDSA, ArcFilterDprIndicateReceive)
+#pragma alloc_text(PAGENDSA, ArcConvertToNdisPacket)
+#pragma alloc_text(PAGENDSA, ArcDestroyPacket)
+#pragma alloc_text(PAGENDSA, ArcFreeNdisPacket)
+#pragma alloc_text(PAGENDSA, ArcDiscardPacketBuffers)
+#pragma alloc_text(PAGENDSA, ArcAllocatePackets)
+#pragma alloc_text(PAGENDSA, ArcAllocateBuffers)
+#pragma alloc_text(PAGENDSA, ArcConvertOidListToEthernet)
+#endif
+
+
+
+NDIS_STATUS
+ArcAllocateBuffers(
+ IN PARC_FILTER Filter
+ )
+/*++
+
+Routine Description:
+
+ This routine allocates Receive buffers for the filter database.
+
+Arguments:
+
+ Filter - The filter db to allocate for.
+
+Returns:
+
+ NDIS_STATUS_SUCCESS if any buffer was allocated.
+
+--*/
+{
+ ULONG i;
+ PARC_BUFFER_LIST Buffer;
+ PVOID DataBuffer;
+
+ for (i = ARC_BUFFER_ALLOCATION_UNIT; i != 0 ; i--) {
+
+ NdisAllocateMemory((PVOID)&Buffer,
+ sizeof(ARC_BUFFER_LIST),
+ 0,
+ HighestAcceptableMax
+ );
+
+ if (Buffer == NULL) {
+
+ if (i == ARC_BUFFER_ALLOCATION_UNIT) {
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ NdisAllocateMemory((PVOID)&DataBuffer,
+ ARC_BUFFER_SIZE,
+ 0,
+ HighestAcceptableMax
+ );
+
+ if (DataBuffer == NULL) {
+
+ NdisFreeMemory(Buffer, sizeof(ARC_BUFFER_LIST), 0);
+
+ if (i == ARC_BUFFER_ALLOCATION_UNIT) {
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // We allocated some packets, that is good enough for now
+ //
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ Buffer->BytesLeft = Buffer->Size = ARC_BUFFER_SIZE;
+ Buffer->Buffer = DataBuffer;
+ Buffer->Next = Filter->FreeBufferList;
+ Filter->FreeBufferList = Buffer;
+
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+
+}
+
+
+NDIS_STATUS
+ArcAllocatePackets(
+ IN PARC_FILTER Filter
+ )
+/*++
+
+Routine Description:
+
+ This routine allocates Receive packets for the filter database.
+
+Arguments:
+
+ Filter - The filter db to allocate for.
+
+Returns:
+
+ NDIS_STATUS_SUCCESS if any packet was allocated.
+
+--*/
+{
+ ULONG i;
+ PARC_PACKET Packet;
+
+ for (i = ARC_PACKET_ALLOCATION_UNIT; i != 0 ; i--) {
+
+ NdisAllocateMemory((PVOID)&Packet,
+ sizeof(ARC_PACKET),
+ 0,
+ HighestAcceptableMax
+ );
+
+ if (Packet == NULL) {
+
+ if (i == ARC_BUFFER_ALLOCATION_UNIT) {
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ NdisZeroMemory(Packet, sizeof(ARC_PACKET));
+
+ NdisReinitializePacket(&(Packet->TmpNdisPacket));
+
+ Packet->Next = Filter->FreePackets;
+ Filter->FreePackets = Packet;
+
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+VOID
+ArcDiscardPacketBuffers(
+ IN PARC_FILTER Filter,
+ IN PARC_PACKET Packet
+ )
+/*++
+
+Routine description:
+
+ This routine takes an arcnet packet that contains buffers of data and
+ puts the buffers on the free list.
+
+ NOTE: This assumes that LastBuffer points to the real last buffer
+ in the chain.
+
+Arguments:
+
+ Filter - The filter to free the buffers to.
+
+ Packet - The packet to free up.
+
+Return values:
+
+ None
+
+--*/
+{
+ PARC_BUFFER_LIST Buffer;
+
+ //
+ // Reset Packet info
+ //
+ Packet->LastFrame = FALSE;
+ Packet->TotalLength = 0;
+
+ //
+ // Reset buffer sizes
+ //
+ Buffer = Packet->FirstBuffer;
+ while (Buffer != NULL) {
+ Buffer->BytesLeft = Buffer->Size;
+ Buffer = Buffer->Next;
+ }
+
+ //
+ // Put buffers on free list
+ //
+ if (Packet->LastBuffer != NULL) {
+
+ Packet->LastBuffer->Next = Filter->FreeBufferList;
+ Filter->FreeBufferList = Packet->FirstBuffer;
+ Packet->FirstBuffer = Packet->LastBuffer = NULL;
+
+ }
+
+}
+
+
+VOID
+ArcFreeNdisPacket(
+ IN PARC_PACKET Packet
+ )
+/*++
+
+Routine description:
+
+ This routine takes an arcnet packet and frees up the corresponding
+ Ndis packet built for it.
+
+Arguments:
+
+ Packet - The packet to free up.
+
+Return values:
+
+ None
+
+--*/
+{
+ PNDIS_BUFFER NdisBuffer, NextNdisBuffer;
+
+ NdisQueryPacket(
+ &(Packet->TmpNdisPacket),
+ NULL,
+ NULL,
+ &NdisBuffer,
+ NULL
+ );
+
+ while (NdisBuffer != NULL) {
+
+ NdisGetNextBuffer(
+ NdisBuffer,
+ &NextNdisBuffer
+ );
+
+ NdisFreeBuffer(
+ NdisBuffer
+ );
+
+ NdisBuffer = NextNdisBuffer;
+ }
+
+ NdisReinitializePacket(&(Packet->TmpNdisPacket));
+
+}
+
+
+VOID
+ArcDestroyPacket(
+ IN PARC_FILTER Filter,
+ IN PARC_PACKET Packet
+ )
+/*++
+
+Routine description:
+
+ This routine takes an arcnet packet and frees up the entire packet.
+
+Arguments:
+
+ Filter - Filter to free to.
+
+ Packet - The packet to free up.
+
+Return values:
+
+ None
+
+--*/
+{
+ ArcFreeNdisPacket(Packet);
+ ArcDiscardPacketBuffers(Filter, Packet);
+
+ //
+ // Now put packet on free list
+ //
+ Packet->Next = Filter->FreePackets;
+ Filter->FreePackets = Packet;
+}
+
+
+BOOLEAN
+ArcConvertToNdisPacket(
+ IN PARC_FILTER Filter,
+ IN PARC_PACKET Packet,
+ IN BOOLEAN ConvertWholePacket
+ )
+/*++
+
+Routine description:
+
+ This routine builds a corresponding NDIS_PACKET in TmpNdisPacket,
+ that corresponds to the arcnet packet. The flag ConvertWholePacket
+ is used to convert only part of the arcnet packet, or the whole
+ stream. If the flag is FALSE, then only the buffers that have
+ free space (starting with buffer LastBuffer on up) are converted.
+
+ NOTE: It assumes TmpNdisPacket is an initialized ndis_packet structure.
+
+Arguments:
+
+ Filter - Filter to allocate from.
+
+ Packet - The packet to convert.
+
+ ConvertWholePacket - Convert the whole stream, or only part?
+
+Return values:
+
+ TRUE - If successful, else FALSE
+
+--*/
+{
+ PNDIS_BUFFER NdisBuffer;
+ PARC_BUFFER_LIST Buffer;
+ NDIS_STATUS NdisStatus;
+
+ Buffer = Packet->FirstBuffer;
+
+ while (Buffer != NULL) {
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ Filter->ReceiveBufferPool,
+ Buffer->Buffer,
+ Buffer->Size - Buffer->BytesLeft
+ );
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ return(FALSE);
+
+ }
+
+ NdisChainBufferAtBack(
+ &(Packet->TmpNdisPacket),
+ NdisBuffer
+ );
+
+ Buffer = Buffer->Next;
+
+ }
+
+ return(TRUE);
+}
+
+
+VOID
+ArcFilterDprIndicateReceive(
+ IN PARC_FILTER Filter, // Pointer to filter database
+ IN PUCHAR pRawHeader, // Pointer to Arcnet frame header
+ IN PUCHAR pData, // Pointer to data portion of Arcnet frame
+ IN UINT Length // Data Length
+ )
+{
+ ARC_PACKET_HEADER NewFrameInfo;
+ PARC_PACKET Packet, PrevPacket;
+ BOOLEAN FrameOk, NewFrame, LastFrame;
+ PARC_BUFFER_LIST Buffer;
+ UCHAR TmpUchar;
+ UINT TmpLength;
+ UINT TotalLength = Length;
+ PUCHAR OrigpData = pData;
+ USHORT TmpUshort;
+
+ //
+ // Check for ethernet encapsulation first
+ //
+
+ NdisReadRegisterUchar(pData, &TmpUchar);
+
+ if ( TmpUchar == 0xE8 ) {
+
+ //
+ // Yes! Indicate it to the wrapper for indicating to all
+ // protocols running ethernet on top of the arcnet miniport
+ // driver.
+ //
+
+ NdisMArcIndicateEthEncapsulatedReceive(
+ Filter->Miniport, // miniport.
+ pRawHeader, // 878.2 header.
+ pData + 1, // ethernet header.
+ Length - 1 // length of ethernet frame.
+ );
+
+ //
+ // We're done.
+ //
+
+ return;
+ }
+
+ //
+ // Get information from packet
+ //
+
+ NdisReadRegisterUchar(pRawHeader,
+ &(NewFrameInfo.ProtHeader.SourceId[0])
+ );
+
+ NdisReadRegisterUchar(pRawHeader + 1,
+ &(NewFrameInfo.ProtHeader.DestId[0])
+ );
+
+ NewFrameInfo.ProtHeader.ProtId = TmpUchar;
+
+ //
+ // Read the split flag. If this is an exception packet (i.e.
+ // TmpUChar == 0xFF then we need to add an extra 3 onto
+ // pData to skip the series of 0xFF 0xFF 0xFF.
+ //
+
+ pData++; //... Skip the SC byte.
+
+ NdisReadRegisterUchar(pData, &TmpUchar); //... Read split flag.
+
+ if ( TmpUchar == 0xFF ) {
+
+ pData += 4;
+ Length -= 4;
+
+ //
+ // Re-read the split flag.
+ //
+
+ NdisReadRegisterUchar(pData, &TmpUchar);
+ }
+
+ //
+ // Save off the split flag.
+ //
+
+ NewFrameInfo.SplitFlag = TmpUchar;
+
+ //
+ // Read the sequence number, which follows the split flag.
+ //
+
+ NdisReadRegisterUchar(pData + 1, &TmpUshort);
+ NdisReadRegisterUchar(pData + 2, &TmpUchar);
+ TmpUshort = TmpUshort | (TmpUchar << 8);
+ NewFrameInfo.FrameSequence = TmpUshort;
+
+ //
+ // Point pData at protocol data.
+ //
+
+ pData += 3; //... Beginning of protocol data.
+ Length -= 4; //... Length of protocol data.
+
+ //
+ // NOTE: Length is now the Length of the data portion of this packet
+ //
+
+#if DBG
+ if ( AfilterDebugFlag ){
+
+ DbgPrint("ArcFilter: Frame received: SourceId= %#1x\nDestId=%#1x\nProtId=%#1x\nSplitFlag=%#1x\nFrameSeq=%d\n",
+ (USHORT)NewFrameInfo.ProtHeader.SourceId[0],
+ (USHORT)NewFrameInfo.ProtHeader.DestId[0],
+ (USHORT)NewFrameInfo.ProtHeader.ProtId,
+ (USHORT)NewFrameInfo.SplitFlag,
+ NewFrameInfo.FrameSequence
+ );
+ DbgPrint("ArcFilter: Data at address: %lx, Length = %ld\n", pData, Length);
+
+ }
+#endif
+
+ FrameOk = TRUE;
+ NewFrame = TRUE;
+ LastFrame = TRUE;
+
+ PrevPacket = NULL;
+ Packet = Filter->OutstandingPackets;
+
+ //
+ // Walk throgh all outstanding packet to see if this frame belongs to any one of them
+ //
+
+ while ( Packet != NULL ) {
+
+ if (Packet->Header.ProtHeader.SourceId[0] == NewFrameInfo.ProtHeader.SourceId[0]){
+
+ //
+ // A packet received from the same source, check packet Sequence number and throw away
+ // outstanding packet if they don't match. We are allowed to do this since we know
+ // all the frames belonging to one packet are sent before starting a new packet. We
+ // HAVE to do this, because this is how we find out that a send at the other end, was aborted
+ // after some of the frames were already sent and received here.
+ //
+
+ if(Packet->Header.FrameSequence == NewFrameInfo.FrameSequence &&
+ Packet->Header.ProtHeader.DestId[0] == NewFrameInfo.ProtHeader.DestId[0] &&
+ Packet->Header.ProtHeader.ProtId == NewFrameInfo.ProtHeader.ProtId){
+
+ //
+ // We found a packet that this frame belongs to, check split flag
+ //
+ if (Packet->Header.FramesReceived * 2 == NewFrameInfo.SplitFlag){
+
+ //
+ // A packet found for this frame and SplitFlag is OK, check to see if it is
+ // the last frame of the packet
+ //
+ NewFrame = FALSE;
+ LastFrame = (BOOLEAN)(NewFrameInfo.SplitFlag == Packet->Header.LastSplitFlag);
+
+ } else {
+
+ //
+ // compare current split flag with the one from the last frame, if not equal
+ // the whole packet should be dropped.
+ //
+
+ if (Packet->Header.SplitFlag != NewFrameInfo.SplitFlag){
+
+ //
+ // Corrupted incomplete packet, get rid of it, but keep the new frame
+ // and we will re-use this Packet pointer.
+ //
+ ArcDiscardPacketBuffers(Filter, Packet);
+ break;
+
+ } else {
+
+ //
+ // We see to have received a duplicate frame. Ignore it.
+ //
+ return;
+
+ }
+
+ }
+
+ } else {
+
+ //
+ // We received a frame from a source that already has an incomplete packet outstanding
+ // But Frame Seq. or DestId or ProtId are not the same.
+ // We have to discard the old packet and check the new frame for validity,
+ // we will re-use this packet pointer below.
+ //
+ ArcDiscardPacketBuffers(Filter, Packet);
+
+ }
+
+ break;
+
+ } else {
+
+ PrevPacket = Packet;
+ Packet = Packet->Next;
+
+ }
+
+ }
+
+
+ if (NewFrame) {
+
+ //
+ // first frame of a packet, split flag must be odd or zero
+ // NewFrame is already TRUE
+ // LastFrame is already TRUE
+ //
+ if (NewFrameInfo.SplitFlag) {
+
+ if (!(NewFrameInfo.SplitFlag & 0x01)) {
+
+ //
+ // This frame is the middle of another split, but we
+ // don't have it on file. Drop the frame.
+ //
+ return;
+
+ }
+
+ //
+ // First Frame of a multiple frame packet
+ //
+ NewFrameInfo.LastSplitFlag = NewFrameInfo.SplitFlag + 1;
+ NewFrameInfo.FramesReceived = 1;
+ LastFrame = FALSE; // New packet and SplitFlag not zero
+
+ } else {
+
+ //
+ // The frame is fully contained in this packet.
+ //
+ }
+
+ //
+ // allocate a new packet descriptor if it is a new packet
+ //
+ if (Packet == NULL) {
+
+ if (Filter->FreePackets == NULL) {
+
+ ArcAllocatePackets(Filter);
+
+ if (Filter->FreePackets == NULL) {
+
+ return;
+
+ }
+
+ }
+
+ Packet = Filter->FreePackets;
+ Filter->FreePackets = Packet->Next;
+
+ if (!LastFrame) {
+
+ //
+ // Insert the packet in list of outstanding packets
+ //
+ Packet->Next = Filter->OutstandingPackets;
+ Filter->OutstandingPackets = Packet;
+
+ }
+
+ } else {
+
+ if (LastFrame) {
+
+ //
+ // remove it from the list
+ //
+ if (PrevPacket == NULL) {
+
+ Filter->OutstandingPackets = Packet->Next;
+
+ } else {
+
+ PrevPacket->Next = Packet->Next;
+
+ }
+
+ }
+
+ }
+
+ Packet->Header = NewFrameInfo;
+
+ } else {
+
+ if (LastFrame) {
+
+ //
+ // Remove it from the queue
+ //
+
+ if (PrevPacket == NULL) {
+
+ Filter->OutstandingPackets = Packet->Next;
+
+ } else {
+
+ PrevPacket->Next = Packet->Next;
+
+ }
+
+ }
+
+ Packet->Header.FramesReceived++;
+
+ //
+ // keep track of last split flag to detect duplicate frames
+ //
+ Packet->Header.SplitFlag=NewFrameInfo.SplitFlag;
+
+ }
+
+ //
+ // At this point we know Packet points to the packet to receive
+ // the buffer into. If this is the LastFrame, then Packet will
+ // have been removed from the OutstandingPackets list, otw it will
+ // be in the list.
+ //
+ // Now get around to getting space for the buffer.
+ //
+
+ //
+ // Find the last buffer in the packet
+ //
+ Buffer = Packet->LastBuffer;
+
+ if (Buffer == NULL) {
+
+ //
+ // Allocate a new buffer to hold the packet
+ //
+ if (Filter->FreeBufferList == NULL) {
+
+ if (ArcAllocateBuffers(Filter) != NDIS_STATUS_SUCCESS) {
+
+ ArcDiscardPacketBuffers(Filter,Packet);
+ //
+ // Do not have to discard any packet that may have
+ // been allocated above, as it will get discarded
+ // the next time a packet comes in from that source.
+ //
+ return;
+
+ }
+
+ }
+
+ Buffer = Filter->FreeBufferList;
+ Filter->FreeBufferList = Buffer->Next;
+
+ Packet->FirstBuffer = Packet->LastBuffer = Buffer;
+ Buffer->Next = NULL;
+
+ }
+
+ // Copy the data off into the ARC_PACKET list.
+ // If it doesn't fit within the current buffer, we'll need to
+ // allocate more
+
+ TmpLength = Length;
+
+ while ( Buffer->BytesLeft < TmpLength ) {
+
+ //
+ // Copy the data
+ //
+
+ NdisMoveFromMappedMemory(
+ (PUCHAR) Buffer->Buffer + (Buffer->Size - Buffer->BytesLeft),
+ pData,
+ Buffer->BytesLeft
+ );
+
+ pData += Buffer->BytesLeft;
+ TmpLength -= Buffer->BytesLeft;
+ Buffer->BytesLeft = 0;
+
+ //
+ // Need to allocate more
+ //
+ if (Filter->FreeBufferList == NULL) {
+
+ if (ArcAllocateBuffers(Filter) != NDIS_STATUS_SUCCESS) {
+
+ ArcDiscardPacketBuffers(Filter,Packet);
+ //
+ // Do not have to discard any packet that may have
+ // been allocated above, as it will get discarded
+ // the next time a packet comes in from that source.
+ //
+ return;
+
+ }
+
+ }
+
+ Buffer->Next = Filter->FreeBufferList;
+ Filter->FreeBufferList = Filter->FreeBufferList->Next;
+ Buffer = Buffer->Next;
+ Buffer->Next = NULL;
+
+ Packet->LastBuffer->Next = Buffer;
+ Packet->LastBuffer = Buffer;
+ }
+
+ //
+ // Copy the last bit
+ //
+
+ NdisMoveFromMappedMemory(
+ (PUCHAR) Buffer->Buffer + (Buffer->Size - Buffer->BytesLeft),
+ pData,
+ TmpLength
+ );
+
+
+ Buffer->BytesLeft -= TmpLength;
+ Packet->TotalLength += Length;
+
+ //
+ // And now we can start indicating the packet to the bindings that want it
+ //
+
+ if (LastFrame){
+
+ ArcFilterDoIndication(
+ Filter,
+ Packet
+ );
+
+ ArcDestroyPacket(Filter, Packet);
+
+ }
+
+}
+
+
+
+BOOLEAN
+ArcCreateFilter(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN ARC_FILTER_CHANGE FilterChangeAction,
+ IN ARC_DEFERRED_CLOSE CloseAction,
+ UCHAR AdapterAddress,
+ IN PNDIS_SPIN_LOCK Lock,
+ OUT PARC_FILTER *Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to create and initialize the Arcnet filter database.
+
+Arguments:
+
+ Miniport - Pointer to the mini-port object.
+
+ ChangeAction - Action routine to call when a binding sets or clears
+ a particular filter class and it is the first or only binding using
+ the filter class.
+
+ CloseAction - This routine is called if a binding closes while
+ it is being indicated to via NdisIndicateReceive. It will be
+ called upon return from NdisIndicateReceive.
+
+ AdapterAddress - the address of the adapter associated with this filter
+ database.
+
+ Lock - Pointer to the lock that should be held when mutual exclusion
+ is required.
+
+ Filter - A pointer to an ARC_FILTER. This is what is allocated and
+ created by this routine.
+
+Return Value:
+
+ If the function returns false then one of the parameters exceeded
+ what the filter was willing to support.
+
+--*/
+
+{
+
+ PARC_FILTER LocalFilter;
+ NDIS_STATUS AllocStatus;
+
+ //
+ // Allocate the database and it's associated arrays.
+ //
+
+ AllocStatus = NdisAllocateMemory(&LocalFilter, sizeof(ARC_FILTER), 0, HighestAcceptableMax);
+ *Filter = LocalFilter;
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+ return FALSE;
+ }
+
+ NdisZeroMemory(
+ LocalFilter,
+ sizeof(ARC_FILTER)
+ );
+
+ LocalFilter->Miniport = Miniport;
+ LocalFilter->FreeBindingMask = (ULONG)(-1);
+ LocalFilter->OpenList = NULL;
+ LocalFilter->AdapterAddress = AdapterAddress ;
+ LocalFilter->Lock = Lock;
+ LocalFilter->FilterChangeAction = FilterChangeAction;
+ LocalFilter->CloseAction = CloseAction;
+
+ NdisAllocateBufferPool(
+ &AllocStatus,
+ (PNDIS_HANDLE)(&LocalFilter->ReceiveBufferPool),
+ ARC_RECEIVE_BUFFERS
+ );
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+ NdisFreeMemory(LocalFilter, sizeof(ARC_FILTER), 0);
+ return(FALSE);
+ }
+
+ ArcReferencePackage();
+
+ return TRUE;
+
+}
+
+//
+// NOTE: THIS CANNOT BE PAGEABLE
+//
+VOID
+ArcDeleteFilter(
+ IN PARC_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to delete the memory associated with a filter
+ database. Note that this routines *ASSUMES* that the database
+ has been cleared of any active filters.
+
+Arguments:
+
+ Filter - A pointer to an ARC_FILTER to be deleted.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PARC_PACKET Packet;
+ PARC_BUFFER_LIST Buffer;
+
+ ASSERT(Filter->FreeBindingMask == (MASK)-1);
+ ASSERT(Filter->OpenList == NULL);
+
+
+ NdisFreeBufferPool(Filter->ReceiveBufferPool);
+
+ //
+ // Free all ARC_PACKETS
+ //
+
+ while (Filter->OutstandingPackets != NULL) {
+
+ Packet = Filter->OutstandingPackets;
+ Filter->OutstandingPackets = Packet->Next;
+
+ //
+ // This puts all the component parts on the free lists.
+ //
+ ArcDestroyPacket(Filter, Packet);
+
+ }
+
+ while (Filter->FreePackets != NULL) {
+
+ Packet = Filter->FreePackets;
+ Filter->FreePackets = Packet->Next;
+
+ ExFreePool(Packet);
+
+ }
+
+ while (Filter->FreeBufferList) {
+
+ Buffer = Filter->FreeBufferList;
+ Filter->FreeBufferList = Buffer->Next;
+
+ ExFreePool(Buffer->Buffer);
+ ExFreePool(Buffer);
+
+ }
+
+ NdisFreeMemory(Filter, sizeof(ARC_FILTER), 0);
+
+ ArcDereferencePackage();
+
+}
+
+
+BOOLEAN
+ArcNoteFilterOpenAdapter(
+ IN PARC_FILTER Filter,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE NdisBindingContext,
+ OUT PNDIS_HANDLE NdisFilterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to add a new binding to the filter database.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE DATABASE IS LOCKED WHEN
+ IT IS CALLED.
+
+Arguments:
+
+ Filter - A pointer to the previously created and initialized filter
+ database.
+
+ MacBindingHandle - The MAC supplied value to the protocol in response
+ to a call to NdisOpenAdapter.
+
+ NdisBindingContext - An NDIS supplied value to the call to NdisOpenAdapter.
+
+ NdisFilterHandle - A pointer to this open.
+
+Return Value:
+
+ Will return false if creating a new filter index will cause the maximum
+ number of filter indexes to be exceeded.
+
+--*/
+
+{
+
+ //
+ // Will hold the value of the filter index so that we
+ // need not indirectly address through pointer parameter.
+ //
+ UINT LocalIndex;
+
+ NDIS_STATUS AllocStatus;
+
+ //
+ // Pointer to new open block.
+ //
+ PARC_BINDING_INFO LocalOpen;
+
+
+ //
+ // Get the first free binding slot and remove that slot from
+ // the free list. We check to see if the list is empty.
+ //
+
+
+ if (Filter->FreeBindingMask == 0) {
+
+ return FALSE;
+
+ }
+
+ AllocStatus = NdisAllocateMemory(
+ &LocalOpen,
+ sizeof(ARC_BINDING_INFO),
+ 0,
+ HighestAcceptableMax
+ );
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Get place for the open and insert it.
+ //
+
+ ARC_FILTER_ALLOC_OPEN(Filter, &LocalIndex);
+
+ LocalOpen->NextOpen = Filter->OpenList;
+
+ if (Filter->OpenList != NULL) {
+ Filter->OpenList->PrevOpen = LocalOpen;
+ }
+
+ LocalOpen->PrevOpen = NULL;
+
+ Filter->OpenList = LocalOpen;
+
+ LocalOpen->FilterIndex = (UCHAR)LocalIndex;
+ LocalOpen->References = 1;
+ LocalOpen->MacBindingHandle = MacBindingHandle;
+ LocalOpen->NdisBindingContext = NdisBindingContext;
+ LocalOpen->PacketFilters = 0;
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ *NdisFilterHandle = (NDIS_HANDLE)LocalOpen;
+
+ return TRUE;
+
+}
+
+
+NDIS_STATUS
+ArcDeleteFilterOpenAdapter(
+ IN PARC_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ When an adapter is being closed this routine should
+ be called to delete knowledge of the adapter from
+ the filter database. This routine is likely to call
+ action routines associated with clearing filter classes
+ and addresses.
+
+ NOTE: THIS ROUTINE SHOULD ****NOT**** BE CALLED IF THE ACTION
+ ROUTINES FOR DELETING THE FILTER CLASSES OR THE MULTICAST ADDRESSES
+ HAVE ANY POSSIBILITY OF RETURNING A STATUS OTHER THAN NDIS_STATUS_PENDING
+ OR NDIS_STATUS_SUCCESS. WHILE THESE ROUTINES WILL NOT BUGCHECK IF
+ SUCH A THING IS DONE, THE CALLER WILL PROBABLY FIND IT DIFFICULT
+ TO CODE A CLOSE ROUTINE!
+
+ NOTE: THIS ROUTINE ASSUMES THAT IT IS CALLED WITH THE LOCK HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routines,
+ this will be passed to it.
+
+Return Value:
+
+ If action routines are called by the various address and filtering
+ routines the this routine will likely return the status returned
+ by those routines. The exception to this rule is noted below.
+
+ Given that the filter and address deletion routines return a status
+ NDIS_STATUS_PENDING or NDIS_STATUS_SUCCESS this routine will then
+ try to return the filter index to the freelist. If the routine
+ detects that this binding is currently being indicated to via
+ NdisIndicateReceive, this routine will return a status of
+ NDIS_STATUS_CLOSING_INDICATING.
+
+--*/
+
+{
+
+ //
+ // Holds the status returned from the packet filter and address
+ // deletion routines. Will be used to return the status to
+ // the caller of this routine.
+ //
+ NDIS_STATUS StatusToReturn;
+
+ //
+ // Local variable.
+ //
+ PARC_BINDING_INFO LocalOpen = (PARC_BINDING_INFO)NdisFilterHandle;
+
+ StatusToReturn = ArcFilterAdjust(
+ Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ (UINT)0,
+ FALSE
+ );
+
+ if ((StatusToReturn == NDIS_STATUS_SUCCESS) ||
+ (StatusToReturn == NDIS_STATUS_PENDING)) {
+
+ //
+ // Remove the reference from the original open.
+ //
+
+ if (--(LocalOpen->References) == 0) {
+
+ //
+ // Remove it from the list.
+ //
+
+ if (LocalOpen->NextOpen != NULL) {
+
+ LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen;
+
+ }
+
+ if (LocalOpen->PrevOpen != NULL) {
+
+ LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen;
+
+ } else {
+
+ Filter->OpenList = LocalOpen->NextOpen;
+
+ }
+
+
+ //
+ // First we finish any NdisIndicateReceiveComplete that
+ // may be needed for this binding.
+ //
+
+ if (LocalOpen->ReceivedAPacket) {
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ }
+ ARC_FILTER_FREE_OPEN(Filter, LocalOpen);
+
+ } else {
+
+ //
+ // Let the caller know that there is a reference to the open
+ // by the receive indication. The close action routine will be
+ // called upon return from NdisIndicateReceive.
+ //
+
+ StatusToReturn = NDIS_STATUS_CLOSING_INDICATING;
+
+ }
+
+ }
+
+ return StatusToReturn;
+
+}
+
+
+NDIS_STATUS
+ArcFilterAdjust(
+ IN PARC_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT FilterClasses,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ The FilterAdjust routine will call an action routine when a
+ particular filter class is changes from not being used by any
+ binding to being used by at least one binding or vice versa.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the packet filters
+ for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - A pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ FilterClasses - The filter classes that are to be added or
+ deleted.
+
+ Set - A boolean that determines whether the filter classes
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ //
+ // Contains the value of the combined filter classes before
+ // it is adjusted.
+ //
+ UINT OldCombined = Filter->CombinedPacketFilter;
+
+ PARC_BINDING_INFO LocalOpen = (PARC_BINDING_INFO)NdisFilterHandle;
+ PARC_BINDING_INFO OpenList;
+
+ //
+ // Contains the value of the particlar opens packet filters
+ // prior to the change. We save this incase the action
+ // routine (if called) returns an "error" status.
+ //
+ UINT OldOpenFilters = LocalOpen->PacketFilters;
+
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfAdjust;
+
+ //
+ // Set the new filter information for the open.
+ //
+
+ LocalOpen->PacketFilters = FilterClasses;
+
+ //
+ // We always have to reform the compbined filter since
+ // this filter index may have been the only filter index
+ // to use a particular bit.
+ //
+
+
+ for (
+ OpenList = Filter->OpenList,
+ Filter->CombinedPacketFilter = 0;
+ OpenList != NULL;
+ OpenList = OpenList->NextOpen
+ ) {
+
+ Filter->CombinedPacketFilter |=
+ OpenList->PacketFilters;
+
+ }
+
+ if (OldCombined != Filter->CombinedPacketFilter) {
+
+ StatusOfAdjust = Filter->FilterChangeAction(
+ OldCombined,
+ Filter->CombinedPacketFilter,
+ LocalOpen->MacBindingHandle,
+ NdisRequest,
+ Set
+ );
+
+ if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) &&
+ (StatusOfAdjust != NDIS_STATUS_PENDING)) {
+
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+
+ LocalOpen->PacketFilters = OldOpenFilters;
+ Filter->CombinedPacketFilter = OldCombined;
+
+ }
+
+ } else {
+
+ StatusOfAdjust = NDIS_STATUS_SUCCESS;
+
+ }
+
+ return StatusOfAdjust;
+
+}
+
+
+VOID
+ArcFilterDoIndication(
+ IN PARC_FILTER Filter,
+ IN PARC_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the filter package only to indicate
+ that a packet is ready to be indicated to procotols.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ Packet - Packet to indicate.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Will hold the type of address that we know we've got.
+ //
+ UINT AddressType;
+
+ NDIS_STATUS StatusOfReceive;
+
+ //
+ // Will hold the filter classes of the binding being indicated.
+ //
+ UINT BindingFilters;
+
+ //
+ // Current Open to indicate to.
+ //
+ PARC_BINDING_INFO LocalOpen;
+
+ if (Packet->Header.ProtHeader.DestId[0] != 0x00) {
+ AddressType = NDIS_PACKET_TYPE_DIRECTED;
+ } else {
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+ }
+
+ //
+ // We need to acquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+
+ LocalOpen = Filter->OpenList;
+
+ if (!ArcConvertToNdisPacket(Filter, Packet, TRUE)) {
+
+ //
+ // Out of resources, abort.
+ //
+ return;
+
+ }
+
+ while (LocalOpen != NULL) {
+
+ //
+ // Reference the open during indication.
+ //
+
+ BindingFilters = LocalOpen->PacketFilters;
+
+ if (BindingFilters & AddressType){
+
+ LocalOpen->References++;
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ //
+ // Indicate the packet to the binding.
+ //
+ FilterIndicateReceive(
+ &StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ &Packet->TmpNdisPacket,
+ &(Packet->Header.ProtHeader),
+ 3,
+ Packet->FirstBuffer->Buffer,
+ Packet->FirstBuffer->Size - Packet->FirstBuffer->BytesLeft,
+ Packet->TotalLength
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ if ((--(LocalOpen->References)) == 0) {
+
+ PARC_BINDING_INFO NextOpen = LocalOpen->NextOpen;
+
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+
+ //
+ // Remove it from the list.
+ //
+
+ if (LocalOpen->NextOpen != NULL) {
+
+ LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen;
+
+ }
+
+ if (LocalOpen->PrevOpen != NULL) {
+
+ LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen;
+
+ } else {
+
+ Filter->OpenList = LocalOpen->NextOpen;
+
+ }
+
+
+
+ //
+ // Call the IndicateComplete routine.
+ //
+
+
+ if (LocalOpen->ReceivedAPacket) {
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ }
+
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+
+ Filter->CloseAction(LocalOpen->MacBindingHandle);
+
+
+ ARC_FILTER_FREE_OPEN(Filter, LocalOpen);
+
+ LocalOpen = NextOpen;
+
+ continue;
+
+ } // end of if binding is shutting down
+
+ } // end of if any binding wants the packet
+
+ LocalOpen = LocalOpen->NextOpen;
+
+ } // end of there are more open bindings
+
+}
+
+
+VOID
+ArcFilterDprIndicateReceiveComplete(
+ IN PARC_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by to indicate that the receive
+ process is complete to all bindings. Only those bindings which
+ have received packets will be notified.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PARC_BINDING_INFO LocalOpen;
+
+ //
+ // We need to acquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+
+ LocalOpen = Filter->OpenList;
+
+ while (LocalOpen != NULL) {
+
+ if (LocalOpen->ReceivedAPacket) {
+
+ //
+ // Indicate the binding.
+ //
+
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ LocalOpen->References++;
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ if ((--(LocalOpen->References)) == 0) {
+
+ PARC_BINDING_INFO NextOpen = LocalOpen->NextOpen;
+
+ //
+ // This binding is shutting down. We have to kill it.
+ //
+
+ //
+ // Remove it from the list.
+ //
+
+ if (LocalOpen->NextOpen != NULL) {
+
+ LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen;
+
+ }
+
+ if (LocalOpen->PrevOpen != NULL) {
+
+ LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen;
+
+ } else {
+
+ Filter->OpenList = LocalOpen->NextOpen;
+
+ }
+
+
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+
+ Filter->CloseAction(LocalOpen->MacBindingHandle);
+
+
+ ARC_FILTER_FREE_OPEN(Filter, LocalOpen);
+
+ LocalOpen = NextOpen;
+
+ continue;
+
+ }
+
+ }
+
+ LocalOpen = LocalOpen->NextOpen;
+
+ }
+
+}
+
+
+NDIS_STATUS ArcConvertOidListToEthernet(
+ IN PNDIS_OID pOidList,
+ IN PULONG pcOidList,
+ IN PNDIS_OID pTmpBuffer
+)
+
+/*++
+
+Routine Description:
+
+ This routine converts an arcnet supported OID list into
+ an ethernet OID list by replacing or removing arcnet
+ OID's.
+
+Arguments:
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG c;
+ ULONG cArcOids;
+ ULONG cMaxOids;
+ NDIS_OID EthernetOidList[ARC_NUMBER_OF_EXTRA_OIDS] = {
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE
+ };
+
+ //
+ // Now we need to copy the returned results into the callers buffer,
+ // removing arcnet OID's and adding in ethernet OID's. At this point
+ // we do not know if the callers buffer is big enough since we may
+ // remove some entries, checking it up front may not yield correct
+ // results (i.e. it may actually be big enough).
+ //
+ for (c = 0, cArcOids = 0; c < *pcOidList; c++)
+ {
+ switch (pOidList[c])
+ {
+ case OID_ARCNET_PERMANENT_ADDRESS:
+ pTmpBuffer[cArcOids++] = OID_802_3_PERMANENT_ADDRESS;
+ break;
+
+ case OID_ARCNET_CURRENT_ADDRESS:
+ pTmpBuffer[cArcOids++] = OID_802_3_CURRENT_ADDRESS;
+ break;
+
+ case OID_ARCNET_RECONFIGURATIONS:
+ break;
+
+ default:
+ if ((pOidList[c] & 0xFFF00000) != 0x06000000)
+ pTmpBuffer[cArcOids++] = pOidList[c];
+
+ break;
+ }
+ }
+
+ //
+ // Copy the ARCnet OIDs from the temp buffer to the
+ // callers buffer.
+ //
+ RtlCopyMemory(pOidList, pTmpBuffer, cArcOids * sizeof(NDIS_OID));
+
+ //
+ // Add the ethernet OIDs.
+ //
+ RtlCopyMemory(
+ (PUCHAR)pOidList + (cArcOids * sizeof(NDIS_OID)),
+ EthernetOidList,
+ ARC_NUMBER_OF_EXTRA_OIDS * sizeof(NDIS_OID)
+ );
+
+ //
+ // Update the size of the buffer to send back to the caller.
+ //
+ *pcOidList = cArcOids + ARC_NUMBER_OF_EXTRA_OIDS;
+
+ return(NDIS_STATUS_SUCCESS);
+}
diff --git a/private/ntos/ndis/ndis30/afilter.h b/private/ntos/ndis/ndis30/afilter.h
new file mode 100644
index 000000000..1bfa9e97f
--- /dev/null
+++ b/private/ntos/ndis/ndis30/afilter.h
@@ -0,0 +1,339 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ afilter.h
+
+Abstract:
+
+ Header file for the address filtering library for NDIS MAC's.
+
+Author:
+
+ Alireza Dabagh creation-date 3-22-1993, mostly borrowed from efilter.h
+
+Revision History:
+
+--*/
+
+#ifndef _ARC_FILTER_DEFS_
+#define _ARC_FILTER_DEFS_
+
+//
+// Number of Ndis buffers in the buffer pool
+//
+#define ARC_RECEIVE_BUFFERS 64
+
+//
+// Linked list Structure for keeping track of allocated memory so we can free them later
+//
+typedef struct _ARC_BUFFER_LIST{
+ PVOID Buffer;
+ UINT Size;
+ UINT BytesLeft;
+ struct _ARC_BUFFER_LIST *Next;
+} ARC_BUFFER_LIST, *PARC_BUFFER_LIST;
+
+//
+// This is the structure that is passed to the protocol as the packet
+// header during receive indication. It is also the header expected from the protocol.
+// This header is NOT the same as the header passed to the mac driver
+//
+
+#define ARCNET_ADDRESS_LEN 1
+
+typedef struct _ARC_PROTOCOL_HEADER {
+ UCHAR SourceId[ARCNET_ADDRESS_LEN]; // Source Address
+ UCHAR DestId[ARCNET_ADDRESS_LEN]; // Destination Address
+ UCHAR ProtId; // Protocol ID
+} ARC_PROTOCOL_HEADER, *PARC_PROTOCOL_HEADER;
+
+//
+// This structure keeps track of information about a received packet
+//
+typedef struct _ARC_PACKET_HEADER {
+ ARC_PROTOCOL_HEADER ProtHeader; // Protocol header
+ USHORT FrameSequence; // Frame sequence Number
+ UCHAR SplitFlag; // Split flag
+ UCHAR LastSplitFlag; // Split Flag for the last frame
+ UCHAR FramesReceived; // Frames in This Packet
+} ARC_PACKET_HEADER, * PARC_PACKET_HEADER;
+
+//
+// Arcnet specific packet header
+//
+typedef struct _ARC_PACKET {
+ ARC_PACKET_HEADER Header; // Information about the packet
+ struct _ARC_PACKET * Next; // Next packet in use by filter
+ ULONG TotalLength;
+ BOOLEAN LastFrame;
+ PARC_BUFFER_LIST FirstBuffer;
+ PARC_BUFFER_LIST LastBuffer;
+ NDIS_PACKET TmpNdisPacket;
+} ARC_PACKET, * PARC_PACKET;
+
+
+#define ARC_PROTOCOL_HEADER_SIZE (sizeof(ARC_PROTOCOL_HEADER))
+#define ARC_MAX_FRAME_SIZE 504
+#define ARC_MAX_ADDRESS_IDS 256
+#define ARC_MAX_FRAME_HEADER_SIZE 6
+#define ARC_MAX_PACKET_SIZE 576
+
+
+//
+// Check whether an address is broadcast.
+//
+
+#define ARC_IS_BROADCAST(Address) \
+ (BOOLEAN)(!(Address))
+
+
+//
+// An action routine type. The routines are called
+// when a filter type is set for the first time or
+// no more bindings require a particular type of filter.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+NDIS_STATUS
+(*ARC_FILTER_CHANGE)(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+
+//
+// This action routine is called when the mac requests a close for
+// a particular binding *WHILE THE BINDING IS BEING INDICATED TO
+// THE PROTOCOL*. The filtering package can't get rid of the open
+// right away. So this routine will be called as soon as the
+// NdisIndicateReceive returns.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+VOID
+(*ARC_DEFERRED_CLOSE)(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+typedef ULONG MASK,*PMASK;
+
+//
+// Maximum number of opens the filter package will support. This is
+// the max so that bit masks can be used instead of a spaghetti of
+// pointers.
+//
+#define ARC_FILTER_MAX_OPENS (sizeof(ULONG) * 8)
+
+
+//
+// The binding info is threaded on two lists. When
+// the binding is free it is on a single freelist.
+//
+// When the binding is being used it is on a doubly linked
+// index list.
+//
+typedef struct _ARC_BINDING_INFO {
+ NDIS_HANDLE MacBindingHandle;
+ NDIS_HANDLE NdisBindingContext;
+ UINT PacketFilters;
+ ULONG References;
+ struct _ARC_BINDING_INFO *NextOpen;
+ struct _ARC_BINDING_INFO *PrevOpen;
+ BOOLEAN ReceivedAPacket;
+ UCHAR FilterIndex;
+} ARC_BINDING_INFO,*PARC_BINDING_INFO;
+
+//
+// An opaque type that contains a filter database.
+// The MAC need not know how it is structured.
+//
+typedef struct _ARC_FILTER {
+
+ //
+ // For accessing the mini-port.
+ //
+ struct _NDIS_MINIPORT_BLOCK *Miniport;
+
+ //
+ // Spin lock used to protect the filter from multiple accesses.
+ //
+ PNDIS_SPIN_LOCK Lock;
+
+ //
+ // Combination of all the filters of all the open bindings.
+ //
+ UINT CombinedPacketFilter;
+
+ //
+ // Pointer for traversing the open list.
+ //
+ PARC_BINDING_INFO OpenList;
+
+ //
+ // Action routines to be invoked on notable changes in the filter.
+ //
+
+ ARC_FILTER_CHANGE FilterChangeAction;
+ ARC_DEFERRED_CLOSE CloseAction;
+
+ //
+ // Bit mask of opens that are available.
+ //
+ ULONG FreeBindingMask;
+
+ NDIS_HANDLE ReceiveBufferPool;
+
+ PARC_BUFFER_LIST FreeBufferList;
+ PARC_PACKET FreePackets;
+
+ PARC_PACKET OutstandingPackets;
+
+ //
+ // Address of the adapter.
+ //
+ UCHAR AdapterAddress;
+
+} ARC_FILTER,*PARC_FILTER;
+
+
+
+
+//
+//UINT
+//ARC_QUERY_FILTER_CLASSES(
+// IN PARC_FILTER Filter
+// )
+//
+// This macro returns the currently enabled filter classes.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define ARC_QUERY_FILTER_CLASSES(Filter) ((Filter)->CombinedPacketFilter)
+
+
+//
+//UINT
+//ARC_QUERY_PACKET_FILTER(
+// IN ARC_FILTER Filter,
+// IN NDIS_HANDLE NdisFilterHandle
+// )
+//
+// This macro returns the currently enabled filter classes for a specific
+// open instance.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define ARC_QUERY_PACKET_FILTER(Filter, NdisFilterHandle) \
+ (((PARC_BINDING_INFO)(NdisFilterHandle))->PacketFilters)
+
+//
+// Only for internal wrapper use.
+//
+VOID
+ArcInitializePackage(
+ VOID
+ );
+
+VOID
+ArcReferencePackage(
+ VOID
+ );
+
+VOID
+ArcDereferencePackage(
+ VOID
+ );
+
+
+//
+// Exported routines
+//
+
+BOOLEAN
+ArcCreateFilter(
+ IN struct _NDIS_MINIPORT_BLOCK *Miniport,
+ IN ARC_FILTER_CHANGE FilterChangeAction,
+ IN ARC_DEFERRED_CLOSE CloseAction,
+ IN UCHAR AdapterAddress,
+ IN PNDIS_SPIN_LOCK Lock,
+ OUT PARC_FILTER *Filter
+ );
+
+VOID
+ArcDeleteFilter(
+ IN PARC_FILTER Filter
+ );
+
+BOOLEAN
+ArcNoteFilterOpenAdapter(
+ IN PARC_FILTER Filter,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE NdisBindingContext,
+ OUT PNDIS_HANDLE NdisFilterHandle
+ );
+
+NDIS_STATUS
+ArcDeleteFilterOpenAdapter(
+ IN PARC_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+NDIS_STATUS
+ArcFilterAdjust(
+ IN PARC_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT FilterClasses,
+ IN BOOLEAN Set
+ );
+
+VOID
+ArcFilterDprIndicateReceiveComplete(
+ IN PARC_FILTER Filter
+ );
+
+VOID
+ArcFilterDprIndicateReceive(
+ IN PARC_FILTER Filter, // Pointer to filter database
+ IN PUCHAR pRawHeader, // Pointer to Arcnet frame header
+ IN PUCHAR pData, // Pointer to data portion of Arcnet frame
+ IN UINT Length // Data Length
+ );
+
+NDIS_STATUS
+ArcFilterTransferData(
+ IN PARC_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransfered
+ );
+
+VOID
+ArcFreeNdisPacket(
+ IN PARC_PACKET Packet
+ );
+
+VOID
+ArcFilterDoIndication(
+ IN PARC_FILTER Filter,
+ IN PARC_PACKET Packet
+ );
+
+VOID
+ArcDestroyPacket(
+ IN PARC_FILTER Filter,
+ IN PARC_PACKET Packet
+ );
+
+#endif // _ARC_FILTER_DEFS_
diff --git a/private/ntos/ndis/ndis30/efilter.c b/private/ntos/ndis/ndis30/efilter.c
new file mode 100644
index 000000000..98ebac0c3
--- /dev/null
+++ b/private/ntos/ndis/ndis30/efilter.c
@@ -0,0 +1,2252 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ efilter.c
+
+Abstract:
+
+ This module implements a set of library routines to handle packet
+ filtering for NDIS MAC drivers.
+
+Author:
+
+ Anthony V. Ercolano (Tonye) 03-Aug-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+ Adam Barr (adamba) 28-Nov-1990
+
+ - Added AddressContexts
+
+ Adam Barr (adamba) 28-May-1991
+
+ - renamed MacXXX to EthXXX, changed filter.c to efilter.c
+
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+//
+// 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);
+
+//
+// ZZZ NonPortable definitions.
+//
+#define AllocPhys(s, l) NdisAllocateMemory((PVOID *)(s), (l), 0, HighestAcceptableMax)
+#define FreePhys(s, l) NdisFreeMemory((PVOID)(s), (l), 0)
+
+#ifdef NDIS_NT
+
+#define MoveMemory(Destination,Source,Length) RtlMoveMemory(Destination,Source,Length)
+#define ZeroMemory(Destination,Length) RtlZeroMemory(Destination,Length)
+
+#endif
+
+#ifdef NDIS_DOS
+
+#define MoveMemory(Destination,Source,Length) NdisMoveOverlappedMemory(Destination,Source,Length)
+#define ZeroMemory(Destination,Length) NdisZeroMemory(Destination,Length)
+
+#endif
+
+#if DBG
+extern BOOLEAN NdisCheckBadDrivers;
+#endif
+
+//
+// A set of macros to manipulate bitmasks.
+//
+
+//VOID
+//CLEAR_BIT_IN_MASK(
+// IN UINT Offset,
+// IN OUT PETH_MASK MaskToClear
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Clear a bit in the bitmask pointed to by the parameter.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to altered.
+//
+// MaskToClear - Pointer to the mask to be adjusted.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+//
+#define CLEAR_BIT_IN_MASK(Offset,MaskToClear) *MaskToClear &= (~(1 << Offset))
+
+//VOID
+//SET_BIT_IN_MASK(
+// IN UINT Offset,
+// IN OUT PETH_MASK MaskToSet
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Set a bit in the bitmask pointed to by the parameter.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to altered.
+//
+// MaskToSet - Pointer to the mask to be adjusted.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+#define SET_BIT_IN_MASK(Offset,MaskToSet) *MaskToSet |= (1 << Offset)
+
+//BOOLEAN
+//IS_BIT_SET_IN_MASK(
+// IN UINT Offset,
+// IN ETH_MASK MaskToTest
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Tests if a particular bit in the bitmask pointed to by the parameter is
+// set.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to test.
+//
+// MaskToTest - The mask to be tested.
+//
+//Return Value:
+//
+// Returns TRUE if the bit is set.
+//
+//--*/
+#define IS_BIT_SET_IN_MASK(Offset,MaskToTest) \
+((MaskToTest & (1 << Offset))?(TRUE):(FALSE))
+
+//BOOLEAN
+//IS_MASK_CLEAR(
+// IN ETH_MASK MaskToTest
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Tests whether there are *any* bits enabled in the mask.
+//
+//Arguments:
+//
+// MaskToTest - The bit mask to test for all clear.
+//
+//Return Value:
+//
+// Will return TRUE if no bits are set in the mask.
+//
+//--*/
+#define IS_MASK_CLEAR(MaskToTest) ((!MaskToTest)?(TRUE):(FALSE))
+
+//VOID
+//CLEAR_MASK(
+// IN OUT PETH_MASK MaskToClear
+// );
+//
+///*++
+//
+//Routine Description:
+//
+// Clears a mask.
+//
+//Arguments:
+//
+// MaskToClear - The bit mask to adjust.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+#define CLEAR_MASK(MaskToClear) *MaskToClear = 0
+
+//
+// VOID
+// ETH_FILTER_ALLOC_OPEN(
+// IN PETH_FILTER Filter,
+// OUT PUINT FilterIndex
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Allocates an open block. This only allocate the index, not memory for
+// the open block.
+//
+//Arguments:
+//
+// Filter - DB from which to allocate the space
+//
+// FilterIndex - pointer to place to store the index.
+//
+//Return Value:
+//
+// FilterIndex of the new open
+//
+//--*/
+#define ETH_FILTER_ALLOC_OPEN(Filter, FilterIndex)\
+{\
+ UINT i; \
+ for (i=0; i < ETH_FILTER_MAX_OPENS; i++) { \
+ if (IS_BIT_SET_IN_MASK(i,(Filter)->FreeBindingMask)) { \
+ *(FilterIndex) = i; \
+ CLEAR_BIT_IN_MASK(i, &((Filter)->FreeBindingMask)); \
+ break; \
+ } \
+ } \
+}
+
+//
+// VOID
+// ETH_FILTER_FREE_OPEN(
+// IN PETH_FILTER Filter,
+// IN PETH_BINDING_INFO LocalOpen
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Frees an open block. Also frees the memory associated with the open.
+//
+//Arguments:
+//
+// Filter - DB from which to allocate the space
+//
+// FilterIndex - Index to free
+//
+//Return Value:
+//
+// FilterIndex of the new open
+//
+//--*/
+#define ETH_FILTER_FREE_OPEN(Filter, LocalOpen)\
+{\
+ SET_BIT_IN_MASK(((LocalOpen)->FilterIndex), &((Filter)->FreeBindingMask)); \
+ FreePhys((LocalOpen), sizeof(ETH_BINDING_INFO));\
+}
+
+
+
+NDIS_SPIN_LOCK EthReferenceLock = {0};
+KEVENT EthPagedInEvent = {0};
+ULONG EthReferenceCount = 0;
+PVOID EthImageHandle = {0};
+
+VOID
+EthInitializePackage(VOID)
+{
+ NdisAllocateSpinLock(&EthReferenceLock);
+ KeInitializeEvent(
+ &EthPagedInEvent,
+ NotificationEvent,
+ FALSE
+ );
+}
+
+VOID
+EthReferencePackage(VOID)
+{
+
+ ACQUIRE_SPIN_LOCK(&EthReferenceLock);
+
+ EthReferenceCount++;
+
+ if (EthReferenceCount == 1) {
+
+ KeResetEvent(
+ &EthPagedInEvent
+ );
+
+ RELEASE_SPIN_LOCK(&EthReferenceLock);
+
+ //
+ // Page in all the functions
+ //
+ EthImageHandle = MmLockPagableCodeSection(EthCreateFilter);
+
+ //
+ // Signal to everyone to go
+ //
+ KeSetEvent(
+ &EthPagedInEvent,
+ 0L,
+ FALSE
+ );
+
+ } else {
+
+ RELEASE_SPIN_LOCK(&EthReferenceLock);
+
+ //
+ // Wait for everything to be paged in
+ //
+ KeWaitForSingleObject(
+ &EthPagedInEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ NULL
+ );
+
+ }
+
+}
+
+VOID
+EthDereferencePackage(VOID)
+{
+ ACQUIRE_SPIN_LOCK(&EthReferenceLock);
+
+ EthReferenceCount--;
+
+ if (EthReferenceCount == 0) {
+
+ RELEASE_SPIN_LOCK(&EthReferenceLock);
+
+ //
+ // Page out all the functions
+ //
+ MmUnlockPagableImageSection(EthImageHandle);
+
+ } else {
+
+ RELEASE_SPIN_LOCK(&EthReferenceLock);
+
+ }
+
+}
+
+
+static
+BOOLEAN
+FindMulticast(
+ IN UINT NumberOfAddresses,
+ IN CHAR AddressArray[][ETH_LENGTH_OF_ADDRESS],
+ IN CHAR MulticastAddress[ETH_LENGTH_OF_ADDRESS],
+ OUT PUINT ArrayIndex
+ );
+
+
+#ifdef ALLOC_PRAGMA
+//#pragma alloc_text(PAGENDSE, EthShouldAddressLoopBack)
+#pragma alloc_text(PAGENDSE, FindMulticast)
+//#pragma alloc_text(PAGENDSE, EthFilterDprIndicateReceiveComplete)
+#pragma alloc_text(PAGENDSE, EthFilterIndicateReceiveComplete)
+//#pragma alloc_text(PAGENDSE, EthFilterDprIndicateReceive)
+#pragma alloc_text(PAGENDSE, EthFilterIndicateReceive)
+#pragma alloc_text(PAGENDSE, EthQueryGlobalFilterAddresses)
+#pragma alloc_text(PAGENDSE, EthQueryOpenFilterAddresses)
+#pragma alloc_text(PAGENDSE, EthNumberOfOpenFilterAddresses)
+#pragma alloc_text(PAGENDSE, EthFilterAdjust)
+#pragma alloc_text(PAGENDSE, EthChangeFilterAddresses)
+#pragma alloc_text(PAGENDSE, EthDeleteFilterOpenAdapter)
+#pragma alloc_text(PAGENDSE, EthNoteFilterOpenAdapter)
+#pragma alloc_text(PAGENDSE, EthCreateFilter)
+
+#endif
+
+
+
+BOOLEAN
+EthCreateFilter(
+ IN UINT MaximumMulticastAddresses,
+ IN ETH_ADDRESS_CHANGE AddressChangeAction,
+ IN ETH_FILTER_CHANGE FilterChangeAction,
+ IN ETH_DEFERRED_CLOSE CloseAction,
+ IN PUCHAR AdapterAddress,
+ IN PNDIS_SPIN_LOCK Lock,
+ OUT PETH_FILTER *Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to create and initialize the filter database.
+
+Arguments:
+
+ MaximumMulticastAddresses - The maximum number of multicast addresses
+ that the MAC will support.
+
+ AddressChangeAction - Action routine to call when the list of
+ multicast addresses the card must enable has changed.
+
+ ChangeAction - Action routine to call when a binding sets or clears
+ a particular filter class and it is the first or only binding using
+ the filter class.
+
+ CloseAction - This routine is called if a binding closes while
+ it is being indicated to via NdisIndicateReceive. It will be
+ called upon return from NdisIndicateReceive.
+
+ AdapterAddress - the address of the adapter associated with this filter
+ database.
+
+ Lock - Pointer to the lock that should be held when mutual exclusion
+ is required.
+
+ Filter - A pointer to an ETH_FILTER. This is what is allocated and
+ created by this routine.
+
+Return Value:
+
+ If the function returns false then one of the parameters exceeded
+ what the filter was willing to support.
+
+--*/
+
+{
+
+ PETH_FILTER LocalFilter;
+ NDIS_STATUS AllocStatus;
+
+ //
+ // Allocate the database and it's associated arrays.
+ //
+
+ AllocStatus = AllocPhys(&LocalFilter, sizeof(ETH_FILTER));
+ *Filter = LocalFilter;
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+ return FALSE;
+ }
+
+ ZeroMemory(
+ LocalFilter,
+ sizeof(ETH_FILTER)
+ );
+
+ if (MaximumMulticastAddresses == 0) {
+
+ //
+ // Why 2 and not 1? Why not. A protocol is going to need at least
+ // one to run on this, so let's give one extra one for any user stuff
+ // that may need it.
+ //
+
+ MaximumMulticastAddresses = 2;
+
+ }
+
+ {
+ PVOID TmpAlloc;
+
+ AllocStatus = AllocPhys(
+ &TmpAlloc,
+ 2*ETH_LENGTH_OF_ADDRESS*MaximumMulticastAddresses
+ );
+
+ LocalFilter->MulticastAddresses = TmpAlloc;
+
+ }
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+ EthDeleteFilter(LocalFilter);
+ return FALSE;
+
+ }
+
+ AllocStatus = AllocPhys(
+ &LocalFilter->BindingsUsingAddress,
+ 2*sizeof(ETH_MASK)*MaximumMulticastAddresses
+ );
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+ EthDeleteFilter(LocalFilter);
+ return FALSE;
+
+ }
+
+ EthReferencePackage();
+
+ LocalFilter->FreeBindingMask = (ULONG)(-1);
+ LocalFilter->OpenList = NULL;
+
+ ETH_COPY_NETWORK_ADDRESS(LocalFilter->AdapterAddress, AdapterAddress);
+ LocalFilter->Lock = Lock;
+ LocalFilter->AddressChangeAction = AddressChangeAction;
+ LocalFilter->FilterChangeAction = FilterChangeAction;
+ LocalFilter->CloseAction = CloseAction;
+ LocalFilter->NumberOfAddresses = 0;
+ LocalFilter->MaximumMulticastAddresses = MaximumMulticastAddresses;
+
+ return TRUE;
+}
+
+
+//
+// NOTE: THIS FUNCTION CANNOT BE PAGEABLE
+//
+VOID
+EthDeleteFilter(
+ IN PETH_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to delete the memory associated with a filter
+ database. Note that this routines *ASSUMES* that the database
+ has been cleared of any active filters.
+
+Arguments:
+
+ Filter - A pointer to an ETH_FILTER to be deleted.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ASSERT(Filter->FreeBindingMask == (ETH_MASK)-1);
+ ASSERT(Filter->OpenList == NULL);
+
+ if (Filter->MulticastAddresses) {
+
+ FreePhys(
+ Filter->MulticastAddresses,
+ 2*ETH_LENGTH_OF_ADDRESS*Filter->MaximumMulticastAddresses
+ );
+
+ }
+
+ if (Filter->BindingsUsingAddress) {
+
+ FreePhys(
+ Filter->BindingsUsingAddress,
+ 2*sizeof(ETH_MASK)*Filter->MaximumMulticastAddresses
+ );
+
+ }
+
+ FreePhys(Filter, sizeof(ETH_FILTER));
+
+ EthDereferencePackage();
+
+}
+
+
+BOOLEAN
+EthNoteFilterOpenAdapter(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE NdisBindingContext,
+ OUT PNDIS_HANDLE NdisFilterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to add a new binding to the filter database.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE DATABASE IS LOCKED WHEN
+ IT IS CALLED.
+
+Arguments:
+
+ Filter - A pointer to the previously created and initialized filter
+ database.
+
+ MacBindingHandle - The MAC supplied value to the protocol in response
+ to a call to EthOpenAdapter.
+
+ NdisBindingContext - An NDIS supplied value to the call to EthOpenAdapter.
+
+ NdisFilterHandle - A pointer to this open.
+
+Return Value:
+
+ Will return false if creating a new filter index will cause the maximum
+ number of filter indexes to be exceeded.
+
+--*/
+
+{
+
+ //
+ // Will hold the value of the filter index so that we
+ // need not indirectly address through pointer parameter.
+ //
+ UINT LocalIndex;
+
+ NDIS_STATUS AllocStatus;
+
+ //
+ // Pointer to new open block.
+ //
+ PETH_BINDING_INFO LocalOpen;
+
+ PNDIS_OPEN_BLOCK NdisOpen = (PNDIS_OPEN_BLOCK)NdisBindingContext;
+
+ //
+ // Get the first free binding slot and remove that slot from
+ // the free list. We check to see if the list is empty.
+ //
+
+
+ if (Filter->FreeBindingMask == 0) {
+
+ return FALSE;
+
+ }
+
+ AllocStatus = AllocPhys(
+ &LocalOpen,
+ sizeof(ETH_BINDING_INFO)
+ );
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Get place for the open and insert it.
+ //
+
+ ETH_FILTER_ALLOC_OPEN(Filter, &LocalIndex);
+
+ LocalOpen->NextOpen = Filter->OpenList;
+
+ if (Filter->OpenList != NULL) {
+ Filter->OpenList->PrevOpen = LocalOpen;
+ }
+
+ LocalOpen->PrevOpen = NULL;
+
+ Filter->OpenList = LocalOpen;
+
+ LocalOpen->FilterIndex = (UCHAR)LocalIndex;
+ LocalOpen->References = 1;
+ LocalOpen->MacBindingHandle = MacBindingHandle;
+ LocalOpen->NdisBindingContext = NdisBindingContext;
+ LocalOpen->PacketFilters = 0;
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ *NdisFilterHandle = (NDIS_HANDLE)LocalOpen;
+
+ return TRUE;
+
+}
+
+
+NDIS_STATUS
+EthDeleteFilterOpenAdapter(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ When an adapter is being closed this routine should
+ be called to delete knowledge of the adapter from
+ the filter database. This routine is likely to call
+ action routines associated with clearing filter classes
+ and addresses.
+
+ NOTE: THIS ROUTINE SHOULD ****NOT**** BE CALLED IF THE ACTION
+ ROUTINES FOR DELETING THE FILTER CLASSES OR THE MULTICAST ADDRESSES
+ HAVE ANY POSSIBILITY OF RETURNING A STATUS OTHER THAN NDIS_STATUS_PENDING
+ OR NDIS_STATUS_SUCCESS. WHILE THESE ROUTINES WILL NOT BUGCHECK IF
+ SUCH A THING IS DONE, THE CALLER WILL PROBABLY FIND IT DIFFICULT
+ TO CODE A CLOSE ROUTINE!
+
+ NOTE: THIS ROUTINE ASSUMES THAT IT IS CALLED WITH THE LOCK HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routines,
+ this will be passed to it.
+
+Return Value:
+
+ If action routines are called by the various address and filtering
+ routines the this routine will likely return the status returned
+ by those routines. The exception to this rule is noted below.
+
+ Given that the filter and address deletion routines return a status
+ NDIS_STATUS_PENDING or NDIS_STATUS_SUCCESS this routine will then
+ try to return the filter index to the freelist. If the routine
+ detects that this binding is currently being indicated to via
+ NdisIndicateReceive, this routine will return a status of
+ NDIS_STATUS_CLOSING_INDICATING.
+
+--*/
+
+{
+
+ //
+ // Holds the status returned from the packet filter and address
+ // deletion routines. Will be used to return the status to
+ // the caller of this routine.
+ //
+ NDIS_STATUS StatusToReturn;
+
+ //
+ // Local variable.
+ //
+ PETH_BINDING_INFO LocalOpen = (PETH_BINDING_INFO)NdisFilterHandle;
+
+ StatusToReturn = EthFilterAdjust(
+ Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ (UINT)0,
+ FALSE
+ );
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS ||
+ StatusToReturn == NDIS_STATUS_PENDING) {
+
+ NDIS_STATUS StatusToReturn2;
+
+ StatusToReturn2 = EthChangeFilterAddresses(
+ Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ 0,
+ NULL,
+ FALSE
+ );
+
+ if (StatusToReturn2 != NDIS_STATUS_SUCCESS) {
+
+ StatusToReturn = StatusToReturn2;
+
+ }
+
+ }
+
+
+ if ((StatusToReturn == NDIS_STATUS_SUCCESS) ||
+ (StatusToReturn == NDIS_STATUS_PENDING)) {
+
+ //
+ // Remove the reference from the original open.
+ //
+
+ if (--(LocalOpen->References) == 0) {
+
+ //
+ // Remove it from the list.
+ //
+
+ if (LocalOpen->NextOpen != NULL) {
+
+ LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen;
+
+ }
+
+ if (LocalOpen->PrevOpen != NULL) {
+
+ LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen;
+
+ } else {
+
+ Filter->OpenList = LocalOpen->NextOpen;
+
+ }
+
+
+ //
+ // First we finish any NdisIndicateReceiveComplete that
+ // may be needed for this binding.
+ //
+
+ if (LocalOpen->ReceivedAPacket) {
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ }
+
+ ETH_FILTER_FREE_OPEN(Filter, LocalOpen);
+
+ } else {
+
+ //
+ // Let the caller know that there is a reference to the open
+ // by the receive indication. The close action routine will be
+ // called upon return from NdisIndicateReceive.
+ //
+
+ StatusToReturn = NDIS_STATUS_CLOSING_INDICATING;
+
+ }
+
+ }
+
+ return StatusToReturn;
+
+}
+
+
+NDIS_STATUS
+EthChangeFilterAddresses(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT AddressCount,
+ IN CHAR Addresses[][ETH_LENGTH_OF_ADDRESS],
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ The ChangeFilterAddress routine will call an action
+ routine when the overall multicast address list for the adapter
+ has changed.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the multicast address
+ list for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ AddressCount - The number of elements (addresses,
+ not bytes) in MulticastAddressList.
+
+ Addresses - The new multicast address list for this
+ binding. This is a sequence of ETH_LENGTH_OF_ADDRESS byte
+ addresses, with no padding between them.
+
+ Set - A boolean that determines whether the multicast addresses
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfChange;
+
+ //
+ // Saves the original length of the address array.
+ //
+ UINT InitialArraySize;
+
+ //
+ // Set true when the address array changes
+ //
+ UINT AddressesChanged = 0;
+
+ //
+ // Use to save data if needed.
+ //
+ PVOID TmpAddressArray, TmpMaskArray;
+
+ //
+ // Simple iteration variables.
+ //
+ UINT ArrayIndex, i;
+
+
+ //
+ // Simple Temp variable
+ //
+ PCHAR CurrentAddress;
+
+ PETH_BINDING_INFO LocalOpen = (PETH_BINDING_INFO)NdisFilterHandle;
+
+
+ TmpAddressArray =
+ (PUCHAR)Filter->MulticastAddresses +
+ (ETH_LENGTH_OF_ADDRESS*Filter->MaximumMulticastAddresses);
+
+ TmpMaskArray =
+ (PUCHAR)Filter->BindingsUsingAddress +
+ (sizeof(ETH_MASK)*Filter->MaximumMulticastAddresses);
+
+
+ //
+ // We have to save the old mask array in
+ // case we need to restore it. If we need
+ // to save the address array too we will
+ // do that later.
+ //
+
+ MoveMemory(
+ TmpMaskArray,
+ (PVOID)Filter->BindingsUsingAddress,
+ Filter->NumberOfAddresses * sizeof(ETH_MASK)
+ );
+
+ //
+ // We have to save the old address array in
+ // case we need to restore it. If we need
+ // to save the address array too we will
+ // do that later.
+ //
+
+ MoveMemory(
+ TmpAddressArray,
+ (PVOID)Filter->MulticastAddresses,
+ Filter->NumberOfAddresses * ETH_LENGTH_OF_ADDRESS
+ );
+
+ InitialArraySize = Filter->NumberOfAddresses;
+
+
+ //
+ // Now modify the original array...
+ //
+
+ //
+ // First go through and turn off the bit for this
+ // binding throughout the array.
+ //
+
+ for (i=0; i<(Filter->NumberOfAddresses); i++) {
+
+ CLEAR_BIT_IN_MASK(
+ LocalOpen->FilterIndex,
+ &(Filter->BindingsUsingAddress[i])
+ );
+
+ }
+
+ //
+ // First we have to remove any addresses from
+ // the multicast array if they have no bits on any more.
+ //
+ for (ArrayIndex = 0; ArrayIndex < Filter->NumberOfAddresses; ) {
+
+ if (IS_MASK_CLEAR(Filter->BindingsUsingAddress[ArrayIndex])) {
+
+ //
+ // yes it is clear, so we have to shift everything
+ // above it down one.
+ //
+
+ MoveMemory(
+ Filter->MulticastAddresses[ArrayIndex],
+ Filter->MulticastAddresses[ArrayIndex+1],
+ (Filter->NumberOfAddresses-(ArrayIndex+1))
+ *ETH_LENGTH_OF_ADDRESS
+ );
+
+ MoveMemory(
+ &Filter->BindingsUsingAddress[ArrayIndex],
+ &Filter->BindingsUsingAddress[ArrayIndex+1],
+ (Filter->NumberOfAddresses-(ArrayIndex+1))*(sizeof(ETH_MASK))
+ );
+
+ Filter->NumberOfAddresses--;
+
+ } else {
+
+ ArrayIndex++;
+
+ }
+
+ }
+
+
+ //
+ // Now go through the new addresses for this binding,
+ // and insert them into the array.
+ //
+
+ for (i=0; i<AddressCount; i++) {
+
+ CurrentAddress = ((PCHAR)Addresses) + (i*ETH_LENGTH_OF_ADDRESS);
+
+ if (FindMulticast(
+ Filter->NumberOfAddresses,
+ Filter->MulticastAddresses,
+ CurrentAddress,
+ &ArrayIndex)) {
+
+ //
+ // The address is there, so just turn the bit
+ // back on.
+ //
+
+ SET_BIT_IN_MASK(
+ LocalOpen->FilterIndex,
+ &Filter->BindingsUsingAddress[ArrayIndex]
+ );
+
+ } else {
+
+ //
+ // The address was not found, add it.
+ //
+
+ if (Filter->NumberOfAddresses < Filter->MaximumMulticastAddresses) {
+
+ //
+ // Save the address array if it hasn't been.
+ //
+
+ MoveMemory(
+ Filter->MulticastAddresses[ArrayIndex+1],
+ Filter->MulticastAddresses[ArrayIndex],
+ (Filter->NumberOfAddresses-ArrayIndex)*ETH_LENGTH_OF_ADDRESS
+ );
+
+ ETH_COPY_NETWORK_ADDRESS(
+ Filter->MulticastAddresses[ArrayIndex],
+ CurrentAddress
+ );
+
+ MoveMemory(
+ &(Filter->BindingsUsingAddress[ArrayIndex+1]),
+ &(Filter->BindingsUsingAddress[ArrayIndex]),
+ (Filter->NumberOfAddresses-ArrayIndex)*sizeof(ETH_MASK)
+ );
+
+ CLEAR_MASK(&Filter->BindingsUsingAddress[ArrayIndex]);
+
+ SET_BIT_IN_MASK(
+ LocalOpen->FilterIndex,
+ &Filter->BindingsUsingAddress[ArrayIndex]
+ );
+
+ Filter->NumberOfAddresses++;
+
+ } else {
+
+ //
+ // No room in the array, oh well.
+ //
+
+ MoveMemory(
+ (PVOID)Filter->MulticastAddresses,
+ TmpAddressArray,
+ InitialArraySize * ETH_LENGTH_OF_ADDRESS
+ );
+
+ MoveMemory(
+ (PVOID)Filter->BindingsUsingAddress,
+ TmpMaskArray,
+ InitialArraySize * sizeof(ETH_MASK)
+ );
+
+ Filter->NumberOfAddresses = InitialArraySize;
+
+ return NDIS_STATUS_MULTICAST_FULL;
+
+ }
+
+ }
+
+ }
+
+ // Check to see if address array has chnaged
+
+ AddressesChanged = Filter->NumberOfAddresses - InitialArraySize;
+
+ for (i=0; i<InitialArraySize && AddressesChanged==0; i++) {
+
+ ETH_COMPARE_NETWORK_ADDRESSES_EQ(Filter->MulticastAddresses[i],
+ (PUCHAR)TmpAddressArray + i * ETH_LENGTH_OF_ADDRESS,
+ &AddressesChanged);
+
+ }
+
+ //
+ // If the address array has changed, we have to call the
+ // action array to inform the adapter of this.
+ //
+
+ if (AddressesChanged != 0) {
+
+ StatusOfChange = Filter->AddressChangeAction(
+ InitialArraySize,
+ TmpAddressArray,
+ Filter->NumberOfAddresses,
+ Filter->MulticastAddresses,
+ LocalOpen->MacBindingHandle,
+ NdisRequest,
+ Set
+ );
+
+ if ((StatusOfChange != NDIS_STATUS_SUCCESS) &&
+ (StatusOfChange != NDIS_STATUS_PENDING)) {
+
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+
+ MoveMemory(
+ (PVOID)Filter->MulticastAddresses,
+ TmpAddressArray,
+ InitialArraySize * ETH_LENGTH_OF_ADDRESS
+ );
+
+ MoveMemory(
+ (PVOID)Filter->MulticastAddresses,
+ TmpAddressArray,
+ InitialArraySize * ETH_LENGTH_OF_ADDRESS
+ );
+
+ }
+
+ } else {
+
+ StatusOfChange = NDIS_STATUS_SUCCESS;
+
+ }
+
+
+ return StatusOfChange;
+
+
+}
+
+
+NDIS_STATUS
+EthFilterAdjust(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT FilterClasses,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ The FilterAdjust routine will call an action routine when a
+ particular filter class is changes from not being used by any
+ binding to being used by at least one binding or vice versa.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the packet filters
+ for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - A pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ FilterClasses - The filter classes that are to be added or
+ deleted.
+
+ Set - A boolean that determines whether the filter classes
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ //
+ // Contains the value of the combined filter classes before
+ // it is adjusted.
+ //
+ UINT OldCombined = Filter->CombinedPacketFilter;
+
+ PETH_BINDING_INFO LocalOpen = (PETH_BINDING_INFO)NdisFilterHandle;
+ PETH_BINDING_INFO OpenList;
+
+ //
+ // Contains the value of the particlar opens packet filters
+ // prior to the change. We save this incase the action
+ // routine (if called) returns an "error" status.
+ //
+ UINT OldOpenFilters = LocalOpen->PacketFilters;
+
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfAdjust;
+
+ //
+ // Set the new filter information for the open.
+ //
+
+ LocalOpen->PacketFilters = FilterClasses;
+
+ //
+ // We always have to reform the compbined filter since
+ // this filter index may have been the only filter index
+ // to use a particular bit.
+ //
+
+
+ for (
+ OpenList = Filter->OpenList,
+ Filter->CombinedPacketFilter = 0;
+ OpenList != NULL;
+ OpenList = OpenList->NextOpen
+ ) {
+
+ Filter->CombinedPacketFilter |=
+ OpenList->PacketFilters;
+
+ }
+
+ if (OldCombined != Filter->CombinedPacketFilter) {
+
+ StatusOfAdjust = Filter->FilterChangeAction(
+ OldCombined,
+ Filter->CombinedPacketFilter,
+ LocalOpen->MacBindingHandle,
+ NdisRequest,
+ Set
+ );
+
+ if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) &&
+ (StatusOfAdjust != NDIS_STATUS_PENDING)) {
+
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+
+ LocalOpen->PacketFilters = OldOpenFilters;
+ Filter->CombinedPacketFilter = OldCombined;
+
+ }
+
+ } else {
+
+ StatusOfAdjust = NDIS_STATUS_SUCCESS;
+
+ }
+
+ return StatusOfAdjust;
+
+}
+
+
+UINT
+EthNumberOfOpenFilterAddresses(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine counts the number of multicast addresses that a specific
+ open has.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to open block.
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ UINT IndexOfAddress;
+ UINT CountOfAddresses = 0;
+
+ UINT FilterIndex = ((PETH_BINDING_INFO)NdisFilterHandle)->FilterIndex;
+
+ for(IndexOfAddress=0;
+ IndexOfAddress < Filter->NumberOfAddresses;
+ IndexOfAddress++
+ ){
+
+ if (IS_BIT_SET_IN_MASK(FilterIndex,
+ Filter->BindingsUsingAddress[IndexOfAddress])) {
+
+ CountOfAddresses++;
+
+
+ }
+
+ }
+
+ return(CountOfAddresses);
+
+}
+
+
+VOID
+EthQueryOpenFilterAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ OUT CHAR AddressArray[][ETH_LENGTH_OF_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ The routine should be used by the MAC before
+ it actually alters the hardware registers to effect a
+ filtering hardware. This is usefull if another binding
+ has altered the address list since the action routine
+ is called.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Status - A pointer to the status of the call, NDIS_STATUS_SUCCESS or
+ NDIS_STATUS_FAILURE. Use EthNumberOfOpenAddresses() to get the
+ size that is needed.
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to the open block
+
+ SizeOfArray - The byte count of the AddressArray.
+
+ NumberOfAddresses - The number of addresses written to the array.
+
+ AddressArray - Will be filled with the addresses currently in the
+ multicast address list.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UINT IndexOfAddress;
+ UINT CountOfAddresses = 0;
+ UINT FilterIndex = ((PETH_BINDING_INFO)NdisFilterHandle)->FilterIndex;
+
+ for(IndexOfAddress=0;
+ IndexOfAddress < Filter->NumberOfAddresses;
+ IndexOfAddress++
+ ){
+
+ if (IS_BIT_SET_IN_MASK(FilterIndex,
+ Filter->BindingsUsingAddress[IndexOfAddress])) {
+
+ if (SizeOfArray < ETH_LENGTH_OF_ADDRESS) {
+
+ *Status = NDIS_STATUS_FAILURE;
+
+ *NumberOfAddresses = 0;
+
+ return;
+
+ }
+
+ SizeOfArray -= ETH_LENGTH_OF_ADDRESS;
+
+ MoveMemory(
+ AddressArray[CountOfAddresses],
+ Filter->MulticastAddresses[IndexOfAddress],
+ ETH_LENGTH_OF_ADDRESS
+ );
+
+ CountOfAddresses++;
+
+ }
+
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ *NumberOfAddresses = CountOfAddresses;
+
+ return;
+
+}
+
+
+VOID
+EthQueryGlobalFilterAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PETH_FILTER Filter,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ IN OUT CHAR AddressArray[][ETH_LENGTH_OF_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ The routine should be used by the MAC before
+ it actually alters the hardware registers to effect a
+ filtering hardware. This is usefull if another binding
+ has altered the address list since the action routine
+ is called.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Status - A pointer to the status of the call, NDIS_STATUS_SUCCESS or
+ NDIS_STATUS_FAILURE. Use ETH_NUMBER_OF_GLOBAL_ADDRESSES() to get the
+ size that is needed.
+
+ Filter - A pointer to the filter database.
+
+ SizeOfArray - The byte count of the AddressArray.
+
+ NumberOfAddresses - A pointer to the number of addresses written to the
+ array.
+
+ AddressArray - Will be filled with the addresses currently in the
+ multicast address list.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ if (SizeOfArray < (Filter->NumberOfAddresses * ETH_LENGTH_OF_ADDRESS)) {
+
+ *Status = NDIS_STATUS_FAILURE;
+
+ *NumberOfAddresses = 0;
+
+ } else {
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ *NumberOfAddresses = Filter->NumberOfAddresses;
+
+ MoveMemory(
+ AddressArray[0],
+ Filter->MulticastAddresses[0],
+ Filter->NumberOfAddresses*ETH_LENGTH_OF_ADDRESS
+ );
+
+ }
+
+}
+
+
+VOID
+EthFilterIndicateReceive(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PCHAR Address,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+{
+ KIRQL oldIrql;
+ KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ EthFilterDprIndicateReceive(
+ Filter,
+ MacReceiveContext,
+ Address,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize
+ );
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ KeLowerIrql( oldIrql );
+ return;
+}
+
+
+VOID
+EthFilterDprIndicateReceive(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PCHAR Address,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate a packet to
+ all bindings. The packet will be filtered so that only the
+ appropriate bindings will receive the packet.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ MacReceiveContext - A MAC supplied context value that must be
+ returned by the protocol if it calls MacTransferData.
+
+ Address - The destination address from the received packet.
+
+ HeaderBuffer - A virtual address of the virtually contiguous
+ buffer containing the MAC header of the packet.
+
+ HeaderBufferSize - An unsigned integer indicating the size of
+ the header buffer, in bytes.
+
+ LookaheadBuffer - A virtual address of the virtually contiguous
+ buffer containing the first LookaheadBufferSize bytes of data
+ of the packet. The packet buffer is valid only within the current
+ call to the receive event handler.
+
+ LookaheadBufferSize - An unsigned integer indicating the size of
+ the lookahead buffer, in bytes.
+
+ PacketSize - An unsigned integer indicating the size of the received
+ packet, in bytes. This number has nothing to do with the lookahead
+ buffer, but indicates how large the arrived packet is so that a
+ subsequent MacTransferData request can be made to transfer the entire
+ packet as necessary.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Will hold the type of address that we know we've got.
+ //
+ UINT AddressType;
+
+ //
+ // Will hold the status of indicating the receive packet.
+ // ZZZ For now this isn't used.
+ //
+ NDIS_STATUS StatusOfReceive;
+
+ //
+ // Will hold the filter classes of the binding being indicated.
+ //
+ UINT BindingFilters;
+ UINT IntersectionOfFilters;
+
+ //
+ // Current Open to indicate to.
+ //
+ PETH_BINDING_INFO LocalOpen;
+
+ //
+ // If the packet is a runt packet, then only indicate to PROMISCUOUS
+ //
+
+ if ( HeaderBufferSize >= 14 && PacketSize != 0 ) {
+
+ //
+ // Valid ethernet header
+ //
+
+ //
+ // Determine whether the input address is a simple direct,
+ // a broadcast, or a multicast address.
+ //
+ //
+ // First check if it *at least* has the multicast address bit.
+ //
+
+ if (ETH_IS_MULTICAST(Address)) {
+
+ //
+ // It is at least a multicast address. Check to see if
+ // it is a broadcast address.
+ //
+
+ if (ETH_IS_BROADCAST(Address)) {
+
+
+#if DBG
+
+if (NdisCheckBadDrivers) {
+
+ if (!(Filter->CombinedPacketFilter & NDIS_PACKET_TYPE_BROADCAST)) {
+
+ //
+ // We should never receive directed packets
+ // to someone else unless in p-mode.
+ //
+ DbgPrint("NDIS: Bad driver, indicating broadcast\n");
+ DbgPrint("NDIS: packets when not set to.\n");
+ DbgBreakPoint();
+
+ }
+
+}
+
+#endif
+
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+
+ } else {
+
+ AddressType = NDIS_PACKET_TYPE_MULTICAST;
+
+ }
+
+ } else {
+
+ //
+ // Verify that the address is directed to the adapter. We
+ // have to check for this because of the following senario.
+ //
+ // Adapter A is in promiscuous mode.
+ // Adapter B only wants directed packets to this adapter.
+ //
+ // The MAC will indicate *all* packets.
+ //
+ // The filter package needs to filter directed packets to
+ // other adapters from ones directed to this adapter.
+ //
+
+ if (Filter->CombinedPacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS) {
+
+ //
+ // The result of comparing an element of the address
+ // array and the multicast address.
+ //
+ // Result < 0 Implies the adapter address is greater.
+ // Result > 0 Implies the address is greater.
+ // Result = 0 Implies that the they are equal.
+ //
+ INT Result;
+
+ ETH_COMPARE_NETWORK_ADDRESSES_EQ(
+ Filter->AdapterAddress,
+ Address,
+ &Result
+ );
+
+ if (Result == 0) {
+
+ AddressType = NDIS_PACKET_TYPE_DIRECTED;
+
+ } else {
+
+ //
+ // This will cause binding that only want a specific
+ // address type to not be indicated.
+ //
+
+ AddressType = NDIS_PACKET_TYPE_PROMISCUOUS;
+
+ }
+
+ } else {
+
+#if DBG
+
+if (NdisCheckBadDrivers) {
+
+ //
+ // The result of comparing an element of the address
+ // array and the multicast address.
+ //
+ // Result < 0 Implies the adapter address is greater.
+ // Result > 0 Implies the address is greater.
+ // Result = 0 Implies that the they are equal.
+ //
+ INT Result;
+
+ ETH_COMPARE_NETWORK_ADDRESSES_EQ(
+ Filter->AdapterAddress,
+ Address,
+ &Result
+ );
+
+ if (Result != 0) {
+
+ //
+ // We should never receive directed packets
+ // to someone else unless in p-mode.
+ //
+ DbgPrint("NDIS: Bad driver, indicating packets\n");
+ DbgPrint("NDIS: to another station when not in\n");
+ DbgPrint("NDIS: promiscuous mode.\n");
+ DbgBreakPoint();
+
+
+ }
+
+}
+
+#endif
+
+ AddressType = NDIS_PACKET_TYPE_DIRECTED;
+
+ }
+
+ }
+
+ } else {
+
+ //
+ // runt packet
+ //
+
+ AddressType = NDIS_PACKET_TYPE_PROMISCUOUS;
+
+ }
+
+ //
+ // We need to acquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+
+ LocalOpen = Filter->OpenList;
+
+ while (LocalOpen != NULL) {
+
+ BindingFilters = LocalOpen->PacketFilters;
+ IntersectionOfFilters = BindingFilters & AddressType;
+
+ //
+ // if the binding wants direct packets and this is a directly
+ // addressed packet then the binding gets the packet.
+ //
+ //
+ // if the binding wants broadcast packets and the packet
+ // is a broadcast packet it will get the packet.
+ //
+
+ if (IntersectionOfFilters & (NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST)) {
+
+ goto IndicatePacket;
+
+ }
+
+ //
+ // if the binding wants multicast packets and the packet
+ // is a multicast packet and it's in the list of addresses
+ // it will get the packet.
+ //
+
+ if (IntersectionOfFilters & NDIS_PACKET_TYPE_MULTICAST) {
+
+ //
+ // Will hold the index of the multicast
+ // address if it finds it.
+ //
+ UINT IndexOfAddress;
+
+ if (FindMulticast(
+ Filter->NumberOfAddresses,
+ Filter->MulticastAddresses,
+ Address,
+ &IndexOfAddress
+ )) {
+
+ if (IS_BIT_SET_IN_MASK(
+ LocalOpen->FilterIndex,
+ Filter->BindingsUsingAddress[IndexOfAddress]
+ )) {
+
+ goto IndicatePacket;
+
+ }
+
+ }
+
+ }
+
+ //
+ // if the binding wants all multicast packets and the packet
+ // has a multicast address it will get the packet
+ //
+
+ if ((AddressType & NDIS_PACKET_TYPE_MULTICAST) &&
+ (BindingFilters & NDIS_PACKET_TYPE_ALL_MULTICAST)) {
+
+ goto IndicatePacket;
+
+ }
+
+ //
+ // if the binding is promiscuous then it will get the packet
+ //
+
+ if (BindingFilters & NDIS_PACKET_TYPE_PROMISCUOUS) {
+
+ goto IndicatePacket;
+
+ }
+
+ goto GetNextBinding;
+
+IndicatePacket:;
+
+ LocalOpen->References++;
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ //
+ // Indicate the packet to the binding.
+ //
+
+ FilterIndicateReceive(
+ &StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ if ((--(LocalOpen->References)) == 0) {
+
+ PETH_BINDING_INFO NextOpen = LocalOpen->NextOpen;
+
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+
+ //
+ // Remove it from the list.
+ //
+
+ if (LocalOpen->NextOpen != NULL) {
+
+ LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen;
+
+ }
+
+ if (LocalOpen->PrevOpen != NULL) {
+
+ LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen;
+
+ } else {
+
+ Filter->OpenList = LocalOpen->NextOpen;
+
+ }
+
+
+
+ //
+ // Call the IndicateComplete routine.
+ //
+
+
+ if (LocalOpen->ReceivedAPacket) {
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ }
+
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+
+ Filter->CloseAction(LocalOpen->MacBindingHandle);
+
+
+ ETH_FILTER_FREE_OPEN(Filter, LocalOpen);
+
+ LocalOpen = NextOpen;
+
+ continue;
+
+ }
+
+GetNextBinding:
+
+ LocalOpen = LocalOpen->NextOpen;
+
+ }
+
+}
+
+
+VOID
+EthFilterIndicateReceiveComplete(
+ IN PETH_FILTER Filter
+ )
+{
+ KIRQL oldIrql;
+ KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ EthFilterDprIndicateReceiveComplete(
+ Filter
+ );
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ KeLowerIrql( oldIrql );
+ return;
+}
+
+
+VOID
+EthFilterDprIndicateReceiveComplete(
+ IN PETH_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate that the receive
+ process is complete to all bindings. Only those bindings which
+ have received packets will be notified.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PETH_BINDING_INFO LocalOpen;
+
+ //
+ // We need to aquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+
+ LocalOpen = Filter->OpenList;
+
+ while (LocalOpen != NULL) {
+
+ if (LocalOpen->ReceivedAPacket) {
+
+ //
+ // Indicate the binding.
+ //
+
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ LocalOpen->References++;
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ if ((--(LocalOpen->References)) == 0) {
+
+ PETH_BINDING_INFO NextOpen = LocalOpen->NextOpen;
+
+ //
+ // This binding is shutting down. We have to kill it.
+ //
+
+ //
+ // Remove it from the list.
+ //
+
+ if (LocalOpen->NextOpen != NULL) {
+
+ LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen;
+
+ }
+
+ if (LocalOpen->PrevOpen != NULL) {
+
+ LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen;
+
+ } else {
+
+ Filter->OpenList = LocalOpen->NextOpen;
+
+ }
+
+
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+
+ Filter->CloseAction(LocalOpen->MacBindingHandle);
+
+
+ ETH_FILTER_FREE_OPEN(Filter, LocalOpen);
+
+ LocalOpen = NextOpen;
+
+ continue;
+
+ }
+
+ }
+
+ LocalOpen = LocalOpen->NextOpen;
+
+ }
+
+}
+
+
+static
+BOOLEAN
+FindMulticast(
+ IN UINT NumberOfAddresses,
+ IN CHAR AddressArray[][ETH_LENGTH_OF_ADDRESS],
+ IN CHAR MulticastAddress[ETH_LENGTH_OF_ADDRESS],
+ OUT PUINT ArrayIndex
+ )
+
+/*++
+
+Routine Description:
+
+ Given an array of multicast addresses search the array for
+ a particular multicast address. It is assumed that the
+ address array is already sorted.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+ NOTE: This ordering is arbitrary but consistant.
+
+Arguments:
+
+ NumberOfAddresses - The number of addresses currently in the
+ address array.
+
+ AddressArray - An array of multicast addresses.
+
+ MulticastAddress - The address to search for in the address array.
+
+ ArrayIndex - Will point to where the MulticastAddress is in
+ the AddressArray, or if it isn't in the array, where it should
+ be in the array.
+
+Return Value:
+
+ If the address is in the sorted list this routine will return
+ TRUE, otherwise FALSE.
+
+--*/
+
+{
+
+ //
+ // Indices into the address array so that we may do a binary
+ // search.
+ //
+ UINT Bottom = 0;
+ UINT Middle = NumberOfAddresses / 2;
+ UINT Top;
+
+ if (NumberOfAddresses) {
+
+ Top = NumberOfAddresses - 1;
+
+ while ((Middle <= Top) && (Middle >= Bottom)) {
+
+ //
+ // The result of comparing an element of the address
+ // array and the multicast address.
+ //
+ // Result < 0 Implies the multicast address is greater.
+ // Result > 0 Implies the address array element is greater.
+ // Result = 0 Implies that the array element and the address
+ // are equal.
+ //
+ INT Result;
+
+ ETH_COMPARE_NETWORK_ADDRESSES(
+ AddressArray[Middle],
+ MulticastAddress,
+ &Result
+ );
+
+ if (Result == 0) {
+
+ *ArrayIndex = Middle;
+ return(TRUE);
+
+ } else if (Result > 0) {
+
+ if (Middle == 0) break;
+ Top = Middle - 1;
+
+
+ } else {
+
+ Bottom = Middle+1;
+
+ }
+
+ Middle = Bottom + (((Top+1) - Bottom)/2);
+
+ }
+
+ }
+
+ *ArrayIndex = Middle;
+
+ return(FALSE);
+
+}
+
+
+BOOLEAN
+EthShouldAddressLoopBack(
+ IN PETH_FILTER Filter,
+ IN CHAR Address[ETH_LENGTH_OF_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ Do a quick check to see whether the input address should
+ loopback.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+ NOTE: THIS ROUTINE DOES NOT CHECK THE SPECIAL CASE OF SOURCE
+ EQUALS DESTINATION.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ Address - A network address to check for loopback.
+
+
+Return Value:
+
+ Returns TRUE if the address is *likely* to need loopback. It
+ will return FALSE if there is *no* chance that the address would
+ require loopback.
+
+--*/
+{
+ BOOLEAN fLoopback, fSelfDirected;
+
+ EthShouldAddressLoopBackMacro(Filter, Address, &fLoopback, &fSelfDirected);
+
+ return(fLoopback);
+}
diff --git a/private/ntos/ndis/ndis30/efilter.h b/private/ntos/ndis/ndis30/efilter.h
new file mode 100644
index 000000000..c33749973
--- /dev/null
+++ b/private/ntos/ndis/ndis30/efilter.h
@@ -0,0 +1,605 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ efilter.h
+
+Abstract:
+
+ Header file for the address filtering library for NDIS MAC's.
+
+Author:
+
+ Anthony V. Ercolano (tonye) creation-date 3-Aug-1990
+
+Environment:
+
+ Runs in the context of a single MAC driver.
+
+Notes:
+
+ None.
+
+Revision History:
+
+ Adam Barr (adamba) 28-May-1991
+
+ - renamed MacXXX to EthXXX, changed filter.h to efilter.h
+
+
+--*/
+
+#ifndef _ETH_FILTER_DEFS_
+#define _ETH_FILTER_DEFS_
+
+#define ETH_LENGTH_OF_ADDRESS 6
+
+
+//
+// ZZZ This is a little-endian specific check.
+//
+#define ETH_IS_MULTICAST(Address) \
+ (((PUCHAR)(Address))[0] & ((UCHAR)0x01))
+
+
+//
+// Check whether an address is broadcast.
+//
+#define ETH_IS_BROADCAST(Address) \
+ ((*((ULONG UNALIGNED *) \
+ (&(((PUCHAR) \
+ Address \
+ )[2] \
+ ) \
+ ) \
+ ) == \
+ ((ULONG)0xffffffff) \
+ ) && \
+ (((PUCHAR)Address)[0] == ((UCHAR)0xff)) && \
+ (((PUCHAR)Address)[1] == ((UCHAR)0xff)))
+
+
+//
+// This macro will compare network addresses.
+//
+// A - Is a network address.
+//
+// B - Is a network address.
+//
+// Result - The result of comparing two network address.
+//
+// Result < 0 Implies the B address is greater.
+// Result > 0 Implies the A element is greater.
+// Result = 0 Implies equality.
+//
+// Note that this is an arbitrary ordering. There is not
+// defined relation on network addresses. This is ad-hoc!
+//
+//
+#define ETH_COMPARE_NETWORK_ADDRESSES(A,B,Result) \
+{ \
+ PUCHAR _A = (PUCHAR)(A); \
+ PUCHAR _B = (PUCHAR)(B); \
+ if ( *(ULONG UNALIGNED *)&_A[2] > \
+ *(ULONG UNALIGNED *)&_B[2] ) { \
+ *Result = 1; \
+ } else if ( *(ULONG UNALIGNED *)&_A[2] < \
+ *(ULONG UNALIGNED *)&_B[2] ) { \
+ *Result = (UINT)-1; \
+ } else if ( *(USHORT UNALIGNED *)_A > \
+ *(USHORT UNALIGNED *)_B ) { \
+ *Result = 1; \
+ } else if ( *(USHORT UNALIGNED *)_A < \
+ *(USHORT UNALIGNED *)_B ) { \
+ *Result = (UINT)-1; \
+ } else { \
+ *Result = 0; \
+ } \
+}
+
+//
+// This macro will compare network addresses.
+//
+// A - Is a network address.
+//
+// B - Is a network address.
+//
+// Result - The result of comparing two network address.
+//
+// Result != 0 Implies inequality.
+// Result == 0 Implies equality.
+//
+//
+#define ETH_COMPARE_NETWORK_ADDRESSES_EQ(A,B,Result) \
+{ \
+ PUCHAR _A = (PUCHAR)(A); \
+ PUCHAR _B = (PUCHAR)(B); \
+ if ( ( *(ULONG UNALIGNED *)&_A[2] == \
+ *(ULONG UNALIGNED *)&_B[2] ) && \
+ ( *(USHORT UNALIGNED *)_A == \
+ *(USHORT UNALIGNED *)_B ) ) { \
+ *Result = 0; \
+ } else { \
+ *Result = 1; \
+ } \
+}
+
+
+//
+// This macro is used to copy from one network address to
+// another.
+//
+#define ETH_COPY_NETWORK_ADDRESS(D,S) \
+{ \
+ PCHAR _D = (D); \
+ PCHAR _S = (S); \
+ *((ULONG UNALIGNED *)_D) = *((ULONG UNALIGNED *)_S); \
+ _D[4] = _S[4]; \
+ _D[5] = _S[5]; \
+}
+
+
+//
+//UINT
+//ETH_QUERY_FILTER_CLASSES(
+// IN PETH_FILTER Filter
+// )
+//
+// This macro returns the currently enabled filter classes.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define ETH_QUERY_FILTER_CLASSES(Filter) ((Filter)->CombinedPacketFilter)
+
+
+//
+//UINT
+//ETH_QUERY_PACKET_FILTER(
+// IN PETH_FILTER Filter,
+// IN NDIS_HANDLE NdisFilterHandle
+// )
+//
+// This macro returns the currently enabled filter classes for a specific
+// open instance.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define ETH_QUERY_PACKET_FILTER(Filter, NdisFilterHandle) \
+ (((PETH_BINDING_INFO)(NdisFilterHandle))->PacketFilters)
+
+
+//
+//UINT
+//ETH_NUMBER_OF_GLOBAL_FILTER_ADDRESSES(
+// IN PETH_FILTER Filter
+// )
+//
+// This macro returns the number of multicast addresses in the
+// multicast address list.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define ETH_NUMBER_OF_GLOBAL_FILTER_ADDRESSES(Filter) ((Filter)->NumberOfAddresses)
+
+
+//
+// An action routine type. The routines are called
+// when a filter type is set for the first time or
+// no more bindings require a particular type of filter.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+NDIS_STATUS
+(*ETH_FILTER_CHANGE)(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+//
+// This action routine is called when a new multicast address
+// list is given to the filter. The action routine is given
+// arrays containing the old and new multicast addresses.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+NDIS_STATUS
+(*ETH_ADDRESS_CHANGE)(
+ IN UINT OldAddressCount,
+ IN CHAR OldAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN UINT NewAddressCount,
+ IN CHAR NewAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+#if 0
+// This action routine is called when a unique multicast address
+// is added to the filter. The action routine is passed an array
+// filled with all of the addresses that are being filtered, as
+// well as the index into this array of the unique address just
+// added. It is also passed an array of contexts, associated
+// with each address; it can store a context for the new address
+// in AddressContexts[NewAddress]. The contexts are passed
+// back to the delete action routine.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+NDIS_STATUS
+(*ETH_ADDRESS_ADD)(
+ IN UINT CurrentAddressCount,
+ IN CHAR CurrentAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN UINT NewAddress,
+ IN OUT NDIS_HANDLE AddressContexts[],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+//
+// This action routine is called when a unique multicast address
+// is no longer requested for filtering by any binding. The
+// action routine is passed an array filled with the all of the
+// addresses that are *still* being used for multicast filtering.
+// It is also passed the array of contexts for those addresses.
+// The routine is also passed the address of the address being deleted,
+// and the context of the address being deleted (as set during
+// the add action routine).
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+NDIS_STATUS
+(*ETH_ADDRESS_DELETE)(
+ IN UINT CurrentAddressCount,
+ IN CHAR CurrentAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN CHAR OldAddress[ETH_LENGTH_OF_ADDRESS],
+ IN NDIS_HANDLE AddressContexts[],
+ IN NDIS_HANDLE OldAddressContext,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+#endif
+
+//
+// This action routine is called when the mac requests a close for
+// a particular binding *WHILE THE BINDING IS BEING INDICATED TO
+// THE PROTOCOL*. The filtering package can't get rid of the open
+// right away. So this routine will be called as soon as the
+// NdisIndicateReceive returns.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+VOID
+(*ETH_DEFERRED_CLOSE)(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+typedef ULONG ETH_MASK,*PETH_MASK;
+
+//
+// Maximum number of opens the filter package will support. This is
+// the max so that bit masks can be used instead of a spaghetti of
+// pointers.
+//
+#define ETH_FILTER_MAX_OPENS (sizeof(ULONG) * 8)
+
+//
+// The binding info is threaded on two lists. When
+// the binding is free it is on a single freelist.
+//
+// When the binding is being used it is on a doubly linked
+// index list.
+//
+typedef struct _ETH_BINDING_INFO {
+ NDIS_HANDLE MacBindingHandle;
+ NDIS_HANDLE NdisBindingContext;
+ UINT PacketFilters;
+ ULONG References;
+ struct _ETH_BINDING_INFO *NextOpen;
+ struct _ETH_BINDING_INFO *PrevOpen;
+ BOOLEAN ReceivedAPacket;
+ UCHAR FilterIndex;
+} ETH_BINDING_INFO,*PETH_BINDING_INFO;
+
+//
+// An opaque type that contains a filter database.
+// The MAC need not know how it is structured.
+//
+typedef struct _ETH_FILTER {
+
+ //
+ // Spin lock used to protect the filter from multiple accesses.
+ //
+ PNDIS_SPIN_LOCK Lock;
+
+ //
+ // Pointer to an array of 6 character arrays holding the
+ // multicast addresses requested for filtering.
+ //
+ CHAR (*MulticastAddresses)[ETH_LENGTH_OF_ADDRESS];
+
+ //
+ // Pointer to an array of ETH_MASKS that work in conjuction with
+ // the MulticastAddress array. In the masks, a bit being enabled
+ // indicates that the binding with the given FilterIndex is using
+ // the corresponding address.
+ //
+ ETH_MASK *BindingsUsingAddress;
+
+ //
+ // Combination of all the filters of all the open bindings.
+ //
+ UINT CombinedPacketFilter;
+
+ //
+ // Pointer for traversing the open list.
+ //
+ PETH_BINDING_INFO OpenList;
+
+
+ //
+ // Action routines to be invoked on notable changes in the filter.
+ //
+
+ ETH_ADDRESS_CHANGE AddressChangeAction;
+ ETH_FILTER_CHANGE FilterChangeAction;
+ ETH_DEFERRED_CLOSE CloseAction;
+
+ //
+ // The maximum number of addresses used for filtering.
+ //
+ UINT MaximumMulticastAddresses;
+
+ //
+ // The current number of addresses in the address filter.
+ //
+ UINT NumberOfAddresses;
+
+ //
+ // Bit mask of opens that are available.
+ //
+ ULONG FreeBindingMask;
+
+ //
+ // Address of the adapter.
+ //
+ UCHAR AdapterAddress[ETH_LENGTH_OF_ADDRESS];
+
+} ETH_FILTER,*PETH_FILTER;
+
+
+//
+// Only for internal wrapper use.
+//
+VOID
+EthInitializePackage(
+ VOID
+ );
+
+VOID
+EthReferencePackage(
+ VOID
+ );
+
+VOID
+EthDereferencePackage(
+ VOID
+ );
+
+//
+// Exported functions
+//
+EXPORT
+BOOLEAN
+EthCreateFilter(
+ IN UINT MaximumMulticastAddresses,
+ IN ETH_ADDRESS_CHANGE AddressChangeAction,
+ IN ETH_FILTER_CHANGE FilterChangeAction,
+ IN ETH_DEFERRED_CLOSE CloseAction,
+ IN PUCHAR AdapterAddress,
+ IN PNDIS_SPIN_LOCK Lock,
+ OUT PETH_FILTER *Filter
+ );
+
+EXPORT
+VOID
+EthDeleteFilter(
+ IN PETH_FILTER Filter
+ );
+
+EXPORT
+BOOLEAN
+EthNoteFilterOpenAdapter(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE NdisBindingContext,
+ OUT PNDIS_HANDLE NdisFilterHandle
+ );
+
+EXPORT
+NDIS_STATUS
+EthDeleteFilterOpenAdapter(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+EXPORT
+NDIS_STATUS
+EthChangeFilterAddresses(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT AddressCount,
+ IN CHAR Addresses[][ETH_LENGTH_OF_ADDRESS],
+ IN BOOLEAN Set
+ );
+
+
+#define EthShouldAddressLoopBackMacro(_Filter, _Address, _pfLoopback, _pfSelfDirected) \
+{ \
+ UINT CombinedFilters; \
+ \
+ CombinedFilters = ETH_QUERY_FILTER_CLASSES(_Filter); \
+ \
+ *(_pfLoopback) = FALSE; \
+ *(_pfSelfDirected) = FALSE; \
+ \
+ do \
+ { \
+ /* \
+ * First check if the filter is promiscuous. \
+ */ \
+ \
+ if (CombinedFilters & NDIS_PACKET_TYPE_PROMISCUOUS) \
+ { \
+ *(_pfLoopback) = TRUE; \
+ break; \
+ } \
+ \
+ /* \
+ * Check if it *at least* has the multicast address bit. \
+ */ \
+ \
+ if (ETH_IS_MULTICAST(_Address)) \
+ { \
+ /* \
+ * It is at least a multicast address. Check to see if \
+ * it is a broadcast address. \
+ */ \
+ \
+ if (ETH_IS_BROADCAST(_Address)) \
+ { \
+ if (CombinedFilters & NDIS_PACKET_TYPE_BROADCAST) \
+ { \
+ *(_pfLoopback) = TRUE; \
+ break; \
+ } \
+ else \
+ { \
+ break; \
+ } \
+ } \
+ else \
+ { \
+ if ((CombinedFilters & NDIS_PACKET_TYPE_ALL_MULTICAST) || \
+ (CombinedFilters & NDIS_PACKET_TYPE_MULTICAST)) \
+ { \
+ *(_pfLoopback) = TRUE; \
+ break; \
+ } \
+ } \
+ } \
+ else \
+ { \
+ /* \
+ * Directed to ourself?? \
+ */ \
+ \
+ if ((*(ULONG UNALIGNED *)&(_Address)[2] == \
+ *(ULONG UNALIGNED *)&(_Filter)->AdapterAddress[2]) && \
+ (*(USHORT UNALIGNED *)&(_Address)[0] == \
+ *(USHORT UNALIGNED *)&(_Filter)->AdapterAddress[0])) \
+ { \
+ *(_pfLoopback) = TRUE; \
+ *(_pfSelfDirected) = TRUE; \
+ } \
+ } \
+ } while (FALSE); \
+}
+
+EXPORT
+BOOLEAN
+EthShouldAddressLoopBack(
+ IN PETH_FILTER Filter,
+ IN CHAR Address[ETH_LENGTH_OF_ADDRESS]
+ );
+
+EXPORT
+NDIS_STATUS
+EthFilterAdjust(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT FilterClasses,
+ IN BOOLEAN Set
+ );
+
+EXPORT
+UINT
+EthNumberOfOpenFilterAddresses(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle
+ );
+
+EXPORT
+VOID
+EthQueryGlobalFilterAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PETH_FILTER Filter,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ IN OUT CHAR AddressArray[][ETH_LENGTH_OF_ADDRESS]
+ );
+
+EXPORT
+VOID
+EthQueryOpenFilterAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ IN OUT CHAR AddressArray[][ETH_LENGTH_OF_ADDRESS]
+ );
+
+
+EXPORT
+VOID
+EthFilterIndicateReceive(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PCHAR Address,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+EXPORT
+VOID
+EthFilterDprIndicateReceive(
+ IN PETH_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PCHAR Address,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+EXPORT
+VOID
+EthFilterIndicateReceiveComplete(
+ IN PETH_FILTER Filter
+ );
+
+EXPORT
+VOID
+EthFilterDprIndicateReceiveComplete(
+ IN PETH_FILTER Filter
+ );
+
+#endif // _ETH_FILTER_DEFS_
+
diff --git a/private/ntos/ndis/ndis30/ffilter.c b/private/ntos/ndis/ndis30/ffilter.c
new file mode 100644
index 000000000..6a6397669
--- /dev/null
+++ b/private/ntos/ndis/ndis30/ffilter.c
@@ -0,0 +1,3193 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ffilter.c
+
+Abstract:
+
+ This module implements a set of library routines to handle packet
+ filtering for NDIS MAC drivers.
+
+Author:
+
+ Anthony V. Ercolano (Tonye) 03-Aug-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+ Sean Selitrennikoff (SeanSe) converted Efilter.* for FDDI filtering.
+
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+//
+// 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);
+
+//
+// ZZZ NonPortable definitions.
+//
+#define AllocPhys(s, l) NdisAllocateMemory((PVOID *)(s), (l), 0, HighestAcceptableMax)
+#define FreePhys(s, l) NdisFreeMemory((PVOID)(s), (l), 0)
+#ifdef NDIS_NT
+#define MoveMemory(Destination,Source,Length) RtlMoveMemory(Destination,Source,Length)
+#define ZeroMemory(Destination,Length) RtlZeroMemory(Destination,Length)
+#endif
+
+#ifdef NDIS_DOS
+#define MoveMemory(Destination,Source,Length) memcpy(Destination,Source,Length)
+#define ZeroMemory(Destination,Length) memset(Destination,0,Length)
+#endif
+
+#if DBG
+extern BOOLEAN NdisCheckBadDrivers;
+#endif
+
+//
+// A set of macros to manipulate bitmasks.
+//
+
+//VOID
+//CLEAR_BIT_IN_MASK(
+// IN UINT Offset,
+// IN OUT PFDDI_MASK MaskToClear
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Clear a bit in the bitmask pointed to by the parameter.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to altered.
+//
+// MaskToClear - Pointer to the mask to be adjusted.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+//
+#define CLEAR_BIT_IN_MASK(Offset,MaskToClear) *MaskToClear &= (~(1 << Offset))
+
+//VOID
+//SET_BIT_IN_MASK(
+// IN UINT Offset,
+// IN OUT PFDDI_MASK MaskToSet
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Set a bit in the bitmask pointed to by the parameter.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to altered.
+//
+// MaskToSet - Pointer to the mask to be adjusted.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+#define SET_BIT_IN_MASK(Offset,MaskToSet) *MaskToSet |= (1 << Offset)
+
+//BOOLEAN
+//IS_BIT_SET_IN_MASK(
+// IN UINT Offset,
+// IN FDDI_MASK MaskToTest
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Tests if a particular bit in the bitmask pointed to by the parameter is
+// set.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to test.
+//
+// MaskToTest - The mask to be tested.
+//
+//Return Value:
+//
+// Returns TRUE if the bit is set.
+//
+//--*/
+#define IS_BIT_SET_IN_MASK(Offset,MaskToTest) \
+((MaskToTest & (1 << Offset))?(TRUE):(FALSE))
+
+//BOOLEAN
+//IS_MASK_CLEAR(
+// IN FDDI_MASK MaskToTest
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Tests whether there are *any* bits enabled in the mask.
+//
+//Arguments:
+//
+// MaskToTest - The bit mask to test for all clear.
+//
+//Return Value:
+//
+// Will return TRUE if no bits are set in the mask.
+//
+//--*/
+#define IS_MASK_CLEAR(MaskToTest) ((!MaskToTest)?(TRUE):(FALSE))
+
+//VOID
+//CLEAR_MASK(
+// IN OUT PFDDI_MASK MaskToClear
+// );
+//
+///*++
+//
+//Routine Description:
+//
+// Clears a mask.
+//
+//Arguments:
+//
+// MaskToClear - The bit mask to adjust.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+#define CLEAR_MASK(MaskToClear) *MaskToClear = 0
+
+//
+// VOID
+// FDDI_FILTER_ALLOC_OPEN(
+// IN PFDDI_FILTER Filter,
+// OUT PUINT FilterIndex
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Allocates an open block. This only allocate the index, not memory for
+// the open block.
+//
+//Arguments:
+//
+// Filter - DB from which to allocate the space
+//
+// FilterIndex - pointer to place to store the index.
+//
+//Return Value:
+//
+// FilterIndex of the new open
+//
+//--*/
+#define FDDI_FILTER_ALLOC_OPEN(Filter, FilterIndex)\
+{\
+ UINT i; \
+ for (i=0; i < FDDI_FILTER_MAX_OPENS; i++) { \
+ if (IS_BIT_SET_IN_MASK(i,(Filter)->FreeBindingMask)) { \
+ *(FilterIndex) = i; \
+ CLEAR_BIT_IN_MASK(i, &((Filter)->FreeBindingMask)); \
+ break; \
+ } \
+ } \
+}
+
+//
+// VOID
+// FDDI_FILTER_FREE_OPEN(
+// IN PFDDI_FILTER Filter,
+// IN PFDDI_BINDING_INFO LocalOpen
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Frees an open block. Also frees the memory associated with the open.
+//
+//Arguments:
+//
+// Filter - DB from which to allocate the space
+//
+// FilterIndex - Index to free
+//
+//Return Value:
+//
+// FilterIndex of the new open
+//
+//--*/
+#define FDDI_FILTER_FREE_OPEN(Filter, LocalOpen)\
+{\
+ SET_BIT_IN_MASK(((LocalOpen)->FilterIndex), &((Filter)->FreeBindingMask)); \
+ FreePhys((LocalOpen), sizeof(FDDI_BINDING_INFO));\
+}
+
+
+NDIS_SPIN_LOCK FddiReferenceLock = {0};
+KEVENT FddiPagedInEvent = {0};
+ULONG FddiReferenceCount = 0;
+PVOID FddiImageHandle = {0};
+
+VOID
+FddiInitializePackage(VOID)
+{
+ NdisAllocateSpinLock(&FddiReferenceLock);
+ KeInitializeEvent(
+ &FddiPagedInEvent,
+ NotificationEvent,
+ FALSE
+ );
+}
+
+VOID
+FddiReferencePackage(VOID)
+{
+
+ ACQUIRE_SPIN_LOCK(&FddiReferenceLock);
+
+ FddiReferenceCount++;
+
+ if (FddiReferenceCount == 1) {
+
+ KeResetEvent(
+ &FddiPagedInEvent
+ );
+
+ RELEASE_SPIN_LOCK(&FddiReferenceLock);
+
+ //
+ // Page in all the functions
+ //
+ FddiImageHandle = MmLockPagableCodeSection(FddiCreateFilter);
+
+ //
+ // Signal to everyone to go
+ //
+ KeSetEvent(
+ &FddiPagedInEvent,
+ 0L,
+ FALSE
+ );
+
+ } else {
+
+ RELEASE_SPIN_LOCK(&FddiReferenceLock);
+
+ //
+ // Wait for everything to be paged in
+ //
+ KeWaitForSingleObject(
+ &FddiPagedInEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ NULL
+ );
+
+ }
+
+}
+
+VOID
+FddiDereferencePackage(VOID)
+{
+ ACQUIRE_SPIN_LOCK(&FddiReferenceLock);
+
+ FddiReferenceCount--;
+
+ if (FddiReferenceCount == 0) {
+
+ RELEASE_SPIN_LOCK(&FddiReferenceLock);
+
+ //
+ // Page out all the functions
+ //
+ MmUnlockPagableImageSection(FddiImageHandle);
+
+ } else {
+
+ RELEASE_SPIN_LOCK(&FddiReferenceLock);
+
+ }
+
+}
+
+static
+BOOLEAN
+FindMulticastLongAddress(
+ IN UINT NumberOfAddresses,
+ IN CHAR AddressArray[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN CHAR MulticastAddress[FDDI_LENGTH_OF_LONG_ADDRESS],
+ OUT PUINT ArrayIndex
+ );
+
+static
+BOOLEAN
+FindMulticastShortAddress(
+ IN UINT NumberOfAddresses,
+ IN CHAR AddressArray[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN CHAR MulticastAddress[FDDI_LENGTH_OF_SHORT_ADDRESS],
+ OUT PUINT ArrayIndex
+ );
+
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGENDSF, FddiShouldAddressLoopBack)
+#pragma alloc_text(PAGENDSF, FindMulticastShortAddress)
+#pragma alloc_text(PAGENDSF, FindMulticastLongAddress)
+#pragma alloc_text(PAGENDSF, FddiFilterDprIndicateReceiveComplete)
+#pragma alloc_text(PAGENDSF, FddiFilterIndicateReceiveComplete)
+#pragma alloc_text(PAGENDSF, FddiFilterDprIndicateReceive)
+#pragma alloc_text(PAGENDSF, FddiFilterIndicateReceive)
+#pragma alloc_text(PAGENDSF, FddiQueryGlobalFilterShortAddresses)
+#pragma alloc_text(PAGENDSF, FddiQueryGlobalFilterLongAddresses)
+#pragma alloc_text(PAGENDSF, FddiQueryOpenFilterShortAddresses)
+#pragma alloc_text(PAGENDSF, FddiQueryOpenFilterLongAddresses)
+#pragma alloc_text(PAGENDSF, FddiNumberOfOpenFilterShortAddresses)
+#pragma alloc_text(PAGENDSF, FddiNumberOfOpenFilterLongAddresses)
+#pragma alloc_text(PAGENDSF, FddiFilterAdjust)
+#pragma alloc_text(PAGENDSF, FddiChangeFilterShortAddresses)
+#pragma alloc_text(PAGENDSF, FddiChangeFilterLongAddresses)
+#pragma alloc_text(PAGENDSF, FddiDeleteFilterOpenAdapter)
+#pragma alloc_text(PAGENDSF, FddiNoteFilterOpenAdapter)
+#pragma alloc_text(PAGENDSF, FddiCreateFilter)
+
+#endif
+
+
+
+
+BOOLEAN
+FddiCreateFilter(
+ IN UINT MaximumMulticastLongAddresses,
+ IN UINT MaximumMulticastShortAddresses,
+ IN FDDI_ADDRESS_CHANGE AddressChangeAction,
+ IN FDDI_FILTER_CHANGE FilterChangeAction,
+ IN FDDI_DEFERRED_CLOSE CloseAction,
+ IN PUCHAR AdapterLongAddress,
+ IN PUCHAR AdapterShortAddress,
+ IN PNDIS_SPIN_LOCK Lock,
+ OUT PFDDI_FILTER *Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to create and initialize the filter database.
+
+Arguments:
+
+ MaximumMulticastLongAddresses - The maximum number of Long multicast addresses
+ that the MAC will support.
+
+ MaximumMulticastShortAddresses - The maximum number of short multicast addresses
+ that the MAC will support.
+
+ AddressChangeAction - Action routine to call when the list of
+ multicast addresses the card must enable has changed.
+
+ ChangeAction - Action routine to call when a binding sets or clears
+ a particular filter class and it is the first or only binding using
+ the filter class.
+
+ CloseAction - This routine is called if a binding closes while
+ it is being indicated to via NdisIndicateReceive. It will be
+ called upon return from NdisIndicateReceive.
+
+ AdapterLongAddress - the long address of the adapter associated with this filter
+ database.
+
+ AdapterShortAddress - the short address of the adapter associated with this filter
+ database.
+
+ Lock - Pointer to the lock that should be held when mutual exclusion
+ is required.w
+
+ Filter - A pointer to an FDDI_FILTER. This is what is allocated and
+ created by this routine.
+
+Return Value:
+
+ If the function returns false then one of the parameters exceeded
+ what the filter was willing to support.
+
+--*/
+
+{
+
+ PFDDI_FILTER LocalFilter;
+ NDIS_STATUS AllocStatus;
+
+ //
+ // Allocate the database and it's associated arrays.
+ //
+
+ AllocStatus = AllocPhys(&LocalFilter, sizeof(FDDI_FILTER));
+ *Filter = LocalFilter;
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+ return FALSE;
+ }
+
+ ZeroMemory(
+ LocalFilter,
+ sizeof(FDDI_FILTER)
+ );
+
+ if (MaximumMulticastLongAddresses == 0) {
+
+ //
+ // Why 2 and not 1? Why not. A protocol is going to need at least
+ // one to run on this, so let's give one extra one for any user stuff
+ // that may need it.
+ //
+
+ MaximumMulticastLongAddresses = 2;
+
+ }
+
+ if (MaximumMulticastShortAddresses == 0) {
+
+ //
+ // Why 2 and not 1? Why not. A protocol is going to need at least
+ // one to run on this, so let's give one extra one for any user stuff
+ // that may need it.
+ //
+
+ MaximumMulticastShortAddresses = 2;
+
+ }
+
+ {
+ PVOID TmpAlloc;
+
+ AllocStatus = AllocPhys(
+ &TmpAlloc,
+ 2*FDDI_LENGTH_OF_LONG_ADDRESS*MaximumMulticastLongAddresses
+ );
+
+ LocalFilter->MulticastLongAddresses = TmpAlloc;
+
+ }
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+ FddiDeleteFilter(LocalFilter);
+ return FALSE;
+
+ }
+
+ {
+ PVOID TmpAlloc;
+
+ AllocStatus = AllocPhys(
+ &TmpAlloc,
+ 2*FDDI_LENGTH_OF_SHORT_ADDRESS*MaximumMulticastShortAddresses
+ );
+
+ LocalFilter->MulticastShortAddresses = TmpAlloc;
+
+ }
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+ FddiDeleteFilter(LocalFilter);
+ return FALSE;
+
+ }
+
+ AllocStatus = AllocPhys(
+ &LocalFilter->BindingsUsingLongAddress,
+ 2*sizeof(FDDI_MASK)*MaximumMulticastLongAddresses
+ );
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+ FddiDeleteFilter(LocalFilter);
+ return FALSE;
+
+ }
+
+ AllocStatus = AllocPhys(
+ &LocalFilter->BindingsUsingShortAddress,
+ 2*sizeof(FDDI_MASK)*MaximumMulticastShortAddresses
+ );
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+ FddiDeleteFilter(LocalFilter);
+ return FALSE;
+
+ }
+
+ FddiReferencePackage();
+
+ LocalFilter->FreeBindingMask = (ULONG)(-1);
+ LocalFilter->OpenList = NULL;
+
+ FDDI_COPY_NETWORK_ADDRESS(LocalFilter->AdapterLongAddress,
+ AdapterLongAddress,
+ FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+
+ FDDI_COPY_NETWORK_ADDRESS(LocalFilter->AdapterShortAddress,
+ AdapterShortAddress,
+ FDDI_LENGTH_OF_SHORT_ADDRESS
+ );
+
+ LocalFilter->Lock = Lock;
+ LocalFilter->AddressChangeAction = AddressChangeAction;
+ LocalFilter->FilterChangeAction = FilterChangeAction;
+ LocalFilter->CloseAction = CloseAction;
+ LocalFilter->NumberOfLongAddresses = 0;
+ LocalFilter->NumberOfShortAddresses = 0;
+ LocalFilter->MaximumMulticastLongAddresses = MaximumMulticastLongAddresses;
+ LocalFilter->MaximumMulticastShortAddresses = MaximumMulticastShortAddresses;
+
+ return TRUE;
+}
+
+//
+// NOTE: THIS CANNOT BE PAGABLE
+//
+VOID
+FddiDeleteFilter(
+ IN PFDDI_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to delete the memory associated with a filter
+ database. Note that this routines *ASSUMES* that the database
+ has been cleared of any active filters.
+
+Arguments:
+
+ Filter - A pointer to an FDDI_FILTER to be deleted.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ASSERT(Filter->FreeBindingMask == (FDDI_MASK)-1);
+ ASSERT(Filter->OpenList == NULL);
+
+ if (Filter->MulticastLongAddresses) {
+
+ FreePhys(
+ Filter->MulticastLongAddresses,
+ 2*FDDI_LENGTH_OF_LONG_ADDRESS*Filter->MaximumMulticastLongAddresses
+ );
+
+ }
+
+ if (Filter->MulticastShortAddresses) {
+
+ FreePhys(
+ Filter->MulticastShortAddresses,
+ 2*FDDI_LENGTH_OF_SHORT_ADDRESS*Filter->MaximumMulticastShortAddresses
+ );
+
+ }
+
+ if (Filter->BindingsUsingLongAddress) {
+
+ FreePhys(
+ Filter->BindingsUsingLongAddress,
+ 2*sizeof(FDDI_MASK)*Filter->MaximumMulticastLongAddresses
+ );
+
+ }
+
+ if (Filter->BindingsUsingShortAddress) {
+
+ FreePhys(
+ Filter->BindingsUsingShortAddress,
+ 2*sizeof(FDDI_MASK)*Filter->MaximumMulticastShortAddresses
+ );
+
+ }
+
+ FreePhys(Filter, sizeof(FDDI_FILTER));
+
+ FddiDereferencePackage();
+}
+
+
+BOOLEAN
+FddiNoteFilterOpenAdapter(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE NdisBindingContext,
+ OUT PNDIS_HANDLE NdisFilterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to add a new binding to the filter database.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE DATABASE IS LOCKED WHEN
+ IT IS CALLED.
+
+Arguments:
+
+ Filter - A pointer to the previously created and initialized filter
+ database.
+
+ MacBindingHandle - The MAC supplied value to the protocol in response
+ to a call to FddiOpenAdapter.
+
+ NdisBindingContext - An NDIS supplied value to the call to FddiOpenAdapter.
+
+ NdisFilterHandle - A pointer to this open.
+
+Return Value:
+
+ Will return false if creating a new filter index will cause the maximum
+ number of filter indexes to be exceeded.
+
+--*/
+
+{
+
+ //
+ // Will hold the value of the filter index so that we
+ // need not indirectly address through pointer parameter.
+ //
+ UINT LocalIndex;
+
+ NDIS_STATUS AllocStatus;
+
+ //
+ // Pointer to new open block.
+ //
+ PFDDI_BINDING_INFO LocalOpen;
+
+ PNDIS_OPEN_BLOCK NdisOpen = (PNDIS_OPEN_BLOCK)NdisBindingContext;
+
+
+ //
+ // Get the first free binding slot and remove that slot from
+ // the free list. We check to see if the list is empty.
+ //
+
+
+ if (Filter->FreeBindingMask == 0) {
+
+ return FALSE;
+
+ }
+
+ AllocStatus = AllocPhys(
+ &LocalOpen,
+ sizeof(FDDI_BINDING_INFO)
+ );
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Get place for the open and insert it.
+ //
+
+ FDDI_FILTER_ALLOC_OPEN(Filter, &LocalIndex);
+
+ LocalOpen->NextOpen = Filter->OpenList;
+
+ if (Filter->OpenList != NULL) {
+ Filter->OpenList->PrevOpen = LocalOpen;
+ }
+
+ LocalOpen->PrevOpen = NULL;
+
+ Filter->OpenList = LocalOpen;
+
+ LocalOpen->FilterIndex = (UCHAR)LocalIndex;
+ LocalOpen->References = 1;
+ LocalOpen->MacBindingHandle = MacBindingHandle;
+ LocalOpen->NdisBindingContext = NdisBindingContext;
+ LocalOpen->PacketFilters = 0;
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ *NdisFilterHandle = (NDIS_HANDLE)LocalOpen;
+
+ return TRUE;
+
+}
+
+
+NDIS_STATUS
+FddiDeleteFilterOpenAdapter(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ When an adapter is being closed this routine should
+ be called to delete knowledge of the adapter from
+ the filter database. This routine is likely to call
+ action routines associated with clearing filter classes
+ and addresses.
+
+ NOTE: THIS ROUTINE SHOULD ****NOT**** BE CALLED IF THE ACTION
+ ROUTINES FOR DELETING THE FILTER CLASSES OR THE MULTICAST ADDRESSES
+ HAVE ANY POSSIBILITY OF RETURNING A STATUS OTHER THAN NDIS_STATUS_PENDING
+ OR NDIS_STATUS_SUCCESS. WHILE THESE ROUTINES WILL NOT BUGCHECK IF
+ SUCH A THING IS DONE, THE CALLER WILL PROBABLY FIND IT DIFFICULT
+ TO CODE A CLOSE ROUTINE!
+
+ NOTE: THIS ROUTINE ASSUMES THAT IT IS CALLED WITH THE LOCK HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routines,
+ this will be passed to it.
+
+Return Value:
+
+ If action routines are called by the various address and filtering
+ routines the this routine will likely return the status returned
+ by those routines. The exception to this rule is noted below.
+
+ Given that the filter and address deletion routines return a status
+ NDIS_STATUS_PENDING or NDIS_STATUS_SUCCESS this routine will then
+ try to return the filter index to the freelist. If the routine
+ detects that this binding is currently being indicated to via
+ NdisIndicateReceive, this routine will return a status of
+ NDIS_STATUS_CLOSING_INDICATING.
+
+--*/
+
+{
+
+ //
+ // Holds the status returned from the packet filter and address
+ // deletion routines. Will be used to return the status to
+ // the caller of this routine.
+ //
+ NDIS_STATUS StatusToReturn;
+
+ //
+ // Local variable.
+ //
+ PFDDI_BINDING_INFO LocalOpen = (PFDDI_BINDING_INFO)NdisFilterHandle;
+
+ StatusToReturn = FddiFilterAdjust(
+ Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ (UINT)0,
+ FALSE
+ );
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS ||
+ StatusToReturn == NDIS_STATUS_PENDING) {
+
+ NDIS_STATUS StatusToReturn2;
+
+ StatusToReturn2 = FddiChangeFilterLongAddresses(
+ Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ 0,
+ NULL,
+ FALSE
+ );
+
+ if (StatusToReturn2 != NDIS_STATUS_SUCCESS) {
+
+ StatusToReturn = StatusToReturn2;
+
+ }
+
+ if ((StatusToReturn == NDIS_STATUS_SUCCESS) ||
+ (StatusToReturn == NDIS_STATUS_PENDING)) {
+
+
+ StatusToReturn2 = FddiChangeFilterShortAddresses(
+ Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ 0,
+ NULL,
+ FALSE
+ );
+
+ if (StatusToReturn2 != NDIS_STATUS_SUCCESS) {
+
+ StatusToReturn = StatusToReturn2;
+
+ }
+
+ }
+
+ }
+
+
+ if ((StatusToReturn == NDIS_STATUS_SUCCESS) ||
+ (StatusToReturn == NDIS_STATUS_PENDING)) {
+
+ //
+ // Remove the reference from the original open.
+ //
+
+ if (--(LocalOpen->References) == 0) {
+
+ //
+ // Remove it from the list.
+ //
+
+ if (LocalOpen->NextOpen != NULL) {
+
+ LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen;
+
+ }
+
+ if (LocalOpen->PrevOpen != NULL) {
+
+ LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen;
+
+ } else {
+
+ Filter->OpenList = LocalOpen->NextOpen;
+
+ }
+
+
+ //
+ // First we finish any NdisIndicateReceiveComplete that
+ // may be needed for this binding.
+ //
+
+ if (LocalOpen->ReceivedAPacket) {
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ }
+
+ FDDI_FILTER_FREE_OPEN(Filter, LocalOpen);
+
+ } else {
+
+ //
+ // Let the caller know that there is a reference to the open
+ // by the receive indication. The close action routine will be
+ // called upon return from NdisIndicateReceive.
+ //
+
+ StatusToReturn = NDIS_STATUS_CLOSING_INDICATING;
+
+ }
+
+ }
+
+ return StatusToReturn;
+
+}
+
+
+NDIS_STATUS
+FddiChangeFilterLongAddresses(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT AddressCount,
+ IN CHAR Addresses[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ The ChangeFilterAddress routine will call an action
+ routine when the overall multicast address list for the adapter
+ has changed.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the multicast address
+ list for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ AddressCount - The number of elements (addresses,
+ not bytes) in MulticastAddressList.
+
+ Addresses - The new multicast address list for this
+ binding. This is a sequence of FDDI_LENGTH_OF_LONG_ADDRESS byte
+ addresses, with no padding between them.
+
+ Set - A boolean that determines whether the multicast addresses
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfChange;
+
+ //
+ // Saves the original length of the address array.
+ //
+ UINT InitialArraySize;
+
+ //
+ // Set true when the address array changes
+ //
+ BOOLEAN AddressesChanged = FALSE;
+
+ //
+ // Use to save data if needed.
+ //
+ PVOID TmpAddressArray, TmpMaskArray;
+
+ //
+ // Simple iteration variables.
+ //
+ UINT ArrayIndex, i;
+
+
+ //
+ // Simple Temp variable
+ //
+ PCHAR CurrentAddress;
+
+ PFDDI_BINDING_INFO LocalOpen = (PFDDI_BINDING_INFO)NdisFilterHandle;
+
+
+ TmpAddressArray =
+ (PUCHAR)Filter->MulticastLongAddresses +
+ (FDDI_LENGTH_OF_LONG_ADDRESS*Filter->MaximumMulticastLongAddresses);
+
+ TmpMaskArray =
+ (PUCHAR)Filter->BindingsUsingLongAddress +
+ (sizeof(FDDI_MASK)*Filter->MaximumMulticastLongAddresses);
+
+
+ //
+ // We have to save the old mask array in
+ // case we need to restore it. If we need
+ // to save the address array too we will
+ // do that later.
+ //
+
+ MoveMemory(
+ TmpMaskArray,
+ (PVOID)Filter->BindingsUsingLongAddress,
+ Filter->NumberOfLongAddresses * sizeof(FDDI_MASK)
+ );
+
+ //
+ // We have to save the old address array in
+ // case we need to restore it. If we need
+ // to save the address array too we will
+ // do that later.
+ //
+
+ MoveMemory(
+ TmpAddressArray,
+ (PVOID)Filter->MulticastLongAddresses,
+ Filter->NumberOfLongAddresses * FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+
+ InitialArraySize = Filter->NumberOfLongAddresses;
+
+
+ //
+ // Now modify the original array...
+ //
+
+ //
+ // First go through and turn off the bit for this
+ // binding throughout the array.
+ //
+
+ for (i=0; i<(Filter->NumberOfLongAddresses); i++) {
+
+ CLEAR_BIT_IN_MASK(
+ LocalOpen->FilterIndex,
+ &(Filter->BindingsUsingLongAddress[i])
+ );
+
+ }
+
+
+ //
+ // Now go through the new addresses for this binding,
+ // and insert them into the array.
+ //
+
+ for (i=0; i<AddressCount; i++) {
+
+ CurrentAddress = ((PCHAR)Addresses) + (i*FDDI_LENGTH_OF_LONG_ADDRESS);
+
+ if (FindMulticastLongAddress(
+ Filter->NumberOfLongAddresses,
+ Filter->MulticastLongAddresses,
+ CurrentAddress,
+ &ArrayIndex)) {
+
+ //
+ // The address is there, so just turn the bit
+ // back on.
+ //
+
+ SET_BIT_IN_MASK(
+ LocalOpen->FilterIndex,
+ &Filter->BindingsUsingLongAddress[ArrayIndex]
+ );
+
+ } else {
+
+ //
+ // The address was not found, add it.
+ //
+ // NOTE: Here we temporarily need more array
+ // space then we may finally, but for now this
+ // will work.
+ //
+
+ if (Filter->NumberOfLongAddresses < Filter->MaximumMulticastLongAddresses) {
+
+ //
+ // Save the address array if it hasn't been.
+ //
+
+ AddressesChanged = TRUE;
+
+ MoveMemory(
+ Filter->MulticastLongAddresses[ArrayIndex+1],
+ Filter->MulticastLongAddresses[ArrayIndex],
+ (Filter->NumberOfLongAddresses-ArrayIndex)*FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+
+ FDDI_COPY_NETWORK_ADDRESS(
+ Filter->MulticastLongAddresses[ArrayIndex],
+ CurrentAddress,
+ FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+
+ MoveMemory(
+ &(Filter->BindingsUsingLongAddress[ArrayIndex+1]),
+ &(Filter->BindingsUsingLongAddress[ArrayIndex]),
+ (Filter->NumberOfLongAddresses-ArrayIndex)*sizeof(FDDI_MASK)
+ );
+
+ CLEAR_MASK(&Filter->BindingsUsingLongAddress[ArrayIndex]);
+
+ SET_BIT_IN_MASK(
+ LocalOpen->FilterIndex,
+ &Filter->BindingsUsingLongAddress[ArrayIndex]
+ );
+
+ Filter->NumberOfLongAddresses++;
+
+ } else {
+
+ //
+ // No room in the array, oh well.
+ //
+
+ MoveMemory(
+ (PVOID)Filter->MulticastLongAddresses,
+ TmpAddressArray,
+ InitialArraySize * FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+
+ MoveMemory(
+ (PVOID)Filter->BindingsUsingLongAddress,
+ TmpMaskArray,
+ InitialArraySize * sizeof(FDDI_MASK)
+ );
+
+ Filter->NumberOfLongAddresses = InitialArraySize;
+
+ return NDIS_STATUS_MULTICAST_FULL;
+
+ }
+
+ }
+
+ }
+
+
+ //
+ // Finally we have to remove any addresses from
+ // the multicast array if they have no bits on any more.
+ //
+ for (ArrayIndex = 0; ArrayIndex < Filter->NumberOfLongAddresses; ) {
+
+ if (IS_MASK_CLEAR(Filter->BindingsUsingLongAddress[ArrayIndex])) {
+
+ //
+ // yes it is clear, so we have to shift everything
+ // above it down one.
+ //
+
+ AddressesChanged = TRUE;
+
+ MoveMemory(
+ Filter->MulticastLongAddresses[ArrayIndex],
+ Filter->MulticastLongAddresses[ArrayIndex+1],
+ (Filter->NumberOfLongAddresses-(ArrayIndex+1))
+ *FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+
+ MoveMemory(
+ &Filter->BindingsUsingLongAddress[ArrayIndex],
+ &Filter->BindingsUsingLongAddress[ArrayIndex+1],
+ (Filter->NumberOfLongAddresses-(ArrayIndex+1))*(sizeof(FDDI_MASK))
+ );
+
+ Filter->NumberOfLongAddresses--;
+
+ } else {
+
+ ArrayIndex++;
+
+ }
+
+ }
+
+ //
+ // If the address array has changed, we have to call the
+ // action array to inform the adapter of this.
+ //
+
+ if (AddressesChanged) {
+
+ StatusOfChange = Filter->AddressChangeAction(
+ InitialArraySize,
+ TmpAddressArray,
+ Filter->NumberOfLongAddresses,
+ Filter->MulticastLongAddresses,
+ Filter->NumberOfShortAddresses,
+ Filter->MulticastShortAddresses,
+ Filter->NumberOfShortAddresses,
+ Filter->MulticastShortAddresses,
+ LocalOpen->MacBindingHandle,
+ NdisRequest,
+ Set
+ );
+
+ if ((StatusOfChange != NDIS_STATUS_SUCCESS) &&
+ (StatusOfChange != NDIS_STATUS_PENDING)) {
+
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+
+ MoveMemory(
+ (PVOID)Filter->MulticastLongAddresses,
+ TmpAddressArray,
+ InitialArraySize * FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+
+ MoveMemory(
+ (PVOID)Filter->MulticastLongAddresses,
+ TmpAddressArray,
+ InitialArraySize * FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+
+ }
+
+ } else {
+
+ StatusOfChange = NDIS_STATUS_SUCCESS;
+
+ }
+
+
+ return StatusOfChange;
+
+
+}
+
+
+NDIS_STATUS
+FddiChangeFilterShortAddresses(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT AddressCount,
+ IN CHAR Addresses[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ The ChangeFilterAddress routine will call an action
+ routine when the overall multicast address list for the adapter
+ has changed.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the multicast address
+ list for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ AddressCount - The number of elements (addresses,
+ not bytes) in MulticastAddressList.
+
+ Addresses - The new multicast address list for this
+ binding. This is a sequence of FDDI_LENGTH_OF_SHORT_ADDRESS byte
+ addresses, with no padding between them.
+
+ Set - A boolean that determines whether the multicast addresses
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfChange;
+
+ //
+ // Saves the original length of the address array.
+ //
+ UINT InitialArraySize;
+
+ //
+ // Set true when the address array changes
+ //
+ BOOLEAN AddressesChanged = FALSE;
+
+ //
+ // Use to save data if needed.
+ //
+ PVOID TmpAddressArray, TmpMaskArray;
+
+ //
+ // Simple iteration variables.
+ //
+ UINT ArrayIndex, i;
+
+
+ //
+ // Simple Temp variable
+ //
+ PCHAR CurrentAddress;
+
+ PFDDI_BINDING_INFO LocalOpen = (PFDDI_BINDING_INFO)NdisFilterHandle;
+
+
+ TmpAddressArray =
+ (PUCHAR)Filter->MulticastShortAddresses +
+ (FDDI_LENGTH_OF_SHORT_ADDRESS*Filter->MaximumMulticastShortAddresses);
+
+ TmpMaskArray =
+ (PUCHAR)Filter->BindingsUsingShortAddress +
+ (sizeof(FDDI_MASK)*Filter->MaximumMulticastShortAddresses);
+
+
+ //
+ // We have to save the old mask array in
+ // case we need to restore it. If we need
+ // to save the address array too we will
+ // do that later.
+ //
+
+ MoveMemory(
+ TmpMaskArray,
+ (PVOID)Filter->BindingsUsingShortAddress,
+ Filter->NumberOfShortAddresses * sizeof(FDDI_MASK)
+ );
+
+ //
+ // We have to save the old address array in
+ // case we need to restore it. If we need
+ // to save the address array too we will
+ // do that later.
+ //
+
+ MoveMemory(
+ TmpAddressArray,
+ (PVOID)Filter->MulticastShortAddresses,
+ Filter->NumberOfShortAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS
+ );
+
+ InitialArraySize = Filter->NumberOfShortAddresses;
+
+
+ //
+ // Now modify the original array...
+ //
+
+ //
+ // First go through and turn off the bit for this
+ // binding throughout the array.
+ //
+
+ for (i=0; i<(Filter->NumberOfShortAddresses); i++) {
+
+ CLEAR_BIT_IN_MASK(
+ LocalOpen->FilterIndex,
+ &(Filter->BindingsUsingShortAddress[i])
+ );
+
+ }
+
+
+ //
+ // Now go through the new addresses for this binding,
+ // and insert them into the array.
+ //
+
+ for (i=0; i<AddressCount; i++) {
+
+ CurrentAddress = ((PCHAR)Addresses) + (i*FDDI_LENGTH_OF_SHORT_ADDRESS);
+
+ if (FindMulticastShortAddress(
+ Filter->NumberOfShortAddresses,
+ Filter->MulticastShortAddresses,
+ CurrentAddress,
+ &ArrayIndex)) {
+
+ //
+ // The address is there, so just turn the bit
+ // back on.
+ //
+
+ SET_BIT_IN_MASK(
+ LocalOpen->FilterIndex,
+ &Filter->BindingsUsingShortAddress[ArrayIndex]
+ );
+
+ } else {
+
+ //
+ // The address was not found, add it.
+ //
+ // NOTE: Here we temporarily need more array
+ // space then we may finally, but for now this
+ // will work.
+ //
+
+ if (Filter->NumberOfShortAddresses < Filter->MaximumMulticastShortAddresses) {
+
+ //
+ // Save the address array if it hasn't been.
+ //
+
+ AddressesChanged = TRUE;
+
+ MoveMemory(
+ Filter->MulticastShortAddresses[ArrayIndex+1],
+ Filter->MulticastShortAddresses[ArrayIndex],
+ (Filter->NumberOfShortAddresses-ArrayIndex)*FDDI_LENGTH_OF_SHORT_ADDRESS
+ );
+
+ FDDI_COPY_NETWORK_ADDRESS(
+ Filter->MulticastShortAddresses[ArrayIndex],
+ CurrentAddress,
+ FDDI_LENGTH_OF_SHORT_ADDRESS
+ );
+
+ MoveMemory(
+ &(Filter->BindingsUsingShortAddress[ArrayIndex+1]),
+ &(Filter->BindingsUsingShortAddress[ArrayIndex]),
+ (Filter->NumberOfShortAddresses-ArrayIndex)*sizeof(FDDI_MASK)
+ );
+
+ CLEAR_MASK(&Filter->BindingsUsingShortAddress[ArrayIndex]);
+
+ SET_BIT_IN_MASK(
+ LocalOpen->FilterIndex,
+ &Filter->BindingsUsingShortAddress[ArrayIndex]
+ );
+
+ Filter->NumberOfShortAddresses++;
+
+ } else {
+
+ //
+ // No room in the array, oh well.
+ //
+
+ MoveMemory(
+ (PVOID)Filter->MulticastShortAddresses,
+ TmpAddressArray,
+ InitialArraySize * FDDI_LENGTH_OF_SHORT_ADDRESS
+ );
+
+ MoveMemory(
+ (PVOID)Filter->BindingsUsingShortAddress,
+ TmpMaskArray,
+ InitialArraySize * sizeof(FDDI_MASK)
+ );
+
+ Filter->NumberOfShortAddresses = InitialArraySize;
+
+ return NDIS_STATUS_MULTICAST_FULL;
+
+ }
+
+ }
+
+ }
+
+
+ //
+ // Finally we have to remove any addresses from
+ // the multicast array if they have no bits on any more.
+ //
+ for (ArrayIndex = 0; ArrayIndex < Filter->NumberOfShortAddresses; ) {
+
+ if (IS_MASK_CLEAR(Filter->BindingsUsingShortAddress[ArrayIndex])) {
+
+ //
+ // yes it is clear, so we have to shift everything
+ // above it down one.
+ //
+
+ AddressesChanged = TRUE;
+
+ MoveMemory(
+ Filter->MulticastShortAddresses[ArrayIndex],
+ Filter->MulticastShortAddresses[ArrayIndex+1],
+ (Filter->NumberOfShortAddresses-(ArrayIndex+1))
+ *FDDI_LENGTH_OF_SHORT_ADDRESS
+ );
+
+ MoveMemory(
+ &Filter->BindingsUsingShortAddress[ArrayIndex],
+ &Filter->BindingsUsingShortAddress[ArrayIndex+1],
+ (Filter->NumberOfShortAddresses-(ArrayIndex+1))*(sizeof(FDDI_MASK))
+ );
+
+ Filter->NumberOfShortAddresses--;
+
+ } else {
+
+ ArrayIndex++;
+
+ }
+
+ }
+
+ //
+ // If the address array has changed, we have to call the
+ // action array to inform the adapter of this.
+ //
+
+ if (AddressesChanged) {
+
+ StatusOfChange = Filter->AddressChangeAction(
+ Filter->NumberOfLongAddresses,
+ Filter->MulticastLongAddresses,
+ Filter->NumberOfLongAddresses,
+ Filter->MulticastLongAddresses,
+ InitialArraySize,
+ TmpAddressArray,
+ Filter->NumberOfShortAddresses,
+ Filter->MulticastShortAddresses,
+ LocalOpen->MacBindingHandle,
+ NdisRequest,
+ Set
+ );
+
+ if ((StatusOfChange != NDIS_STATUS_SUCCESS) &&
+ (StatusOfChange != NDIS_STATUS_PENDING)) {
+
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+
+ MoveMemory(
+ (PVOID)Filter->MulticastShortAddresses,
+ TmpAddressArray,
+ InitialArraySize * FDDI_LENGTH_OF_SHORT_ADDRESS
+ );
+
+ MoveMemory(
+ (PVOID)Filter->MulticastShortAddresses,
+ TmpAddressArray,
+ InitialArraySize * FDDI_LENGTH_OF_SHORT_ADDRESS
+ );
+
+ }
+
+ } else {
+
+ StatusOfChange = NDIS_STATUS_SUCCESS;
+
+ }
+
+
+ return StatusOfChange;
+
+}
+
+
+NDIS_STATUS
+FddiFilterAdjust(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT FilterClasses,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ The FilterAdjust routine will call an action routine when a
+ particular filter class is changes from not being used by any
+ binding to being used by at least one binding or vice versa.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the packet filters
+ for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - A pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ FilterClasses - The filter classes that are to be added or
+ deleted.
+
+ Set - A boolean that determines whether the filter classes
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ //
+ // Contains the value of the combined filter classes before
+ // it is adjusted.
+ //
+ UINT OldCombined = Filter->CombinedPacketFilter;
+
+ PFDDI_BINDING_INFO LocalOpen = (PFDDI_BINDING_INFO)NdisFilterHandle;
+ PFDDI_BINDING_INFO OpenList;
+
+ //
+ // Contains the value of the particlar opens packet filters
+ // prior to the change. We save this incase the action
+ // routine (if called) returns an "error" status.
+ //
+ UINT OldOpenFilters = LocalOpen->PacketFilters;
+
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfAdjust;
+
+ //
+ // Set the new filter information for the open.
+ //
+
+ LocalOpen->PacketFilters = FilterClasses;
+
+ //
+ // We always have to reform the compbined filter since
+ // this filter index may have been the only filter index
+ // to use a particular bit.
+ //
+
+
+ for (
+ OpenList = Filter->OpenList,
+ Filter->CombinedPacketFilter = 0;
+ OpenList != NULL;
+ OpenList = OpenList->NextOpen
+ ) {
+
+ Filter->CombinedPacketFilter |=
+ OpenList->PacketFilters;
+
+ }
+
+ if (OldCombined != Filter->CombinedPacketFilter) {
+
+ StatusOfAdjust = Filter->FilterChangeAction(
+ OldCombined,
+ Filter->CombinedPacketFilter,
+ LocalOpen->MacBindingHandle,
+ NdisRequest,
+ Set
+ );
+
+ if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) &&
+ (StatusOfAdjust != NDIS_STATUS_PENDING)) {
+
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+
+ LocalOpen->PacketFilters = OldOpenFilters;
+ Filter->CombinedPacketFilter = OldCombined;
+
+ }
+
+ } else {
+
+ StatusOfAdjust = NDIS_STATUS_SUCCESS;
+
+ }
+
+ return StatusOfAdjust;
+
+}
+
+
+UINT
+FddiNumberOfOpenFilterLongAddresses(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine counts the number of multicast addresses that a specific
+ open has.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to open block.
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ UINT IndexOfAddress;
+ UINT CountOfAddresses = 0;
+
+ UINT FilterIndex = ((PFDDI_BINDING_INFO)NdisFilterHandle)->FilterIndex;
+
+ for(IndexOfAddress=0;
+ IndexOfAddress < Filter->NumberOfLongAddresses;
+ IndexOfAddress++
+ ){
+
+ if (IS_BIT_SET_IN_MASK(FilterIndex,
+ Filter->BindingsUsingLongAddress[IndexOfAddress])) {
+
+ CountOfAddresses++;
+
+
+ }
+
+ }
+
+ return(CountOfAddresses);
+
+}
+
+
+UINT
+FddiNumberOfOpenFilterShortAddresses(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine counts the number of multicast addresses that a specific
+ open has.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to open block.
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ UINT IndexOfAddress;
+ UINT CountOfAddresses = 0;
+
+ UINT FilterIndex = ((PFDDI_BINDING_INFO)NdisFilterHandle)->FilterIndex;
+
+ for(IndexOfAddress=0;
+ IndexOfAddress < Filter->NumberOfShortAddresses;
+ IndexOfAddress++
+ ){
+
+ if (IS_BIT_SET_IN_MASK(FilterIndex,
+ Filter->BindingsUsingShortAddress[IndexOfAddress])) {
+
+ CountOfAddresses++;
+
+
+ }
+
+ }
+
+ return(CountOfAddresses);
+
+}
+
+
+VOID
+FddiQueryOpenFilterLongAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ OUT CHAR AddressArray[][FDDI_LENGTH_OF_LONG_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ The routine should be used by the MAC before
+ it actually alters the hardware registers to effect a
+ filtering hardware. This is usefull if another binding
+ has altered the address list since the action routine
+ is called.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Status - A pointer to the status of the call, NDIS_STATUS_SUCCESS or
+ NDIS_STATUS_FAILURE. Use EthNumberOfOpenAddresses() to get the
+ size that is needed.
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to the open block
+
+ SizeOfArray - The byte count of the AddressArray.
+
+ NumberOfAddresses - The number of addresses written to the array.
+
+ AddressArray - Will be filled with the addresses currently in the
+ multicast address list.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UINT IndexOfAddress;
+ UINT CountOfAddresses = 0;
+ UINT FilterIndex = ((PFDDI_BINDING_INFO)NdisFilterHandle)->FilterIndex;
+
+ for(IndexOfAddress=0;
+ IndexOfAddress < Filter->NumberOfLongAddresses;
+ IndexOfAddress++
+ ){
+
+ if (IS_BIT_SET_IN_MASK(FilterIndex,
+ Filter->BindingsUsingLongAddress[IndexOfAddress])) {
+
+ if (SizeOfArray < FDDI_LENGTH_OF_LONG_ADDRESS) {
+
+ *Status = NDIS_STATUS_FAILURE;
+
+ *NumberOfAddresses = 0;
+
+ return;
+
+ }
+
+ SizeOfArray -= FDDI_LENGTH_OF_LONG_ADDRESS;
+
+ MoveMemory(
+ AddressArray[CountOfAddresses],
+ Filter->MulticastLongAddresses[IndexOfAddress],
+ FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+
+ CountOfAddresses++;
+
+ }
+
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ *NumberOfAddresses = CountOfAddresses;
+
+ return;
+
+}
+
+
+VOID
+FddiQueryOpenFilterShortAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ OUT CHAR AddressArray[][FDDI_LENGTH_OF_SHORT_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ The routine should be used by the MAC before
+ it actually alters the hardware registers to effect a
+ filtering hardware. This is usefull if another binding
+ has altered the address list since the action routine
+ is called.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Status - A pointer to the status of the call, NDIS_STATUS_SUCCESS or
+ NDIS_STATUS_FAILURE. Use EthNumberOfOpenAddresses() to get the
+ size that is needed.
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - Pointer to the open block
+
+ SizeOfArray - The byte count of the AddressArray.
+
+ NumberOfAddresses - The number of addresses written to the array.
+
+ AddressArray - Will be filled with the addresses currently in the
+ multicast address list.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UINT IndexOfAddress;
+ UINT CountOfAddresses = 0;
+ UINT FilterIndex = ((PFDDI_BINDING_INFO)NdisFilterHandle)->FilterIndex;
+
+ for(IndexOfAddress=0;
+ IndexOfAddress < Filter->NumberOfShortAddresses;
+ IndexOfAddress++
+ ){
+
+ if (IS_BIT_SET_IN_MASK(FilterIndex,
+ Filter->BindingsUsingShortAddress[IndexOfAddress])) {
+
+ if (SizeOfArray < FDDI_LENGTH_OF_SHORT_ADDRESS) {
+
+ *Status = NDIS_STATUS_FAILURE;
+
+ *NumberOfAddresses = 0;
+
+ return;
+
+ }
+
+ SizeOfArray -= FDDI_LENGTH_OF_SHORT_ADDRESS;
+
+ MoveMemory(
+ AddressArray[CountOfAddresses],
+ Filter->MulticastShortAddresses[IndexOfAddress],
+ FDDI_LENGTH_OF_SHORT_ADDRESS
+ );
+
+ CountOfAddresses++;
+
+ }
+
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ *NumberOfAddresses = CountOfAddresses;
+
+ return;
+
+}
+
+
+VOID
+FddiQueryGlobalFilterLongAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PFDDI_FILTER Filter,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ IN OUT CHAR AddressArray[][FDDI_LENGTH_OF_LONG_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ The routine should be used by the MAC before
+ it actually alters the hardware registers to effect a
+ filtering hardware. This is usefull if another binding
+ has altered the address list since the action routine
+ is called.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Status - A pointer to the status of the call, NDIS_STATUS_SUCCESS or
+ NDIS_STATUS_FAILURE. Use FDDI_NUMBER_OF_GLOBAL_LONG_ADDRESSES() to get the
+ size that is needed.
+
+ Filter - A pointer to the filter database.
+
+ SizeOfArray - The byte count of the AddressArray.
+
+ NumberOfAddresses - A pointer to the number of addresses written to the
+ array.
+
+ AddressArray - Will be filled with the addresses currently in the
+ multicast address list.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ if (SizeOfArray < (Filter->NumberOfLongAddresses * FDDI_LENGTH_OF_LONG_ADDRESS)) {
+
+ *Status = NDIS_STATUS_FAILURE;
+
+ *NumberOfAddresses = 0;
+
+ } else {
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ *NumberOfAddresses = Filter->NumberOfLongAddresses;
+
+ MoveMemory(
+ AddressArray[0],
+ Filter->MulticastLongAddresses[0],
+ Filter->NumberOfLongAddresses*FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+
+ }
+
+}
+
+
+VOID
+FddiQueryGlobalFilterShortAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PFDDI_FILTER Filter,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ IN OUT CHAR AddressArray[][FDDI_LENGTH_OF_SHORT_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ The routine should be used by the MAC before
+ it actually alters the hardware registers to effect a
+ filtering hardware. This is usefull if another binding
+ has altered the address list since the action routine
+ is called.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Status - A pointer to the status of the call, NDIS_STATUS_SUCCESS or
+ NDIS_STATUS_FAILURE. Use FDDI_NUMBER_OF_GLOBAL_SHORT_ADDRESSES() to get the
+ size that is needed.
+
+ Filter - A pointer to the filter database.
+
+ SizeOfArray - The byte count of the AddressArray.
+
+ NumberOfAddresses - A pointer to the number of addresses written to the
+ array.
+
+ AddressArray - Will be filled with the addresses currently in the
+ multicast address list.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ if (SizeOfArray < (Filter->NumberOfShortAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS)) {
+
+ *Status = NDIS_STATUS_FAILURE;
+
+ *NumberOfAddresses = 0;
+
+ } else {
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ *NumberOfAddresses = Filter->NumberOfShortAddresses;
+
+ MoveMemory(
+ AddressArray[0],
+ Filter->MulticastShortAddresses[0],
+ Filter->NumberOfShortAddresses*FDDI_LENGTH_OF_SHORT_ADDRESS
+ );
+
+ }
+
+}
+
+
+VOID
+FddiFilterIndicateReceive(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PCHAR Address,
+ IN UINT AddressLength,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate a packet to
+ all bindings. The packet will be filtered so that only the
+ appropriate bindings will receive the packet.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ MacReceiveContext - A MAC supplied context value that must be
+ returned by the protocol if it calls MacTransferData.
+
+ Address - The destination address from the received packet.
+
+ AddressLength - The length of the above address.
+
+ HeaderBuffer - A virtual address of the virtually contiguous
+ buffer containing the MAC header of the packet.
+
+ HeaderBufferSize - An unsigned integer indicating the size of
+ the header buffer, in bytes.
+
+ LookaheadBuffer - A virtual address of the virtually contiguous
+ buffer containing the first LookaheadBufferSize bytes of data
+ of the packet. The packet buffer is valid only within the current
+ call to the receive event handler.
+
+ LookaheadBufferSize - An unsigned integer indicating the size of
+ the lookahead buffer, in bytes.
+
+ PacketSize - An unsigned integer indicating the size of the received
+ packet, in bytes. This number has nothing to do with the lookahead
+ buffer, but indicates how large the arrived packet is so that a
+ subsequent MacTransferData request can be made to transfer the entire
+ packet as necessary.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ KIRQL oldIrql;
+ KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ FddiFilterDprIndicateReceive(
+ Filter,
+ MacReceiveContext,
+ Address,
+ AddressLength,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize
+ );
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ KeLowerIrql( oldIrql );
+ return;
+}
+
+
+VOID
+FddiFilterDprIndicateReceive(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PCHAR Address,
+ IN UINT AddressLength,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate a packet to
+ all bindings. The packet will be filtered so that only the
+ appropriate bindings will receive the packet.
+
+ Called at DPC_LEVEL.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ MacReceiveContext - A MAC supplied context value that must be
+ returned by the protocol if it calls MacTransferData.
+
+ Address - The destination address from the received packet.
+
+ AddressLength - The length of the above address.
+
+ HeaderBuffer - A virtual address of the virtually contiguous
+ buffer containing the MAC header of the packet.
+
+ HeaderBufferSize - An unsigned integer indicating the size of
+ the header buffer, in bytes.
+
+ LookaheadBuffer - A virtual address of the virtually contiguous
+ buffer containing the first LookaheadBufferSize bytes of data
+ of the packet. The packet buffer is valid only within the current
+ call to the receive event handler.
+
+ LookaheadBufferSize - An unsigned integer indicating the size of
+ the lookahead buffer, in bytes.
+
+ PacketSize - An unsigned integer indicating the size of the received
+ packet, in bytes. This number has nothing to do with the lookahead
+ buffer, but indicates how large the arrived packet is so that a
+ subsequent MacTransferData request can be made to transfer the entire
+ packet as necessary.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Will hold the type of address that we know we've got.
+ //
+ UINT AddressType;
+
+ //
+ // Will hold the status of indicating the receive packet.
+ // ZZZ For now this isn't used.
+ //
+ NDIS_STATUS StatusOfReceive;
+
+ //
+ // Will hold the filter classes of the binding being indicated.
+ //
+ UINT BindingFilters;
+
+ //
+ // Holds BindingFilters intersected with the packet type
+ //
+ UINT IntersectionOfFilters;
+
+ //
+ // Current Open to indicate to.
+ //
+ PFDDI_BINDING_INFO LocalOpen;
+
+ //
+ // Holds the result of address determinations.
+ //
+ INT ResultOfAddressCheck;
+
+ //
+ // If the packet is a runt packet, then only indicate to PROMISCUOUS
+ //
+
+ if ( HeaderBufferSize > (2 * AddressLength) && PacketSize != 0 ) {
+
+ //
+ //
+ // Determine whether the input address is a simple direct,
+ // a broadcast, a multicast, or an SMT address.
+ //
+
+ //
+ // First check if it *at least* has the multicast address bit.
+ //
+
+ FDDI_IS_SMT(
+ *((PCHAR)HeaderBuffer),
+ &ResultOfAddressCheck
+ );
+
+ if (ResultOfAddressCheck) {
+
+ AddressType = NDIS_PACKET_TYPE_SMT;
+
+ } else {
+
+ FDDI_IS_MULTICAST(
+ Address,
+ AddressLength,
+ &ResultOfAddressCheck
+ );
+
+ if (ResultOfAddressCheck) {
+
+ //
+ // It is at least a multicast address. Check to see if
+ // it is a broadcast address.
+ //
+
+ FDDI_IS_BROADCAST(
+ Address,
+ AddressLength,
+ &ResultOfAddressCheck
+ );
+
+ if (ResultOfAddressCheck) {
+
+
+#if DBG
+
+if (NdisCheckBadDrivers) {
+
+ if (!(Filter->CombinedPacketFilter & NDIS_PACKET_TYPE_BROADCAST)) {
+
+ //
+ // We should never receive directed packets
+ // to someone else unless in p-mode.
+ //
+ DbgPrint("NDIS: Bad driver, indicating broadcast\n");
+ DbgPrint("NDIS: packets when not set to.\n");
+ DbgBreakPoint();
+
+ }
+
+}
+
+#endif
+
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+
+ } else {
+
+ AddressType = NDIS_PACKET_TYPE_MULTICAST;
+
+ }
+
+ } else {
+
+ //
+ // Verify that the address is directed to the adapter. We
+ // have to check for this because of the following senario.
+ //
+ // Adapter A is in promiscuous mode.
+ // Adapter B only wants directed packets to this adapter.
+ //
+ // The MAC will indicate *all* packets.
+ //
+ // The filter package needs to filter directed packets to
+ // other adapters from ones directed to this adapter.
+ //
+
+ if (Filter->CombinedPacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS) {
+
+ //
+ // The result of comparing an element of the address
+ // array and the multicast address.
+ //
+ // Result < 0 Implies the adapter address is greater.
+ // Result > 0 Implies the address is greater.
+ // Result = 0 Implies that the they are equal.
+ //
+ INT Result;
+
+ if (AddressLength == FDDI_LENGTH_OF_LONG_ADDRESS) {
+
+ FDDI_COMPARE_NETWORK_ADDRESSES_EQ(
+ Filter->AdapterLongAddress,
+ Address,
+ FDDI_LENGTH_OF_LONG_ADDRESS,
+ &Result
+ );
+
+ if (Result == 0) {
+
+ AddressType = NDIS_PACKET_TYPE_DIRECTED;
+
+ } else {
+
+ AddressType = 0;
+
+ }
+
+ } else if (AddressLength == FDDI_LENGTH_OF_SHORT_ADDRESS) {
+
+ FDDI_COMPARE_NETWORK_ADDRESSES_EQ(
+ Filter->AdapterShortAddress,
+ Address,
+ FDDI_LENGTH_OF_SHORT_ADDRESS,
+ &Result
+ );
+
+ if (Result == 0) {
+
+ AddressType = NDIS_PACKET_TYPE_DIRECTED;
+
+ } else {
+
+ AddressType = 0;
+
+ }
+
+ } else {
+
+ //
+ // This will cause binding that only want a specific
+ // address type to not be indicated.
+ //
+
+ AddressType = 0;
+
+ }
+
+ } else {
+
+#if DBG
+
+if (NdisCheckBadDrivers) {
+
+ //
+ // The result of comparing an element of the address
+ // array and the multicast address.
+ //
+ // Result < 0 Implies the adapter address is greater.
+ // Result > 0 Implies the address is greater.
+ // Result = 0 Implies that the they are equal.
+ //
+ INT Result = 0;
+
+ if (AddressLength == FDDI_LENGTH_OF_LONG_ADDRESS) {
+
+ FDDI_COMPARE_NETWORK_ADDRESSES_EQ(
+ Filter->AdapterLongAddress,
+ Address,
+ FDDI_LENGTH_OF_LONG_ADDRESS,
+ &Result
+ );
+
+ } else if (AddressLength == FDDI_LENGTH_OF_SHORT_ADDRESS) {
+
+ FDDI_COMPARE_NETWORK_ADDRESSES_EQ(
+ Filter->AdapterShortAddress,
+ Address,
+ FDDI_LENGTH_OF_SHORT_ADDRESS,
+ &Result
+ );
+
+ }
+
+ if (Result != 0) {
+
+ //
+ // We should never receive directed packets
+ // to someone else unless in p-mode.
+ //
+ DbgPrint("NDIS: Bad driver, indicating packets\n");
+ DbgPrint("NDIS: to another station when not in\n");
+ DbgPrint("NDIS: promiscuous mode.\n");
+ DbgBreakPoint();
+
+
+ }
+
+}
+
+#endif
+
+ AddressType = NDIS_PACKET_TYPE_DIRECTED;
+
+ }
+
+ }
+
+ }
+
+ } else {
+
+ //
+ // Runt
+ //
+
+ AddressType = NDIS_PACKET_TYPE_PROMISCUOUS;
+
+ }
+
+ //
+ // We need to acquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+
+ LocalOpen = Filter->OpenList;
+
+ while (LocalOpen != NULL) {
+
+ BindingFilters = LocalOpen->PacketFilters;
+
+ IntersectionOfFilters = BindingFilters & AddressType;
+
+ //
+ // if the binding wants direct packets and this is a directly
+ // addressed packet then the binding gets the packet.
+ // if Smt and wanted, or broadcast and wanted, indicate it.
+ //
+
+ if (IntersectionOfFilters & (NDIS_PACKET_TYPE_SMT |
+ NDIS_PACKET_TYPE_DIRECTED |
+ NDIS_PACKET_TYPE_BROADCAST)) {
+
+ goto IndicatePacket;
+
+ }
+
+
+ //
+ // if the binding wants multicast packets and the packet
+ // is a multicast packet and it's in the list of addresses
+ // it will get the packet.
+ //
+
+ if (AddressType & (BindingFilters & NDIS_PACKET_TYPE_MULTICAST)) {
+
+ //
+ // Will hold the index of the multicast
+ // address if it finds it.
+ //
+ UINT IndexOfAddress;
+
+ if (AddressLength == FDDI_LENGTH_OF_LONG_ADDRESS) {
+
+ if (FindMulticastLongAddress(
+ Filter->NumberOfLongAddresses,
+ Filter->MulticastLongAddresses,
+ Address,
+ &IndexOfAddress
+ )) {
+
+ if (IS_BIT_SET_IN_MASK(
+ LocalOpen->FilterIndex,
+ Filter->BindingsUsingLongAddress[IndexOfAddress]
+ )) {
+
+ goto IndicatePacket;
+
+ }
+
+ }
+
+ } else {
+
+ if (FindMulticastShortAddress(
+ Filter->NumberOfShortAddresses,
+ Filter->MulticastShortAddresses,
+ Address,
+ &IndexOfAddress
+ )) {
+
+ if (IS_BIT_SET_IN_MASK(
+ LocalOpen->FilterIndex,
+ Filter->BindingsUsingShortAddress[IndexOfAddress]
+ )) {
+
+ goto IndicatePacket;
+
+ }
+
+ }
+
+ }
+ }
+
+ //
+ // if the binding wants all multicast packets and the packet
+ // has a multicast address it will get the packet
+ //
+
+ if ((AddressType & NDIS_PACKET_TYPE_MULTICAST) &&
+ (BindingFilters & NDIS_PACKET_TYPE_ALL_MULTICAST)) {
+
+ goto IndicatePacket;
+
+ }
+
+ //
+ // if the binding is promiscuous then it will get the packet
+ //
+
+ if (BindingFilters & NDIS_PACKET_TYPE_PROMISCUOUS) {
+
+ goto IndicatePacket;
+
+ }
+
+ goto GetNextBinding;
+
+IndicatePacket:;
+
+ LocalOpen->References++;
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ //
+ // Indicate the packet to the binding.
+ //
+
+ FilterIndicateReceive(
+ &StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ if ((--(LocalOpen->References)) == 0) {
+
+ PFDDI_BINDING_INFO NextOpen = LocalOpen->NextOpen;
+
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+
+ //
+ // Remove it from the list.
+ //
+
+ if (LocalOpen->NextOpen != NULL) {
+
+ LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen;
+
+ }
+
+ if (LocalOpen->PrevOpen != NULL) {
+
+ LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen;
+
+ } else {
+
+ Filter->OpenList = LocalOpen->NextOpen;
+
+ }
+
+
+
+ //
+ // Call the IndicateComplete routine.
+ //
+
+
+ if (LocalOpen->ReceivedAPacket) {
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ }
+
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+
+ Filter->CloseAction(LocalOpen->MacBindingHandle);
+
+
+ FDDI_FILTER_FREE_OPEN(Filter, LocalOpen);
+
+ LocalOpen = NextOpen;
+
+ continue;
+
+ }
+
+GetNextBinding:
+
+ LocalOpen = LocalOpen->NextOpen;
+
+ }
+
+}
+
+
+VOID
+FddiFilterIndicateReceiveComplete(
+ IN PFDDI_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate that the receive
+ process is complete to all bindings. Only those bindings which
+ have received packets will be notified.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ KIRQL oldIrql;
+ KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ FddiFilterDprIndicateReceiveComplete(
+ Filter
+ );
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ KeLowerIrql( oldIrql );
+ return;
+}
+
+
+VOID
+FddiFilterDprIndicateReceiveComplete(
+ IN PFDDI_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate that the receive
+ process is complete to all bindings. Only those bindings which
+ have received packets will be notified.
+
+ Called at DPC_LEVEL.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PFDDI_BINDING_INFO LocalOpen;
+
+ //
+ // We need to aquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+
+ LocalOpen = Filter->OpenList;
+
+ while (LocalOpen != NULL) {
+
+ if (LocalOpen->ReceivedAPacket) {
+
+ //
+ // Indicate the binding.
+ //
+
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ LocalOpen->References++;
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ if ((--(LocalOpen->References)) == 0) {
+
+ PFDDI_BINDING_INFO NextOpen = LocalOpen->NextOpen;
+
+ //
+ // This binding is shutting down. We have to kill it.
+ //
+
+ //
+ // Remove it from the list.
+ //
+
+ if (LocalOpen->NextOpen != NULL) {
+
+ LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen;
+
+ }
+
+ if (LocalOpen->PrevOpen != NULL) {
+
+ LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen;
+
+ } else {
+
+ Filter->OpenList = LocalOpen->NextOpen;
+
+ }
+
+
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+
+ Filter->CloseAction(LocalOpen->MacBindingHandle);
+
+
+ FDDI_FILTER_FREE_OPEN(Filter, LocalOpen);
+
+ LocalOpen = NextOpen;
+
+ continue;
+ }
+
+ }
+
+ LocalOpen = LocalOpen->NextOpen;
+
+ }
+
+}
+
+
+BOOLEAN
+FindMulticastLongAddress(
+ IN UINT NumberOfAddresses,
+ IN CHAR AddressArray[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN CHAR MulticastAddress[FDDI_LENGTH_OF_LONG_ADDRESS],
+ OUT PUINT ArrayIndex
+ )
+
+/*++
+
+Routine Description:
+
+ Given an array of multicast addresses search the array for
+ a particular multicast address. It is assumed that the
+ address array is already sorted.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+ NOTE: This ordering is arbitrary but consistant.
+
+Arguments:
+
+ NumberOfAddresses - The number of addresses currently in the
+ address array.
+
+ AddressArray - An array of multicast addresses.
+
+ MulticastAddress - The address to search for in the address array.
+
+ ArrayIndex - Will point to where the MulticastAddress is in
+ the AddressArray, or if it isn't in the array, where it should
+ be in the array.
+
+Return Value:
+
+ If the address is in the sorted list this routine will return
+ TRUE, otherwise FALSE.
+
+--*/
+
+{
+
+ //
+ // Indices into the address array so that we may do a binary
+ // search.
+ //
+ UINT Bottom = 0;
+ UINT Middle = NumberOfAddresses / 2;
+ UINT Top;
+
+ if (NumberOfAddresses) {
+
+ Top = NumberOfAddresses - 1;
+
+ while ((Middle <= Top) && (Middle >= Bottom)) {
+
+ //
+ // The result of comparing an element of the address
+ // array and the multicast address.
+ //
+ // Result < 0 Implies the multicast address is greater.
+ // Result > 0 Implies the address array element is greater.
+ // Result = 0 Implies that the array element and the address
+ // are equal.
+ //
+ INT Result;
+
+ FDDI_COMPARE_NETWORK_ADDRESSES(
+ AddressArray[Middle],
+ MulticastAddress,
+ FDDI_LENGTH_OF_LONG_ADDRESS,
+ &Result
+ );
+
+ if (Result == 0) {
+
+ *ArrayIndex = Middle;
+ return(TRUE);
+
+ } else if (Result > 0) {
+
+ if (Middle == 0) break;
+ Top = Middle - 1;
+
+
+ } else {
+
+ Bottom = Middle+1;
+
+ }
+
+ Middle = Bottom + (((Top+1) - Bottom)/2);
+
+ }
+
+ }
+
+ *ArrayIndex = Middle;
+
+ return(FALSE);
+
+}
+
+
+BOOLEAN
+FindMulticastShortAddress(
+ IN UINT NumberOfAddresses,
+ IN CHAR AddressArray[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN CHAR MulticastAddress[FDDI_LENGTH_OF_SHORT_ADDRESS],
+ OUT PUINT ArrayIndex
+ )
+
+/*++
+
+Routine Description:
+
+ Given an array of multicast addresses search the array for
+ a particular multicast address. It is assumed that the
+ address array is already sorted.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+ NOTE: This ordering is arbitrary but consistant.
+
+Arguments:
+
+ NumberOfAddresses - The number of addresses currently in the
+ address array.
+
+ AddressArray - An array of multicast addresses.
+
+ MulticastAddress - The address to search for in the address array.
+
+ ArrayIndex - Will point to where the MulticastAddress is in
+ the AddressArray, or if it isn't in the array, where it should
+ be in the array.
+
+Return Value:
+
+ If the address is in the sorted list this routine will return
+ TRUE, otherwise FALSE.
+
+--*/
+
+{
+
+ //
+ // Indices into the address array so that we may do a binary
+ // search.
+ //
+ UINT Bottom = 0;
+ UINT Middle = NumberOfAddresses / 2;
+ UINT Top;
+
+ if (NumberOfAddresses) {
+
+ Top = NumberOfAddresses - 1;
+
+ while ((Middle <= Top) && (Middle >= Bottom)) {
+
+ //
+ // The result of comparing an element of the address
+ // array and the multicast address.
+ //
+ // Result < 0 Implies the multicast address is greater.
+ // Result > 0 Implies the address array element is greater.
+ // Result = 0 Implies that the array element and the address
+ // are equal.
+ //
+ INT Result;
+
+ FDDI_COMPARE_NETWORK_ADDRESSES(
+ AddressArray[Middle],
+ MulticastAddress,
+ FDDI_LENGTH_OF_SHORT_ADDRESS,
+ &Result
+ );
+
+ if (Result == 0) {
+
+ *ArrayIndex = Middle;
+ return(TRUE);
+
+ } else if (Result > 0) {
+
+ if (Middle == 0) break;
+ Top = Middle - 1;
+
+
+ } else {
+
+ Bottom = Middle+1;
+
+ }
+
+ Middle = Bottom + (((Top+1) - Bottom)/2);
+
+ }
+
+ }
+
+ *ArrayIndex = Middle;
+
+ return(FALSE);
+
+}
+
+
+BOOLEAN
+FddiShouldAddressLoopBack(
+ IN PFDDI_FILTER Filter,
+ IN CHAR Address[],
+ IN UINT AddressLength
+ )
+
+/*++
+
+Routine Description:
+
+ Do a quick check to see whether the input address should
+ loopback.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+ NOTE: THIS ROUTINE DOES NOT CHECK THE SPECIAL CASE OF SOURCE
+ EQUALS DESTINATION.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ Address - A network address to check for loopback.
+
+ AddressLength - Length of the above address in bytes.
+
+Return Value:
+
+ Returns TRUE if the address needs to be loopback. It
+ will return FALSE if there is *no* chance that the address would
+ require loopback.
+
+--*/
+{
+ BOOLEAN fLoopback, fSelfDirected;
+
+ FddiShouldAddressLoopBackMacro(Filter, Address, AddressLength, &fLoopback, &fSelfDirected);
+
+ return(fLoopback);
+}
diff --git a/private/ntos/ndis/ndis30/ffilter.h b/private/ntos/ndis/ndis30/ffilter.h
new file mode 100644
index 000000000..ae3ae8120
--- /dev/null
+++ b/private/ntos/ndis/ndis30/ffilter.h
@@ -0,0 +1,692 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ffilter.h
+
+Abstract:
+
+ Header file for the address filtering library for NDIS MAC's.
+
+Author:
+
+ Anthony V. Ercolano (tonye) creation-date 3-Aug-1990
+
+Environment:
+
+ Runs in the context of a single MAC driver.
+
+Notes:
+
+ None.
+
+Revision History:
+
+ Sean Selitrennikoff (SeanSe) - converter efilter.* for FDDI support.
+
+
+--*/
+
+#ifndef _FDDI_FILTER_DEFS_
+#define _FDDI_FILTER_DEFS_
+
+#define FDDI_LENGTH_OF_LONG_ADDRESS 6
+#define FDDI_LENGTH_OF_SHORT_ADDRESS 2
+
+
+//
+// ZZZ This is a little-endian specific check.
+//
+#define FDDI_IS_MULTICAST(Address, AddressLength, Result) \
+{ \
+ PUCHAR _A = Address; \
+ *Result = (BOOLEAN)(_A[0] & ((UCHAR)0x01)); \
+}
+
+//
+// Check whether the frame is SMT or not.
+//
+#define FDDI_IS_SMT(FcByte, Result) \
+{ \
+ *Result = ((FcByte & ((UCHAR)0xf0)) == 0x40); \
+}
+
+
+//
+// Check whether an address is broadcast.
+//
+#define FDDI_IS_BROADCAST(Address, AddressLength, Result) \
+{ \
+ PUCHAR _A = Address; \
+ PUCHAR _E = _A + AddressLength;\
+ *Result = TRUE;\
+ for (; _A < _E ; _A++) {\
+ if (*_A != 0xFF) {\
+ *Result = FALSE;\
+ break;\
+ }\
+ }\
+}
+
+
+//
+// This macro will compare network addresses.
+//
+// A - Is a network address.
+//
+// B - Is a network address.
+//
+// Result - The result of comparing two network address.
+//
+// Result < 0 Implies the B address is greater.
+// Result > 0 Implies the A element is greater.
+// Result = 0 Implies equality.
+//
+// Note that this is an arbitrary ordering. There is not
+// defined relation on network addresses. This is ad-hoc!
+//
+//
+#define FDDI_COMPARE_NETWORK_ADDRESSES(A,B,_AddressLength,Result) \
+{ \
+ PUCHAR _A = (PUCHAR)(A); \
+ PUCHAR _B = (PUCHAR)(B); \
+ if ( *(USHORT UNALIGNED *)_A > \
+ *(USHORT UNALIGNED *)_B ) { \
+ *Result = 1; \
+ } else if ( *(USHORT UNALIGNED *)_A < \
+ *(USHORT UNALIGNED *)_B ) { \
+ *Result = (UINT)-1; \
+ } else if (_AddressLength == 2) { \
+ *Result = 0; \
+ } else if ( *(ULONG UNALIGNED *)&_A[2] > \
+ *(ULONG UNALIGNED *)&_B[2] ) { \
+ *Result = 1; \
+ } else if ( *(ULONG UNALIGNED *)&_A[2] < \
+ *(ULONG UNALIGNED *)&_B[2] ) { \
+ *Result = (UINT)-1; \
+ } else { \
+ *Result = 0; \
+ } \
+}
+
+//
+// This macro will compare network addresses.
+//
+// A - Is a network address.
+//
+// B - Is a network address.
+//
+// Result - The result of comparing two network address.
+//
+// Result != 0 Implies inequality.
+// Result == 0 Implies equality.
+//
+//
+#define FDDI_COMPARE_NETWORK_ADDRESSES_EQ(A,B,_AddressLength,Result) \
+{ \
+ PUCHAR _A = (PUCHAR)(A); \
+ PUCHAR _B = (PUCHAR)(B); \
+ if ( ( *(USHORT UNALIGNED *)_A == \
+ *(USHORT UNALIGNED *)_B ) && \
+ ( ( (_AddressLength) == 2 ) || \
+ ( *(ULONG UNALIGNED *)&_A[2] == \
+ *(ULONG UNALIGNED *)&_B[2] ) ) ) { \
+ *Result = 0; \
+ } else { \
+ *Result = 1; \
+ } \
+}
+
+
+//
+// This macro is used to copy from one network address to
+// another.
+//
+#define FDDI_COPY_NETWORK_ADDRESS(D,S,AddressLength) \
+{ \
+ PCHAR _D = (D); \
+ PCHAR _S = (S); \
+ UINT _C = (AddressLength);\
+ for ( ; _C > 0 ; _D++, _S++, _C--) {\
+ *_D = *_S;\
+ }\
+}
+
+
+//
+//UINT
+//FDDI_QUERY_FILTER_CLASSES(
+// IN PFDDI_FILTER Filter
+// )
+//
+// This macro returns the currently enabled filter classes.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define FDDI_QUERY_FILTER_CLASSES(Filter) ((Filter)->CombinedPacketFilter)
+
+
+//
+//UINT
+//FDDI_QUERY_PACKET_FILTER(
+// IN PFDDI_FILTER Filter,
+// IN NDIS_HANDLE NdisFilterHandle
+// )
+//
+// This macro returns the currently enabled filter classes for a specific
+// open instance.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define FDDI_QUERY_PACKET_FILTER(Filter, NdisFilterHandle) \
+ (((PFDDI_BINDING_INFO)(NdisFilterHandle))->PacketFilters)
+
+
+//
+//UINT
+//FDDI_NUMBER_OF_GLOBAL_FILTER_LONG_ADDRESSES(
+// IN PFDDI_FILTER Filter
+// )
+//
+// This macro returns the number of multicast addresses in the
+// multicast address list.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define FDDI_NUMBER_OF_GLOBAL_FILTER_LONG_ADDRESSES(Filter) ((Filter)->NumberOfLongAddresses)
+
+
+//
+//UINT
+//FDDI_NUMBER_OF_GLOBAL_FILTER_SHORT_ADDRESSES(
+// IN PFDDI_FILTER Filter
+// )
+//
+// This macro returns the number of multicast addresses in the
+// multicast address list.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define FDDI_NUMBER_OF_GLOBAL_FILTER_SHORT_ADDRESSES(Filter) ((Filter)->NumberOfShortAddresses)
+
+
+//
+// An action routine type. The routines are called
+// when a filter type is set for the first time or
+// no more bindings require a particular type of filter.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+NDIS_STATUS
+(*FDDI_FILTER_CHANGE)(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+//
+// This action routine is called when a new multicast address
+// list is given to the filter. The action routine is given
+// arrays containing the old and new multicast addresses.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+NDIS_STATUS
+(*FDDI_ADDRESS_CHANGE)(
+ IN UINT OldLongAddressCount,
+ IN CHAR OldLongAddresses[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN UINT NewLongAddressCount,
+ IN CHAR NewLongAddresses[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN UINT OldShortAddressCount,
+ IN CHAR OldShortAddresses[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN UINT NewShortAddressCount,
+ IN CHAR NewShortAddresses[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+//
+// This action routine is called when the mac requests a close for
+// a particular binding *WHILE THE BINDING IS BEING INDICATED TO
+// THE PROTOCOL*. The filtering package can't get rid of the open
+// right away. So this routine will be called as soon as the
+// NdisIndicateReceive returns.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+VOID
+(*FDDI_DEFERRED_CLOSE)(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+typedef ULONG FDDI_MASK,*PFDDI_MASK;
+
+//
+// Maximum number of opens the filter package will support. This is
+// the max so that bit masks can be used instead of a spaghetti of
+// pointers.
+//
+#define FDDI_FILTER_MAX_OPENS (sizeof(ULONG) * 8)
+
+//
+// The binding info is threaded on two lists. When
+// the binding is free it is on a single freelist.
+//
+// When the binding is being used it is on a doubly linked
+// index list.
+//
+typedef struct _FDDI_BINDING_INFO {
+ NDIS_HANDLE MacBindingHandle;
+ NDIS_HANDLE NdisBindingContext;
+ UINT PacketFilters;
+ ULONG References;
+ struct _FDDI_BINDING_INFO *NextOpen;
+ struct _FDDI_BINDING_INFO *PrevOpen;
+ BOOLEAN ReceivedAPacket;
+ UCHAR FilterIndex;
+} FDDI_BINDING_INFO,*PFDDI_BINDING_INFO;
+
+//
+// An opaque type that contains a filter database.
+// The MAC need not know how it is structured.
+//
+typedef struct _FDDI_FILTER {
+
+ //
+ // Spin lock used to protect the filter from multiple accesses.
+ //
+ PNDIS_SPIN_LOCK Lock;
+
+ //
+ // Pointer to an array of 6 character arrays holding the
+ // multicast addresses requested for filtering.
+ //
+ CHAR (*MulticastLongAddresses)[FDDI_LENGTH_OF_LONG_ADDRESS];
+
+ //
+ // Pointer to an array of FDDI_MASKS that work in conjuction with
+ // the MulticastLongAddress array. In the masks, a bit being enabled
+ // indicates that the binding with the given FilterIndex is using
+ // the corresponding address.
+ //
+ FDDI_MASK *BindingsUsingLongAddress;
+
+ //
+ // Pointer to an array of 2 character arrays holding the
+ // multicast addresses requested for filtering.
+ //
+ CHAR (*MulticastShortAddresses)[FDDI_LENGTH_OF_SHORT_ADDRESS];
+
+ //
+ // Pointer to an array of FDDI_MASKS that work in conjuction with
+ // the MulticastShortAddress array. In the masks, a bit being enabled
+ // indicates that the binding with the given FilterIndex is using
+ // the corresponding address.
+ //
+ FDDI_MASK *BindingsUsingShortAddress;
+
+ //
+ // Combination of all the filters of all the open bindings.
+ //
+ UINT CombinedPacketFilter;
+
+ //
+ // Pointer for traversing the open list.
+ //
+ PFDDI_BINDING_INFO OpenList;
+
+
+ //
+ // Action routines to be invoked on notable changes in the filter.
+ //
+
+ FDDI_ADDRESS_CHANGE AddressChangeAction;
+ FDDI_FILTER_CHANGE FilterChangeAction;
+ FDDI_DEFERRED_CLOSE CloseAction;
+
+ //
+ // The maximum number of long addresses used for filtering.
+ //
+ UINT MaximumMulticastLongAddresses;
+
+ //
+ // The maximum number of short addresses used for filtering.
+ //
+ UINT MaximumMulticastShortAddresses;
+
+ //
+ // The current number of addresses in the LongAddress filter.
+ //
+ UINT NumberOfLongAddresses;
+
+ //
+ // The current number of addresses in the ShortAddress filter.
+ //
+ UINT NumberOfShortAddresses;
+
+ //
+ // Bit mask of opens that are available.
+ //
+ ULONG FreeBindingMask;
+
+ //
+ // Long Address of the adapter.
+ //
+ UCHAR AdapterLongAddress[FDDI_LENGTH_OF_LONG_ADDRESS];
+
+ //
+ // Short Address of the adapter.
+ //
+ UCHAR AdapterShortAddress[FDDI_LENGTH_OF_SHORT_ADDRESS];
+
+} FDDI_FILTER,*PFDDI_FILTER;
+
+//
+// Only for internal wrapper use.
+//
+VOID
+FddiInitializePackage(
+ VOID
+ );
+
+VOID
+FddiReferencePackage(
+ VOID
+ );
+
+VOID
+FddiDereferencePackage(
+ VOID
+ );
+
+//
+// Exported routines
+//
+
+EXPORT
+BOOLEAN
+FddiCreateFilter(
+ IN UINT MaximumMulticastLongAddresses,
+ IN UINT MaximumMulticastShortAddresses,
+ IN FDDI_ADDRESS_CHANGE AddressChangeAction,
+ IN FDDI_FILTER_CHANGE FilterChangeAction,
+ IN FDDI_DEFERRED_CLOSE CloseAction,
+ IN PUCHAR AdapterLongAddress,
+ IN PUCHAR AdapterShortAddress,
+ IN PNDIS_SPIN_LOCK Lock,
+ OUT PFDDI_FILTER *Filter
+ );
+
+EXPORT
+VOID
+FddiDeleteFilter(
+ IN PFDDI_FILTER Filter
+ );
+
+EXPORT
+BOOLEAN
+FddiNoteFilterOpenAdapter(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE NdisBindingContext,
+ OUT PNDIS_HANDLE NdisFilterHandle
+ );
+
+EXPORT
+NDIS_STATUS
+FddiDeleteFilterOpenAdapter(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+EXPORT
+NDIS_STATUS
+FddiChangeFilterLongAddresses(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT AddressCount,
+ IN CHAR Addresses[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN BOOLEAN Set
+ );
+
+EXPORT
+NDIS_STATUS
+FddiChangeFilterShortAddresses(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT AddressCount,
+ IN CHAR Addresses[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN BOOLEAN Set
+ );
+
+
+#define FddiShouldAddressLoopBackMacro(_Filter, _Address, _AddressLength, _pfLoopBack, _pfSelfDirected)\
+{ \
+ /* \
+ * Holds the result of address determinations. \
+ */ \
+ INT ResultOfAddressCheck; \
+ \
+ UINT CombinedFilters; \
+ \
+ CombinedFilters = FDDI_QUERY_FILTER_CLASSES(_Filter); \
+ \
+ *(_pfLoopBack) = FALSE; \
+ *(_pfSelfDirected) = FALSE; \
+ \
+ do \
+ { \
+ if (CombinedFilters & NDIS_PACKET_TYPE_PROMISCUOUS) \
+ { \
+ *(_pfLoopBack) = TRUE; \
+ break; \
+ } \
+ \
+ /* \
+ * First check if it *at least* has the multicast address bit. \
+ */ \
+ \
+ FDDI_IS_MULTICAST( \
+ _Address, \
+ _AddressLength, \
+ &ResultOfAddressCheck \
+ ); \
+ \
+ if (ResultOfAddressCheck) \
+ { \
+ /* \
+ * It is at least a multicast address. Check to see if \
+ * it is a broadcast address. \
+ */ \
+ \
+ FDDI_IS_BROADCAST( \
+ _Address, \
+ _AddressLength, \
+ &ResultOfAddressCheck \
+ ); \
+ \
+ if (ResultOfAddressCheck) \
+ { \
+ if (CombinedFilters & NDIS_PACKET_TYPE_BROADCAST) \
+ { \
+ *(_pfLoopBack) = TRUE; \
+ break; \
+ } \
+ else \
+ { \
+ break; \
+ } \
+ \
+ } else { \
+ \
+ if ((CombinedFilters & NDIS_PACKET_TYPE_ALL_MULTICAST) || \
+ (CombinedFilters & NDIS_PACKET_TYPE_MULTICAST)) \
+ { \
+ *(_pfLoopBack) = TRUE; \
+ break; \
+ } \
+ else \
+ { \
+ break; \
+ } \
+ } \
+ } \
+ else \
+ { \
+ /* \
+ * Directed to ourself? \
+ */ \
+ if (AddressLength == FDDI_LENGTH_OF_LONG_ADDRESS) \
+ { \
+ FDDI_COMPARE_NETWORK_ADDRESSES_EQ((_Filter)->AdapterLongAddress, \
+ _Address, \
+ FDDI_LENGTH_OF_LONG_ADDRESS, \
+ &ResultOfAddressCheck \
+ ); \
+ } \
+ else \
+ { \
+ FDDI_COMPARE_NETWORK_ADDRESSES_EQ((_Filter)->AdapterShortAddress, \
+ _Address, \
+ FDDI_LENGTH_OF_SHORT_ADDRESS, \
+ &ResultOfAddressCheck \
+ ); \
+ } \
+ \
+ if (ResultOfAddressCheck == 0) \
+ { \
+ *(_pfLoopBack) = TRUE; \
+ *(_pfSelfDirected) = TRUE; \
+ break; \
+ } \
+ } \
+ } while (FALSE); \
+}
+
+EXPORT
+BOOLEAN
+FddiShouldAddressLoopBack(
+ IN PFDDI_FILTER Filter,
+ IN CHAR Address[],
+ IN UINT LengthOfAddress
+ );
+
+EXPORT
+NDIS_STATUS
+FddiFilterAdjust(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT FilterClasses,
+ IN BOOLEAN Set
+ );
+
+EXPORT
+UINT
+FddiNumberOfOpenFilterLongAddresses(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle
+ );
+
+EXPORT
+UINT
+FddiNumberOfOpenFilterShortAddresses(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle
+ );
+
+EXPORT
+VOID
+FddiQueryGlobalFilterLongAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PFDDI_FILTER Filter,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ IN OUT CHAR AddressArray[][FDDI_LENGTH_OF_LONG_ADDRESS]
+ );
+
+EXPORT
+VOID
+FddiQueryGlobalFilterShortAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PFDDI_FILTER Filter,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ IN OUT CHAR AddressArray[][FDDI_LENGTH_OF_SHORT_ADDRESS]
+ );
+
+EXPORT
+VOID
+FddiQueryOpenFilterLongAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ IN OUT CHAR AddressArray[][FDDI_LENGTH_OF_LONG_ADDRESS]
+ );
+
+EXPORT
+VOID
+FddiQueryOpenFilterShortAddresses(
+ OUT PNDIS_STATUS Status,
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN UINT SizeOfArray,
+ OUT PUINT NumberOfAddresses,
+ IN OUT CHAR AddressArray[][FDDI_LENGTH_OF_SHORT_ADDRESS]
+ );
+
+EXPORT
+VOID
+FddiFilterIndicateReceive(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PCHAR Address,
+ IN UINT AddressLength,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+EXPORT
+VOID
+FddiFilterDprIndicateReceive(
+ IN PFDDI_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PCHAR Address,
+ IN UINT AddressLength,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+EXPORT
+VOID
+FddiFilterIndicateReceiveComplete(
+ IN PFDDI_FILTER Filter
+ );
+
+EXPORT
+VOID
+FddiFilterDprIndicateReceiveComplete(
+ IN PFDDI_FILTER Filter
+ );
+
+#endif // _FDDI_FILTER_DEFS_
+
diff --git a/private/ntos/ndis/ndis30/makefile b/private/ntos/ndis/ndis30/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/ndis30/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/ndis30/makefile.inc b/private/ntos/ndis/ndis30/makefile.inc
new file mode 100644
index 000000000..9462059e7
--- /dev/null
+++ b/private/ntos/ndis/ndis30/makefile.inc
@@ -0,0 +1,2 @@
+obj\$(TARGET_DIRECTORY)\ndis.def: ndis.src
+ $(TARGET_CPP) -nologo -EP $(TARGET_DEFINES) $(TARGET_DBG_DEFINES) ndis.src > obj\$(TARGET_DIRECTORY)\ndis.def
diff --git a/private/ntos/ndis/ndis30/miniport.c b/private/ntos/ndis/ndis30/miniport.c
new file mode 100644
index 000000000..efef74ebb
--- /dev/null
+++ b/private/ntos/ndis/ndis30/miniport.c
@@ -0,0 +1,10214 @@
+/*++
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ miniport.c
+
+Abstract:
+
+ NDIS wrapper functions
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 05-Oct-93
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+--*/
+
+
+#include <precomp.h>
+#pragma hdrstop
+
+PNDIS_M_DRIVER_BLOCK NdisDriverList = NULL;
+NDIS_SPIN_LOCK NdisDriverListLock = {0};
+
+extern UCHAR NdisInternalEaName[4];
+extern UCHAR NdisInternalEaValue[8];
+
+#define BYTE_SWAP(_word) (\
+ (USHORT) (((_word) >> 8) | ((_word) << 8)) )
+
+#define LOW_WORD(_dword) (\
+ (USHORT) ((_dword) & 0x0000FFFF) )
+
+#define HIGH_WORD(_dword) (\
+ (USHORT) (((_dword) >> 16) & 0x0000FFFF) )
+
+#define BYTE_SWAP_ULONG(_ulong) (\
+ (ULONG)((ULONG)(BYTE_SWAP(LOW_WORD(_ulong)) << 16) + \
+ BYTE_SWAP(HIGH_WORD(_ulong))))
+
+//
+// This is the number of extra OIDs that ARCnet with Ethernet encapsulation
+// supports.
+//
+#define ARC_NUMBER_OF_EXTRA_OIDS 2
+
+
+
+#if DBG
+
+#define MINIPORT_DEBUG_LOUD 0x01
+#define MINIPORT_DEBUG_VERY_LOUD 0x02
+#define MINIPORT_DEBUG_PACKETS 0x04
+ULONG MiniportDebug = 0; // MINIPORT_DEBUG_LOUD;
+#define LOUD_DEBUG(A) if (MiniportDebug & MINIPORT_DEBUG_LOUD) { A ; }
+#define VERY_LOUD_DEBUG(A) if (MiniportDebug & MINIPORT_DEBUG_VERY_LOUD) { A ; }
+#define PACKET_DEBUG(A) if (MiniportDebug & MINIPORT_DEBUG_PACKETS) { A ; }
+
+#else
+
+#define LOUD_DEBUG(A)
+#define VERY_LOUD_DEBUG(A)
+#define PACKET_DEBUG(A)
+
+#endif
+
+//
+// Define constants used internally to identify regular opens from
+// query global statistics ones.
+//
+
+#define NDIS_OPEN_INTERNAL 1
+#define NDIS_OPEN_QUERY_STATISTICS 2
+
+//
+// An active query single statistic request.
+//
+
+typedef struct _NDIS_QUERY_GLOBAL_REQUEST {
+ PIRP Irp;
+ NDIS_REQUEST Request;
+} NDIS_QUERY_GLOBAL_REQUEST, *PNDIS_QUERY_GLOBAL_REQUEST;
+
+//
+// An active query all statistics request.
+//
+
+typedef struct _NDIS_QUERY_ALL_REQUEST {
+ PIRP Irp;
+ NDIS_REQUEST Request;
+ NDIS_STATUS NdisStatus;
+ KEVENT Event;
+} NDIS_QUERY_ALL_REQUEST, *PNDIS_QUERY_ALL_REQUEST;
+
+
+//
+// An temporary request used during an open.
+//
+
+typedef struct _NDIS_QUERY_OPEN_REQUEST {
+ PIRP Irp;
+ NDIS_REQUEST Request;
+ NDIS_STATUS NdisStatus;
+ KEVENT Event;
+} NDIS_QUERY_OPEN_REQUEST, *PNDIS_QUERY_OPEN_REQUEST;
+
+
+#define NDIS_STATISTICS_HEADER_SIZE FIELD_OFFSET(NDIS_STATISTICS_VALUE,Data[0])
+
+
+//
+// Timeout values
+//
+#define NDIS_MINIPORT_WAKEUP_TIMEOUT 2000 // Wakeup DPC
+#define NDIS_MINIPORT_TR_RESET_TIMEOUT 15 // Number of WakeUps per reset attempt
+
+extern
+NTSTATUS
+WrapperSaveParameters(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+extern
+NTSTATUS
+WrapperSaveLinkage(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+extern
+NTSTATUS
+WrapperCheckRoute(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+
+NTSTATUS
+NdisCreateIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+NTSTATUS
+NdisDeviceControlIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+NTSTATUS
+NdisCloseIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+NTSTATUS
+NdisSuccessIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+VOID
+HaltOneMiniport(
+ PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+VOID
+MiniportArcCopyFromBufferToPacket(
+ IN PCHAR Buffer,
+ IN UINT BytesToCopy,
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ OUT PUINT BytesCopied
+ );
+
+VOID
+NdisInitReferencePackage(VOID);
+
+VOID
+NdisInitDereferencePackage(VOID);
+
+VOID
+MiniportFinishPendingOpens(
+ PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+//
+// Some Wan functions that crept in because
+// the send/receive paths for WAN drivers is different
+//
+
+VOID
+NdisMWanSendComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ );
+
+NDIS_STATUS
+NdisMWanSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE NdisLinkHandle,
+ IN PVOID Packet
+ );
+
+VOID
+NdisMWanIndicateReceive(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE NdisLinkContext,
+ IN PUCHAR Packet,
+ IN ULONG PacketSize
+ );
+
+VOID
+NdisMWanIndicateReceiveComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE NdisLinkContext
+ );
+
+//
+// Internal definitions
+//
+
+typedef struct _NDIS_PACKET_RESERVED {
+ PNDIS_PACKET Next;
+ PNDIS_M_OPEN_BLOCK Open;
+} NDIS_PACKET_RESERVED, *PNDIS_PACKET_RESERVED;
+
+
+#define PNDIS_RESERVED_FROM_PNDIS_PACKET(_packet) \
+ ((PNDIS_PACKET_RESERVED)((_packet)->WrapperReserved))
+
+
+#define MINIPORT_ENABLE_INTERRUPT(_M_) \
+{ \
+ if (_M_->DriverHandle->MiniportCharacteristics.EnableInterruptHandler != NULL) { \
+ (_M_->DriverHandle->MiniportCharacteristics.EnableInterruptHandler)( \
+ _M_->MiniportAdapterContext \
+ ); \
+ } \
+}
+
+#define MINIPORT_SYNC_ENABLE_INTERRUPT(_M_) \
+{ \
+ if (_M_->DriverHandle->MiniportCharacteristics.EnableInterruptHandler != NULL) { \
+ KeSynchronizeExecution( \
+ (_M_)->Interrupt->InterruptObject, \
+ (PKSYNCHRONIZE_ROUTINE)(_M_->DriverHandle->MiniportCharacteristics.EnableInterruptHandler),\
+ _M_->MiniportAdapterContext \
+ ); \
+ } \
+}
+
+
+#define ARC_PACKET_IS_ENCAPSULATED(Packet) \
+ ( PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Open->UsingEthEncapsulation )
+
+
+#if DBG
+
+//
+// Packet log.
+//
+
+typedef struct _PACKET_LOG {
+
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PNDIS_PACKET Packet;
+ ULONG Ident;
+ ULONG Time;
+} PACKET_LOG, *PPACKET_LOG;
+
+#define PACKET_LOG_SIZE 1024
+
+UINT CurrentLogEntry = (PACKET_LOG_SIZE - 1);
+PPACKET_LOG PacketLogHead = NULL;
+PACKET_LOG PacketLog[PACKET_LOG_SIZE] = {0};
+NDIS_SPIN_LOCK PacketLogSpinLock = { 0 };
+
+VOID NDIS_LOG_PACKET(PNDIS_MINIPORT_BLOCK Miniport, PNDIS_PACKET Packet, UINT Ident)
+{
+ LARGE_INTEGER li;
+
+ ACQUIRE_SPIN_LOCK(&PacketLogSpinLock);
+
+ PacketLogHead = &PacketLog[CurrentLogEntry];
+ PacketLogHead->Miniport = Miniport;
+ PacketLogHead->Packet = Packet;
+ PacketLogHead->Ident = Ident;
+ KeQuerySystemTime(&li);
+ PacketLogHead->Time = li.LowPart;
+
+ if ( CurrentLogEntry-- == 0 ) {
+
+ CurrentLogEntry = (PACKET_LOG_SIZE - 1);
+ }
+
+ RELEASE_SPIN_LOCK(&PacketLogSpinLock);
+}
+
+//
+// Send log.
+//
+
+UCHAR SendLog[256] = {0};
+UCHAR SendLogPlace = 0;
+#define LOG(ch) \
+{\
+ SendLog[SendLogPlace++] = (UCHAR)ch;\
+ SendLog[SendLogPlace] = ' ';\
+ if (SendLogPlace > 250) {\
+ SendLogPlace = 0;\
+ }\
+}
+
+UCHAR SendResourcesBuffer[512] = {0};
+ULONG SendResourcesPlace = 0;
+
+ULONG StartCount = 0x7C;
+
+ULONG
+CountMiniportPackets(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+{
+ ULONG Foo = 0;
+ PNDIS_PACKET Tmp;
+
+ Tmp = Miniport->FirstPacket;
+
+ while (Tmp != Miniport->FirstPendingPacket) {
+ Foo++;
+ Tmp = PNDIS_RESERVED_FROM_PNDIS_PACKET(Tmp)->Next;
+ }
+ return(Foo);
+}
+
+#define REMOVE_RESOURCE(W, C) {\
+ W->SendResourcesAvailable--; \
+ SendResourcesBuffer[SendResourcesPlace++] = (UCHAR)C; \
+ SendResourcesBuffer[SendResourcesPlace++] = (UCHAR)'R'; \
+ SendResourcesBuffer[SendResourcesPlace++] = (UCHAR)W->SendResourcesAvailable;\
+ SendResourcesBuffer[SendResourcesPlace] = (UCHAR)'X'; \
+ if (SendResourcesPlace >= 500) {\
+ SendResourcesPlace = 0;\
+ }\
+}
+
+#define ADD_RESOURCE(W, C) {\
+ W->SendResourcesAvailable=0xffffff;\
+ SendResourcesBuffer[SendResourcesPlace++] = (UCHAR)C; \
+ SendResourcesBuffer[SendResourcesPlace++] = (UCHAR)'A';\
+ SendResourcesBuffer[SendResourcesPlace++] = (UCHAR)W->SendResourcesAvailable;\
+ SendResourcesBuffer[SendResourcesPlace] = (UCHAR)'X'; \
+ if (SendResourcesPlace >= 500) {\
+ SendResourcesPlace = 0;\
+ }\
+}
+
+#define CLEAR_RESOURCE(W, C) {\
+ W->SendResourcesAvailable = 0;\
+ SendResourcesBuffer[SendResourcesPlace++] = (UCHAR)C; \
+ SendResourcesBuffer[SendResourcesPlace++] = (UCHAR)'C';\
+ SendResourcesBuffer[SendResourcesPlace++] = (UCHAR)W->SendResourcesAvailable;\
+ if (SendResourcesPlace >= 500) {\
+ SendResourcesPlace = 0;\
+ }\
+}
+
+#else
+
+#define NDIS_LOG_PACKET(Miniport, Packet, Ident)
+#define LOG(ch)
+
+#define REMOVE_RESOURCE(W, C) W->SendResourcesAvailable--
+#define ADD_RESOURCE(W, C) W->SendResourcesAvailable = 0xffffff
+#define CLEAR_RESOURCE(W, C) W->SendResourcesAvailable = 0
+
+#endif
+
+/*++
+
+VOID
+MiniportFindPacket(
+ PNDIS_MINIPORT_BLOCK Miniport,
+ PNDIS_PACKET Packet,
+ PNDIS_PACKET *PrevPacket
+ )
+
+Routine Description:
+
+ Searchs the miniport send queue for a packet.
+
+Arguments:
+
+ Miniport - Miniport to send to.
+ Packet - Packet to find.
+
+Return Value:
+
+ Pointer to packet which immediately preceeds the packet to search for or
+ NULL if the packet is not found.
+
+--*/
+
+#define MiniportFindPacket(_Miniport, _Packet, _PrevPacket) \
+{ \
+ PNDIS_PACKET CurrPacket = ((PNDIS_MINIPORT_BLOCK)(_Miniport))->FirstPacket; \
+ PNDIS_PACKET TempPacket = NULL; \
+ \
+ ASSERT( CurrPacket != NULL ); \
+ \
+ do { \
+ \
+ if ( CurrPacket == ((PNDIS_PACKET)(_Packet)) ) { \
+ \
+ break; \
+ } \
+ \
+ TempPacket = CurrPacket; \
+ CurrPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(CurrPacket)->Next; \
+ } \
+ while( CurrPacket != NULL ); \
+ \
+ *((PNDIS_PACKET *)(_PrevPacket)) = TempPacket; \
+ \
+ ASSERT( CurrPacket != NULL ); \
+}
+
+//
+// Routines for dealing with making the entire miniport package pagable
+//
+
+NDIS_SPIN_LOCK MiniportReferenceLock = {0};
+KEVENT MiniportPagedInEvent = {0};
+ULONG MiniportReferenceCount = 0;
+PVOID MiniportImageHandle = {0};
+
+VOID
+MiniportInitializePackage(VOID)
+{
+ //
+ // Allocate the spin lock
+ //
+ NdisAllocateSpinLock(&MiniportReferenceLock);
+
+ //
+ // Initialize the "in page" event.
+ //
+ KeInitializeEvent(
+ &MiniportPagedInEvent,
+ NotificationEvent,
+ FALSE
+ );
+}
+
+VOID
+MiniportReferencePackage(VOID)
+{
+
+ //
+ // Grab the spin lock
+ //
+ ACQUIRE_SPIN_LOCK(&MiniportReferenceLock);
+
+ //
+ // Increment the reference count
+ //
+ MiniportReferenceCount++;
+
+ if (MiniportReferenceCount == 1) {
+
+ //
+ // We are the first reference. Page everything in.
+ //
+
+ //
+ // Clear the event
+ //
+ KeResetEvent(
+ &MiniportPagedInEvent
+ );
+
+ //
+ // Set the spin lock free
+ //
+ RELEASE_SPIN_LOCK(&MiniportReferenceLock);
+
+ //
+ // Page in all the functions
+ //
+ MiniportImageHandle = MmLockPagableCodeSection(NdisMReset);
+
+ //
+ // Signal to everyone to go
+ //
+ KeSetEvent(
+ &MiniportPagedInEvent,
+ 0L,
+ FALSE
+ );
+
+ } else {
+
+ //
+ // Set the spin lock free
+ //
+ RELEASE_SPIN_LOCK(&MiniportReferenceLock);
+
+ //
+ // Wait for everything to be paged in
+ //
+ KeWaitForSingleObject(
+ &MiniportPagedInEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ NULL
+ );
+
+ }
+
+}
+
+VOID
+MiniportDereferencePackage(VOID)
+{
+
+ //
+ // Get the spin lock
+ //
+ ACQUIRE_SPIN_LOCK(&MiniportReferenceLock);
+
+ MiniportReferenceCount--;
+
+ if (MiniportReferenceCount == 0) {
+
+ //
+ // Let next one in
+ //
+ RELEASE_SPIN_LOCK(&MiniportReferenceLock);
+
+ //
+ // Page out all the functions
+ //
+ MmUnlockPagableImageSection(MiniportImageHandle);
+
+ } else {
+
+ //
+ // Let next one in
+ //
+ RELEASE_SPIN_LOCK(&MiniportReferenceLock);
+
+ }
+
+}
+
+
+//
+// Forward declarations
+//
+
+VOID
+MiniportArcCopyFromBufferToPacket(
+ IN PCHAR Buffer,
+ IN UINT BytesToCopy,
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ OUT PUINT BytesCopied
+ );
+
+
+VOID
+NdisMTimerDpc(
+ PKDPC Dpc,
+ PVOID Context,
+ PVOID SystemContext1,
+ PVOID SystemContext2
+ );
+
+VOID
+AbortMiniportPacketsAndPending(
+ PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+VOID
+AbortQueryStatisticsRequest(
+ PNDIS_REQUEST Request,
+ NDIS_STATUS Status
+ );
+
+VOID
+FASTCALL
+MiniportStartSends(
+ PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+BOOLEAN
+FASTCALL
+MiniportSendLoopback(
+ PNDIS_MINIPORT_BLOCK Miniport,
+ PNDIS_PACKET Packet
+ );
+
+VOID
+MiniportDoRequests(
+ PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+NDIS_STATUS
+MiniportAdjustMaximumLookahead(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+VOID
+MiniportCopyFromPacketToBuffer(
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ IN UINT BytesToCopy,
+ OUT PCHAR Buffer,
+ OUT PUINT BytesCopied
+ );
+
+NTSTATUS
+NdisMShutdown(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+VOID
+NdisMUnload(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+NTSTATUS
+NdisMQueryOidList(
+ PNDIS_M_USER_OPEN_CONTEXT OpenContext,
+ PIRP Irp
+ );
+
+VOID
+FinishClose(
+ PNDIS_MINIPORT_BLOCK Miniport,
+ PNDIS_M_OPEN_BLOCK Open
+ );
+
+BOOLEAN
+NdisMKillOpen(
+ PNDIS_OPEN_BLOCK OldOpenP
+ );
+
+#if !defined(BUILD_FOR_3_1)
+VOID
+NdisBugcheckHandler(
+ IN PNDIS_WRAPPER_CONTEXT WrapperContext,
+ IN ULONG Size
+ );
+#endif
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGENDSM, NdisMReadDmaCounter)
+#pragma alloc_text(PAGENDSM, NdisMCancelTimer)
+#pragma alloc_text(PAGENDSM, MiniportArcCopyFromBufferToPacket)
+#pragma alloc_text(PAGENDSM, NdisMArcTransferData)
+#pragma alloc_text(PAGENDSM, NdisMArcIndicateEthEncapsulatedReceive)
+#pragma alloc_text(PAGENDSM, HaltOneMiniport)
+#pragma alloc_text(PAGENDSM, NdisMDeregisterDmaChannel)
+#pragma alloc_text(PAGENDSM, NdisMRegisterDmaChannel)
+#pragma alloc_text(PAGENDSM, NdisMFreeSharedMemory)
+#pragma alloc_text(PAGENDSM, NdisMAllocateSharedMemory)
+#pragma alloc_text(PAGENDSM, NdisMSynchronizeWithInterrupt)
+#pragma alloc_text(PAGENDSM, NdisMDeregisterInterrupt)
+#pragma alloc_text(PAGENDSM, NdisMRegisterInterrupt)
+#pragma alloc_text(PAGENDSM, NdisMUnmapIoSpace)
+#pragma alloc_text(PAGENDSM, NdisMMapIoSpace)
+#pragma alloc_text(PAGENDSM, NdisMRequest)
+#pragma alloc_text(PAGENDSM, NdisMReset)
+//#pragma alloc_text(PAGENDSM, NdisMTransferDataSync)
+//#pragma alloc_text(PAGENDSM, NdisMTransferData)
+//#pragma alloc_text(PAGENDSM, NdisMSend)
+#pragma alloc_text(PAGENDSM, NdisMQueryInformationComplete)
+#pragma alloc_text(PAGENDSM, NdisMTransferDataComplete)
+#pragma alloc_text(PAGENDSM, NdisMResetComplete)
+#pragma alloc_text(PAGENDSM, NdisMSetInformationComplete)
+#pragma alloc_text(PAGENDSM, NdisMSendResourcesAvailable)
+//#pragma alloc_text(PAGENDSM, NdisMSendComplete)
+#pragma alloc_text(PAGENDSM, NdisMIndicateStatusComplete)
+#pragma alloc_text(PAGENDSM, NdisMIndicateStatus)
+#pragma alloc_text(PAGENDSI, NdisMSetAttributes)
+#pragma alloc_text(PAGENDSM, NdisMDeregisterIoPortRange)
+#pragma alloc_text(PAGENDSM, NdisMRegisterIoPortRange)
+#pragma alloc_text(PAGENDSM, NdisMDpcTimer)
+//#pragma alloc_text(PAGENDSM, NdisMDpc)
+//#pragma alloc_text(PAGENDSM, NdisMIsr)
+#pragma alloc_text(PAGENDSM, NdisMFreeMapRegisters)
+#pragma alloc_text(PAGENDSI, NdisMAllocateMapRegisters)
+//#pragma alloc_text(PAGENDSM, NdisMWakeUpDpc)
+#pragma alloc_text(PAGENDSM, NdisMInitializeTimer)
+#pragma alloc_text(PAGENDSM, NdisMTimerDpc)
+//#pragma alloc_text(PAGENDSM, MiniportProcessDeferred)
+#pragma alloc_text(PAGENDSM, AbortMiniportPacketsAndPending)
+#pragma alloc_text(PAGENDSM, AbortQueryStatisticsRequest)
+//#pragma alloc_text(PAGENDSM, MiniportStartSends)
+//#pragma alloc_text(PAGENDSM, MiniportSendLoopback)
+#pragma alloc_text(PAGENDSM, MiniportDoRequests)
+#pragma alloc_text(PAGENDSM, MiniportAdjustMaximumLookahead)
+//#pragma alloc_text(PAGENDSM, MiniportCopyFromPacketToBuffer)
+#pragma alloc_text(PAGENDSM, NdisMShutdown)
+#pragma alloc_text(PAGENDSM, NdisMUnload)
+#pragma alloc_text(PAGENDSM, NdisDequeueMiniportOnDriver)
+#pragma alloc_text(PAGENDSM, NdisQueueMiniportOnDriver)
+#pragma alloc_text(PAGENDSM, NdisDereferenceMiniport)
+#pragma alloc_text(PAGENDSM, NdisDereferenceDriver)
+#pragma alloc_text(PAGENDSM, NdisMQueryOidList)
+#pragma alloc_text(PAGENDSM, NdisMChangeFddiAddresses)
+#pragma alloc_text(PAGENDSM, NdisMChangeGroupAddress)
+#pragma alloc_text(PAGENDSM, NdisMChangeFunctionalAddress)
+#pragma alloc_text(PAGENDSM, NdisMCloseAction)
+#pragma alloc_text(PAGENDSM, FinishClose)
+#pragma alloc_text(PAGENDSM, NdisMChangeClass)
+#pragma alloc_text(PAGENDSM, NdisMChangeEthAddresses)
+#pragma alloc_text(PAGENDSM, NdisMKillOpen)
+
+#pragma alloc_text(PAGENDSM, NdisMWanSend)
+#pragma alloc_text(PAGENDSM, NdisMWanSendComplete)
+#pragma alloc_text(PAGENDSM, NdisMWanIndicateReceive)
+#pragma alloc_text(PAGENDSM, NdisMWanIndicateReceiveComplete)
+
+#pragma alloc_text(PAGENDSM, NdisMRegisterAdapterShutdownHandler)
+#pragma alloc_text(PAGENDSM, NdisMDeregisterAdapterShutdownHandler)
+#pragma alloc_text(PAGENDSM, NdisMPciAssignResources)
+
+#endif
+
+//
+// Routines for dealing with opens
+//
+
+
+BOOLEAN
+NdisMKillOpen(
+ PNDIS_OPEN_BLOCK OldOpenP
+ )
+
+/*++
+
+Routine Description:
+
+ Closes an open. Used when NdisCloseAdapter is called, and also
+ for internally generated closes.
+
+Arguments:
+
+ OldOpenP - The open to be closed.
+
+Return Value:
+
+ TRUE if the open finished, FALSE if it pended.
+
+--*/
+
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(OldOpenP->AdapterHandle);
+ PNDIS_M_OPEN_BLOCK MiniportOpen;
+ BOOLEAN LocalLock;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+
+ //
+ // Find the Miniport open block
+ //
+ MiniportOpen = Miniport->OpenQueue;
+ while (MiniportOpen != NULL) {
+
+ if (MiniportOpen->FakeOpen == OldOpenP) {
+
+ break;
+
+ }
+
+ MiniportOpen = MiniportOpen->MiniportNextOpen;
+ }
+
+ ASSERT(MiniportOpen != NULL);
+
+ ACQUIRE_SPIN_LOCK(&MiniportOpen->SpinLock);
+
+ //
+ // See if this open is already closing.
+ //
+
+ if (MiniportOpen->Closing) {
+ RELEASE_SPIN_LOCK(&MiniportOpen->SpinLock);
+ return TRUE;
+ }
+
+
+ //
+ // Indicate to others that this open is closing.
+ //
+
+ MiniportOpen->Closing = TRUE;
+ RELEASE_SPIN_LOCK(&MiniportOpen->SpinLock);
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Remove us from the filter package
+ //
+ switch (Miniport->MediaType) {
+
+ case NdisMediumArcnet878_2:
+
+ if ( !MiniportOpen->UsingEthEncapsulation ) {
+
+ Status = ArcDeleteFilterOpenAdapter(
+ Miniport->ArcDB,
+ MiniportOpen->FilterHandle,
+ NULL
+ );
+
+ break;
+ }
+
+ //
+ // If we're using encapsulation then we
+ // didn't open an arcnet filter but rather
+ // an ethernet filter.
+ //
+
+ case NdisMedium802_3:
+
+ Status = EthDeleteFilterOpenAdapter(
+ Miniport->EthDB,
+ MiniportOpen->FilterHandle,
+ NULL
+ );
+ break;
+
+ case NdisMedium802_5:
+
+ Status = TrDeleteFilterOpenAdapter(
+ Miniport->TrDB,
+ MiniportOpen->FilterHandle,
+ NULL
+ );
+ break;
+
+ case NdisMediumFddi:
+
+ Status = FddiDeleteFilterOpenAdapter(
+ Miniport->FddiDB,
+ MiniportOpen->FilterHandle,
+ NULL
+ );
+ break;
+ }
+
+ if (Status != NDIS_STATUS_CLOSING_INDICATING) {
+
+ //
+ // Otherwise the close action routine will fix this up.
+ //
+ MiniportOpen->References--;
+ }
+
+ //
+ // If we're able to grab the local lock then we can do some
+ // deferred processing now.
+ //
+
+ if ( LocalLock ) {
+
+ //
+ // Process any changes that may have occured.
+ //
+
+ if (!Miniport->ProcessingDeferred) {
+
+ MiniportProcessDeferred(Miniport);
+
+ }
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Remove us from the adapter and protocol open queues.
+ //
+
+ if (MiniportOpen->References != 0) {
+
+ //
+ // Wait for close to complete, reference count will drop to 0.
+ //
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ return FALSE;
+
+ } else {
+
+ //
+ // This sends an IRP_MJ_CLOSE IRP.
+ //
+ ObDereferenceObject((PVOID)(OldOpenP->FileObject));
+
+ NdisDeQueueOpenOnProtocol(OldOpenP, OldOpenP->ProtocolHandle);
+ NdisDeQueueOpenOnMiniport(MiniportOpen, MiniportOpen->MiniportHandle);
+
+ NdisDereferenceProtocol(OldOpenP->ProtocolHandle);
+ NdisDereferenceMiniport(MiniportOpen->MiniportHandle);
+
+ NdisFreeSpinLock(&MiniportOpen->SpinLock);
+ ExFreePool((PVOID)MiniportOpen);
+ ExFreePool(OldOpenP);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ return TRUE;
+ }
+
+}
+
+
+//
+// Filter package callback handlers
+//
+
+#define PNDIS_M_OPEN_FROM_BINDING_HANDLE(_handle) ((PNDIS_M_OPEN_BLOCK)(_handle))
+
+
+NDIS_STATUS
+NdisMChangeEthAddresses(
+ IN UINT OldAddressCount,
+ IN CHAR OldAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN UINT NewAddressCount,
+ 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 the multicast address
+ list has changed.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ OldAddressCount - The number of addresses in OldAddresses.
+
+ OldAddresses - The old multicast address list.
+
+ NewAddressCount - The number of addresses in NewAddresses.
+
+ NewAddresses - The new multicast address list.
+
+ MacBindingHandle - The context value returned by the driver when the
+ adapter was opened. In reality, it is a pointer to W_OPEN_BLOCK.
+
+ RequestHandle - A value supplied by the NDIS interface that the driver
+ must use when completing this request.
+
+ Set - If true the change resulted from a set, otherwise the
+ change resulted from a open closing.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ PNDIS_M_OPEN_BLOCK Open = PNDIS_M_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter ChangeEthAddresses\n");)
+
+ if ((Open->MiniportHandle->MediaType == NdisMediumArcnet878_2) &&
+ (Open->UsingEthEncapsulation)) {
+
+ if (NewAddressCount > 0) {
+
+ //
+ // Turn on broadcast acceptance.
+ //
+ Open->MiniportHandle->ArcnetBroadcastSet = TRUE;
+
+ } else {
+
+ //
+ // Unset the broadcast filter.
+ //
+ Open->MiniportHandle->ArcnetBroadcastSet = FALSE;
+
+ }
+
+ Open->MiniportHandle->NeedToUpdatePacketFilter = TRUE;
+ Open->MiniportHandle->RunDoRequests = TRUE;
+ Open->MiniportHandle->ProcessOddDeferredStuff = TRUE;
+
+ return(NDIS_STATUS_SUCCESS);
+ }
+
+ //
+ // Queue a call to fix this up.
+ //
+ Open->MiniportHandle->NeedToUpdateEthAddresses = TRUE;
+ Open->MiniportHandle->RunDoRequests = TRUE;
+ Open->MiniportHandle->ProcessOddDeferredStuff = TRUE;
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit ChangeEthAddresses\n");)
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+NdisMChangeClass(
+ 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 a particular filter
+ class is first used or last cleared.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ OldFilterClasses - The values of the class filter before it
+ was changed.
+
+ NewFilterClasses - The current value of the class filter
+
+ MacBindingHandle - The context value returned by the driver when the
+ adapter was opened. In reality, it is a pointer to W_OPEN_BLOCK.
+
+ RequestHandle - A value supplied by the NDIS interface that the driver
+ must use when completing this request.
+
+ Set - If true the change resulted from a set, otherwise the
+ change resulted from a open closing.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ PNDIS_M_OPEN_BLOCK Open = PNDIS_M_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter change class\n");)
+
+ //
+ // Queue a call to fix this up.
+ //
+ Open->MiniportHandle->NeedToUpdatePacketFilter = TRUE;
+ Open->MiniportHandle->RunDoRequests = TRUE;
+ Open->MiniportHandle->ProcessOddDeferredStuff = TRUE;
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit change class\n");)
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+VOID
+FinishClose(
+ PNDIS_MINIPORT_BLOCK Miniport,
+ PNDIS_M_OPEN_BLOCK Open
+ )
+
+/*++
+
+Routine Description:
+
+ Finishes off a close adapter call.
+
+ CALLED WITH LOCK HELD!!
+
+Arguments:
+
+ Miniport - The mini-port the open is queued on.
+
+ Open - The open to close
+
+Return Value:
+
+ None.
+
+
+--*/
+
+
+{
+
+ ASSERT(Open->Closing);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.CloseAdapterCompleteHandler) (
+ Open->ProtocolBindingContext,
+ NDIS_STATUS_SUCCESS
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ NdisDeQueueOpenOnProtocol(Open->FakeOpen, Open->ProtocolHandle);
+ NdisDeQueueOpenOnMiniport(Open, Open->MiniportHandle);
+ ExFreePool(Open->FakeOpen);
+
+ NdisDereferenceMiniport(Open->MiniportHandle);
+ NdisDereferenceProtocol(Open->ProtocolHandle);
+
+ NdisFreeSpinLock(&Open->SpinLock);
+
+ //
+ // This sends an IRP_MJ_CLOSE IRP.
+ //
+
+ ObDereferenceObject((PVOID)(Open->FileObject));
+
+ ExFreePool((PVOID)Open);
+
+}
+
+
+VOID
+NdisMCloseAction(
+ 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 driver when the
+ adapter was opened. In reality, it is a pointer to W_OPEN_BLOCK.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ PNDIS_M_OPEN_BLOCK Open = PNDIS_M_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+ PNDIS_MINIPORT_BLOCK Miniport = Open->MiniportHandle;
+
+ Open->References--;
+ if (Open->References == 0) {
+
+ FinishClose(Miniport,Open);
+
+ }
+
+}
+
+
+NDIS_STATUS
+NdisMChangeFunctionalAddress(
+ IN TR_FUNCTIONAL_ADDRESS OldFunctionalAddress,
+ IN TR_FUNCTIONAL_ADDRESS NewFunctionalAddress,
+ 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:
+
+ OldFunctionalAddress - The previous functional address.
+
+ NewFunctionalAddress - The new functional address.
+
+ MacBindingHandle - The context value returned by the driver when the
+ adapter was opened. In reality, it is a pointer to W_OPEN_BLOCK.
+
+ NdisRequest - A pointer to the Request that submitted the set command.
+
+ Set - If true the change resulted from a set, otherwise the
+ change resulted from a open closing.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ PNDIS_M_OPEN_BLOCK Open = PNDIS_M_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter change functional\n");)
+
+ //
+ // Queue a call to fix this up.
+ //
+ Open->MiniportHandle->NeedToUpdateFunctionalAddress = TRUE;
+ Open->MiniportHandle->RunDoRequests = TRUE;
+ Open->MiniportHandle->ProcessOddDeferredStuff = TRUE;
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit change functional\n");)
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+NdisMChangeGroupAddress(
+ IN TR_FUNCTIONAL_ADDRESS OldGroupAddress,
+ IN TR_FUNCTIONAL_ADDRESS NewGroupAddress,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a group address is to
+ be changed.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ OldGroupAddress - The previous group address.
+
+ NewGroupAddress - The new group address.
+
+ MacBindingHandle - The context value returned by the driver when the
+ adapter was opened. In reality, it is a pointer to W_OPEN_BLOCK.
+
+ NdisRequest - A pointer to the Request that submitted the set command.
+
+ Set - If true the change resulted from a set, otherwise the
+ change resulted from a open closing.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ PNDIS_M_OPEN_BLOCK Open = PNDIS_M_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter change group\n");)
+
+ //
+ // Queue a call to fix this up.
+ //
+ Open->MiniportHandle->NeedToUpdateGroupAddress = TRUE;
+ Open->MiniportHandle->RunDoRequests = TRUE;
+ Open->MiniportHandle->ProcessOddDeferredStuff = TRUE;
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit change group\n");)
+
+ return(NDIS_STATUS_SUCCESS);
+
+}
+
+
+NDIS_STATUS
+NdisMChangeFddiAddresses(
+ IN UINT oldLongAddressCount,
+ IN CHAR oldLongAddresses[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN UINT newLongAddressCount,
+ IN CHAR newLongAddresses[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN UINT oldShortAddressCount,
+ IN CHAR oldShortAddresses[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN UINT newShortAddressCount,
+ IN CHAR newShortAddresses[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when the multicast address
+ list has changed.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ oldAddressCount - The number of addresses in oldAddresses.
+
+ oldAddresses - The old multicast address list.
+
+ newAddressCount - The number of addresses in newAddresses.
+
+ newAddresses - The new multicast address list.
+
+ macBindingHandle - The context value returned by the driver when the
+ adapter was opened. In reality, it is a pointer to W_OPEN_BLOCK.
+
+ requestHandle - A value supplied by the NDIS interface that the driver
+ must use when completing this request.
+
+ Set - If true the change resulted from a set, otherwise the
+ change resulted from a open closing.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ PNDIS_M_OPEN_BLOCK Open = PNDIS_M_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter change fddi addresses\n");)
+
+ //
+ // Queue a call to fix this up.
+ //
+ Open->MiniportHandle->NeedToUpdateFddiLongAddresses = TRUE;
+ Open->MiniportHandle->NeedToUpdateFddiShortAddresses = TRUE;
+ Open->MiniportHandle->RunDoRequests = TRUE;
+ Open->MiniportHandle->ProcessOddDeferredStuff = TRUE;
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit change fddi addresses\n");)
+
+ return(NDIS_STATUS_SUCCESS);
+
+}
+
+//
+// IRP handlers established on behalf of NDIS devices by
+// the wrapper.
+//
+
+
+
+NTSTATUS
+NdisMQueryOidList(
+ PNDIS_M_USER_OPEN_CONTEXT OpenContext,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will take care of querying the complete OID
+ list for the driver and filling in OpenContext->OidArray
+ with the ones that are statistics. It blocks when the
+ driver pends and so is synchronous.
+
+Arguments:
+
+ OpenContext - The open context.
+ Irp = The IRP that the open was done on (used at completion
+ to distinguish the request).
+
+Return Value:
+
+ STATUS_SUCCESS if it should be.
+
+--*/
+
+{
+ NDIS_QUERY_OPEN_REQUEST OpenRequest;
+ NDIS_STATUS NdisStatus;
+ PNDIS_OID TmpBuffer;
+ ULONG TmpBufferLength;
+ UINT i, j;
+ PNDIS_REQUEST_RESERVED Reserved;
+ BOOLEAN LocalLock;
+ PNDIS_MINIPORT_BLOCK Miniport = OpenContext->MiniportBlock;
+ KIRQL OldIrql;
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter query oid list\n");)
+
+ KeRaiseIrql( DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // First query the OID list with no buffer, to find out
+ // how big it should be.
+ //
+
+ KeInitializeEvent(
+ &OpenRequest.Event,
+ NotificationEvent,
+ FALSE
+ );
+
+ OpenRequest.Irp = Irp;
+
+ //
+ // Build fake request
+ //
+
+ OpenRequest.Request.RequestType = NdisRequestQueryStatistics;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_SUPPORTED_LIST;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBuffer = NULL;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBufferLength = 0;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded = 0;
+
+ //
+ // Put request on queue
+ //
+
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(&(OpenRequest.Request));
+ Reserved->Next = NULL;
+ Miniport->LastPendingRequest = &(OpenRequest.Request);
+
+ if (Miniport->FirstPendingRequest == NULL) {
+
+ Miniport->FirstPendingRequest = &(OpenRequest.Request);
+
+ } else {
+
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Miniport->LastPendingRequest)->Next =
+ &(OpenRequest.Request);
+
+ }
+
+ if (Miniport->MiniportRequest == NULL) {
+
+ Miniport->RunDoRequests = TRUE;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ }
+
+ if ( LocalLock ) {
+
+ if (!Miniport->ProcessingDeferred) {
+
+ MiniportProcessDeferred(Miniport);
+ }
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ KeLowerIrql(OldIrql);
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &OpenRequest.Event,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ KeRaiseIrql( DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisStatus = OpenRequest.NdisStatus;
+
+ if ((NdisStatus != NDIS_STATUS_INVALID_LENGTH) &&
+ (NdisStatus != NDIS_STATUS_BUFFER_TOO_SHORT)) {
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ KeLowerIrql(OldIrql);
+ return(NdisStatus);
+
+ }
+
+ //
+ // Now we know how much is needed, allocate temp storage...
+ //
+
+ TmpBufferLength = OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded;
+ TmpBuffer = ExAllocatePool(NonPagedPool, TmpBufferLength);
+
+ if (TmpBuffer == NULL) {
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ KeLowerIrql(OldIrql);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // ...and query the real list.
+ //
+
+ KeResetEvent(
+ &OpenRequest.Event
+ );
+
+ OpenRequest.Request.RequestType = NdisRequestQueryStatistics;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_SUPPORTED_LIST;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBuffer = TmpBuffer;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBufferLength = TmpBufferLength;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded = 0;
+
+ //
+ // Put request on queue
+ //
+
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(&(OpenRequest.Request));
+ Reserved->Next = NULL;
+ Miniport->LastPendingRequest = &(OpenRequest.Request);
+
+ if (Miniport->FirstPendingRequest == NULL) {
+
+ Miniport->FirstPendingRequest = &(OpenRequest.Request);
+
+ } else {
+
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Miniport->LastPendingRequest)->Next =
+ &(OpenRequest.Request);
+
+ }
+
+ if (Miniport->MiniportRequest == NULL) {
+
+ Miniport->RunDoRequests = TRUE;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ }
+
+ if ( LocalLock ) {
+
+ if (!Miniport->ProcessingDeferred) {
+
+ MiniportProcessDeferred(Miniport);
+ }
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ KeLowerIrql(OldIrql);
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &OpenRequest.Event,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ KeRaiseIrql( DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisStatus = OpenRequest.NdisStatus;
+
+ ASSERT (NdisStatus == NDIS_STATUS_SUCCESS);
+
+
+ //
+ // Now go through the buffer, counting the statistics OIDs.
+ //
+
+ for (i=0; i<TmpBufferLength/sizeof(NDIS_OID); i++) {
+ if ((TmpBuffer[i] & 0x00ff0000) == 0x00020000) {
+ ++OpenContext->OidCount;
+ }
+ }
+
+ //
+ // Now allocate storage for the real OID array.
+ //
+
+ OpenContext->OidArray = ExAllocatePool (NonPagedPool, OpenContext->OidCount * sizeof(NDIS_OID));
+
+ if (OpenContext->OidArray == NULL) {
+ ExFreePool (TmpBuffer);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ KeLowerIrql(OldIrql);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now go through the buffer, copying the statistics OIDs.
+ //
+
+ j = 0;
+ for (i=0; i<TmpBufferLength/sizeof(NDIS_OID); i++) {
+
+ if ((TmpBuffer[i] & 0x00ff0000) == 0x00020000) {
+ OpenContext->OidArray[j] = TmpBuffer[i];
+ ++j;
+ }
+ }
+
+ ASSERT (j == OpenContext->OidCount);
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit query oid list\n");)
+
+ ExFreePool (TmpBuffer);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ KeLowerIrql(OldIrql);
+ return STATUS_SUCCESS;
+}
+
+VOID
+NdisLastCountRemovedFunction(
+ IN struct _KDPC *Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+#define NdisReferenceDriver(WDriver) NdisReferenceRef(&(WDriver)->Ref)
+
+
+VOID
+NdisDereferenceDriver(
+ PNDIS_M_DRIVER_BLOCK WDriver
+ )
+/*++
+
+Routine Description:
+
+ Removes a reference from the mini-port driver, deleting it if the count goes to 0.
+
+Arguments:
+
+ Miniport - The mini-port block to dereference.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if (NdisDereferenceRef(&(WDriver)->Ref)) {
+
+ //
+ // Remove it from the global list.
+ //
+
+ ACQUIRE_SPIN_LOCK(&NdisDriverListLock);
+
+ if (NdisDriverList == WDriver) {
+
+ NdisDriverList = WDriver->NextDriver;
+
+ } else {
+
+ PNDIS_M_DRIVER_BLOCK TmpDriver = NdisDriverList;
+
+ while(TmpDriver->NextDriver != WDriver) {
+
+ TmpDriver = TmpDriver->NextDriver;
+
+ }
+
+ TmpDriver->NextDriver = TmpDriver->NextDriver->NextDriver;
+
+ }
+
+ RELEASE_SPIN_LOCK(&NdisDriverListLock);
+
+ if (WDriver->FakeMac != NULL) {
+ ExFreePool((PVOID)(WDriver->FakeMac));
+ }
+
+ ExFreePool((PVOID)(WDriver));
+
+ }
+}
+
+
+VOID
+NdisDereferenceMiniport(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+/*++
+
+Routine Description:
+
+ Removes a reference from the mini-port driver, deleting it if the count goes to 0.
+
+Arguments:
+
+ Miniport - The mini-port block to dereference.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if (NdisDereferenceRef(&(Miniport)->Ref)) {
+
+ if (Miniport->EthDB) {
+ EthDeleteFilter(Miniport->EthDB);
+ }
+
+ if (Miniport->TrDB) {
+ TrDeleteFilter(Miniport->TrDB);
+ }
+
+ if (Miniport->FddiDB) {
+ FddiDeleteFilter(Miniport->FddiDB);
+ }
+
+ if (Miniport->ArcDB) {
+ ArcDeleteFilter(Miniport->ArcDB);
+ }
+
+ if (((PNDIS_WRAPPER_CONTEXT)Miniport->WrapperContext)->AssignedSlotResources != NULL ) {
+ ExFreePool( ((PNDIS_WRAPPER_CONTEXT)Miniport->WrapperContext)->AssignedSlotResources );
+ }
+
+ NdisDequeueMiniportOnDriver(Miniport, Miniport->DriverHandle);
+ NdisDereferenceDriver(Miniport->DriverHandle);
+ NdisMDeregisterAdapterShutdownHandler( Miniport );
+ IoUnregisterShutdownNotification(Miniport->DeviceObject);
+ IoDeleteDevice(Miniport->DeviceObject);
+
+ }
+}
+
+
+
+BOOLEAN
+NdisQueueMiniportOnDriver(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_M_DRIVER_BLOCK WDriver
+ )
+
+/*++
+
+Routine Description:
+
+ Adds an mini-port to a list of mini-port for a driver.
+
+Arguments:
+
+ Miniport - The mini-port block to queue.
+ WDriver - The driver block to queue it to.
+
+Return Value:
+
+ FALSE if the driver is closing.
+ TRUE otherwise.
+
+--*/
+
+{
+ ACQUIRE_SPIN_LOCK(&WDriver->Ref.SpinLock);
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter queue mini-port on driver\n");)
+ LOUD_DEBUG(DbgPrint("NdisM: queue mini-port 0x%x\n", Miniport);)
+ LOUD_DEBUG(DbgPrint("NdisM: driver 0x%x\n", WDriver);)
+
+
+ //
+ // Make sure the driver is not closing.
+ //
+
+ if (WDriver->Ref.Closing) {
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit queue mini-port on driver\n");)
+
+ RELEASE_SPIN_LOCK(&WDriver->Ref.SpinLock);
+ return FALSE;
+ }
+
+
+ //
+ // Add this adapter at the head of the queue
+ //
+
+ Miniport->NextMiniport = WDriver->MiniportQueue;
+ WDriver->MiniportQueue = Miniport;
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit queue mini-port on driver\n");)
+
+ RELEASE_SPIN_LOCK(&WDriver->Ref.SpinLock);
+ return TRUE;
+}
+
+
+VOID
+NdisDequeueMiniportOnDriver(
+ PNDIS_MINIPORT_BLOCK Miniport,
+ PNDIS_M_DRIVER_BLOCK WDriver
+ )
+
+/*++
+
+Routine Description:
+
+ Removes an mini-port from a list of mini-port for a driver.
+
+Arguments:
+
+ Miniport - The mini-port block to dequeue.
+ WDriver - The driver block to dequeue it from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ACQUIRE_SPIN_LOCK(&WDriver->Ref.SpinLock);
+
+ LOUD_DEBUG(DbgPrint("NdisM: Dequeue on driver\n");)
+ LOUD_DEBUG(DbgPrint("NdisM: dequeue mini-port 0x%x\n", Miniport);)
+ LOUD_DEBUG(DbgPrint("NdisM: driver 0x%x\n", WDriver);)
+
+ //
+ // Find the driver on the queue, and remove it.
+ //
+
+ if (WDriver->MiniportQueue == Miniport) {
+ WDriver->MiniportQueue = Miniport->NextMiniport;
+ } else {
+ PNDIS_MINIPORT_BLOCK MP = WDriver->MiniportQueue;
+
+ while (MP->NextMiniport != Miniport) {
+ MP = MP->NextMiniport;
+ }
+
+ MP->NextMiniport = MP->NextMiniport->NextMiniport;
+ }
+
+ RELEASE_SPIN_LOCK(&WDriver->Ref.SpinLock);
+
+ if (WDriver->Unloading && (WDriver->MiniportQueue == (PNDIS_MINIPORT_BLOCK)NULL)) {
+
+ KeSetEvent(
+ &WDriver->MiniportsRemovedEvent,
+ 0L,
+ FALSE
+ );
+
+ }
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit dequeue mini-port on driver\n");)
+}
+
+
+
+
+VOID
+NdisMUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+/*++
+
+Routine Description:
+
+ This routine is called when a driver is supposed to unload. Ndis
+ converts this into a set of calls to MiniportHalt() for each
+ adapter that the driver has open.
+
+Arguments:
+
+ DriverObject - the driver object for the mac that is to unload.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_M_DRIVER_BLOCK WDriver;
+ PNDIS_MINIPORT_BLOCK Miniport, NextMiniport;
+ KIRQL OldIrql;
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter unload\n");)
+
+ //
+ // Search for the driver
+ //
+
+ ACQUIRE_SPIN_LOCK(&NdisDriverListLock);
+
+ WDriver = NdisDriverList;
+
+ while (WDriver != (PNDIS_M_DRIVER_BLOCK)NULL) {
+
+ if (WDriver->NdisDriverInfo->NdisWrapperDriver == DriverObject) {
+
+ break;
+
+ }
+
+ WDriver = WDriver->NextDriver;
+
+ }
+
+ RELEASE_SPIN_LOCK(&NdisDriverListLock);
+
+ if (WDriver == (PNDIS_M_DRIVER_BLOCK)NULL) {
+
+ //
+ // It is already gone. Just return.
+ //
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit unload\n");)
+
+ return;
+
+ }
+
+ WDriver->Unloading = TRUE;
+
+
+ LOUD_DEBUG(DbgPrint("NdisM: Halting mini-port\n");)
+
+ //
+ // Now call MiniportHalt() for each Miniport.
+ //
+
+ Miniport = WDriver->MiniportQueue;
+
+ while (Miniport != (PNDIS_MINIPORT_BLOCK)NULL) {
+
+ NextMiniport = Miniport->NextMiniport; // since queue may change
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter shutdown\n");)
+
+ Miniport->HaltingMiniport = TRUE;
+ Miniport->NormalInterrupts = FALSE;
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ HaltOneMiniport(Miniport);
+
+ Miniport = NextMiniport;
+ }
+
+ //
+ // Wait for all adapters to be gonzo.
+ //
+
+ KeWaitForSingleObject(
+ &WDriver->MiniportsRemovedEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PTIME)NULL
+ );
+
+ KeResetEvent(
+ &WDriver->MiniportsRemovedEvent
+ );
+
+ //
+ // Now remove the last reference (this will remove it from the list)
+ //
+
+ ASSERT(WDriver->Ref.ReferenceCount == 1);
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit unload\n");)
+
+ NdisDereferenceDriver(WDriver);
+}
+
+
+NTSTATUS
+NdisMShutdown(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ The "shutdown handler" for the SHUTDOWN Irp. Will call the Ndis
+ shutdown routine, if one is registered.
+
+Arguments:
+
+ DeviceObject - The adapter's device object.
+ Irp - The IRP.
+
+Return Value:
+
+ Always STATUS_SUCCESS.
+
+--*/
+
+{
+ PNDIS_WRAPPER_CONTEXT WrapperContext = (PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(WrapperContext + 1);
+ KIRQL OldIrql;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Miniport->HaltingMiniport = TRUE;
+ Miniport->NormalInterrupts = FALSE;
+
+ if (WrapperContext->ShutdownHandler != NULL) {
+
+ while (Miniport->LockAcquired) {
+
+ //
+ // This can only happen on an MP system. We must now
+ // wait for the other processor to exit the mini-port.
+ //
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ NdisStallExecution(1000);
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+ }
+
+ //
+ // Lock miniport so that nothing will enter it.
+ //
+
+ Miniport->LockAcquired = TRUE;
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ //
+ // Call the shutdown routine.
+ //
+
+ if (WrapperContext->ShutdownHandler != NULL) {
+ WrapperContext->ShutdownHandler(WrapperContext->ShutdownContext);
+ }
+
+ Miniport->LockAcquired = FALSE;
+
+ } else {
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ }
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisMShutdown\n");
+
+ return STATUS_SUCCESS;
+}
+
+//
+// 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);
+
+
+
+
+VOID
+MiniportCopyFromPacketToBuffer(
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ IN UINT BytesToCopy,
+ OUT PCHAR Buffer,
+ OUT PUINT BytesCopied
+ )
+
+/*++
+
+Routine Description:
+
+ Copy from an ndis packet into a buffer.
+
+Arguments:
+
+ Packet - The packet to copy from.
+
+ Offset - The offset from which to start the copy.
+
+ BytesToCopy - The number of bytes to copy from the packet.
+
+ Buffer - The destination of the copy.
+
+ BytesCopied - The number of bytes actually copied. Can be less then
+ BytesToCopy if the packet is shorter than BytesToCopy.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ //
+ // Holds the number of ndis buffers comprising the packet.
+ //
+ UINT NdisBufferCount;
+
+ //
+ // Points to the buffer from which we are extracting data.
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+ //
+ // Holds the virtual address of the current buffer.
+ //
+ PVOID VirtualAddress;
+
+ //
+ // Holds the length of the current buffer of the packet.
+ //
+ UINT CurrentLength;
+
+ //
+ // Keep a local variable of BytesCopied so we aren't referencing
+ // through a pointer.
+ //
+ UINT LocalBytesCopied = 0;
+
+ //
+ // Take care of boundary condition of zero length copy.
+ //
+
+ *BytesCopied = 0;
+ if (!BytesToCopy) return;
+
+ //
+ // Get the first buffer.
+ //
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ &NdisBufferCount,
+ &CurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (!NdisBufferCount) return;
+
+ NdisQueryBuffer(
+ CurrentBuffer,
+ &VirtualAddress,
+ &CurrentLength
+ );
+
+ while (LocalBytesCopied < BytesToCopy) {
+
+ if (CurrentLength == 0) {
+
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.
+ //
+
+ if (!CurrentBuffer) break;
+
+ NdisQueryBuffer(
+ CurrentBuffer,
+ &VirtualAddress,
+ &CurrentLength
+ );
+ continue;
+
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (Offset) {
+
+ if (Offset > CurrentLength) {
+
+ //
+ // What we want isn't in this buffer.
+ //
+
+ Offset -= CurrentLength;
+ CurrentLength = 0;
+ continue;
+
+ } else {
+
+ VirtualAddress = (PCHAR)VirtualAddress + Offset;
+ CurrentLength -= Offset;
+ Offset = 0;
+
+ }
+
+ }
+
+ //
+ // Copy the data.
+ //
+
+
+ {
+
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ AmountToMove =
+ ((CurrentLength <= (BytesToCopy - LocalBytesCopied))?
+ (CurrentLength):(BytesToCopy - LocalBytesCopied));
+
+ NdisMoveMemory(
+ Buffer,
+ VirtualAddress,
+ AmountToMove
+ );
+
+ Buffer = (PCHAR)Buffer + AmountToMove;
+ VirtualAddress = (PCHAR)VirtualAddress + AmountToMove;
+
+ LocalBytesCopied += AmountToMove;
+ CurrentLength -= AmountToMove;
+
+ }
+
+ }
+
+ *BytesCopied = LocalBytesCopied;
+
+}
+
+
+
+NDIS_STATUS
+MiniportAdjustMaximumLookahead(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ )
+/*++
+
+Routine Description:
+
+ This routine finds the open with the maximum lookahead value and
+ stores that in the mini-port block.
+
+Arguments:
+
+ Miniport - A pointer to the mini-port block.
+
+Returns:
+
+ Status of the operation
+
+--*/
+{
+ ULONG CurrentMax = 0;
+ PNDIS_M_OPEN_BLOCK CurrentOpen;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ CurrentOpen = Miniport->OpenQueue;
+
+ while (CurrentOpen != NULL) {
+
+ if (CurrentOpen->CurrentLookahead > CurrentMax) {
+
+ CurrentMax = CurrentOpen->CurrentLookahead;
+
+ }
+
+ CurrentOpen = CurrentOpen->MiniportNextOpen;
+ }
+
+ if (CurrentMax == 0) {
+
+ CurrentMax = Miniport->MaximumLookahead;
+
+ } else if (CurrentMax > Miniport->MaximumLookahead) {
+
+ CurrentMax = Miniport->MaximumLookahead;
+
+ }
+
+ if (Miniport->CurrentLookahead != CurrentMax) {
+
+ BOOLEAN CompleteRequestMyself = TRUE;
+
+ if (Miniport->MiniportRequest) {
+
+ CompleteRequestMyself = FALSE;
+
+ //
+ // This is due to a request -- complete it before submitting a
+ // new one to the mini-port.
+ //
+ NdisMSetInformationComplete(
+ (NDIS_HANDLE)Miniport,
+ NDIS_STATUS_SUCCESS
+ );
+ }
+
+ //
+ // Change it
+ //
+
+ NdisMoveMemory(Miniport->MulticastBuffer, &CurrentMax, sizeof(CurrentMax));
+
+ Miniport->CurrentLookahead = CurrentMax;
+ Miniport->MiniportRequest = &(Miniport->InternalRequest);
+ Miniport->InternalRequest.RequestType = NdisRequestSetInformation;
+
+ Status =
+ (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ Miniport->MulticastBuffer,
+ sizeof(CurrentMax),
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesRead,
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesNeeded
+ );
+
+ if (CompleteRequestMyself && (Status != NDIS_STATUS_PENDING)) {
+
+ //
+ // This is not called from within a request, so no-one will be
+ // expecting to complete this, so we must do it now.
+ //
+
+ NdisMSetInformationComplete(
+ (NDIS_HANDLE)Miniport,
+ Status
+ );
+
+ }
+
+ }
+
+ return Status;
+
+}
+
+NDIS_STATUS FilterOutOidStatistics(
+ PNDIS_MINIPORT_BLOCK Miniport,
+ PNDIS_REQUEST pRequest,
+ PNDIS_OID pDstOid,
+ PULONG pcbDestination,
+ PNDIS_OID pSrcOid,
+ ULONG cbSource
+)
+{
+ BOOLEAN fARCnet;
+ ULONG cGlobalOids;
+ ULONG cInfoOids;
+ ULONG cbListSizeNeeded;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PNDIS_REQUEST_RESERVED pReserved =
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(pRequest);
+
+ //????
+ // Currently there are two different mappings:
+ // ARCnet -> Map Ethernet OIDs to ARCnet & remove
+ // non-statistics OIDs.
+ // Other -> Everything else is just the removal of
+ // statistics OIDs.
+ //
+ // Since we need to remove statistics OIDs from both we copy
+ // the OIDs that we want into the buffer passed to us.
+ // Then if the request is from an ARCnet NIC we filter into
+ // our temp buffer and copy it back to the callers buffer....
+ // I think that this will be better than an inplace shuffle for
+ // the ARCnet OIDs.
+ //????
+
+ //
+ // Are we using ARCnet with Ethernet encapsulation>
+ //
+ fARCnet = ((Miniport->MediaType == NdisMediumArcnet878_2) &&
+ pReserved->Open->UsingEthEncapsulation) ? TRUE : FALSE;
+
+ //
+ // Count the number of non-statistics OIDs.
+ //
+ for
+ (
+ cGlobalOids = 0, cInfoOids = 0;
+ cGlobalOids < (cbSource / sizeof(NDIS_OID));
+ cGlobalOids++
+ )
+ {
+ if ((pSrcOid[cGlobalOids] & 0x00FF0000) != 0x00020000)
+ cInfoOids++;
+ }
+
+ //
+ // Determine the list size that is needed.
+ //
+ cbListSizeNeeded = (cInfoOids * sizeof(NDIS_OID));
+ if (fARCnet)
+ cbListSizeNeeded += (ARC_NUMBER_OF_EXTRA_OIDS * sizeof(NDIS_OID));
+
+ //
+ // Verify that the buffer passed in on the original request
+ // is large enough for the OID list.
+ //
+ if (cbListSizeNeeded > *pcbDestination)
+ {
+ //
+ // Save the correct buffer size in the
+ // appropriate spot.
+ //
+ *pcbDestination = cInfoOids * sizeof(NDIS_OID);
+
+ return(NDIS_STATUS_BUFFER_TOO_SHORT);
+ }
+
+ //
+ // Copy the information OIDs to the buffer that
+ // was passed with the original request.
+ //
+ for
+ (
+ cGlobalOids = 0, cInfoOids = 0;
+ cGlobalOids < (cbSource / sizeof(NDIS_OID));
+ cGlobalOids++
+ )
+ {
+ //
+ // If its not a statistic OID then save it.
+ //
+ if ((pSrcOid[cGlobalOids] & 0x00FF0000) != 0x00020000)
+ {
+ pDstOid[cInfoOids] = pSrcOid[cGlobalOids];
+ cInfoOids++;
+ }
+ }
+
+ //
+ // If ARCnet then do the filtering.
+ //
+ if (fARCnet)
+ {
+ Status = ArcConvertOidListToEthernet(
+ pDstOid,
+ &cInfoOids,
+ pSrcOid
+ );
+ }
+
+ //
+ // Save the amount of data that was kept.
+ //
+ *pcbDestination = cInfoOids * sizeof(NDIS_OID);
+
+ return(Status);
+}
+
+
+VOID
+MiniportDoRequests(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Submits a request to the mini-port.
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS Status;
+ BOOLEAN DoneSomething = TRUE;
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter do requests\n");)
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ while (DoneSomething)
+ {
+ DoneSomething = FALSE;
+ Status = NDIS_STATUS_SUCCESS;
+
+ if (Miniport->NeedToUpdateEthAddresses)
+ {
+ UINT NumberOfAddresses;
+
+ DoneSomething = TRUE;
+ //
+ // This is an internal update that is needed.
+ //
+
+ Miniport->MiniportRequest = &(Miniport->InternalRequest);
+ Miniport->NeedToUpdateEthAddresses = FALSE;
+
+ //
+ // Get information needed
+ //
+
+ LOUD_DEBUG(DbgPrint("NdisM: Updating eth multicast list\n");)
+
+ EthQueryGlobalFilterAddresses(
+ &Status,
+ Miniport->EthDB,
+ NDIS_M_MAX_MULTI_LIST * ETH_LENGTH_OF_ADDRESS,
+ &NumberOfAddresses,
+ (PVOID)Miniport->MulticastBuffer
+ );
+
+ //
+ // Submit Request
+ //
+ Miniport->InternalRequest.RequestType = NdisRequestSetInformation;
+
+ Status =
+ (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ OID_802_3_MULTICAST_LIST,
+ Miniport->MulticastBuffer,
+ NumberOfAddresses * ETH_LENGTH_OF_ADDRESS,
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesRead,
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesNeeded
+ );
+
+ if ((Status == NDIS_STATUS_PENDING) && (Miniport->MiniportRequest)) {
+
+ //
+ // Still outstanding
+ //
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit do requests\n");)
+
+ Miniport->RunDoRequests = FALSE;
+
+ return;
+
+ }
+
+ if (Status != NDIS_STATUS_PENDING) {
+ NdisMSetInformationComplete(
+ (NDIS_HANDLE)Miniport,
+ Status
+ );
+ }
+
+ }
+
+ if (Miniport->NeedToUpdatePacketFilter) {
+
+ UINT PacketFilter;
+
+ DoneSomething = TRUE;
+ //
+ // This is an internal update that is needed.
+ //
+
+ Miniport->MiniportRequest = &(Miniport->InternalRequest);
+ Miniport->NeedToUpdatePacketFilter = FALSE;
+
+ //
+ // Get information needed
+ //
+ switch (Miniport->MediaType) {
+
+ case NdisMedium802_3:
+
+ PacketFilter = ETH_QUERY_FILTER_CLASSES(Miniport->EthDB);
+ break;
+
+ case NdisMedium802_5:
+
+ PacketFilter = TR_QUERY_FILTER_CLASSES(Miniport->TrDB);
+ break;
+
+ case NdisMediumFddi:
+
+ PacketFilter = FDDI_QUERY_FILTER_CLASSES(Miniport->FddiDB);
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ PacketFilter = ARC_QUERY_FILTER_CLASSES(Miniport->ArcDB);
+ PacketFilter |= ETH_QUERY_FILTER_CLASSES(Miniport->EthDB);
+
+ if ( Miniport->ArcnetBroadcastSet ||
+ (PacketFilter & NDIS_PACKET_TYPE_MULTICAST) ) {
+
+ PacketFilter &= ~NDIS_PACKET_TYPE_MULTICAST;
+ PacketFilter |= NDIS_PACKET_TYPE_BROADCAST;
+ }
+ break;
+ }
+
+ NdisMoveMemory(
+ Miniport->MulticastBuffer,
+ &PacketFilter,
+ sizeof(PacketFilter)
+ );
+
+ LOUD_DEBUG(DbgPrint("NdisM: Updating packet filter\n");)
+
+ //
+ // Submit Request
+ //
+ Miniport->InternalRequest.RequestType = NdisRequestSetInformation;
+
+ Status =
+ (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ Miniport->MulticastBuffer,
+ sizeof(PacketFilter),
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesRead,
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesNeeded
+ );
+
+ if ((Status == NDIS_STATUS_PENDING) && (Miniport->MiniportRequest)) {
+
+ //
+ // Still outstanding
+ //
+ LOUD_DEBUG(DbgPrint("NdisM: Exit do requests\n");)
+
+ Miniport->RunDoRequests = FALSE;
+
+ return;
+
+ }
+
+ if (Status != NDIS_STATUS_PENDING) {
+ NdisMSetInformationComplete(
+ (NDIS_HANDLE)Miniport,
+ Status
+ );
+ }
+
+ }
+
+ if (Miniport->NeedToUpdateFunctionalAddress) {
+ UINT FunctionalAddress;
+
+ DoneSomething = TRUE;
+ //
+ // This is an internal update that is needed.
+ //
+
+ Miniport->MiniportRequest = &(Miniport->InternalRequest);
+ Miniport->NeedToUpdateFunctionalAddress = FALSE;
+
+ //
+ // Get information needed
+ //
+ FunctionalAddress = TR_QUERY_FILTER_ADDRESSES(Miniport->TrDB);
+ FunctionalAddress = BYTE_SWAP_ULONG(FunctionalAddress);
+ NdisMoveMemory(Miniport->MulticastBuffer,
+ &FunctionalAddress,
+ sizeof(FunctionalAddress)
+ );
+
+ //
+ // Submit Request
+ //
+ LOUD_DEBUG(DbgPrint("NdisM: Updating functional address\n");)
+
+ Miniport->InternalRequest.RequestType = NdisRequestSetInformation;
+
+ Status =
+ (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ OID_802_5_CURRENT_FUNCTIONAL,
+ Miniport->MulticastBuffer,
+ sizeof(FunctionalAddress),
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesRead,
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesNeeded
+ );
+
+ if ((Status == NDIS_STATUS_PENDING) && (Miniport->MiniportRequest)) {
+
+ //
+ // Still outstanding
+ //
+ LOUD_DEBUG(DbgPrint("NdisM: Exit do requests\n");)
+
+ Miniport->RunDoRequests = FALSE;
+
+ return;
+
+ }
+
+ if (Status != NDIS_STATUS_PENDING) {
+ NdisMSetInformationComplete(
+ (NDIS_HANDLE)Miniport,
+ Status
+ );
+ }
+
+ }
+
+ if (Miniport->NeedToUpdateGroupAddress) {
+ UINT GroupAddress;
+
+ DoneSomething = TRUE;
+ //
+ // This is an internal update that is needed.
+ //
+
+ Miniport->MiniportRequest = &(Miniport->InternalRequest);
+ Miniport->NeedToUpdateGroupAddress = FALSE;
+
+ //
+ // Get information needed
+ //
+ GroupAddress = TR_QUERY_FILTER_GROUP(Miniport->TrDB);
+ GroupAddress = BYTE_SWAP_ULONG(GroupAddress);
+ NdisMoveMemory(Miniport->MulticastBuffer,
+ &GroupAddress,
+ sizeof(GroupAddress)
+ );
+
+ //
+ // Submit Request
+ //
+ LOUD_DEBUG(DbgPrint("NdisM: Updating group address\n");)
+
+ Miniport->InternalRequest.RequestType = NdisRequestSetInformation;
+
+ Status =
+ (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ OID_802_5_CURRENT_GROUP,
+ Miniport->MulticastBuffer,
+ sizeof(GroupAddress),
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesRead,
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesNeeded
+ );
+
+ if ((Status == NDIS_STATUS_PENDING) && (Miniport->MiniportRequest)) {
+
+ //
+ // Still outstanding
+ //
+ LOUD_DEBUG(DbgPrint("NdisM: Exit do requests\n");)
+
+ Miniport->RunDoRequests = FALSE;
+
+ return;
+
+ }
+
+ if (Status != NDIS_STATUS_PENDING) {
+ NdisMSetInformationComplete(
+ (NDIS_HANDLE)Miniport,
+ Status
+ );
+ }
+
+ }
+
+ if (Miniport->NeedToUpdateFddiLongAddresses) {
+ UINT NumberOfAddresses;
+
+ DoneSomething = TRUE;
+ //
+ // This is an internal update that is needed.
+ //
+
+ Miniport->MiniportRequest = &(Miniport->InternalRequest);
+ Miniport->NeedToUpdateFddiLongAddresses = FALSE;
+
+ //
+ // Get information needed
+ //
+
+ FddiQueryGlobalFilterLongAddresses(
+ &Status,
+ Miniport->FddiDB,
+ NDIS_M_MAX_MULTI_LIST * FDDI_LENGTH_OF_LONG_ADDRESS,
+ &NumberOfAddresses,
+ (PVOID)Miniport->MulticastBuffer
+ );
+
+ //
+ // Submit Request
+ //
+ LOUD_DEBUG(DbgPrint("NdisM: Updating fddi long addresses\n");)
+
+ Miniport->InternalRequest.RequestType = NdisRequestSetInformation;
+
+ Status =
+ (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ OID_FDDI_LONG_MULTICAST_LIST,
+ Miniport->MulticastBuffer,
+ NumberOfAddresses * FDDI_LENGTH_OF_LONG_ADDRESS,
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesRead,
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesNeeded
+ );
+
+ if ((Status == NDIS_STATUS_PENDING) && (Miniport->MiniportRequest)) {
+
+ //
+ // Still outstanding
+ //
+ LOUD_DEBUG(DbgPrint("NdisM: Exit do requests\n");)
+
+ Miniport->RunDoRequests = FALSE;
+
+ return;
+
+ }
+
+ if (Status != NDIS_STATUS_PENDING) {
+ NdisMSetInformationComplete(
+ (NDIS_HANDLE)Miniport,
+ Status
+ );
+ }
+
+ }
+
+ if (Miniport->NeedToUpdateFddiShortAddresses) {
+ UINT NumberOfAddresses;
+
+ DoneSomething = TRUE;
+ //
+ // This is an internal update that is needed.
+ //
+
+ Miniport->MiniportRequest = &(Miniport->InternalRequest);
+ Miniport->NeedToUpdateFddiShortAddresses = FALSE;
+
+ //
+ // Get information needed
+ //
+
+ FddiQueryGlobalFilterShortAddresses(
+ &Status,
+ Miniport->FddiDB,
+ NDIS_M_MAX_MULTI_LIST * FDDI_LENGTH_OF_SHORT_ADDRESS,
+ &NumberOfAddresses,
+ (PVOID)Miniport->MulticastBuffer
+ );
+
+ //
+ // Submit Request
+ //
+ LOUD_DEBUG(DbgPrint("NdisM: Updating fddi short addresses\n");)
+
+ Miniport->InternalRequest.RequestType = NdisRequestSetInformation;
+
+ Status =
+ (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ OID_FDDI_SHORT_MULTICAST_LIST,
+ Miniport->MulticastBuffer,
+ NumberOfAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS,
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesRead,
+ &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesNeeded
+ );
+
+ if ((Status == NDIS_STATUS_PENDING) && (Miniport->MiniportRequest)) {
+
+ //
+ // Still outstanding
+ //
+ LOUD_DEBUG(DbgPrint("NdisM: Exit do requests\n");)
+
+ Miniport->RunDoRequests = FALSE;
+
+ return;
+
+ }
+
+ if (Status != NDIS_STATUS_PENDING) {
+ NdisMSetInformationComplete(
+ (NDIS_HANDLE)Miniport,
+ Status
+ );
+ }
+
+ }
+
+ if ( Miniport->FirstPendingRequest != NULL ) {
+
+ PNDIS_REQUEST_RESERVED Reserved;
+ PNDIS_REQUEST NdisRequest;
+ UINT MulticastAddresses;
+ ULONG PacketFilter;
+ BOOLEAN DoMove;
+ PVOID MoveSource;
+ UINT MoveBytes;
+ UINT Lookahead;
+ ULONG GenericULong;
+ UCHAR Address[ETH_LENGTH_OF_ADDRESS];
+
+ //
+ // Set defaults.
+ //
+ DoMove = TRUE;
+ DoneSomething = TRUE;
+ Status = NDIS_STATUS_SUCCESS;
+
+ //
+ // Remove first request
+ //
+ NdisRequest = Miniport->FirstPendingRequest;
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(NdisRequest);
+ Miniport->FirstPendingRequest = Reserved->Next;
+
+ //
+ // Reset the pending request timeout.
+ //
+ Miniport->PendingRequestTimeout = FALSE;
+
+ LOUD_DEBUG(DbgPrint("NdisM: Starting protocol request 0x%x\n", NdisRequest);)
+
+ //
+ // Put it on mini-port queue
+ //
+ Miniport->MiniportRequest = NdisRequest;
+
+ //
+ // Submit to mini-port
+ //
+ switch (NdisRequest->RequestType)
+ {
+ case NdisRequestQueryInformation:
+
+ MoveSource = &GenericULong;
+ MoveBytes = sizeof(GenericULong);
+
+ //
+ // We intercept some calls
+ //
+ switch (NdisRequest->DATA.QUERY_INFORMATION.Oid)
+ {
+ case OID_GEN_SUPPORTED_LIST:
+ {
+ PNDIS_OID pOidList;
+ PNDIS_REQUEST pFakeRequest;
+ PNDIS_REQUEST_RESERVED pFakeReserved;
+ PNDIS_M_OPEN_BLOCK Open;
+ ULONG cbDestination;
+ BOOLEAN fAllocFailed;
+
+ do
+ {
+ //
+ // Allocate our own request structure.
+ // We can't use the internal request structure
+ // since we don't have any way differentiate between
+ // internal requests that are blocking on an event
+ // and those that are not.
+ //
+ pFakeRequest = ExAllocatePool(
+ NonPagedPool,
+ sizeof(NDIS_REQUEST)
+ );
+ if (NULL == pFakeRequest)
+ {
+ fAllocFailed = TRUE;
+ break;
+ }
+
+ //
+ // Allocate a buffer to hold all possible OIDs.
+ // Currently there are about 196 possible OIDs for the
+ // FDDI case. In order to be sure that i get the whole
+ // OID list i allocate a buffer that can hold 250.
+ //
+ pOidList = ExAllocatePool(
+ NonPagedPool,
+ 250 * sizeof(NDIS_OID)
+ );
+ if (NULL == pOidList)
+ {
+ fAllocFailed = TRUE;
+ break;
+ }
+
+ //
+ // We succeeded with the allocations.
+ //
+ DoMove = FALSE;
+ fAllocFailed = FALSE;
+ NdisZeroMemory(pFakeRequest, sizeof(NDIS_REQUEST));
+ NdisZeroMemory(pOidList, 250 * sizeof(NDIS_OID));
+
+ //
+ // Save our fake request with the miniport.
+ //
+ Miniport->MiniportRequest = pFakeRequest;
+
+ //
+ // Save relevant information in the internal request structure
+ // in case this pends.
+ //
+ pFakeRequest->RequestType = NdisRequestQueryInformation;
+ pFakeRequest->DATA.QUERY_INFORMATION.Oid = OID_GEN_SUPPORTED_LIST;
+ pFakeRequest->DATA.QUERY_INFORMATION.InformationBuffer = pOidList;
+ pFakeRequest->DATA.QUERY_INFORMATION.InformationBufferLength = 250 * sizeof(NDIS_OID);
+
+ //
+ // Since we are faking the request we need to save the
+ // pointer to the original request that was passed by
+ // the caller.
+ //
+ pFakeReserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(pFakeRequest);
+ pFakeReserved->Next = NdisRequest;
+
+ //
+ // Fire off the request to the miniport.
+ // We let NdisMQueryInformationComplete() handle
+ // all situations of the return value.
+ //
+ Status = (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ OID_GEN_SUPPORTED_LIST,
+ pOidList,
+ 250 * sizeof(NDIS_OID),
+ &pFakeRequest->DATA.QUERY_INFORMATION.BytesWritten,
+ &pFakeRequest->DATA.QUERY_INFORMATION.BytesNeeded
+ );
+ } while (FALSE);
+
+ //
+ // Did our allocations fail?
+ //
+ if (fAllocFailed)
+ {
+ //
+ // This is the only resource that could have
+ // been allocated above.
+ //
+ if (NULL != pFakeRequest)
+ ExFreePool(pFakeRequest);
+
+ //
+ // We have to notify the protocol and return
+ // from here. NdisMQueryInformationComplete()
+ // cannot handle the case where memory allocations
+ // failed.
+ //
+ Miniport->Timeout = FALSE;
+ Miniport->MiniportRequest = NULL;
+ Open = Reserved->Open;
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.RequestCompleteHandler)(
+ Open->ProtocolBindingContext,
+ NdisRequest,
+ NDIS_STATUS_RESOURCES
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open->References--;
+
+ if (Open->References == 0)
+ {
+ FinishClose(Miniport, Open);
+ }
+
+ Miniport->RunDoRequests = FALSE;
+
+ if (Miniport->NeedToUpdateEthAddresses ||
+ Miniport->NeedToUpdatePacketFilter ||
+ Miniport->NeedToUpdateFunctionalAddress ||
+ Miniport->NeedToUpdateGroupAddress ||
+ Miniport->NeedToUpdateFddiLongAddresses ||
+ Miniport->NeedToUpdateFddiShortAddresses ||
+ (Miniport->FirstPendingRequest != NULL)
+ )
+ {
+ Miniport->RunDoRequests = TRUE;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+ }
+
+ return;
+ }
+ }
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ switch (Miniport->MediaType) {
+ case NdisMedium802_3:
+ PacketFilter = ETH_QUERY_PACKET_FILTER(
+ Miniport->EthDB,
+ Reserved->Open->FilterHandle
+ );
+ break;
+ case NdisMedium802_5:
+ PacketFilter = TR_QUERY_PACKET_FILTER(
+ Miniport->TrDB,
+ Reserved->Open->FilterHandle
+ );
+ break;
+ case NdisMediumFddi:
+ PacketFilter = FDDI_QUERY_PACKET_FILTER(
+ Miniport->FddiDB,
+ Reserved->Open->FilterHandle
+ );
+ break;
+ case NdisMediumArcnet878_2:
+
+ if (Reserved->Open->UsingEthEncapsulation) {
+
+ PacketFilter = ETH_QUERY_PACKET_FILTER(
+ Miniport->EthDB,
+ Reserved->Open->FilterHandle
+ );
+ } else {
+
+ PacketFilter = ARC_QUERY_PACKET_FILTER(
+ Miniport->ArcDB,
+ Reserved->Open->FilterHandle
+ );
+ }
+ break;
+ }
+ GenericULong = (ULONG)(PacketFilter);
+ break;
+
+ case OID_GEN_MEDIA_IN_USE:
+ case OID_GEN_MEDIA_SUPPORTED:
+
+ if (Miniport->MediaType == NdisMediumArcnet878_2) {
+
+ if (Reserved->Open->UsingEthEncapsulation) {
+
+ GenericULong = (ULONG)(NdisMedium802_3);
+
+ } else {
+
+ GenericULong = (ULONG)(NdisMediumArcnet878_2);
+
+ }
+
+ } else {
+
+ GenericULong = (ULONG)(Miniport->MediaType);
+
+ }
+ MoveBytes = sizeof(NDIS_MEDIUM);
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ GenericULong = (ULONG)(Reserved->Open->CurrentLookahead);
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+ GenericULong = (ULONG)(Miniport->MaximumLookahead);
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+
+ if ( (NdisRequest->DATA.SET_INFORMATION.InformationBufferLength %
+ ETH_LENGTH_OF_ADDRESS) == 0) {
+
+ EthQueryOpenFilterAddresses(
+ &Status,
+ Miniport->EthDB,
+ Reserved->Open->FilterHandle,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &MulticastAddresses,
+ (PVOID)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer)
+ );
+
+ MoveSource = (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
+ MoveBytes = MulticastAddresses * ETH_LENGTH_OF_ADDRESS;
+ } else {
+ //
+ // The data must be a multiple of the Ethernet address size.
+ //
+
+ Status = NDIS_STATUS_INVALID_DATA;
+ }
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+ GenericULong = Miniport->MaximumLongAddresses;
+ break;
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+ GenericULong = TR_QUERY_FILTER_BINDING_ADDRESS(
+ Miniport->TrDB,
+ Reserved->Open->FilterHandle
+ );
+ GenericULong = BYTE_SWAP_ULONG(GenericULong);
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+ GenericULong = TR_QUERY_FILTER_GROUP(
+ Miniport->TrDB
+ );
+ GenericULong = BYTE_SWAP_ULONG(GenericULong);
+ break;
+
+ case OID_FDDI_LONG_MULTICAST_LIST:
+ FddiQueryOpenFilterLongAddresses(
+ &Status,
+ Miniport->FddiDB,
+ Reserved->Open->FilterHandle,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &MulticastAddresses,
+ (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer
+ );
+
+ MoveSource = (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
+ MoveBytes = FDDI_LENGTH_OF_LONG_ADDRESS *
+ FddiNumberOfOpenFilterLongAddresses(
+ Miniport->FddiDB,
+ Reserved->Open->FilterHandle);
+ break;
+
+ case OID_FDDI_LONG_MAX_LIST_SIZE:
+ GenericULong = Miniport->MaximumLongAddresses;
+ break;
+
+ case OID_FDDI_SHORT_MULTICAST_LIST:
+ FddiQueryOpenFilterShortAddresses(
+ &Status,
+ Miniport->FddiDB,
+ Reserved->Open->FilterHandle,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &MulticastAddresses,
+ (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer
+ );
+
+ MoveSource = (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
+ MoveBytes = FDDI_LENGTH_OF_SHORT_ADDRESS *
+ FddiNumberOfOpenFilterShortAddresses(
+ Miniport->FddiDB,
+ Reserved->Open->FilterHandle);
+ break;
+
+ case OID_FDDI_SHORT_MAX_LIST_SIZE:
+ GenericULong = Miniport->MaximumShortAddresses;
+ break;
+
+ //
+ //
+ // Start interceptions for running an ethernet
+ // protocol on top of an arcnet mini-port.
+ //
+ //
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+
+ if (Miniport->MediaType == NdisMediumArcnet878_2) {
+
+ if (Reserved->Open->UsingEthEncapsulation) {
+
+ //
+ // 504 - 14 (ethernet header) == 490.
+ //
+
+ GenericULong = ARC_MAX_FRAME_SIZE - 14;
+
+ break;
+ }
+ }
+ goto SubmitToMiniportDriver;
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+
+ if (Miniport->MediaType == NdisMediumArcnet878_2) {
+
+ if (Reserved->Open->UsingEthEncapsulation) {
+
+ GenericULong = ARC_MAX_FRAME_SIZE;
+
+ break;
+ }
+ }
+ goto SubmitToMiniportDriver;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+ case OID_802_3_CURRENT_ADDRESS:
+
+ if ( Miniport->MediaType == NdisMediumArcnet878_2 ) {
+
+ if (Reserved->Open->UsingEthEncapsulation) {
+
+ //
+ // The following stuff makes the copy code
+ // below copy the source address into the
+ // the users request buffer.
+ //
+
+ MoveSource = Address;
+ MoveBytes = ETH_LENGTH_OF_ADDRESS;
+
+ //
+ // Arcnet-to-ethernet conversion.
+ //
+
+ NdisZeroMemory(
+ Address,
+ ETH_LENGTH_OF_ADDRESS
+ );
+
+ Address[5] = Miniport->ArcnetAddress;
+
+ break;
+ }
+ }
+
+ goto SubmitToMiniportDriver;
+
+ default:
+
+SubmitToMiniportDriver:
+
+ DoMove = FALSE;
+
+ Status =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &(NdisRequest->DATA.QUERY_INFORMATION.BytesWritten),
+ &(NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded)
+ );
+
+ break;
+
+ }
+
+ if (DoMove) {
+
+ //
+ // This was an intercepted request. Finish it off
+ //
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ if (MoveBytes >
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength) {
+
+ //
+ // Not enough room in InformationBuffer. Punt
+ //
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = MoveBytes;
+
+ Status = NDIS_STATUS_INVALID_LENGTH;
+
+ } else {
+
+ //
+ // Copy result into InformationBuffer
+ //
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesWritten = MoveBytes;
+
+ if ((MoveBytes > 0) &&
+ (MoveSource != NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer)) {
+
+ NdisMoveMemory(
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
+ MoveSource,
+ MoveBytes
+ );
+ }
+ }
+
+ } else {
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = MoveBytes;
+
+ }
+
+ }
+
+ break;
+
+ case NdisRequestQueryStatistics:
+
+ //
+ // Query GLOBAL statistics
+ //
+ MoveSource = &GenericULong;
+ MoveBytes = sizeof(GenericULong);
+
+ //
+ // We intercept some calls
+ //
+
+ switch (NdisRequest->DATA.QUERY_INFORMATION.Oid) {
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ switch (Miniport->MediaType) {
+ case NdisMedium802_3:
+ PacketFilter = ETH_QUERY_FILTER_CLASSES(Miniport->EthDB);
+ break;
+ case NdisMedium802_5:
+ PacketFilter = TR_QUERY_FILTER_CLASSES(Miniport->TrDB);
+ break;
+ case NdisMediumFddi:
+ PacketFilter = FDDI_QUERY_FILTER_CLASSES(Miniport->FddiDB);
+ break;
+ case NdisMediumArcnet878_2:
+ PacketFilter = ARC_QUERY_FILTER_CLASSES(Miniport->ArcDB);
+ PacketFilter |= ETH_QUERY_FILTER_CLASSES(Miniport->EthDB);
+ break;
+ }
+ GenericULong = (ULONG)(PacketFilter);
+ break;
+
+ case OID_GEN_MEDIA_IN_USE:
+ case OID_GEN_MEDIA_SUPPORTED:
+ MoveSource = (PVOID) (&(Miniport->MediaType));
+ MoveBytes = sizeof(NDIS_MEDIUM);
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ GenericULong = (ULONG)(Miniport->CurrentLookahead);
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+ GenericULong = (ULONG)(Miniport->MaximumLookahead);
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+
+ EthQueryGlobalFilterAddresses(
+ &Status,
+ Miniport->EthDB,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &MulticastAddresses,
+ (PVOID)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer)
+ );
+
+ MoveSource = (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
+ MoveBytes = MulticastAddresses * ETH_LENGTH_OF_ADDRESS;
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+ GenericULong = Miniport->MaximumLongAddresses;
+ break;
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+ GenericULong = TR_QUERY_FILTER_ADDRESSES(
+ Miniport->TrDB
+ );
+ GenericULong = BYTE_SWAP_ULONG(GenericULong);
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+ GenericULong = TR_QUERY_FILTER_GROUP(
+ Miniport->TrDB
+ );
+ GenericULong = BYTE_SWAP_ULONG(GenericULong);
+ break;
+
+ case OID_FDDI_LONG_MULTICAST_LIST:
+ FddiQueryGlobalFilterLongAddresses(
+ &Status,
+ Miniport->FddiDB,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &MulticastAddresses,
+ (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+
+ MoveSource = (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
+ MoveBytes = FDDI_LENGTH_OF_LONG_ADDRESS * MulticastAddresses;
+ break;
+
+ case OID_FDDI_LONG_MAX_LIST_SIZE:
+ GenericULong = Miniport->MaximumLongAddresses;
+ break;
+
+ case OID_FDDI_SHORT_MULTICAST_LIST:
+ FddiQueryGlobalFilterShortAddresses(
+ &Status,
+ Miniport->FddiDB,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &MulticastAddresses,
+ (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+
+ MoveSource = (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
+ MoveBytes = FDDI_LENGTH_OF_SHORT_ADDRESS * MulticastAddresses;
+ break;
+
+ case OID_FDDI_SHORT_MAX_LIST_SIZE:
+ GenericULong = Miniport->MaximumShortAddresses;
+ break;
+
+ default:
+
+ DoMove = FALSE;
+
+ Status =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &(NdisRequest->DATA.QUERY_INFORMATION.BytesWritten),
+ &(NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded)
+ );
+
+ break;
+
+ }
+
+ if (DoMove) {
+
+ //
+ // This was an intercepted request. Finish it off
+ //
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ if (MoveBytes >
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength) {
+
+ //
+ // Not enough room in InformationBuffer. Punt
+ //
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = MoveBytes;
+
+ Status = NDIS_STATUS_INVALID_LENGTH;
+
+ } else {
+
+ //
+ // Copy result into InformationBuffer
+ //
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesWritten = MoveBytes;
+
+ if ((MoveBytes > 0) &&
+ (MoveSource != NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer)) {
+ NdisMoveMemory(
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
+ MoveSource,
+ MoveBytes
+ );
+ }
+
+ }
+
+ } else {
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = MoveBytes;
+
+ }
+
+ }
+ break;
+
+
+
+
+ case NdisRequestSetInformation:
+
+ //
+ // We intercept some calls
+ //
+
+ switch (NdisRequest->DATA.SET_INFORMATION.Oid) {
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ if (NdisRequest->DATA.SET_INFORMATION.InformationBufferLength
+ != 4) {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+ break;
+ }
+
+ //
+ // Now call the filter package to set the packet filter.
+ //
+ NdisMoveMemory ((PVOID)&PacketFilter,
+ NdisRequest->DATA.SET_INFORMATION.InformationBuffer,
+ sizeof(ULONG)
+ );
+
+ if (PacketFilter & ~(Miniport->SupportedPacketFilters)) {
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 4;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+ break;
+ }
+
+ switch (Miniport->MediaType) {
+ case NdisMedium802_3:
+ Status = EthFilterAdjust(
+ Miniport->EthDB,
+ Reserved->Open->FilterHandle,
+ (PNDIS_REQUEST)NdisRequest,
+ PacketFilter,
+ TRUE
+ );
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 4;
+ break;
+
+ case NdisMedium802_5:
+ Status = TrFilterAdjust(
+ Miniport->TrDB,
+ Reserved->Open->FilterHandle,
+ (PNDIS_REQUEST)NdisRequest,
+ PacketFilter,
+ TRUE
+ );
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 4;
+ break;
+
+ case NdisMediumFddi:
+ Status = FddiFilterAdjust(
+ Miniport->FddiDB,
+ Reserved->Open->FilterHandle,
+ (PNDIS_REQUEST)NdisRequest,
+ PacketFilter,
+ TRUE
+ );
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 4;
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ if (Reserved->Open->UsingEthEncapsulation) {
+
+ Status = EthFilterAdjust(
+ Miniport->EthDB,
+ Reserved->Open->FilterHandle,
+ (PNDIS_REQUEST)NdisRequest,
+ PacketFilter,
+ TRUE
+ );
+
+ } else {
+
+ Status = ArcFilterAdjust(
+ Miniport->ArcDB,
+ Reserved->Open->FilterHandle,
+ (PNDIS_REQUEST)NdisRequest,
+ PacketFilter,
+ TRUE
+ );
+ }
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 4;
+ break;
+ }
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ //
+ // Verify length
+ //
+ if (NdisRequest->DATA.SET_INFORMATION.InformationBufferLength
+ != 4) {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+ break;
+ }
+
+ NdisMoveMemory(&Lookahead,
+ NdisRequest->DATA.SET_INFORMATION.InformationBuffer,
+ 4
+ );
+
+ if (Lookahead > Miniport->MaximumLookahead) {
+
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+ break;
+
+ }
+
+ Reserved->Open->CurrentLookahead = Lookahead;
+ Status = MiniportAdjustMaximumLookahead(Miniport);
+
+ //
+ // Since this routine may submit another request, update our
+ // pointer to the currently executing request.
+ //
+ NdisRequest = Miniport->MiniportRequest;
+
+ break;
+
+ case OID_GEN_PROTOCOL_OPTIONS:
+
+ if (NdisRequest->DATA.SET_INFORMATION.InformationBufferLength
+ != 4) {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+ break;
+ }
+
+ NdisMoveMemory(&(Reserved->Open->ProtocolOptions),
+ NdisRequest->DATA.SET_INFORMATION.InformationBuffer,
+ 4
+ );
+
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+
+ if ( (NdisRequest->DATA.SET_INFORMATION.InformationBufferLength
+ % ETH_LENGTH_OF_ADDRESS) != 0) {
+
+ //
+ // The data must be a multiple of the Ethernet
+ // address size.
+ //
+
+ Status = NDIS_STATUS_INVALID_DATA;
+ break;
+
+ }
+
+ if ((Miniport->MediaType != NdisMedium802_3) &&
+ !((Miniport->MediaType == NdisMediumArcnet878_2) &&
+ (Reserved->Open->UsingEthEncapsulation))) {
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ //
+ // Now call the filter package to set up the addresses.
+ //
+
+ Status = EthChangeFilterAddresses(
+ Miniport->EthDB,
+ Reserved->Open->FilterHandle,
+ (PNDIS_REQUEST)NdisRequest,
+ NdisRequest->DATA.SET_INFORMATION.InformationBufferLength
+ / ETH_LENGTH_OF_ADDRESS,
+ NdisRequest->DATA.SET_INFORMATION.InformationBuffer,
+ TRUE
+ );
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead =
+ NdisRequest->DATA.SET_INFORMATION.InformationBufferLength;
+ break;
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+ if (Miniport->MediaType != NdisMedium802_5) {
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if (NdisRequest->DATA.SET_INFORMATION.InformationBufferLength
+ != 4) {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+ break;
+ }
+
+ Status = TrChangeFunctionalAddress(
+ Reserved->Open->MiniportHandle->TrDB,
+ Reserved->Open->FilterHandle,
+ NdisRequest,
+ (PUCHAR)(NdisRequest->DATA.SET_INFORMATION.InformationBuffer),
+ TRUE
+ );
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+ if (Miniport->MediaType != NdisMedium802_5) {
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if (NdisRequest->DATA.SET_INFORMATION.InformationBufferLength
+ != 4) {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+ break;
+ }
+
+ Status = TrChangeGroupAddress(
+ Reserved->Open->MiniportHandle->TrDB,
+ Reserved->Open->FilterHandle,
+ NdisRequest,
+ (PUCHAR)(NdisRequest->DATA.SET_INFORMATION.InformationBuffer),
+ TRUE
+ );
+ break;
+
+ case OID_FDDI_LONG_MULTICAST_LIST:
+ if (Miniport->MediaType != NdisMediumFddi) {
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if (NdisRequest->DATA.SET_INFORMATION.InformationBufferLength
+ % FDDI_LENGTH_OF_LONG_ADDRESS != 0) {
+
+ //
+ // The data must be a multiple of the Ethernet
+ // address size.
+ //
+
+ Status = NDIS_STATUS_INVALID_DATA;
+ break;
+
+ }
+
+ //
+ // Now call the filter package to set up the addresses.
+ //
+ Status = FddiChangeFilterLongAddresses(
+ Miniport->FddiDB,
+ Reserved->Open->FilterHandle,
+ (PNDIS_REQUEST)NdisRequest,
+ NdisRequest->DATA.SET_INFORMATION.InformationBufferLength
+ / FDDI_LENGTH_OF_LONG_ADDRESS,
+ NdisRequest->DATA.SET_INFORMATION.InformationBuffer,
+ TRUE
+ );
+ NdisRequest->DATA.SET_INFORMATION.BytesRead =
+ NdisRequest->DATA.SET_INFORMATION.InformationBufferLength;
+ break;
+
+ case OID_FDDI_SHORT_MULTICAST_LIST:
+ if (Miniport->MediaType != NdisMediumFddi) {
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if (NdisRequest->DATA.SET_INFORMATION.InformationBufferLength
+ % FDDI_LENGTH_OF_SHORT_ADDRESS != 0) {
+
+ //
+ // The data must be a multiple of the Ethernet
+ // address size.
+ //
+
+ Status = NDIS_STATUS_INVALID_DATA;
+ break;
+
+ }
+
+ //
+ // Now call the filter package to set up the addresses.
+ //
+ Status = FddiChangeFilterShortAddresses(
+ Miniport->FddiDB,
+ Reserved->Open->FilterHandle,
+ (PNDIS_REQUEST)NdisRequest,
+ NdisRequest->DATA.SET_INFORMATION.InformationBufferLength
+ / FDDI_LENGTH_OF_SHORT_ADDRESS,
+ NdisRequest->DATA.SET_INFORMATION.InformationBuffer,
+ TRUE
+ );
+ NdisRequest->DATA.SET_INFORMATION.BytesRead =
+ NdisRequest->DATA.SET_INFORMATION.InformationBufferLength;
+ break;
+
+ default:
+
+ Status =
+ (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ NdisRequest->DATA.SET_INFORMATION.Oid,
+ NdisRequest->DATA.SET_INFORMATION.InformationBuffer,
+ NdisRequest->DATA.SET_INFORMATION.InformationBufferLength,
+ &(NdisRequest->DATA.SET_INFORMATION.BytesRead),
+ &(NdisRequest->DATA.SET_INFORMATION.BytesNeeded)
+ );
+
+ break;
+
+ }
+ break;
+
+ }
+
+ if ((Status == NDIS_STATUS_PENDING) && (Miniport->MiniportRequest)) {
+
+ //
+ // Still outstanding
+ //
+ LOUD_DEBUG(DbgPrint("NdisM: Exit do requests\n");)
+
+ Miniport->RunDoRequests = FALSE;
+
+ return;
+
+ }
+
+ //
+ // Complete request
+ //
+
+ if (Status != NDIS_STATUS_PENDING) {
+
+ switch (NdisRequest->RequestType) {
+
+ case NdisRequestQueryStatistics:
+ case NdisRequestQueryInformation:
+
+ NdisMQueryInformationComplete(
+ (NDIS_HANDLE)Miniport,
+ Status
+ );
+ break;
+
+ case NdisRequestSetInformation:
+
+ NdisMSetInformationComplete(
+ (NDIS_HANDLE)Miniport,
+ Status
+ );
+ break;
+ }
+ }
+ }
+ }
+
+ if ((Miniport->NeedToUpdateEthAddresses ||
+ Miniport->NeedToUpdatePacketFilter ||
+ Miniport->NeedToUpdateFunctionalAddress ||
+ Miniport->NeedToUpdateGroupAddress ||
+ Miniport->NeedToUpdateFddiLongAddresses ||
+ Miniport->NeedToUpdateFddiShortAddresses ||
+ (Miniport->FirstPendingRequest != NULL))
+ &&
+ (Miniport->MiniportRequest == NULL))
+ {
+ Miniport->RunDoRequests = TRUE;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+ }
+ else
+ {
+ Miniport->RunDoRequests = FALSE;
+ }
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit do requests\n");)
+ return;
+
+}
+
+
+
+BOOLEAN
+FASTCALL
+MiniportSendLoopback(
+ PNDIS_MINIPORT_BLOCK Miniport,
+ PNDIS_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ Checks if a packet needs to be loopbacked and does so if necessary.
+
+ NOTE: Must be called at DPC_LEVEL with lock HELD!
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+ Packet - Packet to loopback.
+
+Return Value:
+
+ FALSE if the packet should be sent on the net, TRUE if it is
+ a self-directed packet.
+
+--*/
+
+{
+
+ BOOLEAN Loopback;
+ BOOLEAN SelfDirected;
+ INT FddiAddressCheck;
+ PNDIS_BUFFER FirstBuffer;
+ UINT BufferLength;
+ PUCHAR BufferAddress;
+ UINT Length;
+ UINT AddressLength;
+
+ // We should not be here if the driver handles loopback
+ ASSERT(Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK);
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ FirstBuffer = Packet->Private.Head;
+ BufferAddress = MmGetSystemAddressForMdl(FirstBuffer);
+
+ switch (Miniport->MediaType) {
+
+ case NdisMedium802_3:
+
+ //
+ // If the card does not do loopback, then we check if
+ // we need to send it to ourselves, then if that is the
+ // case we also check for it being self-directed.
+ //
+
+ EthShouldAddressLoopBackMacro(Miniport->EthDB, BufferAddress, &Loopback, &SelfDirected);
+
+ if (!Loopback) {
+ ASSERT(!SelfDirected);
+ return FALSE;
+ }
+ break;
+
+ case NdisMedium802_5:
+
+ Loopback = TrShouldAddressLoopBack(
+ Miniport->TrDB,
+ BufferAddress + 2, // Skip FC & AC bytes.
+ BufferAddress + 8 // Destination address.
+ );
+
+ if (!Loopback) {
+ return FALSE;
+ }
+
+ //
+ // See if it is self-directed.
+ //
+
+ if ((*(ULONG UNALIGNED *)&BufferAddress[4] ==
+ *(ULONG UNALIGNED *)&Miniport->TrDB->AdapterAddress[2]) &&
+ (*(USHORT UNALIGNED *)&BufferAddress[2] ==
+ *(USHORT UNALIGNED *)&Miniport->TrDB->AdapterAddress[0])) {
+
+ SelfDirected = TRUE;
+ Loopback = TRUE;
+
+ } else {
+
+ SelfDirected = FALSE;
+ }
+
+ break;
+
+ case NdisMediumFddi:
+
+ AddressLength = (BufferAddress[0] & 0x40)? FDDI_LENGTH_OF_LONG_ADDRESS:
+ FDDI_LENGTH_OF_SHORT_ADDRESS;
+
+ FddiShouldAddressLoopBackMacro(Miniport->FddiDB,
+ BufferAddress + 1, // Skip FC byte to dest address.
+ AddressLength,
+ &Loopback,
+ &SelfDirected);
+
+ if (!Loopback) {
+ return FALSE;
+ }
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ if ( ARC_PACKET_IS_ENCAPSULATED(Packet) ) {
+
+ //
+ // The second buffer in the packet is the ethernet
+ // header so we need to get that one before we can
+ // proceed.
+ //
+
+ NdisGetNextBuffer(FirstBuffer, &FirstBuffer);
+
+ BufferAddress = MmGetSystemAddressForMdl(FirstBuffer);
+
+ // Length -= 3; Length is not valid at this point. Do this later when
+ // we determine that we need to loopback for certain
+
+ //
+ // Now we can continue as though this were ethernet.
+ //
+
+ EthShouldAddressLoopBackMacro(
+ Miniport->EthDB,
+ BufferAddress,
+ &Loopback,
+ &SelfDirected);
+
+ if (!Loopback) {
+ return FALSE;
+ }
+ } else {
+
+ Loopback = ((BufferAddress[0] == BufferAddress[1]) ||
+ ((BufferAddress[1] == 0x00) &&
+ (ARC_QUERY_FILTER_CLASSES(Miniport->ArcDB) |
+ NDIS_PACKET_TYPE_BROADCAST)));
+
+ if (BufferAddress[0] == BufferAddress[1]) {
+ SelfDirected = TRUE;
+ Loopback = TRUE;
+ } else {
+ SelfDirected = FALSE;
+ }
+ }
+
+ break;
+ }
+
+ if (Loopback) {
+
+ //
+ // Get the buffer length
+ //
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ NULL,
+ NULL,
+ &Length
+ );
+
+ if ((Miniport->MediaType == NdisMediumArcnet878_2) &&
+ ARC_PACKET_IS_ENCAPSULATED(Packet))
+ {
+ Length -= 3;
+ }
+
+ //
+ // See if we need to copy the data from the packet
+ // into the loopback buffer.
+ //
+ // We need to copy to the local loopback buffer if
+ // the first buffer of the packet is less than the
+ // minimum loopback size AND the first buffer isn't
+ // the total packet.
+ //
+
+ BufferLength = MmGetMdlByteCount(FirstBuffer);
+
+ if ((BufferLength < NDIS_M_MAX_LOOKAHEAD) && (BufferLength != Length)) {
+
+ UINT BytesToCopy;
+ UINT Offset = 0;
+
+ switch( Miniport->MediaType ) {
+
+ case NdisMedium802_3:
+ case NdisMedium802_5:
+
+ BytesToCopy = 14;
+ break;
+
+ case NdisMediumFddi:
+
+ BytesToCopy = 1 + (2 * AddressLength);
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ if ( ARC_PACKET_IS_ENCAPSULATED(Packet) ) {
+
+ BytesToCopy = 14; // Copy encapsulated ethernet header.
+ Offset = 3; // Skip fake arcnet header.
+
+ } else {
+
+ BytesToCopy = 3; // Copy arcnet header.
+ }
+ break;
+ }
+
+ BytesToCopy += Miniport->CurrentLookahead;
+
+ BufferAddress = Miniport->LookaheadBuffer;
+
+ MiniportCopyFromPacketToBuffer(
+ Packet, // Packet to copy from.
+ Offset, // Offset from beginning of packet.
+ BytesToCopy, // Number of bytes to copy.
+ BufferAddress, // The destination buffer.
+ &BufferLength // The number of bytes copied.
+ );
+ }
+
+ Miniport->LoopbackPacket = Packet;
+
+ NDIS_LOG_PACKET(Miniport, Packet, 'L');
+
+ if (BufferLength >= 14) {
+
+ //
+ // Not a runt packet
+ //
+ //
+ // Indicate the packet to every open binding
+ // that could want it.
+ //
+
+ switch (Miniport->MediaType) {
+
+ case NdisMedium802_3:
+
+ //
+ // NOTE: Code re-use for 878.2 (arcnet) encapsulated
+ // ethernet packets.
+ //
+
+EthIndicateLoopbackFullPacket:
+
+ Miniport->LoopbackPacketHeaderSize = 14;
+
+ EthFilterDprIndicateReceive(
+ Miniport->EthDB,
+ Packet,
+ ((PCHAR)BufferAddress),
+ BufferAddress,
+ 14,
+ ((PUCHAR)BufferAddress) + 14,
+ BufferLength - 14,
+ Length - 14
+ );
+
+ EthFilterDprIndicateReceiveComplete(
+ Miniport->EthDB
+ );
+
+ break;
+
+ case NdisMedium802_5:
+
+ Miniport->LoopbackPacketHeaderSize = 14;
+
+ TrFilterDprIndicateReceive(
+ Miniport->TrDB,
+ Packet,
+ BufferAddress,
+ 14,
+ ((PUCHAR)BufferAddress) + 14,
+ BufferLength - 14,
+ Length - 14
+ );
+
+ TrFilterDprIndicateReceiveComplete(
+ Miniport->TrDB
+ );
+
+ break;
+
+ case NdisMediumFddi:
+
+ Miniport->LoopbackPacketHeaderSize = 1+(2*AddressLength);
+
+ FddiFilterDprIndicateReceive(
+ Miniport->FddiDB,
+ Packet,
+ ((PCHAR)BufferAddress) + 1,
+ AddressLength,
+ BufferAddress,
+ Miniport->LoopbackPacketHeaderSize,
+ ((PUCHAR)BufferAddress) + Miniport->LoopbackPacketHeaderSize,
+ BufferLength - Miniport->LoopbackPacketHeaderSize,
+ Length - Miniport->LoopbackPacketHeaderSize
+ );
+
+ FddiFilterDprIndicateReceiveComplete(
+ Miniport->FddiDB
+ );
+
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ if ( ARC_PACKET_IS_ENCAPSULATED(Packet) ) {
+
+ goto EthIndicateLoopbackFullPacket;
+
+ } else {
+
+ PUCHAR PlaceInBuffer;
+ PUCHAR ArcDataBuffer;
+ UINT ArcDataLength;
+ UINT PacketDataOffset;
+ UCHAR FrameCount;
+ UCHAR i;
+ UINT IndicateDataLength;
+ //
+ // Calculate how many frames we will need.
+ //
+
+ ArcDataLength = Length - 3;
+ PacketDataOffset = 3;
+
+ FrameCount = (UCHAR) (ArcDataLength / ARC_MAX_FRAME_SIZE);
+
+ if ( (ArcDataLength % ARC_MAX_FRAME_SIZE) != 0) {
+
+ FrameCount++;
+ }
+
+ for (i = 0; i < FrameCount; ++i) {
+
+ PlaceInBuffer = Miniport->LookaheadBuffer;
+
+ //
+ // Point data buffer to start of 'data'
+ //
+
+ ArcDataBuffer = Miniport->LookaheadBuffer + 2;
+
+ //
+ // Copy Header (SrcId/DestId/ProtId)
+ //
+
+ MiniportCopyFromPacketToBuffer(
+ Packet,
+ 0,
+ 3,
+ PlaceInBuffer,
+ &BufferLength
+ );
+
+ PlaceInBuffer += 3;
+
+ //
+ // Put in split flag
+ //
+
+ if ( FrameCount > 1 ) {
+
+ //
+ // Multi-frame indication...
+ //
+
+ if ( i == 0 ) {
+
+ //
+ // first frame
+ //
+
+ // *PlaceInBuffer = ( (FrameCount - 2) * 2 ) + 1;
+
+ *PlaceInBuffer = 2 * FrameCount - 3;
+ } else {
+
+ //
+ // Subsequent frame
+ //
+ *PlaceInBuffer = ( i * 2 );
+ }
+
+ } else {
+
+ //
+ // Only frame in the indication
+ //
+
+ *PlaceInBuffer = 0;
+ }
+
+ //
+ // Skip split flag
+ //
+
+ PlaceInBuffer++;
+
+ //
+ // Put in packet number.
+ //
+
+ *PlaceInBuffer++ = 0;
+ *PlaceInBuffer++ = 0;
+
+ //
+ // Copy data
+ //
+
+ if ( ArcDataLength > ARC_MAX_FRAME_SIZE ) {
+
+ IndicateDataLength = ARC_MAX_FRAME_SIZE;
+ } else {
+
+ IndicateDataLength = ArcDataLength;
+ }
+
+ MiniportCopyFromPacketToBuffer(
+ Packet,
+ PacketDataOffset,
+ IndicateDataLength,
+ PlaceInBuffer,
+ &BufferLength
+ );
+
+ ArcFilterDprIndicateReceive(
+ Miniport->ArcDB,
+ Miniport->LookaheadBuffer,
+ ArcDataBuffer,
+ IndicateDataLength + 4
+ );
+
+ ArcDataLength -= ARC_MAX_FRAME_SIZE;
+ PacketDataOffset += ARC_MAX_FRAME_SIZE;
+ }
+ }
+
+ ArcFilterDprIndicateReceiveComplete(
+ Miniport->ArcDB
+ );
+
+ break;
+
+ }
+
+ } else {
+
+ //
+ // A runt packet
+ //
+ //
+ // Indicate the packet to every open binding
+ // that could want it.
+ //
+
+ Miniport->LoopbackPacketHeaderSize = BufferLength;
+
+ switch (Miniport->MediaType) {
+ case NdisMedium802_3:
+
+ //
+ // NOTE: Code re-use for 878.2 (arcnet) encapsulated
+ // ethernet packets.
+ //
+
+EthIndicateLoopbackRuntPacket:
+
+ EthFilterDprIndicateReceive(
+ Miniport->EthDB,
+ Packet,
+ ((PCHAR)BufferAddress),
+ BufferAddress,
+ BufferLength,
+ NULL,
+ 0,
+ 0
+ );
+
+ EthFilterDprIndicateReceiveComplete(
+ Miniport->EthDB
+ );
+
+ break;
+
+ case NdisMedium802_5:
+
+ TrFilterDprIndicateReceive(
+ Miniport->TrDB,
+ Packet,
+ BufferAddress,
+ BufferLength,
+ NULL,
+ 0,
+ 0
+ );
+
+ TrFilterDprIndicateReceiveComplete(
+ Miniport->TrDB
+ );
+
+ break;
+
+ case NdisMediumFddi:
+
+ FddiFilterDprIndicateReceive(
+ Miniport->FddiDB,
+ Packet,
+ ((PCHAR)BufferAddress) + 1,
+ 0,
+ BufferAddress,
+ BufferLength,
+ NULL,
+ 0,
+ 0
+ );
+
+ FddiFilterDprIndicateReceiveComplete(
+ Miniport->FddiDB
+ );
+
+ break;
+
+ case NdisMediumArcnet878_2:
+
+
+ if ( ARC_PACKET_IS_ENCAPSULATED(Packet) ) {
+
+ goto EthIndicateLoopbackRuntPacket;
+
+ } else {
+
+ ArcFilterDprIndicateReceive(
+ Miniport->ArcDB,
+ BufferAddress,
+ ((PCHAR)BufferAddress) + Miniport->LoopbackPacketHeaderSize,
+ Length - Miniport->LoopbackPacketHeaderSize
+ );
+
+ ArcFilterDprIndicateReceiveComplete(
+ Miniport->ArcDB
+ );
+ }
+
+ break;
+
+ }
+
+ }
+
+ Miniport->LoopbackPacket = NULL;
+
+ }
+
+ return SelfDirected;
+
+}
+
+VOID
+MiniportFreeArcnetHeader(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+ This function strips off the arcnet header appended to
+ ethernet encapsulated packets
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+ Packet - Ndis packet.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_M_OPEN_BLOCK Open;
+ PARC_BUFFER_LIST Buffer, TmpBuffer;
+ PNDIS_BUFFER NdisBuffer;
+ PVOID BufferVa;
+ UINT Length;
+
+ Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Open;
+
+ if ( Open->UsingEthEncapsulation ) {
+
+ NdisUnchainBufferAtFront(
+ Packet,
+ &NdisBuffer
+ );
+
+ NdisQueryBuffer(NdisBuffer,
+ (PVOID *) &BufferVa,
+ &Length
+ );
+
+ NdisFreeBuffer(NdisBuffer);
+
+ Buffer = Miniport->ArcnetUsedBufferList;
+
+ if (Buffer->Buffer == BufferVa) {
+
+ Miniport->ArcnetUsedBufferList = Buffer->Next;
+
+ } else {
+
+ while (Buffer->Next->Buffer != BufferVa) {
+
+ Buffer = Buffer->Next;
+ }
+
+ TmpBuffer = Buffer->Next;
+ Buffer->Next = Buffer->Next->Next;
+ Buffer = TmpBuffer;
+
+ }
+
+ Buffer->Next = Miniport->ArcnetFreeBufferList;
+ Miniport->ArcnetFreeBufferList = Buffer;
+ }
+}
+
+
+VOID
+FASTCALL
+MiniportStartSends(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Submits as many sends as possible to the mini-port.
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PARC_BUFFER_LIST Buffer;
+ PNDIS_BUFFER NdisBuffer;
+ PNDIS_BUFFER TmpBuffer;
+ PNDIS_PACKET Packet;
+ PNDIS_PACKET PrevPacket;
+ NDIS_STATUS Status;
+ PNDIS_PACKET_RESERVED Reserved;
+ PNDIS_M_OPEN_BLOCK Open;
+ UINT Flags;
+ PUCHAR Address;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter sends\n");)
+
+ LOG('s');
+
+ Miniport->SendCompleteCalled = FALSE;
+
+ do {
+ Packet = Miniport->FirstPendingPacket;
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ Open = Reserved->Open;
+
+ NDIS_LOG_PACKET(Miniport, Packet, 's');
+
+ if (Miniport->MediaType == NdisMediumArcnet878_2) {
+
+ goto BuildArcnetHeader;
+
+ }
+
+DoneBuildingArcnetHeader:
+
+ //
+ // Remove from Queue
+ //
+ Miniport->FirstPendingPacket = Reserved->Next;
+
+ //
+ // Put on finish queue
+ //
+
+ PrevPacket = Miniport->LastMiniportPacket;
+ Miniport->LastMiniportPacket = Packet;
+
+ //
+ // Indicate the packet loopback if necessary.
+ //
+
+ if ((Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) &&
+ (!Miniport->AlreadyLoopedBack) &&
+ MiniportSendLoopback(Miniport, Packet)
+ )
+ {
+
+ LOUD_DEBUG(DbgPrint("NdisM: Not sending packet 0x%x\n", Packet);)
+
+ LOG('l');
+ NDIS_LOG_PACKET(Miniport, Packet, 'l');
+
+ Status = NDIS_STATUS_SUCCESS;
+ goto NoCardSend;
+ }
+
+ //
+ // Submit to card
+ //
+
+ LOUD_DEBUG(DbgPrint("NdisM: Sending packet 0x%x\n", Packet);)
+
+ REMOVE_RESOURCE(Miniport, 'S');
+
+ NdisQuerySendFlags(Packet, &Flags);
+
+ LOG('M');
+
+ NDIS_LOG_PACKET(Miniport, Packet, 'M');
+
+ Status = (Open->SendHandler)(
+ Open->MiniportAdapterContext,
+ Packet,
+ Flags
+ );
+ if (Status == NDIS_STATUS_PENDING)
+ {
+ LOG('p');
+ NDIS_LOG_PACKET(Miniport, Packet, 'p');
+
+ LOUD_DEBUG(DbgPrint("NdisM: Complete is pending\n");)
+
+ //
+ // We need to clear the loop back flag here also.
+ //
+ Miniport->AlreadyLoopedBack = FALSE;
+
+ continue;
+
+ }
+
+NoCardSend:
+
+ if (Miniport->MediaType == NdisMediumArcnet878_2) {
+
+ MiniportFreeArcnetHeader(Miniport, Packet);
+ }
+
+ if (Status != NDIS_STATUS_RESOURCES)
+ {
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ ADD_RESOURCE(Miniport, 'F');
+
+ LOG('F');
+ NDIS_LOG_PACKET(Miniport, Packet, 'F');
+ }
+
+ //
+ // Remove from finish queue
+ //
+
+ LOUD_DEBUG(DbgPrint("NdisM: Completed 0x%x\n", Status);)
+
+ //
+ // If send complete was called from the miniport's send handler
+ // then our local PrevPacket pointer may no longer be valid.
+ //
+
+ if ( Miniport->SendCompleteCalled )
+ {
+ Miniport->SendCompleteCalled = FALSE;
+ MiniportFindPacket(Miniport, Packet, &PrevPacket);
+ }
+
+ Miniport->LastMiniportPacket = PrevPacket;
+
+ if ( PrevPacket == NULL ) {
+
+ Miniport->FirstPacket = Reserved->Next;
+ Miniport->DeadPacket = NULL;
+
+ } else {
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = Reserved->Next;
+
+ //
+ // If we just unlinked the last packet then we need to update
+ // our last packet pointer.
+ //
+
+ if ( Packet == Miniport->LastPacket ) {
+
+ Miniport->LastPacket = PrevPacket;
+ }
+ }
+
+ //
+ // Reset for the next packet in the pending queue.
+ //
+ Miniport->AlreadyLoopedBack = FALSE;
+
+ //
+ // Indicate the completion to the protocol.
+ //
+ NDIS_LOG_PACKET(Miniport, Packet, 'C');
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Packet,
+ Status
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open->References--;
+
+ if (Open->References == 0) {
+
+ FinishClose(Miniport, Open);
+ }
+
+ } else {
+
+ LOUD_DEBUG(DbgPrint("NdisM: Deferring send\n");)
+
+ //
+ // If send complete was called from the miniport's send handler
+ // then our local PrevPacket pointer may no longer be valid.
+ //
+
+ if ( Miniport->SendCompleteCalled ) {
+
+ Miniport->SendCompleteCalled = FALSE;
+ MiniportFindPacket(Miniport, Packet, &PrevPacket);
+ }
+
+ //
+ // Remove from finish queue
+ //
+ Miniport->LastMiniportPacket = PrevPacket;
+
+ //
+ // Put on pending queue
+ //
+ Miniport->FirstPendingPacket = Packet;
+
+ //
+ // Mark the packet at the head of the pending queue as having
+ // been looped back.
+ //
+ Miniport->AlreadyLoopedBack = TRUE;
+
+ LOG('o');
+ NDIS_LOG_PACKET(Miniport, Packet, 'o');
+
+ //
+ // Set flag
+ //
+ CLEAR_RESOURCE(Miniport, 'S');
+ }
+
+ } while ((Miniport->SendResourcesAvailable != 0) && (Miniport->FirstPendingPacket));
+
+ LOG('S');
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit sends\n");)
+
+ return;
+
+BuildArcnetHeader:
+
+ if (Open->UsingEthEncapsulation) {
+
+ if (Miniport->ArcnetFreeBufferList == NULL) {
+
+ //
+ // Set flag
+ //
+ CLEAR_RESOURCE(Miniport, 'S');
+ return;
+
+ }
+
+ NdisQueryPacket(Packet,
+ NULL,
+ NULL,
+ &TmpBuffer,
+ NULL
+ );
+
+ NdisQueryBuffer(TmpBuffer, &Address, &Flags);
+
+ Buffer = Miniport->ArcnetFreeBufferList;
+ Miniport->ArcnetFreeBufferList = Buffer->Next;
+
+ NdisAllocateBuffer(
+ &Status,
+ &NdisBuffer,
+ Miniport->ArcnetBufferPool,
+ Buffer->Buffer,
+ 3
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ Buffer->Next = Miniport->ArcnetFreeBufferList;
+ Miniport->ArcnetFreeBufferList = Buffer;
+ CLEAR_RESOURCE(Miniport, 'S');
+ return;
+
+ }
+
+ Buffer->Next = Miniport->ArcnetUsedBufferList;
+ Miniport->ArcnetUsedBufferList = Buffer;
+
+ NdisChainBufferAtFront(Packet, NdisBuffer);
+
+ ((PUCHAR)Buffer->Buffer)[0] = Miniport->ArcnetAddress;
+
+ if (Address[0] & 0x01) {
+
+ //
+ // Broadcast
+ //
+ ((PUCHAR)Buffer->Buffer)[1] = 0x00;
+
+ } else {
+
+ ((PUCHAR)Buffer->Buffer)[1] = Address[5];
+
+ }
+
+ ((PUCHAR) Buffer->Buffer)[2] = 0xE8;
+
+ }
+
+ goto DoneBuildingArcnetHeader;
+}
+
+
+
+VOID
+AbortMiniportPacketsAndPending(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Aborts all outstanding requests on a mini-port.
+
+ CALLED WITH THE LOCK HELD!!
+
+Arguments:
+
+ Miniport - Miniport to abort.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_PACKET Packet;
+ PNDIS_PACKET TmpPacket;
+ PNDIS_REQUEST Request;
+ PNDIS_REQUEST TmpRequest;
+ PNDIS_M_OPEN_BLOCK Open;
+ PNDIS_PACKET ArcnetLimitPacket;
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter abort packets and pending\n");)
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ Miniport->Timeout = FALSE;
+
+ //
+ // Abort Packets
+ //
+
+ Packet = Miniport->FirstPacket;
+ ArcnetLimitPacket = Miniport->FirstPendingPacket;
+
+ Miniport->LastMiniportPacket = NULL;
+ Miniport->FirstPendingPacket = NULL;
+ Miniport->FirstPacket = NULL;
+ Miniport->LastPacket = NULL;
+ Miniport->DeadPacket = NULL;
+
+ NDIS_LOG_PACKET(Miniport, NULL, 'a');
+
+ while (Packet != NULL) {
+
+ TmpPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next;
+
+ Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Open;
+
+ //
+ // Set flag that we've reached the packets that are
+ // not on the mini-port.
+ //
+
+ if ( Packet == ArcnetLimitPacket ) {
+
+ ArcnetLimitPacket = NULL;
+ }
+
+ //
+ // Now free the arcnet header.
+ //
+
+ if ( Miniport->MediaType == NdisMediumArcnet878_2 && ArcnetLimitPacket ) {
+
+ MiniportFreeArcnetHeader(Miniport, Packet);
+ }
+
+ NDIS_LOG_PACKET(Miniport, Packet, 'C');
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Packet,
+ NDIS_STATUS_REQUEST_ABORTED
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open->References--;
+
+ if (Open->References == 0) {
+
+ FinishClose(Miniport,Open);
+ }
+
+ Packet = TmpPacket;
+ }
+
+ NDIS_LOG_PACKET(Miniport, NULL, 'A');
+
+ //
+ // Abort Requests
+ //
+ Request = Miniport->MiniportRequest;
+ Miniport->MiniportRequest = NULL;
+
+ if (Request != NULL) {
+
+ Open = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open;
+
+ if (Request != &(Miniport->InternalRequest)) {
+
+ if (Request->RequestType == NdisRequestQueryStatistics) {
+
+ AbortQueryStatisticsRequest( Request, NDIS_STATUS_REQUEST_ABORTED );
+
+ } else {
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.RequestCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Request,
+ NDIS_STATUS_REQUEST_ABORTED
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open->References--;
+
+ if (Open->References == 0) {
+
+ FinishClose(Miniport,Open);
+
+ }
+
+ }
+
+ } else {
+
+ if (Request->RequestType == NdisRequestSetInformation) {
+
+ NdisMSetInformationComplete(
+ (NDIS_HANDLE)Miniport,
+ NDIS_STATUS_FAILURE
+ );
+
+ } else {
+
+ NdisMQueryInformationComplete(
+ (NDIS_HANDLE)Miniport,
+ NDIS_STATUS_FAILURE
+ );
+
+ }
+
+ }
+
+ }
+
+ Request = Miniport->FirstPendingRequest;
+ Miniport->FirstPendingRequest = NULL;
+ Miniport->LastPendingRequest = NULL;
+ Miniport->PendingRequestTimeout = FALSE;
+
+ while (Request != NULL) {
+
+ TmpRequest = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Next;
+
+ Open = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open;
+
+ if (Request->RequestType == NdisRequestQueryStatistics) {
+
+ AbortQueryStatisticsRequest( Request, NDIS_STATUS_REQUEST_ABORTED );
+
+ } else {
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.RequestCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Request,
+ NDIS_STATUS_REQUEST_ABORTED
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open->References--;
+
+ if (Open->References == 0) {
+
+ FinishClose(Miniport,Open);
+
+ }
+
+ }
+
+ Request = TmpRequest;
+
+ }
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit abort packets and pending\n");)
+
+}
+
+VOID
+AbortQueryStatisticsRequest(
+ PNDIS_REQUEST Request,
+ NDIS_STATUS Status
+ )
+{
+ PNDIS_QUERY_GLOBAL_REQUEST GlobalRequest;
+ PNDIS_QUERY_ALL_REQUEST AllRequest;
+ PNDIS_QUERY_OPEN_REQUEST OpenRequest;
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+
+ GlobalRequest = CONTAINING_RECORD (Request,
+ NDIS_QUERY_GLOBAL_REQUEST,
+ Request
+ );
+ Irp = GlobalRequest->Irp;
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ switch (IrpSp->MajorFunction) {
+
+ case IRP_MJ_CREATE:
+
+ //
+ // This request is one of the ones made during an open,
+ // while we are trying to determine the OID list. We
+ // set the event we are waiting for, the open code
+ // takes care of the rest.
+ //
+
+ OpenRequest = (PNDIS_QUERY_OPEN_REQUEST)GlobalRequest;
+
+ OpenRequest->NdisStatus = Status;
+ KeSetEvent(
+ &OpenRequest->Event,
+ 0L,
+ FALSE);
+
+ break;
+
+ case IRP_MJ_DEVICE_CONTROL:
+
+ //
+ // This is a real user request, process it as such.
+ //
+
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
+
+ case IOCTL_NDIS_QUERY_GLOBAL_STATS:
+
+ //
+ // A single query, complete the IRP.
+ //
+
+ Irp->IoStatus.Information =
+ Request->DATA.QUERY_INFORMATION.BytesWritten;
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ } else if (Status == NDIS_STATUS_INVALID_LENGTH) {
+ Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
+ } else {
+ Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; // what else
+ }
+
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ ExFreePool (GlobalRequest);
+ break;
+
+ case IOCTL_NDIS_QUERY_ALL_STATS:
+
+ //
+ // An "all" query.
+ //
+
+ AllRequest = (PNDIS_QUERY_ALL_REQUEST)GlobalRequest;
+
+ AllRequest->NdisStatus = Status;
+ KeSetEvent(
+ &AllRequest->Event,
+ 0L,
+ FALSE);
+
+ break;
+
+ }
+
+ break;
+
+ }
+
+ return;
+
+} // AbortQueryStatisticsRequest
+
+
+VOID
+FASTCALL
+MiniportProcessDeferred(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Processes all outstanding operations.
+
+ CALLED WITH THE LOCK HELD!!
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ BOOLEAN DoneSomething;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ VERY_LOUD_DEBUG(DbgPrint("NdisM: Enter processing deferred \n");)
+
+ Miniport->ProcessingDeferred = TRUE;
+
+ do
+ {
+ DoneSomething = FALSE;
+
+ //
+ // Check for outstanding timers and dpcs first.
+ //
+ if (Miniport->ProcessOddDeferredStuff)
+ {
+ Miniport->ProcessOddDeferredStuff = FALSE;
+
+ if (Miniport->HaltingMiniport && Miniport->ResetInProgress == NULL)
+ {
+ //
+ // Do nothing
+ //
+ Miniport->ProcessingDeferred = FALSE;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ VERY_LOUD_DEBUG(DbgPrint("NdisM: Exit processing deferred\n");)
+
+ return;
+ }
+
+ if (Miniport->RunDpc && Miniport->ResetInProgress == NULL)
+ {
+ VERY_LOUD_DEBUG(DbgPrint("NdisM: queuing dpc timer\n");)
+ Miniport->RunDpc = FALSE;
+ Miniport->ProcessingDeferred = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 0);
+
+ if (Miniport->RunTimer ||
+ Miniport->HaltingMiniport ||
+ Miniport->ResetRequested ||
+ Miniport->RunDoRequests) {
+
+ Miniport->ProcessOddDeferredStuff = TRUE;
+ }
+
+ return;
+ }
+
+ if (Miniport->RunTimer != NULL)
+ {
+ PNDIS_MINIPORT_TIMER MiniportTimer;
+
+ VERY_LOUD_DEBUG(DbgPrint("NdisM: queueing timer timer\n");)
+
+ MiniportTimer = Miniport->RunTimer;
+ Miniport->RunTimer = MiniportTimer->NextDeferredTimer;
+ Miniport->ProcessingDeferred = FALSE;
+
+ NdisMSetTimer(MiniportTimer, 0);
+
+ if (Miniport->RunTimer ||
+ Miniport->HaltingMiniport ||
+ Miniport->ResetRequested ||
+ Miniport->RunDoRequests) {
+
+ Miniport->ProcessOddDeferredStuff = TRUE;
+ }
+
+ return;
+ }
+
+ //
+ // If we have a reset in progress then bail now.
+ //
+
+ if ( Miniport->ResetInProgress != NULL ) {
+
+ Miniport->ProcessOddDeferredStuff = TRUE;
+ return;
+ }
+
+ //
+ // If we have any pending opens, complete them now.
+ //
+
+ if ( Miniport->FirstPendingOpen != NULL )
+ {
+ MiniportFinishPendingOpens(Miniport);
+ }
+
+ //
+ // Do we need to reset?
+ //
+
+ if (Miniport->ResetRequested != NULL)
+ {
+ NDIS_STATUS Status;
+ BOOLEAN AddressingReset;
+ PNDIS_M_OPEN_BLOCK Open = Miniport->ResetRequested;
+
+ VERY_LOUD_DEBUG(DbgPrint("NdisM: Reset requested \n");)
+
+ if (Open != (PNDIS_M_OPEN_BLOCK)(Miniport)) {
+
+ //
+ // Real reset. Wait for card to go slow
+ //
+
+ if ((Miniport->LastMiniportPacket != NULL) ||
+ (Miniport->MiniportRequest != NULL)) {
+
+ //
+ // Wait for send/request to complete
+ //
+
+ VERY_LOUD_DEBUG(DbgPrint("NdisM: Card is busy\n");)
+ VERY_LOUD_DEBUG(DbgPrint("NdisM: Exit do deferred\n");)
+
+ Miniport->ProcessingDeferred = FALSE;
+
+ if (Miniport->RunTimer ||
+ Miniport->HaltingMiniport ||
+ Miniport->ResetRequested ||
+ Miniport->RunDoRequests) {
+
+ Miniport->ProcessOddDeferredStuff = TRUE;
+ }
+
+ return;
+ }
+
+ }
+
+ //
+ // Start Miniport reset.
+ //
+
+ DoneSomething = TRUE;
+
+ Miniport->ResetInProgress = Miniport->ResetRequested;
+ Miniport->ResetRequested = NULL;
+
+ //
+ // Indicate status to protocols
+ //
+
+ NdisMIndicateStatus(Miniport,
+ NDIS_STATUS_RESET_START,
+ NULL,
+ 0
+ );
+
+ NdisMIndicateStatusComplete(Miniport);
+
+ VERY_LOUD_DEBUG(DbgPrint("NdisM: calling mini-port reset\n");)
+
+ Status =
+ (Miniport->DriverHandle->MiniportCharacteristics.ResetHandler)(
+ &AddressingReset,
+ Miniport->MiniportAdapterContext
+ );
+
+ if (Status != NDIS_STATUS_PENDING) {
+
+ AbortMiniportPacketsAndPending(Miniport);
+
+ VERY_LOUD_DEBUG(DbgPrint("NdisM: Reset completed\n");)
+
+ //
+ // Check if we are going to have to reset the
+ // adapter again. This happens when we are doing
+ // the reset because of a ring failure.
+ //
+ if (Miniport->TrResetRing == 1) {
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ Miniport->TrResetRing = 0;
+
+ } else {
+
+ Miniport->TrResetRing = NDIS_MINIPORT_TR_RESET_TIMEOUT;
+
+ }
+
+ }
+
+ //
+ // Finish off reset
+ //
+
+ Miniport->ResetInProgress = NULL;
+
+ NdisMIndicateStatus(Miniport,
+ NDIS_STATUS_RESET_END,
+ &Status,
+ sizeof(Status)
+ );
+
+ NdisMIndicateStatusComplete(Miniport);
+
+ if (Open != (PNDIS_M_OPEN_BLOCK)(Miniport)) {
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.ResetCompleteHandler)(
+ Open->ProtocolBindingContext,
+ Status
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open->References--;
+
+ if (Open->References == 0) {
+
+ FinishClose(Miniport, Open);
+
+ }
+
+ }
+
+ if (AddressingReset &&
+ (Status == NDIS_STATUS_SUCCESS) &&
+ ((Miniport->EthDB != NULL) ||
+ (Miniport->TrDB != NULL) ||
+ (Miniport->FddiDB != NULL) ||
+ (Miniport->ArcDB != NULL))) {
+
+ Miniport->NeedToUpdatePacketFilter = TRUE;
+ switch (Miniport->MediaType) {
+ case NdisMedium802_3:
+ Miniport->NeedToUpdateEthAddresses = TRUE;
+ break;
+ case NdisMedium802_5:
+ Miniport->NeedToUpdateFunctionalAddress = TRUE;
+ Miniport->NeedToUpdateGroupAddress = TRUE;
+ break;
+ case NdisMediumFddi:
+ Miniport->NeedToUpdateFddiLongAddresses = TRUE;
+ Miniport->NeedToUpdateFddiShortAddresses = TRUE;
+ break;
+ case NdisMediumArcnet878_2:
+ break;
+ }
+
+ Miniport->RunDoRequests = TRUE;
+
+ }
+
+ if (Miniport->RunTimer ||
+ Miniport->HaltingMiniport ||
+ Miniport->ResetRequested ||
+ Miniport->RunDoRequests) {
+
+ Miniport->ProcessOddDeferredStuff = TRUE;
+ }
+ }
+ else
+ {
+ VERY_LOUD_DEBUG(DbgPrint("NdisM: Reset is pending\n");)
+ VERY_LOUD_DEBUG(DbgPrint("NdisM: Exit do deferred\n");)
+
+ //
+ // Lock everything else out while processing
+ //
+ Miniport->ProcessingDeferred = FALSE;
+
+ if (Miniport->RunDpc)
+ {
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 0);
+ }
+
+ if (Miniport->RunTimer ||
+ Miniport->HaltingMiniport ||
+ Miniport->ResetRequested ||
+ Miniport->RunDoRequests) {
+
+ Miniport->ProcessOddDeferredStuff = TRUE;
+ }
+
+ return;
+ }
+ }
+
+ if ((Miniport->RunDoRequests) &&
+ (Miniport->ResetInProgress == NULL)
+ )
+ {
+ MiniportDoRequests(Miniport);
+ DoneSomething = TRUE;
+ }
+ }
+
+ if ((Miniport->FirstPendingPacket != NULL) &&
+ (Miniport->SendResourcesAvailable != 0) &&
+ (Miniport->ResetInProgress == NULL)
+ )
+ {
+ MiniportStartSends(Miniport);
+ DoneSomething = TRUE;
+ }
+
+ } while ( DoneSomething );
+
+ Miniport->ProcessingDeferred = FALSE;
+
+ VERY_LOUD_DEBUG(DbgPrint("NdisM: Exit do deferred\n");)
+
+}
+
+//
+// Timers
+//
+
+
+VOID
+NdisMTimerDpc(
+ PKDPC Dpc,
+ PVOID Context,
+ PVOID SystemContext1,
+ PVOID SystemContext2
+ )
+/*++
+
+Routine Description:
+
+ This function services all mini-port timer interrupts. It then calls the
+ appropriate function that mini-port consumers have registered in the
+ call to NdisMInitializeTimer.
+
+Arguments:
+
+ Dpc - Not used.
+
+ Context - A pointer to the NDIS_MINIPORT_TIMER which is bound to this DPC.
+
+ SystemContext1,2 - not used.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_TIMER MiniportTimer = (PNDIS_MINIPORT_TIMER)(Context);
+ PNDIS_TIMER_FUNCTION TimerFunction;
+ PNDIS_MINIPORT_BLOCK Miniport = MiniportTimer->Miniport;
+ BOOLEAN LocalLock;
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(SystemContext1);
+ UNREFERENCED_PARAMETER(SystemContext2);
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ if (Miniport->HaltingMiniport) {
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ return;
+
+ }
+
+ if ((Miniport->LockAcquired) || (Miniport->InInitialize)) {
+
+ PNDIS_MINIPORT_TIMER TmpTimer;
+
+ //
+ // Make sure it is not already on the list
+ //
+ TmpTimer = Miniport->RunTimer;
+
+ while (TmpTimer != NULL) {
+
+ if (TmpTimer == MiniportTimer) {
+
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ return;
+
+ }
+
+ TmpTimer = TmpTimer->NextDeferredTimer;
+ }
+
+ //
+ // A DPC or timer is already running, queue this for later.
+ //
+
+ MiniportTimer->NextDeferredTimer = Miniport->RunTimer;
+ Miniport->RunTimer = MiniportTimer;
+
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ return;
+
+ }
+
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Call Miniport timer function
+ //
+
+ TimerFunction = MiniportTimer->MiniportTimerFunction;
+
+ (*TimerFunction)(NULL, MiniportTimer->MiniportTimerContext, NULL, NULL);
+
+ if (!Miniport->ProcessingDeferred) {
+
+ MiniportProcessDeferred(Miniport);
+
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+}
+
+
+VOID
+NdisMInitializeTimer(
+ IN OUT PNDIS_MINIPORT_TIMER MiniportTimer,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_TIMER_FUNCTION TimerFunction,
+ IN PVOID FunctionContext
+ )
+/*++
+
+Routine Description:
+
+ Sets up an Miniport Timer object, initializing the DPC in the timer to
+ the function and context.
+
+Arguments:
+
+ MiniportTimer - the timer object.
+ MiniportAdapterHandle - pointer to the mini-port block;
+ TimerFunction - Routine to start.
+ FunctionContext - Context of TimerFunction.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ KeInitializeTimer(&(MiniportTimer->Timer));
+
+ MiniportTimer->Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ MiniportTimer->MiniportTimerFunction = TimerFunction;
+ MiniportTimer->MiniportTimerContext = FunctionContext;
+
+ //
+ // Initialize our dpc. If Dpc was previously initialized, this will
+ // reinitialize it.
+ //
+
+ KeInitializeDpc(
+ &(MiniportTimer->Dpc),
+ (PKDEFERRED_ROUTINE) NdisMTimerDpc,
+ (PVOID)MiniportTimer
+ );
+}
+
+
+
+
+VOID
+NdisMWakeUpDpc(
+ PKDPC Dpc,
+ PVOID Context,
+ PVOID SystemContext1,
+ PVOID SystemContext2
+ )
+/*++
+
+Routine Description:
+
+ This function services all mini-port. It checks to see if a mini-port is
+ ever stalled.
+
+Arguments:
+
+ Dpc - Not used.
+
+ Context - A pointer to the NDIS_TIMER which is bound to this DPC.
+
+ SystemContext1,2 - not used.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(Context);
+ BOOLEAN Hung = FALSE;
+ BOOLEAN LocalLock;
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(SystemContext1);
+ UNREFERENCED_PARAMETER(SystemContext2);
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ if (Miniport->HaltingMiniport)
+ {
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ return;
+ }
+
+ //
+ // Slam the window open
+ //
+ Miniport->SendResourcesAvailable = 0xffffff;
+
+ if (Miniport->LockAcquired)
+ {
+ //
+ // A DPC or timer is already running, assume that means things are fine.
+ //
+
+ NdisSetTimer(&Miniport->WakeUpDpcTimer, NDIS_MINIPORT_WAKEUP_TIMEOUT);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ return;
+ }
+
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Call Miniport stall checker.
+ //
+ if (Miniport->DriverHandle->MiniportCharacteristics.CheckForHangHandler != NULL)
+ {
+ Hung = (Miniport->DriverHandle->MiniportCharacteristics.CheckForHangHandler)(
+ Miniport->MiniportAdapterContext
+ );
+ }
+
+ //
+ // Did a request pend to long?
+ //
+ if (Miniport->MiniportRequest != NULL)
+ {
+ if (Miniport->Timeout)
+ Hung = TRUE;
+ else
+ Miniport->Timeout = TRUE;
+ }
+
+ //
+ // Did a packet send pend to long?
+ //
+ if (Miniport->FirstPacket != NULL)
+ {
+ if ((Miniport->Timeout) &&
+ (Miniport->FirstPacket == Miniport->DeadPacket)
+ )
+ {
+ Hung = TRUE;
+ }
+ else
+ {
+ Miniport->Timeout = TRUE;
+ Miniport->DeadPacket = Miniport->FirstPacket;
+ }
+ }
+
+ if ((Miniport->TrResetRing == 1) && (Miniport->ResetRequested == NULL))
+ {
+ Hung = TRUE;
+ }
+ else if (Miniport->TrResetRing > 1)
+ {
+ Miniport->TrResetRing--;
+ }
+
+ //
+ // Check to see if we have a request that is pending to long.
+ //
+ if (Miniport->FirstPendingRequest != NULL)
+ {
+ if (Miniport->PendingRequestTimeout)
+ {
+ Hung = TRUE;
+ }
+ else
+ {
+ Miniport->PendingRequestTimeout = TRUE;
+ }
+ }
+
+ if (Hung)
+ {
+ if (Miniport->InAddDriver)
+ {
+ //
+ // Just abort everything
+ //
+ AbortMiniportPacketsAndPending(Miniport);
+ }
+ else
+ {
+ PNDIS_M_OPEN_BLOCK Open = Miniport->ResetRequested;
+
+ LOUD_DEBUG(DbgPrint("NdisM: WakeUpDpc is resetting mini-port\n");)
+
+ if ((Open != NULL) && (Open != (PNDIS_M_OPEN_BLOCK)Miniport))
+ {
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.ResetCompleteHandler)(
+ Open->ProtocolBindingContext,
+ NDIS_STATUS_REQUEST_ABORTED
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+ }
+
+ //
+ // If there isn't already a reset in progress, issue a
+ // reset, otherwise let the current reset complete.
+ //
+
+ if ( !Miniport->ResetInProgress )
+ {
+ Miniport->ResetRequested = (PNDIS_M_OPEN_BLOCK)Miniport;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ if (!Miniport->ProcessingDeferred)
+ {
+ MiniportProcessDeferred(Miniport);
+ }
+ }
+ }
+ }
+ else
+ {
+ //
+ // Process any changes that may have occured.
+ //
+ if (!Miniport->ProcessingDeferred)
+ {
+ MiniportProcessDeferred(Miniport);
+ }
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisSetTimer(&Miniport->WakeUpDpcTimer, NDIS_MINIPORT_WAKEUP_TIMEOUT);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+}
+
+//
+// Dma operations
+//
+
+extern
+IO_ALLOCATION_ACTION
+NdisDmaExecutionRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ );
+
+
+//
+// Map Registers
+//
+
+extern
+IO_ALLOCATION_ACTION
+NdisAllocationExecutionRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ );
+
+
+NDIS_STATUS
+NdisMAllocateMapRegisters(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT DmaChannel,
+ IN BOOLEAN Dma32BitAddresses,
+ IN ULONG PhysicalMapRegistersNeeded,
+ IN ULONG MaximumPhysicalMapping
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates map registers for bus mastering devices.
+
+Arguments:
+
+ MiniportAdapterHandle - Handle passed to MiniportInitialize.
+
+ PhysicalMapRegistersNeeded - The maximum number of map registers needed
+ by the Miniport at any one time.
+
+ MaximumPhysicalMapping - Maximum length of a buffer that will have to be mapped.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Convert the handle to our internal structure.
+ //
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportAdapterHandle;
+
+ //
+ // This is needed by HalGetAdapter.
+ //
+ DEVICE_DESCRIPTION DeviceDescription;
+
+ //
+ // Returned by HalGetAdapter.
+ //
+ ULONG MapRegistersAllowed;
+
+ //
+ // Returned by HalGetAdapter.
+ //
+ PADAPTER_OBJECT AdapterObject;
+
+ //
+ // Map registers needed per channel.
+ //
+ ULONG MapRegistersPerChannel;
+
+ NTSTATUS NtStatus;
+
+ KIRQL OldIrql;
+
+ UINT i;
+
+ LARGE_INTEGER TimeoutValue;
+
+ //
+ // If the device is a busmaster, we get an adapter
+ // object for it.
+ // If map registers are needed, we loop, allocating an
+ // adapter channel for each map register needed.
+ //
+
+ if ((Miniport->Master) &&
+ (Miniport->BusType != (NDIS_INTERFACE_TYPE)-1) &&
+ (Miniport->BusNumber != (ULONG)-1)) {
+
+ TimeoutValue.QuadPart = Int32x32To64(2 * 1000, -10000);
+
+ Miniport->PhysicalMapRegistersNeeded = PhysicalMapRegistersNeeded;
+ Miniport->MaximumPhysicalMapping = MaximumPhysicalMapping;
+
+ //
+ // Allocate storage for holding the appropriate
+ // information for each map register.
+ //
+
+ Miniport->MapRegisters = (PMAP_REGISTER_ENTRY)
+ ExAllocatePool(
+ NonPagedPool,
+ sizeof(MAP_REGISTER_ENTRY) * PhysicalMapRegistersNeeded
+ );
+
+ if (Miniport->MapRegisters == (PMAP_REGISTER_ENTRY)NULL) {
+
+ //
+ // Error out
+ //
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 1,
+ 0xFFFFFFFF
+ );
+
+ return (NDIS_STATUS_RESOURCES);
+
+ }
+
+ //
+ // Use this event to tell us when NdisAllocationExecutionRoutine
+ // has been called.
+ //
+
+ KeInitializeEvent(
+ &Miniport->AllocationEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+
+ //
+ // Set up the device description; zero it out in case its
+ // size changes.
+ //
+
+ RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
+
+ DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
+ DeviceDescription.Master = TRUE;
+ DeviceDescription.ScatterGather = TRUE;
+
+ DeviceDescription.BusNumber = Miniport->BusNumber;
+ DeviceDescription.DmaChannel = DmaChannel;
+ DeviceDescription.InterfaceType = Miniport->AdapterType;
+
+ if (DeviceDescription.InterfaceType == NdisInterfaceIsa) {
+
+ //
+ // For ISA devices, the width is based on the DMA channel:
+ // 0-3 == 8 bits, 5-7 == 16 bits. Timing is compatibility
+ // mode.
+ //
+
+ if (DmaChannel > 4) {
+ DeviceDescription.DmaWidth = Width16Bits;
+ } else {
+ DeviceDescription.DmaWidth = Width8Bits;
+ }
+ DeviceDescription.DmaSpeed = Compatible;
+
+ } else if ((DeviceDescription.InterfaceType == NdisInterfaceEisa) ||
+ (DeviceDescription.InterfaceType == NdisInterfacePci) ||
+ (DeviceDescription.InterfaceType == NdisInterfaceMca)) {
+
+ DeviceDescription.Dma32BitAddresses = Dma32BitAddresses;
+ }
+
+ DeviceDescription.MaximumLength = MaximumPhysicalMapping;
+
+ //
+ // Get the adapter object.
+ //
+
+ AdapterObject = HalGetAdapter (&DeviceDescription, &MapRegistersAllowed);
+
+ if (AdapterObject == NULL) {
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 1,
+ 0xFFFFFFFF
+ );
+
+ ExFreePool(Miniport->MapRegisters);
+ Miniport->MapRegisters = NULL;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return(NDIS_STATUS_RESOURCES);
+
+ }
+
+ //
+ // We save this to call IoFreeMapRegisters later.
+ //
+
+ Miniport->SystemAdapterObject = AdapterObject;
+
+ //
+ // Determine how many map registers we need per channel.
+ //
+
+ MapRegistersPerChannel = ((MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2;
+
+ ASSERT (MapRegistersAllowed >= MapRegistersPerChannel);
+
+ //
+ // Now loop, allocating an adapter channel each time, then
+ // freeing everything but the map registers.
+ //
+
+ for (i=0; i<Miniport->PhysicalMapRegistersNeeded; i++) {
+
+ Miniport->CurrentMapRegister = i;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NtStatus = IoAllocateAdapterChannel(
+ AdapterObject,
+ Miniport->DeviceObject,
+ MapRegistersPerChannel,
+ NdisAllocationExecutionRoutine,
+ (PVOID)Miniport
+ );
+
+ KeLowerIrql(OldIrql);
+
+ if (!NT_SUCCESS(NtStatus)) {
+
+ NdisPrint2("AllocateAdapterChannel: %lx\n", NtStatus);
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ for (; i != 0; i--) {
+ IoFreeMapRegisters(
+ Miniport->SystemAdapterObject,
+ Miniport->MapRegisters[i-1].MapRegister,
+ MapRegistersPerChannel
+ );
+ }
+
+ KeLowerIrql(OldIrql);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 1,
+ 0xFFFFFFFF
+ );
+
+ ExFreePool(Miniport->MapRegisters);
+ Miniport->MapRegisters = NULL;
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ TimeoutValue.QuadPart = Int32x32To64(2 * 1000, -10000);
+
+ //
+ // NdisAllocationExecutionRoutine will set this event
+ // when it has gotten FirstTranslationEntry.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->AllocationEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ NdisPrint2("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus);
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ for (; i != 0; i--) {
+ IoFreeMapRegisters(
+ Miniport->SystemAdapterObject,
+ Miniport->MapRegisters[i-1].MapRegister,
+ MapRegistersPerChannel
+ );
+ }
+
+ KeLowerIrql(OldIrql);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 1,
+ 0xFFFFFFFF
+ );
+
+ ExFreePool(Miniport->MapRegisters);
+ Miniport->MapRegisters = NULL;
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ KeResetEvent(
+ &Miniport->AllocationEvent
+ );
+
+ }
+
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+VOID
+NdisMFreeMapRegisters(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Releases allocated map registers
+
+Arguments:
+
+ MiniportAdapterHandle - Handle passed to MiniportInitialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Convert the handle to our internal structure.
+ //
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportAdapterHandle;
+
+ KIRQL OldIrql;
+
+ ULONG i;
+
+ if (Miniport->Master && (Miniport->MapRegisters != NULL)) {
+
+ ULONG MapRegistersPerChannel =
+ ((Miniport->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2;
+
+ for (i=0; i<Miniport->PhysicalMapRegistersNeeded; i++) {
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ IoFreeMapRegisters(
+ Miniport->SystemAdapterObject,
+ Miniport->MapRegisters[i].MapRegister,
+ MapRegistersPerChannel
+ );
+
+ KeLowerIrql(OldIrql);
+ }
+
+ ExFreePool(Miniport->MapRegisters);
+
+ Miniport->MapRegisters = NULL;
+
+ }
+
+}
+
+
+
+
+//
+// Interrupt stuff
+//
+
+
+BOOLEAN
+NdisMIsr(
+ IN PKINTERRUPT KInterrupt,
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ Handles ALL Miniport interrupts, calling the appropriate Miniport ISR and DPC
+ depending on the context.
+
+Arguments:
+
+ Interrupt - Interrupt object for the Mac.
+
+ Context - Really a pointer to the interrupt.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Get adapter from context.
+ //
+
+ PNDIS_MINIPORT_INTERRUPT Interrupt = (PNDIS_MINIPORT_INTERRUPT)Context;
+ PNDIS_MINIPORT_BLOCK Miniport = Interrupt->Miniport;
+
+ BOOLEAN InterruptRecognized;
+ BOOLEAN QueueDpc;
+
+ if (Miniport->NormalInterrupts) {
+
+ //
+ // Call to disable the interrupt
+ //
+
+ ASSERT(Miniport->DriverHandle->MiniportCharacteristics.DisableInterruptHandler != NULL);
+
+ MINIPORT_DISABLE_INTERRUPT(Miniport);
+
+ InterruptRecognized = TRUE;
+
+queue_dpc:
+
+ Increment((PLONG)&Interrupt->DpcCount,&Interrupt->DpcCountLock);
+
+ if (KeInsertQueueDpc(&Interrupt->InterruptDpc,NULL,NULL)) {
+ return InterruptRecognized;
+ }
+
+ //
+ // The DPC was already queued, so we have an extra reference (we
+ // do it this way to ensure that the reference is added *before*
+ // the DPC is queued).
+ //
+
+ Decrement((PLONG)&Interrupt->DpcCount,&Interrupt->DpcCountLock);
+
+ if (Miniport->HaltingMiniport && (Interrupt->DpcCount==0)) {
+
+ //
+ // We need to queue a DPC to set the event because we
+ // can't do it from the ISR. We know that the interrupt
+ // DPC won't fire because the refcount is 0, so we reuse it.
+ //
+
+ KeInitializeDpc(
+ &Interrupt->InterruptDpc,
+ NdisLastCountRemovedFunction,
+ (PVOID)&Interrupt->DpcsCompletedEvent
+ );
+
+ //
+ // When NdisLastCountRemovedFunction runs it will set
+ // the event.
+ //
+
+ KeInsertQueueDpc(&Interrupt->InterruptDpc, NULL, NULL);
+
+ }
+
+ return InterruptRecognized;
+
+ }
+
+ if (!Miniport->HaltingMiniport) {
+
+ //
+ // Call MiniportIsr
+ //
+
+ Interrupt->MiniportIsr(&InterruptRecognized,
+ &QueueDpc,
+ Miniport->MiniportAdapterContext
+ );
+ if (QueueDpc) goto queue_dpc;
+ return InterruptRecognized;
+
+ }
+
+ if (!Interrupt->SharedInterrupt &&
+ !Interrupt->IsrRequested &&
+ !Miniport->InInitialize) {
+
+ //
+ // Call to disable the interrupt
+ //
+
+ ASSERT(Miniport->DriverHandle->MiniportCharacteristics.DisableInterruptHandler != NULL);
+
+ MINIPORT_DISABLE_INTERRUPT(Miniport);
+ return TRUE;
+
+ }
+
+ //
+ // Call MiniportIsr, but don't queue a DPC.
+ //
+
+ Interrupt->MiniportIsr(&InterruptRecognized,
+ &QueueDpc,
+ Miniport->MiniportAdapterContext
+ );
+ return InterruptRecognized;
+
+}
+
+
+VOID
+NdisMDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+/*++
+
+Routine Description:
+
+ Handles ALL Miniport interrupt DPCs, calling the appropriate Miniport DPC
+ depending on the context.
+
+Arguments:
+
+ Interrupt - Interrupt object for the Mac.
+
+ Context - Really a pointer to the Interrupt.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Get adapter from context.
+ //
+
+ PNDIS_MINIPORT_INTERRUPT Interrupt = (PNDIS_MINIPORT_INTERRUPT)(InterruptContext);
+ PNDIS_MINIPORT_BLOCK Miniport = Interrupt->Miniport;
+ BOOLEAN LocalLock;
+
+ W_HANDLE_INTERRUPT_HANDLER MiniportDpc = Interrupt->MiniportDpc;
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ LOG('d');
+
+ if (Miniport->HaltingMiniport) {
+
+ Decrement((PLONG)&Interrupt->DpcCount,&Interrupt->DpcCountLock);
+
+ if (Interrupt->DpcCount==0) {
+
+ KeSetEvent(
+ &Interrupt->DpcsCompletedEvent,
+ 0L,
+ FALSE
+ );
+
+ }
+
+ LOG('h');
+ LOG('D');
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ return;
+ }
+
+ if (Miniport->LockAcquired) {
+
+ //
+ // A DPC is already running, queue this for later.
+ //
+
+ Miniport->RunDpc = TRUE;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ Decrement((PLONG)&Interrupt->DpcCount,&Interrupt->DpcCountLock);
+
+ LOG('L');
+ LOG('D');
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ return;
+
+ }
+
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Call MiniportDpc
+ //
+
+ (*MiniportDpc)(Miniport->MiniportAdapterContext);
+
+ Decrement((PLONG)&Interrupt->DpcCount,&Interrupt->DpcCountLock);
+
+ if (!Miniport->HaltingMiniport) {
+
+ //
+ // Enable interrupts
+ //
+
+ MINIPORT_SYNC_ENABLE_INTERRUPT(Miniport);
+
+ if (!Miniport->ProcessingDeferred) {
+
+ MiniportProcessDeferred(Miniport);
+
+ }
+
+ } else {
+
+ if (Interrupt->DpcCount == 0) {
+
+ KeSetEvent(
+ &Interrupt->DpcsCompletedEvent,
+ 0L,
+ FALSE
+ );
+
+ }
+
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ LOG('D');
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+}
+
+
+VOID
+NdisMDpcTimer(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+/*++
+
+Routine Description:
+
+ Handles a deferred interrupt dpc.
+
+Arguments:
+
+ Context - Really a pointer to the Miniport block.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Get adapter from context.
+ //
+
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(InterruptContext);
+ BOOLEAN LocalLock;
+
+ W_HANDLE_INTERRUPT_HANDLER MiniportDpc =
+ Miniport->DriverHandle->MiniportCharacteristics.HandleInterruptHandler;
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ if ((Miniport->HaltingMiniport) ||
+ (Miniport->InInitialize)) {
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ return;
+ }
+
+ if (Miniport->LockAcquired) {
+
+ //
+ // A DPC is already running, queue this for later.
+ //
+
+ Miniport->RunDpc = TRUE;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ return;
+
+ }
+
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ MINIPORT_SYNC_DISABLE_INTERRUPT(Miniport);
+
+ //
+ // Call MiniportDpc
+ //
+
+ if (MiniportDpc != NULL) {
+
+ (*MiniportDpc)(Miniport->MiniportAdapterContext);
+
+ }
+
+ //
+ // Enable interrupts
+ //
+ MINIPORT_SYNC_ENABLE_INTERRUPT(Miniport);
+
+ //
+ // Check if we need to shutdown.
+ //
+ if (!Miniport->HaltingMiniport) {
+
+ if (!Miniport->ProcessingDeferred) {
+
+ MiniportProcessDeferred(Miniport);
+
+ }
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ return;
+
+}
+
+//
+// Io Port stuff
+//
+
+
+NDIS_STATUS
+NdisMRegisterIoPortRange(
+ OUT PVOID *PortOffset,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT InitialPort,
+ IN UINT NumberOfPorts
+ )
+
+/*++
+
+Routine Description:
+
+ Sets up an IO port for operations.
+
+Arguments:
+
+ PortOffset - The mapped port address the Miniport uses for NdisRaw functions.
+
+ MiniportAdapterHandle - Handle passed to Miniport Initialize.
+
+ InitialPort - Physical address of the starting port number.
+
+ NumberOfPorts - Number of ports to map.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(MiniportAdapterHandle);
+ PHYSICAL_ADDRESS PortAddress;
+ PHYSICAL_ADDRESS InitialPortAddress;
+ ULONG addressSpace;
+ ULONG NumberOfElements;
+
+ BOOLEAN Conflict;
+ PCM_RESOURCE_LIST Resources;
+ NDIS_STATUS Status;
+
+ //
+ // First check if any bus access is allowed
+ //
+
+ if ((Miniport->BusType == (NDIS_INTERFACE_TYPE)-1) ||
+ (Miniport->BusNumber == (ULONG)-1)) {
+
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ //
+ // First check for resource conflict by expanding current resource list,
+ // adding in the mapped space, and then re-submitting the resource list.
+ //
+
+ if (Miniport->Resources != NULL) {
+
+ NumberOfElements = Miniport->Resources->List[0].PartialResourceList.Count + 1;
+
+ } else {
+
+ NumberOfElements = 1;
+ }
+
+ Resources = (PCM_RESOURCE_LIST)ExAllocatePool(
+ NonPagedPool,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ NumberOfElements
+ );
+
+ if (Resources == NULL) {
+
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ if (Miniport->Resources != NULL) {
+
+ RtlMoveMemory (Resources,
+ Miniport->Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ Miniport->Resources->List[0].PartialResourceList.Count
+ );
+
+ } else {
+
+ //
+ // Setup initial resource info
+ //
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = Miniport->AdapterType;
+ Resources->List[0].BusNumber = Miniport->BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ }
+
+ //
+ // Setup port
+ //
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type =
+ CmResourceTypePort;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition =
+ CmResourceShareDeviceExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags =
+ (Miniport->AdapterType == NdisInterfaceInternal)?
+ CM_RESOURCE_PORT_MEMORY : CM_RESOURCE_PORT_IO;
+#if !defined(BUILD_FOR_3_1)
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Port.Start.QuadPart =
+ (ULONG)InitialPort;
+#else
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Port.Start =
+ RtlConvertUlongToLargeInteger((ULONG)(InitialPort));
+#endif
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Port.Length =
+ NumberOfPorts;
+ Resources->List[0].PartialResourceList.Count++;
+
+ //
+ // Make the call
+ //
+
+ Status = IoReportResourceUsage(
+ NULL,
+ Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver,
+ NULL,
+ 0,
+ Miniport->DeviceObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ Resources->List[0].PartialResourceList.Count,
+ TRUE,
+ &Conflict
+ );
+
+ if (Miniport->Resources != NULL) {
+ ExFreePool(Miniport->Resources);
+ }
+
+ Miniport->Resources = Resources;
+
+ //
+ // Check for conflict.
+ //
+
+ if (Conflict || (Status != STATUS_SUCCESS)) {
+
+
+ if (Conflict) {
+
+
+ //
+ // Log an error
+ //
+
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ ULONG i;
+ ULONG StringSize;
+ PUCHAR Place;
+ PWCH baseFileName;
+
+ baseFileName = Miniport->MiniportName.Buffer;
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+
+ for ( i = 0; i < Miniport->MiniportName.Length / sizeof(WCHAR); i++ ) {
+
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+
+ if ( Miniport->MiniportName.Buffer[i] == OBJ_NAME_PATH_SEPARATOR ) {
+ baseFileName = &(Miniport->MiniportName.Buffer[++i]);
+ }
+
+ }
+
+ StringSize = Miniport->MiniportName.MaximumLength -
+ (((ULONG)baseFileName) - ((ULONG)Miniport->MiniportName.Buffer)) ;
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ Miniport->DeviceObject,
+ (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize +
+ 6) // wstrlen("99") * sizeof(WHCAR) + sizeof(UNICODE_NULL)
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_IO_PORT_CONFLICT;
+
+ //
+ // store the time
+ //
+
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+
+ //
+ // Set string information
+ //
+
+ if (StringSize != 0) {
+
+ errorLogEntry->NumberOfStrings = 1;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+
+ RtlMoveMemory (
+ ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET),
+ (PVOID)baseFileName,
+ StringSize
+ );
+
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize;
+
+ } else {
+
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET);
+
+ errorLogEntry->NumberOfStrings = 0;
+
+ }
+
+ //
+ // write it out
+ //
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+ return NDIS_STATUS_RESOURCE_CONFLICT;
+
+ }
+
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ //
+ // Now Map the ports
+ //
+
+
+
+ //
+ // Get the system physical address for this card. The card uses
+ // I/O space, except for "internal" Jazz devices which use
+ // memory space.
+ //
+
+ addressSpace = (Miniport->AdapterType == NdisInterfaceInternal) ? 0 : 1;
+
+ InitialPortAddress.LowPart = InitialPort;
+ InitialPortAddress.HighPart = 0;
+
+ if ( !HalTranslateBusAddress(
+ Miniport->BusType, // InterfaceType
+ Miniport->BusNumber, // BusNumber
+ InitialPortAddress, // Bus Address
+ &addressSpace, // AddressSpace
+ &PortAddress // Translated address
+ ) ) {
+
+ //
+ // It would be nice to return a better status here, but we only get
+ // TRUE/FALSE back from HalTranslateBusAddress.
+ //
+
+ return NDIS_STATUS_FAILURE;
+ }
+
+ if (addressSpace == 0) {
+
+ //
+ // memory space
+ //
+
+ *(PortOffset) = (PULONG)MmMapIoSpace(
+ PortAddress,
+ NumberOfPorts,
+ FALSE
+ );
+
+ if (*(PortOffset) == (PULONG)NULL) {
+
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ } else {
+
+ //
+ // I/O space
+ //
+
+ *(PortOffset) = (PULONG)PortAddress.LowPart;
+
+ }
+
+ return NDIS_STATUS_SUCCESS;
+
+}
+
+
+
+VOID
+NdisMDeregisterIoPortRange(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT InitialPort,
+ IN UINT NumberOfPorts,
+ IN PVOID PortOffset
+ )
+
+/*++
+
+Routine Description:
+
+ Sets up an IO port for operations.
+
+Arguments:
+
+ MiniportAdapterHandle - Handle passed to Miniport Initialize.
+
+ InitialPort - Physical address of the starting port number.
+
+ NumberOfPorts - Number of ports to map.
+
+ PortOffset - The mapped port address the Miniport uses for NdisRaw functions.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(MiniportAdapterHandle);
+ PHYSICAL_ADDRESS PortAddress;
+ PHYSICAL_ADDRESS InitialPortAddress;
+ ULONG addressSpace;
+
+ //
+ // Get the system physical address for this card. The card uses
+ // I/O space, except for "internal" Jazz devices which use
+ // memory space.
+ //
+
+ addressSpace = (Miniport->AdapterType == NdisInterfaceInternal) ? 0 : 1;
+
+ InitialPortAddress.LowPart = InitialPort;
+ InitialPortAddress.HighPart = 0;
+
+ if ( !HalTranslateBusAddress(
+ Miniport->BusType, // InterfaceType
+ Miniport->BusNumber, // BusNumber
+ InitialPortAddress, // Bus Address
+ &addressSpace, // AddressSpace
+ &PortAddress // Translated address
+ ) ) {
+
+ //
+ // It would be nice to return a better status here, but we only get
+ // TRUE/FALSE back from HalTranslateBusAddress.
+ //
+
+ return;
+ }
+
+ if (addressSpace == 0) {
+
+ //
+ // memory space
+ //
+
+ MmUnmapIoSpace(
+ PortOffset,
+ NumberOfPorts
+ );
+
+ } else {
+
+ //
+ // I/O space
+ //
+
+ }
+
+}
+
+
+//
+// Attribute functions
+//
+
+
+VOID
+NdisMSetAttributes(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN BOOLEAN BusMaster,
+ IN NDIS_INTERFACE_TYPE AdapterType
+ )
+/*++
+
+Routine Description:
+
+ This function sets specific information about an adapter.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+ MiniportAdapterContext - Context to pass to all Miniport driver functions.
+
+ BusMaster - TRUE if a bus mastering adapter.
+
+ AdapterType - Eisa, Isa, Mca or Internal.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+
+ Miniport->MiniportAdapterContext = MiniportAdapterContext;
+ Miniport->Master = BusMaster;
+ Miniport->AdapterType = AdapterType;
+
+ MiniportReferencePackage();
+}
+
+
+
+//
+// Interface functions
+//
+
+
+
+VOID
+NdisMIndicateStatus(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ )
+/*++
+
+Routine Description:
+
+ This function indicates a new status of the media/mini-port.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+ GeneralStatus - The status to indicate.
+
+ StatusBuffer - Additional information.
+
+ StatusBufferSize - Length of the buffer.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+ NDIS_STATUS Status;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ if ((GeneralStatus == NDIS_STATUS_RING_STATUS) &&
+ (StatusBufferSize == sizeof(NDIS_STATUS))) {
+
+ Status = *((PNDIS_STATUS)StatusBuffer);
+
+ if (Status & (NDIS_RING_LOBE_WIRE_FAULT |
+ NDIS_RING_HARD_ERROR |
+ NDIS_RING_SIGNAL_LOSS)) {
+
+ Miniport->TrResetRing = NDIS_MINIPORT_TR_RESET_TIMEOUT;
+
+ }
+
+ }
+
+ Open = Miniport->OpenQueue;
+
+ while (Open != NULL) {
+
+ //
+ // Call Protocol to indicate status
+ //
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.StatusHandler) (
+ Open->ProtocolBindingContext,
+ GeneralStatus,
+ StatusBuffer,
+ StatusBufferSize
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open = Open->MiniportNextOpen;
+
+ }
+
+}
+
+
+
+VOID
+NdisMIndicateStatusComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the status is complete.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ Open = Miniport->OpenQueue;
+
+ while (Open != NULL) {
+
+ //
+ // Call Protocol to indicate status
+ //
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.StatusCompleteHandler) (
+ Open->ProtocolBindingContext
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open = Open->MiniportNextOpen;
+
+ }
+
+}
+
+
+VOID
+NdisMSendComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the completion of a send.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+ PNDIS_PACKET_RESERVED Reserved;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter send complete\n");)
+ LOUD_DEBUG(DbgPrint("NdisM: packet 0x%x\n", Packet);)
+
+ Miniport->SendCompleteCalled = TRUE;
+
+ //
+ // If the packet is not equal to the first packet then we have to find
+ // it because it may have completed out of order.
+ //
+
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+
+ if ( Miniport->FirstPacket == Packet )
+ {
+ Miniport->FirstPacket = Reserved->Next;
+ Miniport->DeadPacket = NULL;
+
+ if ( Miniport->LastMiniportPacket == Packet )
+ {
+ Miniport->LastMiniportPacket = NULL;
+ }
+ }
+ else
+ {
+ PNDIS_PACKET PrevPacket;
+
+ //
+ // Search for the packet.
+ //
+ MiniportFindPacket(Miniport, Packet, &PrevPacket);
+
+ ASSERT( PrevPacket != NULL );
+
+ //
+ // If we just completed the last packet then
+ // we need to update our last packet pointer.
+ //
+ if (Packet != Miniport->LastPacket)
+ {
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = Reserved->Next;
+ }
+ else
+ {
+ Miniport->LastPacket = PrevPacket;
+ }
+
+ //
+ // If we just completed the last miniport packet then
+ // last miniport packet is the previous packet.
+ //
+
+ if ( Miniport->LastMiniportPacket == Packet )
+ {
+ Miniport->LastMiniportPacket = PrevPacket;
+ }
+ }
+
+ //
+ // Indicate to Protocol;
+ //
+
+ Open = Reserved->Open;
+
+ Miniport->Timeout = FALSE;
+
+ //
+ // If this is arcnet, then free the appended header.
+ //
+ if ( Miniport->MediaType == NdisMediumArcnet878_2 )
+ {
+ MiniportFreeArcnetHeader(Miniport, Packet);
+ }
+
+ LOG('C');
+ NDIS_LOG_PACKET(Miniport, Packet, 'C');
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)(
+ Open->ProtocolBindingContext,
+ Packet,
+ Status
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ ADD_RESOURCE(Miniport, 'P');
+
+ Open->References--;
+
+ if (Open->References == 0)
+ {
+ FinishClose(Miniport,Open);
+ }
+
+ if (!Miniport->ProcessingDeferred)
+ MiniportProcessDeferred(Miniport);
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit send complete\n");)
+}
+
+
+VOID
+NdisMWanSendComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ )
+
+/*++
+
+Routine Description:
+
+ This function indicates the status is complete.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ Open = Miniport->OpenQueue;
+
+ while (Open != NULL) {
+
+ //
+ // Call Protocol to indicate status
+ //
+
+ NDIS_LOG_PACKET(Miniport, Packet, 'C');
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Packet,
+ Status
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open = Open->MiniportNextOpen;
+
+ }
+
+}
+
+
+
+typedef
+NDIS_STATUS
+(*WAN_RECEIVE_HANDLER) (
+ IN NDIS_HANDLE NdisLinkContext,
+ IN PUCHAR Packet,
+ IN ULONG PacketSize
+ );
+
+VOID
+NdisMWanIndicateReceive(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE NdisLinkContext,
+ IN PUCHAR Packet,
+ IN ULONG PacketSize
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the status is complete.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ Open = Miniport->OpenQueue;
+
+ while (Open != NULL) {
+
+ //
+ // Call Protocol to indicate status
+ //
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ *Status =
+ ((WAN_RECEIVE_HANDLER)(Open->ProtocolHandle->ProtocolCharacteristics.ReceiveHandler)) (
+ NdisLinkContext,
+ Packet,
+ PacketSize);
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open = Open->MiniportNextOpen;
+
+ }
+}
+
+
+
+VOID
+NdisMWanIndicateReceiveComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE NdisLinkContext
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the status is complete.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ Open = Miniport->OpenQueue;
+
+ while (Open != NULL) {
+
+ //
+ // Call Protocol to indicate status
+ //
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.ReceiveCompleteHandler) (
+ NdisLinkContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open = Open->MiniportNextOpen;
+
+ }
+}
+
+
+VOID
+NdisMSendResourcesAvailable(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ )
+/*++
+
+Routine Description:
+
+ This function indicates that some send resources are available and are free for
+ processing more sends.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ LOG('a');
+
+ ADD_RESOURCE(Miniport, 'V');
+
+ Miniport->Timeout = FALSE;
+
+ if (!Miniport->ProcessingDeferred) {
+
+ MiniportProcessDeferred(Miniport);
+ }
+}
+
+
+VOID
+NdisMSetInformationComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the completion of a set information operation.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+ Status - Status of the operation
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_REQUEST Request;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+ LOUD_DEBUG(DbgPrint("NdisM: Enter set information complete\n");)
+
+ //
+ // Remove request.
+ //
+
+ Miniport->Timeout = FALSE;
+
+ if (Miniport->MiniportRequest == NULL) {
+
+ //
+ // Assume this is a complete that was aborted due to the wake up dpc
+ //
+ return;
+
+ }
+
+ Request = Miniport->MiniportRequest;
+ Miniport->MiniportRequest = NULL;
+
+ LOUD_DEBUG(DbgPrint("NdisM: Request 0x%x\n", Request);)
+
+ Open = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open;
+
+ if (Request != &(Miniport->InternalRequest)) {
+
+ //
+ // Indicate to Protocol;
+ //
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.RequestCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Request,
+ Status
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open->References--;
+
+ if (Open->References == 0) {
+
+ FinishClose(Miniport,Open);
+
+ }
+
+ } else if (Request->RequestType == NdisRequestQueryStatistics) {
+
+ //
+ // Flag meaning that we need to set the request event
+ //
+ Miniport->RequestStatus = Status;
+ KeSetEvent(
+ &Miniport->RequestEvent,
+ 0L,
+ FALSE
+ );
+
+ } else if ((Open != NULL) && (Open->Closing)) {
+
+ Open->References--;
+
+ if (Open->References == 0) {
+
+ FinishClose(Miniport,Open);
+
+ }
+
+ } else {
+
+ //
+ // Internal request, check if we need to do more work now.
+ //
+ if ((Miniport->NeedToUpdateEthAddresses ||
+ Miniport->NeedToUpdatePacketFilter ||
+ Miniport->NeedToUpdateFunctionalAddress ||
+ Miniport->NeedToUpdateGroupAddress ||
+ Miniport->NeedToUpdateFddiLongAddresses ||
+ Miniport->NeedToUpdateFddiShortAddresses ||
+ (Miniport->FirstPendingRequest != NULL))
+ &&
+ (Miniport->MiniportRequest == NULL)) {
+ Miniport->RunDoRequests = TRUE;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+ } else {
+ Miniport->RunDoRequests = FALSE;
+ }
+
+
+ }
+
+ if (!Miniport->ProcessingDeferred) {
+
+ MiniportProcessDeferred(Miniport);
+
+ }
+ LOUD_DEBUG(DbgPrint("NdisM: Exit set information complete\n");)
+
+}
+
+
+VOID
+NdisMResetComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_STATUS Status,
+ IN BOOLEAN AddressingReset
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the completion of a reset.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+ Status - Status of the reset.
+
+ AddressingReset - Do we have to submit a request to reload the address
+ information. This includes packet filter, and multicast/functional addresses.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ //
+ // Destroy all outstanding packets and requests.
+ //
+ AbortMiniportPacketsAndPending(Miniport);
+
+ //
+ // Check if we are going to have to reset the
+ // adapter again. This happens when we are doing
+ // the reset because of a ring failure.
+ //
+ if (Miniport->TrResetRing == 1) {
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ Miniport->TrResetRing = 0;
+
+ } else {
+
+ Miniport->TrResetRing = NDIS_MINIPORT_TR_RESET_TIMEOUT;
+
+ }
+
+ }
+
+ //
+ // Indicate to Protocols the reset is complete
+ //
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter reset complete\n");)
+
+ Open = Miniport->ResetInProgress;
+ Miniport->ResetInProgress = NULL;
+ Miniport->ProcessingDeferred = FALSE;
+
+ NdisMIndicateStatus(Miniport,
+ NDIS_STATUS_RESET_END,
+ &Status,
+ sizeof(Status)
+ );
+
+ NdisMIndicateStatusComplete(Miniport);
+
+ if ( Open != (PNDIS_M_OPEN_BLOCK) Miniport && Open != NULL ) {
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.ResetCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Status
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open->References--;
+
+ if (Open->References == 0) {
+
+ FinishClose(Miniport,Open);
+ }
+ }
+
+ if (AddressingReset &&
+ (Status == NDIS_STATUS_SUCCESS) &&
+ ((Miniport->EthDB != NULL) ||
+ (Miniport->TrDB != NULL) ||
+ (Miniport->FddiDB != NULL) ||
+ (Miniport->ArcDB != NULL))) {
+
+
+ Miniport->NeedToUpdatePacketFilter = TRUE;
+ switch (Miniport->MediaType) {
+ case NdisMedium802_3:
+ Miniport->NeedToUpdateEthAddresses = TRUE;
+ break;
+ case NdisMedium802_5:
+ Miniport->NeedToUpdateFunctionalAddress = TRUE;
+ Miniport->NeedToUpdateGroupAddress = TRUE;
+ break;
+ case NdisMediumFddi:
+ Miniport->NeedToUpdateFddiLongAddresses = TRUE;
+ Miniport->NeedToUpdateFddiShortAddresses = TRUE;
+ break;
+ case NdisMediumArcnet878_2:
+ break;
+ }
+
+ Miniport->RunDoRequests = TRUE;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ }
+
+ if (!Miniport->ProcessingDeferred) {
+
+ MiniportProcessDeferred(Miniport);
+
+ }
+ LOUD_DEBUG(DbgPrint("NdisM: Exit reset complete\n");)
+
+}
+
+
+
+VOID
+NdisMTransferDataComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the completion of a transfer data request.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+ Packet - The packet the data was copied into.
+
+ Status - Status of the operation.
+
+ BytesTransferred - Total number of bytes transferred.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+ PNDIS_PACKET PrevPacket;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+ ASSERT(Miniport->FirstTDPacket != NULL);
+
+ //
+ // Find the packet
+ //
+
+ if (Packet == Miniport->FirstTDPacket) {
+
+ Miniport->FirstTDPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next;
+
+ } else {
+
+ PrevPacket = Miniport->FirstTDPacket;
+
+ while (PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next != Packet) {
+
+ PrevPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next;
+
+ ASSERT(PrevPacket != NULL);
+ }
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next =
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next;
+
+ if (Packet == Miniport->LastTDPacket) {
+
+ Miniport->LastTDPacket = PrevPacket;
+
+ }
+
+ }
+
+ //
+ // Indicate to Protocol;
+ //
+
+ Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Open;
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.TransferDataCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Packet,
+ Status,
+ BytesTransferred
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+}
+
+
+
+VOID
+NdisMQueryInformationComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the completion of a query information operation.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+ Status - Status of the operation
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_REQUEST Request;
+ PNDIS_M_OPEN_BLOCK Open;
+ PNDIS_REQUEST_RESERVED Reserved;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+ LOUD_DEBUG(DbgPrint("NdisM: Enter query information complete\n");)
+
+ //
+ // Check for global statistics request
+ //
+ Miniport->Timeout = FALSE;
+
+ if (Miniport->MiniportRequest == NULL)
+ {
+ //
+ // Assume this is a complete that was aborted due to the wake up dpc
+ //
+ return;
+ }
+
+ //
+ // Get the request that was completed.
+ //
+ Request = Miniport->MiniportRequest;
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request);
+ Miniport->MiniportRequest = NULL;
+
+ if (Request->RequestType == NdisRequestQueryStatistics)
+ {
+ PNDIS_QUERY_GLOBAL_REQUEST GlobalRequest;
+ PNDIS_QUERY_ALL_REQUEST AllRequest;
+ PNDIS_QUERY_OPEN_REQUEST OpenRequest;
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+
+ GlobalRequest = CONTAINING_RECORD (Request,
+ NDIS_QUERY_GLOBAL_REQUEST,
+ Request
+ );
+ Irp = GlobalRequest->Irp;
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ switch (IrpSp->MajorFunction) {
+
+ case IRP_MJ_CREATE:
+
+ //
+ // This request is one of the ones made during an open,
+ // while we are trying to determine the OID list. We
+ // set the event we are waiting for, the open code
+ // takes care of the rest.
+ //
+
+ OpenRequest = (PNDIS_QUERY_OPEN_REQUEST)GlobalRequest;
+
+ OpenRequest->NdisStatus = Status;
+ KeSetEvent(
+ &OpenRequest->Event,
+ 0L,
+ FALSE);
+
+ break;
+
+ case IRP_MJ_DEVICE_CONTROL:
+
+ //
+ // This is a real user request, process it as such.
+ //
+
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
+
+ case IOCTL_NDIS_QUERY_GLOBAL_STATS:
+
+ //
+ // A single query, complete the IRP.
+ //
+
+ Irp->IoStatus.Information =
+ Request->DATA.QUERY_INFORMATION.BytesWritten;
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ } else if (Status == NDIS_STATUS_INVALID_LENGTH) {
+ Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
+ } else {
+ Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; // BUGBUG
+ }
+
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ ExFreePool (GlobalRequest);
+ break;
+
+ case IOCTL_NDIS_QUERY_ALL_STATS:
+
+ //
+ // An "all" query.
+ //
+
+ AllRequest = (PNDIS_QUERY_ALL_REQUEST)GlobalRequest;
+
+ AllRequest->NdisStatus = Status;
+ KeSetEvent(
+ &AllRequest->Event,
+ 0L,
+ FALSE);
+
+ break;
+
+ }
+
+ break;
+
+ }
+
+ if (!Miniport->ProcessingDeferred) {
+
+ MiniportProcessDeferred(Miniport);
+
+ }
+ LOUD_DEBUG(DbgPrint("NdisM: Exit qeury information complete\n");)
+ return;
+
+ }
+
+ //
+ // Remove request.
+ //
+ LOUD_DEBUG(DbgPrint("NdisM: Request 0x%x\n", Request);)
+
+ //
+ // Was this an internal request?
+ //
+ if (Request == &(Miniport->InternalRequest))
+ {
+ Miniport->RequestStatus = Status;
+ KeSetEvent(
+ &Miniport->RequestEvent,
+ 0L,
+ FALSE
+ );
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit qeury information complete\n");)
+ return;
+ }
+
+ //
+ // If the request is OID_GEN_SUPPORTED_LIST
+ //
+ if (OID_GEN_SUPPORTED_LIST == Request->DATA.QUERY_INFORMATION.Oid)
+ {
+ ULONG cbDestination;
+ PNDIS_REQUEST pFakeRequest;
+ PNDIS_REQUEST_RESERVED pFakeReserved;
+
+ //
+ // Restore the original request.
+ //
+ pFakeRequest = Request;
+ pFakeReserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(pFakeRequest);
+ Request = pFakeReserved->Next;
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request);
+
+ //
+ // If the request succeeded then filter out the statistics oids.
+ // Otherwise pass the relevant information back to the protocol.
+ //
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ //
+ // There was an error....
+ //
+ Request->DATA.QUERY_INFORMATION.BytesWritten =
+ pFakeRequest->DATA.QUERY_INFORMATION.BytesWritten;
+ Request->DATA.QUERY_INFORMATION.BytesNeeded =
+ pFakeRequest->DATA.QUERY_INFORMATION.BytesNeeded;
+ }
+ else
+ {
+ //
+ // Size of the request originators buffer.
+ //
+ cbDestination =
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength;
+
+ //
+ // Do the OID fix ups.
+ //
+ Status = FilterOutOidStatistics(
+ Miniport,
+ Request,
+ Request->DATA.QUERY_INFORMATION.InformationBuffer,
+ &cbDestination,
+ pFakeRequest->DATA.QUERY_INFORMATION.InformationBuffer,
+ pFakeRequest->DATA.QUERY_INFORMATION.BytesWritten
+ );
+ if (NDIS_STATUS_BUFFER_TOO_SHORT == Status)
+ {
+ //
+ // Save the size needed with the original request.
+ //
+ Request->DATA.QUERY_INFORMATION.BytesNeeded = cbDestination;
+ Request->DATA.QUERY_INFORMATION.BytesWritten = 0;
+ }
+ else
+ {
+ //
+ // Save the bytes written with the original request.
+ //
+ Request->DATA.QUERY_INFORMATION.BytesNeeded = 0;
+ Request->DATA.QUERY_INFORMATION.BytesWritten = cbDestination;
+ }
+
+ //
+ // Free the allocated resources.
+ //
+ ExFreePool(pFakeRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+ ExFreePool(pFakeRequest);
+ }
+
+ //
+ // Fall through to protocol indication.
+ //
+ }
+
+ //
+ // Indicate to Protocol;
+ //
+ Open = Reserved->Open;
+
+ LOUD_DEBUG(DbgPrint("NdisM: Open 0x%x\n", Open);)
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.RequestCompleteHandler)(
+ Open->ProtocolBindingContext,
+ Request,
+ Status
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ Open->References--;
+
+ if (Open->References == 0)
+ {
+ FinishClose(Miniport,Open);
+ }
+
+ if (!Miniport->ProcessingDeferred)
+ {
+ MiniportProcessDeferred(Miniport);
+ }
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit query information complete\n");)
+}
+
+NDIS_STATUS
+NdisMRegisterMiniport(
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN PNDIS_MINIPORT_CHARACTERISTICS MiniportCharacteristics,
+ IN UINT CharacteristicsLength
+ )
+
+/*++
+
+Routine Description:
+
+ Used to register a Miniport driver with the wrapper.
+
+Arguments:
+
+ Status - Status of the operation.
+
+ NdisWrapperHandle - Handle returned by NdisWInitializeWrapper.
+
+ MiniportCharacteritics - The NDIS_MINIPORT_CHARACTERISTICS table.
+
+ CharacteristicsLength - The length of MiniportCharacteristics.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_M_DRIVER_BLOCK WDriver;
+ PNDIS_WRAPPER_HANDLE DriverInfo = (PNDIS_WRAPPER_HANDLE)(NdisWrapperHandle);
+ UINT MemNeeded;
+ UINT charLength;
+ NDIS_STATUS Status;
+
+ //
+ // Do any initial initialization that may be necessary. Note: this
+ // routine will notice if this is the second or later call to it.
+ //
+ Status = NdisInitialInit( DriverInfo->NdisWrapperDriver );
+ if (!NT_SUCCESS(Status)) {
+ return Status;
+ }
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter mini-port register\n");)
+
+ if (DriverInfo == NULL) {
+
+ return NDIS_STATUS_FAILURE;
+
+
+ }
+
+ if (MiniportCharacteristics->MajorNdisVersion != 3 ||
+ MiniportCharacteristics->MinorNdisVersion != 0) {
+
+ return NDIS_STATUS_BAD_VERSION;
+ }
+
+ //
+ // Check that CharacteristicsLength is enough.
+ //
+
+ charLength = sizeof(NDIS_MINIPORT_CHARACTERISTICS);
+ if (CharacteristicsLength < charLength) {
+ return NDIS_STATUS_BAD_CHARACTERISTICS;
+ }
+
+ //
+ // Allocate memory for the NDIS MINIPORT block.
+ //
+ MemNeeded = sizeof(NDIS_M_DRIVER_BLOCK);
+
+ WDriver = (PNDIS_M_DRIVER_BLOCK)ExAllocatePool(NonPagedPool, MemNeeded);
+
+ if (WDriver == (PNDIS_M_DRIVER_BLOCK)NULL) {
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ NdisZeroMemory(WDriver, MemNeeded);
+
+ WDriver->Length = MemNeeded;
+
+
+ //
+ // Copy over the characteristics table.
+ //
+
+ RtlMoveMemory((PVOID)&WDriver->MiniportCharacteristics,
+ (PVOID)MiniportCharacteristics, charLength);
+
+ //
+ // No adapters yet registered for this Miniport.
+ //
+
+ WDriver->MiniportQueue = (PNDIS_MINIPORT_BLOCK)NULL;
+
+ //
+ // Set up unload handler
+ //
+
+ DriverInfo->NdisWrapperDriver->DriverUnload = NdisMUnload;
+
+ //
+ // Set up shutdown handler
+ //
+ DriverInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_SHUTDOWN] = NdisMShutdown;
+
+ //
+ // Set up the handlers for this driver (they all do nothing).
+ //
+
+ DriverInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CREATE] = NdisCreateIrpHandler;
+ DriverInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NdisDeviceControlIrpHandler;
+ DriverInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CLEANUP] = NdisSuccessIrpHandler;
+ DriverInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CLOSE] = NdisCloseIrpHandler;
+
+ //
+ // Put Driver on global list.
+ //
+
+ ACQUIRE_SPIN_LOCK(&NdisDriverListLock);
+
+ WDriver->NextDriver = NdisDriverList;
+ NdisDriverList = WDriver;
+
+ RELEASE_SPIN_LOCK(&NdisDriverListLock);
+
+ //
+ // Use this event to tell us when all adapters are removed from the mac
+ // during an unload
+ //
+
+ KeInitializeEvent(
+ &WDriver->MiniportsRemovedEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ WDriver->Unloading = FALSE;
+ WDriver->NdisDriverInfo = DriverInfo;
+ WDriver->MiniportIdField = (NDIS_HANDLE)0x1;
+
+ NdisInitializeRef(&WDriver->Ref);
+ NdisInitReferencePackage();
+
+ LOUD_DEBUG(DbgPrint("NdisM: Exit mini-port register\n");)
+
+ if (DriverInfo->NdisWrapperConfigurationHandle) {
+
+ if (NdisCallDriverAddAdapter((PNDIS_MAC_BLOCK)WDriver) == NDIS_STATUS_SUCCESS) {
+
+ NdisInitDereferencePackage();
+ return NDIS_STATUS_SUCCESS;
+ } else {
+ NdisDereferenceDriver(WDriver);
+ NdisInitDereferencePackage();
+ return NDIS_STATUS_FAILURE;
+ }
+ } else {
+ NdisInitDereferencePackage();
+ return NDIS_STATUS_FAILURE;
+ }
+
+}
+
+//
+// Protocol entry points
+//
+NDIS_STATUS FASTCALL MiniportSyncSend(
+ PNDIS_MINIPORT_BLOCK Miniport,
+ PNDIS_PACKET Packet
+)
+
+/*++
+
+Routine Description:
+
+ Submits an immediate send to a miniport. The miniport has
+ the send on the pending queue, and it is the only element on the send
+ queue. This routine is also called with the lock held.
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PARC_BUFFER_LIST Buffer;
+ PARC_BUFFER_LIST ArcTmpBuffer;
+ PNDIS_BUFFER NdisBuffer;
+ PNDIS_BUFFER TmpBuffer;
+ PNDIS_PACKET PrevPacket;
+ NDIS_STATUS Status;
+ PNDIS_PACKET_RESERVED Reserved;
+ PNDIS_M_OPEN_BLOCK Open;
+ UINT Flags;
+ PVOID BufferVa;
+ PUCHAR Address;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ LOUD_DEBUG(DbgPrint("NdisM: Enter Sync send.\n");)
+
+ LOG('+');
+ NDIS_LOG_PACKET(Miniport, Packet, '+');
+
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ Open = Reserved->Open;
+
+ if (Miniport->MediaType == NdisMediumArcnet878_2)
+ goto BuildArcnetHeader;
+
+DoneBuildingArcnetHeader:
+
+ //
+ // Remove from Queue
+ //
+ Miniport->FirstPendingPacket = Reserved->Next;
+
+ //
+ // Put on finish queue
+ //
+ PrevPacket = Miniport->LastMiniportPacket;
+ Miniport->LastMiniportPacket = Packet;
+ Miniport->SendCompleteCalled = FALSE;
+
+ //
+ // Indicate the packet loopback if necessary.
+ //
+ if ((Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) &&
+ MiniportSendLoopback(Miniport, Packet)
+ )
+ {
+ LOUD_DEBUG(DbgPrint("NdisM: Not sending packet 0x%x\n", Packet);)
+
+ LOG('l');
+ NDIS_LOG_PACKET(Miniport, Packet, 'l');
+
+ Status = NDIS_STATUS_SUCCESS;
+ goto SyncNoCardSend;
+ }
+
+ //
+ // Submit to card
+ //
+ LOUD_DEBUG(DbgPrint("NdisM: Sending packet 0x%x\n", Packet);)
+
+ REMOVE_RESOURCE(Miniport, 'S');
+
+ NdisQuerySendFlags(Packet, &Flags);
+
+ LOG('M');
+
+ NDIS_LOG_PACKET(Miniport, Packet, 'M');
+
+ Status = (Open->SendHandler)(
+ Open->MiniportAdapterContext,
+ Packet,
+ Flags
+ );
+ if (Status == NDIS_STATUS_PENDING)
+ {
+ LOG('p');
+ NDIS_LOG_PACKET(Miniport, Packet, 'p');
+
+ LOUD_DEBUG(DbgPrint("NdisM: Complete sync send is pending\n");)
+
+ return(Status);
+ }
+
+SyncNoCardSend:
+
+ if (Miniport->MediaType == NdisMediumArcnet878_2)
+ MiniportFreeArcnetHeader(Miniport, Packet);
+
+ if (Status != NDIS_STATUS_RESOURCES)
+ {
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ ADD_RESOURCE(Miniport, 'F');
+
+ LOG('F');
+ NDIS_LOG_PACKET(Miniport, Packet, 'F');
+ }
+
+ //
+ // Remove from finish queue
+ //
+ LOUD_DEBUG(DbgPrint("NdisM: Completed 0x%x\n", Status);)
+
+ //
+ // If send complete was called from the miniport's send handler
+ // then our local PrevPacket pointer may no longer be valid....
+ //
+ MiniportFindPacket(Miniport, Packet, &PrevPacket);
+
+ Miniport->LastMiniportPacket = PrevPacket;
+
+ if (PrevPacket == NULL)
+ {
+ Miniport->FirstPacket = Reserved->Next;
+ Miniport->DeadPacket = NULL;
+ }
+ else
+ {
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = Reserved->Next;
+
+ if ( Packet == Miniport->LastPacket ) {
+
+ Miniport->LastPacket = PrevPacket;
+ }
+ }
+
+ Open->References--;
+
+ if (Open->References == 0)
+ FinishClose(Miniport, Open);
+
+ NDIS_LOG_PACKET(Miniport, Packet, 'C');
+ return(Status);
+ }
+
+ // Status == NDIS_STATUS_RESOURCES!!!!
+
+ LOUD_DEBUG(DbgPrint("NdisM: Deferring send\n");)
+
+ //
+ // If send complete was called from the miniport's send handler
+ // then our local PrevPacket pointer may no longer be valid.
+ //
+ MiniportFindPacket(Miniport, Packet, &PrevPacket);
+
+ //
+ // Remove from finish queue
+ //
+ Miniport->LastMiniportPacket = PrevPacket;
+
+ //
+ // Put on pending queue
+ //
+ Miniport->FirstPendingPacket = Packet;
+
+ //
+ // Mark the packet at the head of the pending queue as having
+ // been looped back.
+ //
+ Miniport->AlreadyLoopedBack = TRUE;
+
+ LOG('o');
+ NDIS_LOG_PACKET(Miniport, Packet, 'o');
+
+ //
+ // Set flag
+ //
+ CLEAR_RESOURCE(Miniport, 'S');
+
+ return(NDIS_STATUS_PENDING);
+
+BuildArcnetHeader:
+
+ if (Open->UsingEthEncapsulation)
+ {
+ if (Miniport->ArcnetFreeBufferList == NULL)
+ {
+ //
+ // Set flag
+ //
+ CLEAR_RESOURCE(Miniport, 'S');
+ return(NDIS_STATUS_PENDING);
+ }
+
+ NdisQueryPacket(Packet, NULL, NULL, &TmpBuffer, NULL);
+ NdisQueryBuffer(TmpBuffer, &Address, &Flags);
+
+ Buffer = Miniport->ArcnetFreeBufferList;
+ Miniport->ArcnetFreeBufferList = Buffer->Next;
+
+ NdisAllocateBuffer(
+ &Status,
+ &NdisBuffer,
+ Miniport->ArcnetBufferPool,
+ Buffer->Buffer,
+ 3
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ Buffer->Next = Miniport->ArcnetFreeBufferList;
+ Miniport->ArcnetFreeBufferList = Buffer;
+ CLEAR_RESOURCE(Miniport, 'S');
+ return(NDIS_STATUS_PENDING);
+ }
+
+ Buffer->Next = Miniport->ArcnetUsedBufferList;
+ Miniport->ArcnetUsedBufferList = Buffer;
+
+ NdisChainBufferAtFront(Packet, NdisBuffer);
+
+ ((PUCHAR)Buffer->Buffer)[0] = Miniport->ArcnetAddress;
+
+ if (Address[0] & 0x01)
+ {
+ //
+ // Broadcast
+ //
+ ((PUCHAR)Buffer->Buffer)[1] = 0x00;
+ }
+ else
+ {
+ ((PUCHAR)Buffer->Buffer)[1] = Address[5];
+ }
+
+ ((PUCHAR)Buffer->Buffer)[2] = 0xE8;
+ }
+
+ goto DoneBuildingArcnetHeader;
+}
+
+
+
+NDIS_STATUS NdisMSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+)
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ PNDIS_PACKET_RESERVED Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ BOOLEAN LocalLock;
+ KIRQL OldIrql;
+ BOOLEAN FirstSend = FALSE;
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_PENDING;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ if (!Miniport->HaltingMiniport)
+ {
+ NDIS_LOG_PACKET(Miniport, Packet, 'w');
+
+ ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++;
+
+ //
+ // Handle protocol requests
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+
+ if ( Miniport->FirstPacket == NULL )
+ {
+ Miniport->FirstPacket = Packet;
+ Miniport->DeadPacket = NULL;
+ }
+ else
+ {
+#if DBG
+ {
+ PNDIS_PACKET p;
+
+ for (p = Miniport->FirstPacket; p != NULL; p = PNDIS_RESERVED_FROM_PNDIS_PACKET(p)->Next)
+ {
+ if (Packet == p)
+ {
+ DbgBreakPoint();
+ }
+ }
+ }
+#endif
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = Packet;
+ }
+
+ Miniport->LastPacket = Packet;
+
+ //
+ // Initialize some variables.
+ //
+ FirstSend = FALSE;
+ StatusToReturn = NDIS_STATUS_PENDING;
+
+ if (Miniport->FirstPendingPacket == NULL)
+ {
+ FirstSend = TRUE;
+ Miniport->FirstPendingPacket = Packet;
+ Miniport->AlreadyLoopedBack = FALSE;
+ }
+
+ if (LocalLock)
+ {
+ //
+ // If we did not lock down the mini-port, then some other routine will
+ // do this processing for us. Otherwise we need to do this processing.
+ //
+ if (!Miniport->ProcessingDeferred)
+ {
+ Miniport->ProcessingDeferred = TRUE;
+
+ if (FirstSend &&
+ !(Miniport->RunTimer ||
+ Miniport->HaltingMiniport ||
+ Miniport->ResetRequested ||
+ Miniport->ResetInProgress ||
+ Miniport->RunDoRequests ||
+ Miniport->ProcessOddDeferredStuff)
+ )
+ {
+ //
+ // There aren't any pending sends, we are not processing
+ // odd deferred stuff (i.e. we are obeying the priority
+ // in processdeferred, and we have the lock. If all is
+ // not perfect we will defer and try again later.)
+ //
+ StatusToReturn = MiniportSyncSend(Miniport, Packet);
+ Miniport->ProcessingDeferred = FALSE;
+ }
+ else
+ {
+ MiniportProcessDeferred(Miniport);
+ }
+ }
+ }
+
+ NDIS_LOG_PACKET(Miniport, Packet, 'W');
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ return(StatusToReturn);
+ }
+ else
+ {
+ NDIS_LOG_PACKET(Miniport, Packet, 'F');
+ NDIS_LOG_PACKET(Miniport, Packet, 'W');
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ return(NDIS_STATUS_FAILURE);
+ }
+}
+
+typedef
+NDIS_STATUS
+(*PNDIS_M_WAN_SEND) (
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE NdisLinkHandle,
+ IN PVOID Packet
+ );
+
+//
+// Protocol entry point for WAN miniport
+//
+
+NDIS_STATUS
+NdisMWanSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE NdisLinkHandle,
+ IN PVOID Packet
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ BOOLEAN LocalLock;
+ KIRQL OldIrql;
+ NDIS_STATUS Status;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Call MAC to send WAN packet
+ //
+
+ Status=
+ ((PNDIS_M_WAN_SEND)(Miniport->DriverHandle->MiniportCharacteristics.SendHandler)) (
+ Miniport->MiniportAdapterContext,
+ NdisLinkHandle,
+ Packet);
+
+ if (LocalLock) {
+
+ //
+ // Process any changes that may have occured.
+ //
+
+ if (!Miniport->ProcessingDeferred) {
+ MiniportProcessDeferred(Miniport);
+ }
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+ return(Status);
+}
+
+
+NDIS_STATUS
+NdisMTransferDataSync(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ PNDIS_PACKET_RESERVED Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+ ASSERT((Miniport->MacOptions & NDIS_MAC_OPTION_TRANSFERS_NOT_PEND) != 0);
+
+ //
+ // Handle non-loopback as the default case.
+ //
+
+ if (Miniport->LoopbackPacket == NULL) {
+
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+
+ //
+ // Call Miniport.
+ //
+
+ Status =
+ (Reserved->Open->TransferDataHandler)(
+ Packet,
+ BytesTransferred,
+ Reserved->Open->MiniportAdapterContext,
+ MacReceiveContext,
+ ByteOffset,
+ BytesToTransfer
+ );
+
+ //
+ // This miniport better not pend this send.
+ //
+
+ ASSERT(Status != NDIS_STATUS_PENDING);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ return Status;
+ }
+
+ //
+ // This packet is a loopback packet!
+ //
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ NdisCopyFromPacketToPacket(
+ Packet,
+ 0,
+ BytesToTransfer,
+ Miniport->LoopbackPacket,
+ ByteOffset + Miniport->LoopbackPacketHeaderSize,
+ BytesTransferred
+ );
+
+ if ( *BytesTransferred == BytesToTransfer ) {
+
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ return NDIS_STATUS_FAILURE;
+}
+
+NDIS_STATUS
+NdisMTransferData(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ PNDIS_PACKET_RESERVED Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ PNDIS_PACKET PrevLast;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ //
+ // Handle non-loopback as the default case.
+ //
+
+ if (Miniport->LoopbackPacket == NULL) {
+
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+
+ //
+ // Put this guy on the transfer data queue.
+ //
+
+ PrevLast = Miniport->LastTDPacket;
+
+ if (Miniport->FirstTDPacket == NULL) {
+
+ Miniport->FirstTDPacket = Packet;
+
+ } else {
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastTDPacket)->Next = Packet;
+ }
+
+ Miniport->LastTDPacket = Packet;
+
+ //
+ // Call Miniport
+ //
+
+ Status =
+ (Reserved->Open->TransferDataHandler)(
+ Packet,
+ BytesTransferred,
+ Reserved->Open->MiniportAdapterContext,
+ MacReceiveContext,
+ ByteOffset,
+ BytesToTransfer
+ );
+
+ //
+ // If it didn't pend then we won't get a transfer data complte call
+ // so we need to remove this guy now.
+ //
+
+ if ( Status != NDIS_STATUS_PENDING ) {
+
+ //
+ // Remove from queue
+ //
+
+ if (Miniport->FirstTDPacket != Packet) {
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevLast)->Next = NULL;
+ Miniport->LastTDPacket = PrevLast;
+
+ } else {
+
+ Miniport->FirstTDPacket = NULL;
+ Miniport->LastTDPacket = NULL;
+
+ }
+ }
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ return Status;
+ }
+
+ //
+ // This packet is a loopback packet!
+ //
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ NdisCopyFromPacketToPacket(
+ Packet,
+ 0,
+ BytesToTransfer,
+ Miniport->LoopbackPacket,
+ ByteOffset + Miniport->LoopbackPacketHeaderSize,
+ BytesTransferred
+ );
+
+ if ( *BytesTransferred == BytesToTransfer ) {
+
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ return NDIS_STATUS_FAILURE;
+}
+
+NDIS_STATUS
+NdisMReset(
+ IN NDIS_HANDLE NdisBindingHandle
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ BOOLEAN LocalLock;
+ KIRQL OldIrql;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ if (Miniport->HaltingMiniport) {
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ return(NDIS_STATUS_FAILURE);
+
+ }
+
+ Miniport->ResetRequested = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++;
+
+ if (LocalLock) {
+
+ //
+ // If we did not lock down the mini-port, then some other routine will
+ // do this processing for us. Otherwise we need to do this processing.
+ //
+ if (!Miniport->ProcessingDeferred) {
+
+ MiniportProcessDeferred(Miniport);
+
+ }
+
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ return(NDIS_STATUS_PENDING);
+}
+
+
+NDIS_STATUS
+NdisMRequest(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ PNDIS_REQUEST_RESERVED Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(NdisRequest);
+ BOOLEAN LocalLock;
+ KIRQL OldIrql;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ if (Miniport->HaltingMiniport) {
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ return(NDIS_STATUS_FAILURE);
+
+ }
+
+ LOUD_DEBUG(DbgPrint("NdisM: Got request 0x%x\n",NdisRequest);)
+
+ //
+ // Handle protocol requests
+ //
+
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+ ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++;
+
+ if (Miniport->FirstPendingRequest == NULL) {
+
+ Miniport->FirstPendingRequest = NdisRequest;
+
+ } else {
+
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Miniport->LastPendingRequest)->Next = NdisRequest;
+
+ }
+
+ Miniport->LastPendingRequest = NdisRequest;
+
+ if (Miniport->MiniportRequest == NULL)
+ {
+ Miniport->RunDoRequests = TRUE;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+ }
+
+ if (LocalLock)
+ {
+ //
+ // If we did not lock down the mini-port, then some other routine will
+ // do this processing for us. Otherwise we need to do this processing.
+ //
+ if (!Miniport->ProcessingDeferred) {
+
+ MiniportProcessDeferred(Miniport);
+
+ }
+
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ return (NDIS_STATUS_PENDING);
+}
+
+
+NDIS_STATUS
+NdisMMapIoSpace(
+ OUT PVOID * VirtualAddress,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress,
+ IN UINT Length
+ )
+{
+ NDIS_STATUS Status;
+ NdisMapIoSpace(&Status,
+ VirtualAddress,
+ MiniportAdapterHandle,
+ PhysicalAddress,
+ Length
+ );
+ return(Status);
+}
+
+
+VOID
+NdisMUnmapIoSpace(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PVOID VirtualAddress,
+ IN UINT Length
+ )
+{
+
+#ifdef _ALPHA_
+
+#else
+ MmUnmapIoSpace(VirtualAddress, Length);
+#endif
+
+}
+
+
+NDIS_STATUS
+NdisMRegisterInterrupt(
+ OUT PNDIS_MINIPORT_INTERRUPT Interrupt,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT InterruptVector,
+ IN UINT InterruptLevel,
+ IN BOOLEAN RequestIsr,
+ IN BOOLEAN SharedInterrupt,
+ IN NDIS_INTERRUPT_MODE InterruptMode
+ )
+{
+ NDIS_STATUS Status;
+ NdisInitializeInterrupt(&Status,
+ (PNDIS_INTERRUPT)Interrupt,
+ MiniportAdapterHandle,
+ NULL,
+ NULL,
+ (PNDIS_DEFERRED_PROCESSING)RequestIsr,
+ InterruptVector,
+ InterruptLevel,
+ SharedInterrupt,
+ InterruptMode
+ );
+
+ return(Status);
+}
+
+
+VOID
+NdisMDeregisterInterrupt(
+ IN PNDIS_MINIPORT_INTERRUPT Interrupt
+ )
+{
+ NdisRemoveInterrupt((PNDIS_INTERRUPT)Interrupt);
+}
+
+
+BOOLEAN
+NdisMSynchronizeWithInterrupt(
+ IN PNDIS_MINIPORT_INTERRUPT Interrupt,
+ IN PVOID SynchronizeFunction,
+ IN PVOID SynchronizeContext
+ )
+{
+ return (KeSynchronizeExecution(
+ (Interrupt)->InterruptObject,
+ (PKSYNCHRONIZE_ROUTINE)SynchronizeFunction,
+ SynchronizeContext
+ )
+ );
+}
+
+
+
+VOID
+NdisMAllocateSharedMemory(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN ULONG Length,
+ IN BOOLEAN Cached,
+ OUT PVOID *VirtualAddress,
+ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress
+ )
+{
+ //
+ // Convert the handle to our internal structure.
+ //
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportAdapterHandle;
+
+ if (Miniport->SystemAdapterObject == NULL) {
+
+ *VirtualAddress = NULL;
+ return;
+
+ }
+
+ NdisAllocateSharedMemory(MiniportAdapterHandle,
+ Length,
+ Cached,
+ VirtualAddress,
+ PhysicalAddress
+ );
+}
+
+VOID
+NdisMFreeSharedMemory(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN ULONG Length,
+ IN BOOLEAN Cached,
+ IN PVOID VirtualAddress,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
+ )
+{
+ NdisFreeSharedMemory(MiniportAdapterHandle,
+ Length,
+ Cached,
+ VirtualAddress,
+ PhysicalAddress);
+}
+
+
+
+NDIS_STATUS
+NdisMRegisterDmaChannel(
+ OUT PNDIS_HANDLE MiniportDmaHandle,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT DmaChannel,
+ IN BOOLEAN Dma32BitAddresses,
+ IN PNDIS_DMA_DESCRIPTION DmaDescription,
+ IN ULONG MaximumLength
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(MiniportAdapterHandle);
+ NDIS_STATUS Status;
+ Miniport->ChannelNumber = (DmaChannel);
+ Miniport->Dma32BitAddresses = (Dma32BitAddresses);
+ NdisAllocateDmaChannel(&Status,
+ MiniportDmaHandle,
+ (NDIS_HANDLE)Miniport,
+ DmaDescription,
+ MaximumLength
+ );
+ return(Status);
+}
+
+
+
+VOID
+NdisMDeregisterDmaChannel(
+ IN PNDIS_HANDLE MiniportDmaHandle
+ )
+{
+ NdisFreeDmaChannel(MiniportDmaHandle);
+}
+
+
+VOID
+HaltOneMiniport(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Does all the clean up for a mini-port.
+
+Arguments:
+
+ Miniport - pointer to the mini-port to halt
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ BOOLEAN LocalLock;
+ BOOLEAN Canceled;
+ KIRQL OldIrql;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ while (Miniport->LockAcquired) {
+
+ //
+ // This can only happen on an MP system. We must now
+ // wait for the other processor to exit the mini-port.
+ //
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ NdisStallExecution(1000);
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ }
+
+ //
+ // Lock mini-port so that nothing will enter it.
+ //
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // We can now release safely
+ //
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ NdisCancelTimer(&Miniport->WakeUpDpcTimer, &Canceled);
+
+ if (!Canceled) {
+
+ NdisStallExecution(500000);
+ }
+
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler)(
+ Miniport->MiniportAdapterContext
+ );
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ AbortMiniportPacketsAndPending(Miniport);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ //
+ // If a shutdown handler was registered then deregister it.
+ //
+
+ NdisMDeregisterAdapterShutdownHandler(Miniport);
+
+ NdisDereferenceMiniport(Miniport);
+ MiniportDereferencePackage();
+
+ return;
+
+}
+
+//
+// Arcnet support routines
+//
+
+VOID
+NdisMArcIndicateEthEncapsulatedReceive(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PVOID HeaderBuffer,
+ IN PVOID DataBuffer,
+ IN UINT Length
+ )
+/*++
+
+ HeaderBuffer - This is the 878.2 header.
+ DataBuffer - This is the 802.3 header.
+ Length - This is the length of the ethernet frame.
+
+--*/
+
+{
+ ULONG MacReceiveContext[2];
+
+ //
+ // Indicate the packet.
+ //
+
+ MacReceiveContext[0] = (ULONG) DataBuffer;
+ MacReceiveContext[1] = (ULONG) Length;
+
+ if (Length > 14) {
+
+ NdisMEthIndicateReceive(
+ (NDIS_HANDLE) Miniport, // miniport handle.
+ (NDIS_HANDLE) MacReceiveContext, // receive context.
+ DataBuffer, // ethernet header.
+ 14, // ethernet header length.
+ (PUCHAR)DataBuffer + 14, // ethernet data.
+ Length - 14, // ethernet data length.
+ Length - 14 // ethernet data length.
+ );
+
+ } else {
+
+ NdisMEthIndicateReceive(
+ (NDIS_HANDLE) Miniport, // miniport handle.
+ (NDIS_HANDLE) MacReceiveContext, // receive context.
+ DataBuffer, // ethernet header.
+ Length, // ethernet header length.
+ NULL, // ethernet data.
+ 0, // ethernet data length.
+ 0 // ethernet data length.
+ );
+ }
+}
+
+
+NDIS_STATUS
+NdisMArcTransferData(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET DstPacket,
+ OUT PUINT BytesTransferred
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the transfer data calls to arcnet mini-port.
+
+Arguments:
+
+ NdisBindingHandle - Pointer to open block.
+
+ MacReceiveContext - Context given for the indication
+
+ ByteOffset - Offset to start transfer at.
+
+ BytesToTransfer - Number of bytes to transfer
+
+ Packet - Packet to transfer into
+
+ BytesTransferred - the number of actual bytes copied
+
+Return values:
+
+ NDIS_STATUS_SUCCESS, if successful, else NDIS_STATUS_FAILURE.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PNDIS_M_OPEN_BLOCK MiniportOpen;
+ KIRQL OldIrql;
+ PNDIS_PACKET SrcPacket;
+ PNDIS_BUFFER NdisBuffer;
+ NDIS_STATUS Status;
+ NDIS_PACKET TempPacket;
+
+ MiniportOpen = (PNDIS_M_OPEN_BLOCK) NdisBindingHandle;
+ Miniport = MiniportOpen->MiniportHandle;
+ NdisBuffer = NULL;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ //
+ // If this is encapsulated ethernet then we don't currently
+ // have the source packet from which to copy from.
+ //
+
+ if ( MiniportOpen->UsingEthEncapsulation ) {
+
+ //
+ // If this is not loopback then we need to create a
+ // temp NDIS_PACKET for the packet-to-packet copy.
+ //
+
+ if ( !Miniport->LoopbackPacket ) {
+
+ PUCHAR DataBuffer = (PUCHAR) ((PULONG) MacReceiveContext)[0];
+ UINT DataLength = (UINT) ((PULONG) MacReceiveContext)[1];
+
+ //
+ // We'll always be in the scope of this function so we
+ // can use local stack space rather than allocating dynamic
+ // memory.
+ //
+
+ SrcPacket = &TempPacket; // Use the local stack for packet store.
+
+ NdisZeroMemory(
+ SrcPacket,
+ sizeof(NDIS_PACKET)
+ );
+
+ NdisAllocateBuffer(
+ &Status, // Status code.
+ &NdisBuffer, // NDIS buffer to chain onto the packet.
+ NULL, // On NT, this parameter is ignored.
+ DataBuffer, // The ethernet frame.
+ DataLength // The ethernet frame length.
+ );
+
+ NdisChainBufferAtFront(SrcPacket, NdisBuffer);
+
+ } else {
+
+ SrcPacket = Miniport->LoopbackPacket;
+
+ ByteOffset += 3; // Skip fake arcnet header.
+ }
+
+ //
+ // Skip the ethernet header.
+ //
+
+ ByteOffset += 14;
+
+ } else {
+
+ SrcPacket = (PNDIS_PACKET) MacReceiveContext;
+ }
+
+ //
+ // Now we can simply copy from the source packet to the
+ // destination packet.
+ //
+
+ NdisCopyFromPacketToPacket(
+ DstPacket, // destination packet.
+ 0, // destination offset.
+ BytesToTransfer, // bytes to copy.
+ SrcPacket, // source packet.
+ ByteOffset, // source offset.
+ BytesTransferred // bytes copied.
+ );
+
+ //
+ // If we allocated an NDIS_BUFFER then we need to free it. We don't
+ // need to unchain the buffer from the packet since the packet is
+ // a local stack variable the will just get trashed anyway.
+ //
+
+ if ( NdisBuffer != NULL ) {
+
+ NdisFreeBuffer(NdisBuffer);
+ }
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+VOID
+MiniportArcCopyFromBufferToPacket(
+ IN PCHAR Buffer,
+ IN UINT BytesToCopy,
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ OUT PUINT BytesCopied
+ )
+
+/*++
+
+Routine Description:
+
+ Copy from a buffer into an ndis packet.
+
+Arguments:
+
+ Buffer - The packet to copy from.
+
+ Offset - The offset from which to start the copy.
+
+ BytesToCopy - The number of bytes to copy from the buffer.
+
+ Packet - The destination of the copy.
+
+ BytesCopied - The number of bytes actually copied. Will be less
+ than BytesToCopy if the packet is not large enough.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ //
+ // Holds the count of the number of ndis buffers comprising the
+ // destination packet.
+ //
+ UINT DestinationBufferCount;
+
+ //
+ // Points to the buffer into which we are putting data.
+ //
+ PNDIS_BUFFER DestinationCurrentBuffer;
+
+ //
+ // Points to the location in Buffer from which we are extracting data.
+ //
+ PUCHAR SourceCurrentAddress;
+
+ //
+ // Holds the virtual address of the current destination buffer.
+ //
+ PVOID DestinationVirtualAddress;
+
+ //
+ // Holds the length of the current destination buffer.
+ //
+ UINT DestinationCurrentLength;
+
+ //
+ // Keep a local variable of BytesCopied so we aren't referencing
+ // through a pointer.
+ //
+ UINT LocalBytesCopied = 0;
+
+
+ //
+ // Take care of boundary condition of zero length copy.
+ //
+
+ *BytesCopied = 0;
+ if (!BytesToCopy) return;
+
+ //
+ // Get the first buffer of the destination.
+ //
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ &DestinationBufferCount,
+ &DestinationCurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (!DestinationBufferCount) return;
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ //
+ // Set up the source address.
+ //
+
+ SourceCurrentAddress = Buffer;
+
+
+ while (LocalBytesCopied < BytesToCopy) {
+
+ //
+ // Check to see whether we've exhausted the current destination
+ // buffer. If so, move onto the next one.
+ //
+
+ if (!DestinationCurrentLength) {
+
+ NdisGetNextBuffer(
+ DestinationCurrentBuffer,
+ &DestinationCurrentBuffer
+ );
+
+ if (!DestinationCurrentBuffer) {
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.)
+ //
+
+ break;
+
+ }
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ continue;
+
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (Offset) {
+
+ if (Offset > DestinationCurrentLength) {
+
+ //
+ // What we want isn't in this buffer.
+ //
+
+ Offset -= DestinationCurrentLength;
+ DestinationCurrentLength = 0;
+ continue;
+
+ } else {
+
+ DestinationVirtualAddress = (PCHAR)DestinationVirtualAddress
+ + Offset;
+ DestinationCurrentLength -= Offset;
+ Offset = 0;
+
+ }
+
+ }
+
+
+ //
+ // Copy the data.
+ //
+
+ {
+
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ //
+ // Holds the amount desired remaining.
+ //
+ UINT Remaining = BytesToCopy - LocalBytesCopied;
+
+
+ AmountToMove = DestinationCurrentLength;
+
+ AmountToMove = ((Remaining < AmountToMove)?
+ (Remaining):(AmountToMove));
+
+ NdisMoveFromMappedMemory(
+ DestinationVirtualAddress,
+ SourceCurrentAddress,
+ AmountToMove
+ );
+
+ SourceCurrentAddress += AmountToMove;
+ LocalBytesCopied += AmountToMove;
+ DestinationCurrentLength -= AmountToMove;
+
+ }
+
+ }
+
+ *BytesCopied = LocalBytesCopied;
+
+
+}
+
+
+VOID
+NdisMCancelTimer(
+ IN PNDIS_MINIPORT_TIMER Timer,
+ OUT PBOOLEAN TimerCancelled
+ )
+/*++
+
+Routine Description:
+
+ Cancels a timer.
+
+Arguments:
+
+ Timer - The timer to cancel.
+
+ TimerCancelled - TRUE if the timer was canceled, else FALSE.
+
+Return Value:
+
+ None
+
+--*/
+{
+ *TimerCancelled = KeCancelTimer(&((((PNDIS_TIMER)(Timer))->Timer)));
+}
+
+
+ULONG
+NdisMReadDmaCounter(
+ IN NDIS_HANDLE MiniportDmaHandle
+ )
+/*++
+
+Routine Description:
+
+ Reads the current value of the dma counter
+
+Arguments:
+
+ MiniportDmaHandle - Handle for the DMA transfer.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ return HalReadDmaCounter(((PNDIS_DMA_BLOCK)(MiniportDmaHandle))->SystemAdapterObject);
+}
+
+
+#if !defined(BUILD_FOR_3_1)
+VOID
+NdisBugcheckHandler(
+ IN PNDIS_WRAPPER_CONTEXT WrapperContext,
+ IN ULONG Size
+ )
+/*++
+
+Routine Description:
+
+ This routine is called when a bugcheck occurs in the system.
+
+Arguments:
+
+ Buffer -- Ndis wrapper context.
+
+ Size -- Size of wrapper context
+
+Return Value:
+
+ Void.
+
+--*/
+{
+ if ( Size == sizeof(NDIS_WRAPPER_CONTEXT) ) {
+
+ if ( WrapperContext->ShutdownHandler != NULL ) {
+
+ WrapperContext->ShutdownHandler(WrapperContext->ShutdownContext);
+ }
+ }
+}
+#endif
+
+VOID
+NdisMRegisterAdapterShutdownHandler(
+ IN NDIS_HANDLE MiniportHandle,
+ IN PVOID ShutdownContext,
+ IN ADAPTER_SHUTDOWN_HANDLER ShutdownHandler
+ )
+/*++
+
+Routine Description:
+
+ Deregisters an NDIS adapter.
+
+Arguments:
+
+ MiniportHandle - The miniport.
+
+ ShutdownHandler - The Handler for the Adapter, to be called on shutdown.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportHandle;
+ PNDIS_WRAPPER_CONTEXT WrapperContext = Miniport->WrapperContext;
+
+ if (WrapperContext->ShutdownHandler == NULL) {
+
+ //
+ // Store information
+ //
+
+ WrapperContext->ShutdownHandler = ShutdownHandler;
+ WrapperContext->ShutdownContext = ShutdownContext;
+
+#if !defined(BUILD_FOR_3_1)
+ //
+ // Register our shutdown handler for a bugcheck. (Note that we are
+ // already registered for shutdown notification.)
+ //
+
+ KeInitializeCallbackRecord(&WrapperContext->BugcheckCallbackRecord);
+
+ KeRegisterBugCheckCallback(
+ &WrapperContext->BugcheckCallbackRecord, // callback record.
+ (PVOID) NdisBugcheckHandler, // callback routine.
+ (PVOID) WrapperContext, // free form buffer.
+ sizeof(NDIS_WRAPPER_CONTEXT), // buffer size.
+ "Ndis miniport" // component id.
+ );
+#endif
+ }
+}
+
+
+VOID
+NdisMDeregisterAdapterShutdownHandler(
+ IN NDIS_HANDLE MiniportHandle
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+ MiniportHandle - The miniport.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportHandle;
+ PNDIS_WRAPPER_CONTEXT WrapperContext = Miniport->WrapperContext;
+
+ //
+ // Clear information
+ //
+
+ if ( WrapperContext->ShutdownHandler != NULL ) {
+
+#if !defined(BUILD_FOR_3_1)
+ KeDeregisterBugCheckCallback(&WrapperContext->BugcheckCallbackRecord);
+#endif
+
+ WrapperContext->ShutdownHandler = NULL;
+ }
+}
+
+#if !defined(BUILD_FOR_3_1)
+
+NDIS_STATUS
+NdisMPciAssignResources(
+ IN NDIS_HANDLE MiniportHandle,
+ IN ULONG SlotNumber,
+ OUT PNDIS_RESOURCE_LIST *AssignedResources
+ )
+/*++
+
+Routine Description:
+
+ This routine uses the Hal to assign a set of resources to a PCI
+ device.
+
+Arguments:
+
+ MiniportHandle - The miniport.
+
+ SlotNumber - Slot number of the device.
+
+ AssignedResources - The returned resources.
+
+Return Value:
+
+ Status of the operation
+
+--*/
+{
+ NTSTATUS NtStatus;
+ PCM_RESOURCE_LIST AllocatedResources = NULL;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportHandle;
+
+ NtStatus = HalAssignSlotResources (
+ (PUNICODE_STRING)(Miniport->DriverHandle->NdisDriverInfo->NdisWrapperConfigurationHandle),
+ NULL,
+ Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver,
+ Miniport->DeviceObject,
+ Miniport->BusType,
+ Miniport->BusNumber,
+ SlotNumber,
+ &AllocatedResources
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+ *AssignedResources = NULL;
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Store resources into the driver wide block
+ //
+ ((PNDIS_WRAPPER_CONTEXT)Miniport->WrapperContext)->AssignedSlotResources = AllocatedResources;
+
+ *AssignedResources = &(AllocatedResources->List[0].PartialResourceList);
+
+ return(NDIS_STATUS_SUCCESS);
+
+}
+
+#else // !defined(BUILD_FOR_3_1)
+
+NDIS_STATUS
+NdisMPciAssignResources(
+ IN NDIS_HANDLE MiniportHandle,
+ IN ULONG SlotNumber,
+ OUT PNDIS_RESOURCE_LIST *AssignedResources
+ )
+{
+ return NDIS_STATUS_FAILURE;
+}
+
+#endif // else !defined(BUILD_FOR_3_1)
+
+NDIS_STATUS
+NdisMQueryAdapterResources(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PNDIS_RESOURCE_LIST ResourceList,
+ IN OUT PUINT BufferSize
+ )
+{
+ return NDIS_STATUS_NOT_SUPPORTED;
+}
+
diff --git a/private/ntos/ndis/ndis30/minisub.c b/private/ntos/ndis/ndis30/minisub.c
new file mode 100644
index 000000000..4454cd129
--- /dev/null
+++ b/private/ntos/ndis/ndis30/minisub.c
@@ -0,0 +1,280 @@
+/*++
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ miniport.c
+
+Abstract:
+
+ NDIS wrapper functions
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 05-Oct-93
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#undef NdisAllocateSpinLock
+#undef NdisFreeSpinLock
+#undef NdisAcquireSpinLock
+#undef NdisReleaseSpinLock
+#undef NdisDprAcquireSpinLock
+#undef NdisDprReleaseSpinLock
+#undef NdisFreeBuffer
+#undef NdisQueryBuffer
+#undef NdisQueryBufferOffset
+#undef NDIS_BUFFER_TO_SPAN_PAGES
+#undef NdisGetBufferPhysicalArraySize
+#undef NdisEqualString
+#undef NdisMStartBufferPhysicalMapping
+#undef NdisMCompleteBufferPhysicalMapping
+
+VOID
+NdisAllocateSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+VOID
+NdisFreeSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+VOID
+NdisAcquireSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+VOID
+NdisReleaseSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+VOID
+NdisDprAcquireSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+VOID
+NdisDprReleaseSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+VOID
+NdisFreeBuffer(
+ IN PNDIS_BUFFER Buffer
+ );
+
+VOID
+NdisQueryBuffer(
+ IN PNDIS_BUFFER Buffer,
+ OUT PVOID *VirtualAddress OPTIONAL,
+ OUT PUINT Length
+ );
+
+VOID
+NdisQueryBufferOffset(
+ IN PNDIS_BUFFER Buffer,
+ OUT PUINT Offset,
+ OUT PUINT Length
+ );
+
+ULONG
+NDIS_BUFFER_TO_SPAN_PAGES(
+ IN PNDIS_BUFFER Buffer
+ );
+
+VOID
+NdisGetBufferPhysicalArraySize(
+ IN PNDIS_BUFFER Buffer,
+ OUT PUINT ArraySize
+ );
+
+BOOLEAN
+NdisEqualString(
+ IN PNDIS_STRING String1,
+ IN PNDIS_STRING String2,
+ IN BOOLEAN CaseInsensitive
+ );
+
+VOID
+NdisMStartBufferPhysicalMapping(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG PhysicalMapRegister,
+ IN BOOLEAN WriteToDevice,
+ OUT PNDIS_PHYSICAL_ADDRESS_UNIT PhysicalAddressArray,
+ OUT PUINT ArraySize
+ );
+
+VOID
+NdisMCompleteBufferPhysicalMapping(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG PhysicalMapRegister
+ );
+
+
+VOID
+NdisAllocateSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ KeInitializeSpinLock(&SpinLock->SpinLock);
+}
+
+VOID
+NdisFreeSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ UNREFERENCED_PARAMETER (SpinLock);
+}
+
+VOID
+NdisAcquireSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ KeAcquireSpinLock(&SpinLock->SpinLock, &SpinLock->OldIrql);
+}
+
+VOID
+NdisReleaseSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ KeReleaseSpinLock(&SpinLock->SpinLock, SpinLock->OldIrql);
+}
+
+VOID
+NdisDprAcquireSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ KeAcquireSpinLockAtDpcLevel(&SpinLock->SpinLock);
+ SpinLock->OldIrql = DISPATCH_LEVEL;
+}
+
+VOID
+NdisDprReleaseSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ KeReleaseSpinLockFromDpcLevel(&SpinLock->SpinLock);
+}
+VOID
+NdisFreeBuffer(
+ IN PNDIS_BUFFER Buffer
+ )
+{
+ IoFreeMdl(Buffer);
+}
+
+VOID
+NdisQueryBuffer(
+ IN PNDIS_BUFFER Buffer,
+ OUT PVOID *VirtualAddress OPTIONAL,
+ OUT PUINT Length
+ )
+{
+ if ( ARGUMENT_PRESENT(VirtualAddress) ) {
+ *VirtualAddress = MmGetSystemAddressForMdl(Buffer);
+ }
+ *Length = MmGetMdlByteCount(Buffer);
+}
+
+VOID
+NdisQueryBufferOffset(
+ IN PNDIS_BUFFER Buffer,
+ OUT PUINT Offset,
+ OUT PUINT Length
+ )
+{
+ *Offset = MmGetMdlByteOffset(Buffer);
+ *Length = MmGetMdlByteCount(Buffer);
+}
+
+ULONG
+NDIS_BUFFER_TO_SPAN_PAGES(
+ IN PNDIS_BUFFER Buffer
+ )
+{
+ if (MmGetMdlByteCount(Buffer) == 0) {
+ return 1;
+ }
+ return COMPUTE_PAGES_SPANNED(
+ MmGetMdlVirtualAddress(Buffer),
+ MmGetMdlByteCount(Buffer)
+ );
+}
+
+VOID
+NdisGetBufferPhysicalArraySize(
+ IN PNDIS_BUFFER Buffer,
+ OUT PUINT ArraySize
+ )
+{
+ if (MmGetMdlByteCount(Buffer) == 0) {
+ *ArraySize = 1;
+ } else {
+ *ArraySize = COMPUTE_PAGES_SPANNED(
+ MmGetMdlVirtualAddress(Buffer),
+ MmGetMdlByteCount(Buffer)
+ );
+ }
+}
+
+BOOLEAN
+NdisEqualString(
+ IN PNDIS_STRING String1,
+ IN PNDIS_STRING String2,
+ IN BOOLEAN CaseInsensitive
+ )
+{
+ return RtlEqualUnicodeString(String1, String2, CaseInsensitive);
+}
+
+VOID
+NdisMStartBufferPhysicalMapping(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG PhysicalMapRegister,
+ IN BOOLEAN WriteToDevice,
+ OUT PNDIS_PHYSICAL_ADDRESS_UNIT PhysicalAddressArray,
+ OUT PUINT ArraySize
+ )
+{
+ NdisMStartBufferPhysicalMappingMacro(
+ MiniportAdapterHandle,
+ Buffer,
+ PhysicalMapRegister,
+ WriteToDevice,
+ PhysicalAddressArray,
+ ArraySize
+ );
+}
+
+VOID
+NdisMCompleteBufferPhysicalMapping(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG PhysicalMapRegister
+ )
+{
+ NdisMCompleteBufferPhysicalMappingMacro(
+ MiniportAdapterHandle,
+ Buffer,
+ PhysicalMapRegister
+ );
+}
+
diff --git a/private/ntos/ndis/ndis30/ndis.prf b/private/ntos/ndis/ndis30/ndis.prf
new file mode 100644
index 000000000..cf7a25416
--- /dev/null
+++ b/private/ntos/ndis/ndis30/ndis.prf
@@ -0,0 +1,102 @@
+NdisMTimerDpc@16
+NDIS_BUFFER_TO_SPAN_PAGES@4
+NdisMSendComplete@12
+NdisMSend@8
+NdisMIsr@8
+NdisSetTimer@8
+EthFilterDprIndicateReceiveComplete@4
+@MiniportProcessDeferred@4
+EthFilterDprIndicateReceive@32
+NdisMDpc@16
+@MiniportStartSends@4
+NdisMWakeUpDpc@16
+NdisMCompleteBufferPhysicalMapping@12
+NdisMStartBufferPhysicalMapping@24
+NdisQueryBuffer@12
+@InterlockedIncrement@4
+@MiniportSyncSend@8
+@InterlockedDecrement@4
+_allmul
+NdisMSendResourcesAvailable@4
+NdisAllocateBuffer@20
+NdisUnchainBufferAtFront@8
+NdisMTransferDataSync@24
+MiniportDereferencePackage@0
+NdisMRegisterMiniport@12
+NdisMacDereferencePackage@0
+EthDereferencePackage@0
+NdisMacInitializePackage@0
+NdisInitDereferencePackage@0
+NdisInitializeTimer@12
+NdisAllocateSharedMemory@20
+NdisInitReferencePackage@0
+EthInitializePackage@0
+NdisInitInitializePackage@0
+EthReferencePackage@0
+MiniportReferencePackage@0
+NdisUnmapFile@4
+WrapperCheckRoute@24
+NdisOpenFile@24
+NdisCloseFile@4
+NdisMapFile@12
+NdisAllocateBufferPool@12
+FddiDeleteFilter@4
+FddiDereferencePackage@0
+FddiReferencePackage@0
+FddiInitializePackage@0
+TrDeleteFilter@4
+TrDereferencePackage@0
+TrReferencePackage@0
+ArcDeleteFilter@4
+ArcInitializePackage@0
+ArcReferencePackage@0
+ArcDereferencePackage@0
+NdisAllocateMemory@20
+NdisFreeMemory@12
+NdisInitialInit@4
+MiniportOpenAdapter@48
+NdisRegisterProtocol@16
+NdisOpenAdapter@44
+NdisFreeBufferPool@4
+TrInitializePackage@0
+NdisAllocationExecutionRoutine@16
+NdisMacReferencePackage@0
+MiniportInitializePackage@0
+EthDeleteFilter@4
+NdisReferenceRef@4
+NdisInitializeRef@4
+memmove
+NdisQueueOpenOnProtocol@8
+NdisCreateIrpHandler@8
+NdisSuccessIrpHandler@8
+WrapperSaveLinkage@24
+NdisMRegisterAdapterShutdownHandler@12
+EthNoteFilterOpenAdapter@16
+EthFilterAdjust@20
+NdisMAllocateSharedMemory@20
+NdisMAllocateMapRegisters@20
+NdisInitializeWrapper@16
+NdisCloseConfiguration@4
+NdisReadConfiguration@20
+NdisMSetAttributes@16
+NdisInitializeInterrupt@40
+NdisOpenConfiguration@12
+NdisReadNetworkAddress@16
+NdisCallDriverAddAdapter@4
+WrapperSaveParameters@24
+NdisMRegisterInterrupt@28
+MiniportDoRequests@4
+ArcCreateFilter@24
+NdisMQueryInformationComplete@8
+NdisMSetInformationComplete@8
+NdisMRequest@8
+NdisMChangeClass@20
+NdisMInitializeTimer@16
+MiniportAdjustMaximumLookahead@4
+NdisMDpcTimer@16
+NdisQueueMiniportOnDriver@8
+FddiCreateFilter@36
+TrCreateFilter@28
+EthCreateFilter@28
+NdisMRegisterIoPortRange@16
+NdisReadEisaSlotInformation@16
diff --git a/private/ntos/ndis/ndis30/ndis.rc b/private/ntos/ndis/ndis30/ndis.rc
new file mode 100644
index 000000000..3d5b057d2
--- /dev/null
+++ b/private/ntos/ndis/ndis30/ndis.rc
@@ -0,0 +1,39 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "NDIS 3.0 wrapper driver"
+#define VER_INTERNALNAME_STR "NDIS.SYS"
+#define VER_ORIGINALFILENAME_STR "NDIS.SYS"
+
+#include "common.ver"
+
diff --git a/private/ntos/ndis/ndis30/ndis.src b/private/ntos/ndis/ndis30/ndis.src
new file mode 100644
index 000000000..bdbfdff44
--- /dev/null
+++ b/private/ntos/ndis/ndis30/ndis.src
@@ -0,0 +1,185 @@
+NAME NDIS.SYS
+
+DESCRIPTION 'NDIS.SYS'
+
+EXPORTS
+ ArcFilterDprIndicateReceive
+ ArcFilterDprIndicateReceiveComplete
+ EthChangeFilterAddresses
+ EthCreateFilter
+ EthDeleteFilter
+ EthDeleteFilterOpenAdapter
+ EthFilterAdjust
+ EthFilterDprIndicateReceive
+ EthFilterDprIndicateReceiveComplete
+ EthFilterIndicateReceive
+ EthFilterIndicateReceiveComplete
+ EthNoteFilterOpenAdapter
+ EthNumberOfOpenFilterAddresses
+ EthQueryGlobalFilterAddresses
+ EthQueryOpenFilterAddresses
+ EthShouldAddressLoopBack
+ FddiChangeFilterLongAddresses
+ FddiChangeFilterShortAddresses
+ FddiCreateFilter
+ FddiDeleteFilter
+ FddiDeleteFilterOpenAdapter
+ FddiFilterAdjust
+ FddiFilterDprIndicateReceive
+ FddiFilterDprIndicateReceiveComplete
+ FddiFilterIndicateReceive
+ FddiFilterIndicateReceiveComplete
+ FddiNoteFilterOpenAdapter
+ FddiNumberOfOpenFilterLongAddresses
+ FddiNumberOfOpenFilterShortAddresses
+ FddiQueryGlobalFilterLongAddresses
+ FddiQueryGlobalFilterShortAddresses
+ FddiQueryOpenFilterLongAddresses
+ FddiQueryOpenFilterShortAddresses
+ FddiShouldAddressLoopBack
+ NdisAllocateBuffer
+ NdisAllocateBufferPool
+ NdisAllocateDmaChannel
+ NdisAllocateMemory
+ NdisAllocatePacket
+ NdisAllocatePacketPool
+ NdisAllocateSharedMemory
+ NdisCloseAdapter
+ NdisCloseConfiguration
+ NdisCloseFile
+ NdisCloseRef
+ NdisCompleteCloseAdapter
+ NdisCompleteDmaTransfer
+ NdisCompleteOpenAdapter
+ NdisCompleteQueryStatistics
+ NdisCopyBuffer
+ NdisCopyFromPacketToPacket
+ NdisDereferenceRef
+#if ALPHA
+ NdisCreateLookaheadBufferFromSharedMemory
+ NdisDestroyLookaheadBufferFromSharedMemory
+#endif
+ NdisDeregisterAdapter
+ NdisDeregisterAdapterShutdownHandler
+ NdisDeregisterMac
+ NdisDeregisterProtocol
+ NdisFinishOpen
+ NdisFreeBufferPool
+ NdisFreeDmaChannel
+ NdisFreeMemory
+ NdisFreeSharedMemory
+ NdisImmediateReadPciSlotInformation
+ NdisImmediateReadPortUchar
+ NdisImmediateReadPortUshort
+ NdisImmediateReadPortUlong
+ NdisImmediateReadSharedMemory
+ NdisImmediateWritePciSlotInformation
+ NdisImmediateWritePortUchar
+ NdisImmediateWritePortUshort
+ NdisImmediateWritePortUlong
+ NdisImmediateWriteSharedMemory
+ NdisInitializeInterrupt
+ NdisInitializePacketPool
+ NdisInitializeRef
+ NdisInitializeTimer
+ NdisInitializeWrapper
+ NdisMapFile
+ NdisMapIoSpace
+ NdisOpenAdapter
+ NdisOpenConfiguration
+ NdisOpenFile
+ NdisPciAssignResources
+ NdisReadConfiguration
+ NdisReadBindingInformation
+ NdisReadEisaSlotInformation
+ NdisReadEisaSlotInformationEx
+ NdisReadMcaPosInformation
+ NdisReadNetworkAddress
+ NdisReadPciSlotInformation
+ NdisReferenceRef
+ NdisRegisterAdapter
+ NdisRegisterAdapterShutdownHandler
+ NdisRegisterMac
+ NdisRegisterProtocol
+ NdisReleaseAdapterResources
+ NdisRemoveInterrupt
+ NdisSetTimer
+ NdisSetupDmaTransfer
+ NdisTerminateWrapper
+ NdisUnchainBufferAtFront
+ NdisUnchainBufferAtBack
+ NdisUnmapFile
+ NdisUpdateSharedMemory
+ NdisWriteErrorLogEntry
+ NdisWritePciSlotInformation
+
+ NdisMAllocateMapRegisters
+ NdisMCancelTimer
+ NdisMDeregisterIoPortRange
+ NdisMFreeMapRegisters
+ NdisMIndicateStatus
+ NdisMIndicateStatusComplete
+ NdisMInitializeTimer
+ NdisMQueryInformationComplete
+ NdisMRegisterIoPortRange
+ NdisMRegisterMiniport
+ NdisMResetComplete
+ NdisMSendComplete
+ NdisMSendResourcesAvailable
+ NdisMSetAttributes
+ NdisMSetInformationComplete
+ NdisMTransferDataComplete
+
+ NdisAllocateSpinLock
+ NdisFreeSpinLock
+ NdisAcquireSpinLock
+ NdisReleaseSpinLock
+ NdisDprAcquireSpinLock
+ NdisDprReleaseSpinLock
+ NdisFreeBuffer
+ NdisQueryBuffer
+ NdisQueryBufferOffset
+ NDIS_BUFFER_TO_SPAN_PAGES
+ NdisGetBufferPhysicalArraySize
+ NdisEqualString
+
+ NdisMMapIoSpace
+ NdisMUnmapIoSpace
+ NdisMRegisterInterrupt
+ NdisMDeregisterInterrupt
+ NdisMSynchronizeWithInterrupt
+ NdisMAllocateSharedMemory
+ NdisMFreeSharedMemory
+ NdisMRegisterDmaChannel
+ NdisMDeregisterDmaChannel
+ NdisMReadDmaCounter
+
+ TrChangeFunctionalAddress
+ TrChangeGroupAddress
+ TrCreateFilter
+ TrDeleteFilter
+ TrDeleteFilterOpenAdapter
+ TrFilterAdjust
+ TrFilterDprIndicateReceive
+ TrFilterDprIndicateReceiveComplete
+ TrFilterIndicateReceive
+ TrFilterIndicateReceiveComplete
+ TrNoteFilterOpenAdapter
+ TrShouldAddressLoopBack
+
+ NdisMWanSendComplete
+ NdisMWanIndicateReceive
+ NdisMWanIndicateReceiveComplete
+
+ NdisMStartBufferPhysicalMapping
+ NdisMCompleteBufferPhysicalMapping
+ NdisSystemProcessorCount
+ NdisWriteConfiguration
+
+ NdisMRegisterAdapterShutdownHandler
+ NdisMDeregisterAdapterShutdownHandler
+
+ NdisMPciAssignResources
+ NdisOverrideBusNumber
+
+ NdisMQueryAdapterResources
diff --git a/private/ntos/ndis/ndis30/ndismac.h b/private/ntos/ndis/ndis30/ndismac.h
new file mode 100644
index 000000000..a5395883a
--- /dev/null
+++ b/private/ntos/ndis/ndis30/ndismac.h
@@ -0,0 +1,1218 @@
+typedef
+BOOLEAN
+(*PNDIS_INTERRUPT_SERVICE) (
+ IN PVOID InterruptContext
+ );
+
+typedef
+VOID
+(*PNDIS_DEFERRED_PROCESSING) (
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+
+typedef struct _NDIS_INTERRUPT {
+ PKINTERRUPT InterruptObject;
+ KSPIN_LOCK DpcCountLock;
+ PNDIS_INTERRUPT_SERVICE MacIsr; // Pointer to Mac ISR routine
+ PNDIS_DEFERRED_PROCESSING MacDpc; // Pointer to Mac DPC routine
+ KDPC InterruptDpc;
+ PVOID InterruptContext; // Pointer to context for calling
+ // adapters ISR and DPC.
+ UCHAR DpcCount;
+ BOOLEAN Removing; // TRUE if removing interrupt
+
+ //
+ // This is used to tell when all the Dpcs for the adapter are completed.
+ //
+ KEVENT DpcsCompletedEvent;
+
+} NDIS_INTERRUPT, *PNDIS_INTERRUPT;
+
+//
+// Ndis Adapter Information
+//
+
+typedef
+NDIS_STATUS
+(*PNDIS_ACTIVATE_CALLBACK) (
+ IN NDIS_HANDLE NdisAdatperHandle,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN ULONG DmaChannel
+ );
+
+typedef struct _NDIS_PORT_DESCRIPTOR {
+ ULONG InitialPort;
+ ULONG NumberOfPorts;
+ PVOID *PortOffset;
+} NDIS_PORT_DESCRIPTOR, *PNDIS_PORT_DESCRIPTOR;
+
+typedef struct _NDIS_ADAPTER_INFORMATION {
+ ULONG DmaChannel;
+ BOOLEAN Master;
+ BOOLEAN Dma32BitAddresses;
+ PNDIS_ACTIVATE_CALLBACK ActivateCallback;
+ NDIS_INTERFACE_TYPE AdapterType;
+ ULONG PhysicalMapRegistersNeeded;
+ ULONG MaximumPhysicalMapping;
+ ULONG NumberOfPortDescriptors;
+ NDIS_PORT_DESCRIPTOR PortDescriptors[1]; // as many as needed
+} NDIS_ADAPTER_INFORMATION, *PNDIS_ADAPTER_INFORMATION;
+
+//
+// Function types for NDIS_MAC_CHARACTERISTICS
+//
+
+typedef
+NDIS_STATUS
+(*OPEN_ADAPTER_HANDLER) (
+ 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
+ );
+
+typedef
+NDIS_STATUS
+(*CLOSE_ADAPTER_HANDLER) (
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+typedef
+NDIS_STATUS
+(*SEND_HANDLER) (
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+typedef
+NDIS_STATUS
+(*TRANSFER_DATA_HANDLER) (
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+typedef
+NDIS_STATUS
+(*RESET_HANDLER) (
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+typedef
+NDIS_STATUS
+(*REQUEST_HANDLER) (
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+typedef
+NDIS_STATUS
+(*QUERY_GLOBAL_STATISTICS_HANDLER) (
+ IN NDIS_HANDLE MacAdapterContext,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+typedef
+VOID
+(*UNLOAD_MAC_HANDLER) (
+ IN NDIS_HANDLE MacMacContext
+ );
+
+typedef
+NDIS_STATUS
+(*ADD_ADAPTER_HANDLER) (
+ IN NDIS_HANDLE MacMacContext,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN PNDIS_STRING AdapterName
+ );
+
+typedef
+VOID
+(*REMOVE_ADAPTER_HANDLER) (
+ IN NDIS_HANDLE MacAdapterContext
+ );
+
+
+typedef struct _NDIS_MAC_CHARACTERISTICS {
+ UCHAR MajorNdisVersion;
+ UCHAR MinorNdisVersion;
+ UINT Reserved;
+ OPEN_ADAPTER_HANDLER OpenAdapterHandler;
+ CLOSE_ADAPTER_HANDLER CloseAdapterHandler;
+ SEND_HANDLER SendHandler;
+ TRANSFER_DATA_HANDLER TransferDataHandler;
+ RESET_HANDLER ResetHandler;
+ REQUEST_HANDLER RequestHandler;
+ QUERY_GLOBAL_STATISTICS_HANDLER QueryGlobalStatisticsHandler;
+ UNLOAD_MAC_HANDLER UnloadMacHandler;
+ ADD_ADAPTER_HANDLER AddAdapterHandler;
+ REMOVE_ADAPTER_HANDLER RemoveAdapterHandler;
+ NDIS_STRING Name;
+} NDIS_MAC_CHARACTERISTICS, *PNDIS_MAC_CHARACTERISTICS;
+
+
+//
+// Function types for NDIS_PROTOCOL_CHARACTERISTICS
+//
+//
+
+typedef
+VOID
+(*OPEN_ADAPTER_COMPLETE_HANDLER) (
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status,
+ IN NDIS_STATUS OpenErrorStatus
+ );
+
+typedef
+VOID
+(*CLOSE_ADAPTER_COMPLETE_HANDLER) (
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status
+ );
+
+typedef
+VOID
+(*RESET_COMPLETE_HANDLER) (
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status
+ );
+
+typedef
+VOID
+(*REQUEST_COMPLETE_HANDLER) (
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS Status
+ );
+
+typedef
+VOID
+(*STATUS_HANDLER) (
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ );
+
+typedef
+VOID
+(*STATUS_COMPLETE_HANDLER) (
+ IN NDIS_HANDLE ProtocolBindingContext
+ );
+
+typedef struct _NDIS_PROTOCOL_CHARACTERISTICS {
+ UCHAR MajorNdisVersion;
+ UCHAR MinorNdisVersion;
+ UINT Reserved;
+ OPEN_ADAPTER_COMPLETE_HANDLER OpenAdapterCompleteHandler;
+ CLOSE_ADAPTER_COMPLETE_HANDLER CloseAdapterCompleteHandler;
+ SEND_COMPLETE_HANDLER SendCompleteHandler;
+ TRANSFER_DATA_COMPLETE_HANDLER TransferDataCompleteHandler;
+ RESET_COMPLETE_HANDLER ResetCompleteHandler;
+ REQUEST_COMPLETE_HANDLER RequestCompleteHandler;
+ RECEIVE_HANDLER ReceiveHandler;
+ RECEIVE_COMPLETE_HANDLER ReceiveCompleteHandler;
+ STATUS_HANDLER StatusHandler;
+ STATUS_COMPLETE_HANDLER StatusCompleteHandler;
+ NDIS_STRING Name;
+} NDIS_PROTOCOL_CHARACTERISTICS, *PNDIS_PROTOCOL_CHARACTERISTICS;
+
+//
+// MAC specific considerations.
+//
+
+struct _NDIS_WRAPPER_HANDLE {
+
+ //
+ // These store the PDRIVER_OBJECT that
+ // the MAC passes to NdisInitializeWrapper until it can be
+ // used by NdisRegisterMac and NdisTerminateWrapper.
+ //
+
+ PDRIVER_OBJECT NdisWrapperDriver;
+
+ HANDLE NdisWrapperConfigurationHandle;
+
+};
+
+
+
+
+//
+// one of these per MAC
+//
+
+struct _NDIS_MAC_BLOCK {
+ PNDIS_ADAPTER_BLOCK AdapterQueue; // queue of adapters for this MAC
+ NDIS_HANDLE MacMacContext; // Context for calling MACUnload and
+ // MACAddAdapter.
+
+ REFERENCE Ref; // contains spinlock for AdapterQueue
+ UINT Length; // of this NDIS_MAC_BLOCK structure
+ NDIS_MAC_CHARACTERISTICS MacCharacteristics; // handler addresses
+ PNDIS_WRAPPER_HANDLE NdisMacInfo; // Mac information.
+ PNDIS_MAC_BLOCK NextMac;
+ KEVENT AdaptersRemovedEvent; // used to find when all adapters are gone.
+ BOOLEAN Unloading; // TRUE if unloading
+
+ //
+ // Extensions added for NT 3.5 support
+ //
+ PCM_RESOURCE_LIST PciAssignedResources;
+};
+
+//
+// one of these per adapter registered on a MAC
+//
+
+struct _NDIS_ADAPTER_BLOCK {
+ PDEVICE_OBJECT DeviceObject; // created by NdisRegisterAdapter
+ PNDIS_MAC_BLOCK MacHandle; // pointer to our MAC block
+ NDIS_HANDLE MacAdapterContext; // context when calling MacOpenAdapter
+ NDIS_STRING AdapterName; // how NdisOpenAdapter refers to us
+ PNDIS_OPEN_BLOCK OpenQueue; // queue of opens for this adapter
+ PNDIS_ADAPTER_BLOCK NextAdapter; // used by MAC's AdapterQueue
+ REFERENCE Ref; // contains spinlock for OpenQueue
+ BOOLEAN BeingRemoved; // TRUE if adapter is being removed
+
+ //
+ // Resource information
+ //
+ PCM_RESOURCE_LIST Resources;
+
+ //
+ // Obsolete field.
+ //
+ ULONG NotUsed;
+
+ //
+ // Wrapper context.
+ //
+ PVOID WrapperContext;
+
+ //
+ // contains adapter information
+ //
+ ULONG BusNumber;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG ChannelNumber;
+ NDIS_INTERFACE_TYPE AdapterType;
+ BOOLEAN Master;
+ ULONG PhysicalMapRegistersNeeded;
+ ULONG MaximumPhysicalMapping;
+ ULONG InitialPort;
+ ULONG NumberOfPorts;
+
+ //
+ // Holds the mapping for ports, if needed.
+ //
+ PUCHAR InitialPortMapping;
+
+ //
+ // TRUE if InitialPortMapping was mapped with NdisMapIoSpace.
+ //
+ BOOLEAN InitialPortMapped;
+
+ //
+ // This is the offset added to the port passed to NdisXXXPort to
+ // get to the real value to be passed to the NDIS_XXX_PORT macros.
+ // It equals InitialPortMapping - InitialPort; that is, the
+ // mapped "address" of port 0, even if we didn't actually
+ // map port 0.
+ //
+ PUCHAR PortOffset;
+
+ //
+ // Holds the map registers for this adapter.
+ //
+ PMAP_REGISTER_ENTRY MapRegisters;
+
+ //
+ // These two are used temporarily while allocating
+ // the map registers.
+ //
+ KEVENT AllocationEvent;
+ UINT CurrentMapRegister;
+ PADAPTER_OBJECT SystemAdapterObject;
+};
+
+//
+// one of these per protocol registered
+//
+
+struct _NDIS_PROTOCOL_BLOCK {
+ PNDIS_OPEN_BLOCK OpenQueue; // queue of opens for this protocol
+ REFERENCE Ref; // contains spinlock for OpenQueue
+ UINT Length; // of this NDIS_PROTOCOL_BLOCK struct
+ NDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics; // handler addresses
+};
+
+//
+// one of these per open on an adapter/protocol
+//
+
+struct _NDIS_OPEN_BLOCK {
+ PNDIS_MAC_BLOCK MacHandle; // pointer to our MAC
+ NDIS_HANDLE MacBindingHandle; // context when calling MacXX funcs
+ PNDIS_ADAPTER_BLOCK AdapterHandle; // pointer to our adapter
+ PNDIS_PROTOCOL_BLOCK ProtocolHandle; // pointer to our protocol
+ NDIS_HANDLE ProtocolBindingContext; // context when calling ProtXX funcs
+ PNDIS_OPEN_BLOCK AdapterNextOpen; // used by adapter's OpenQueue
+ PNDIS_OPEN_BLOCK ProtocolNextOpen; // used by protocol's OpenQueue
+ PFILE_OBJECT FileObject; // created by operating system
+ BOOLEAN Closing; // TRUE when removing this struct
+ NDIS_HANDLE CloseRequestHandle; // 0 indicates an internal close
+ NDIS_SPIN_LOCK SpinLock; // guards Closing
+
+ //
+ // These are optimizations for getting to MAC routines. They are not
+ // necessary, but are here to save a dereference through the MAC block.
+ //
+
+ SEND_HANDLER SendHandler;
+ TRANSFER_DATA_HANDLER TransferDataHandler;
+
+ //
+ // These are optimizations for getting to PROTOCOL routines. They are not
+ // necessary, but are here to save a dereference through the PROTOCOL block.
+ //
+
+ SEND_COMPLETE_HANDLER SendCompleteHandler;
+ TRANSFER_DATA_COMPLETE_HANDLER TransferDataCompleteHandler;
+ RECEIVE_HANDLER ReceiveHandler;
+ RECEIVE_COMPLETE_HANDLER ReceiveCompleteHandler;
+
+ //
+ // Extentions to the OPEN_BLOCK since Product 1.
+ //
+ RECEIVE_HANDLER PostNt31ReceiveHandler;
+ RECEIVE_COMPLETE_HANDLER PostNt31ReceiveCompleteHandler;
+ PNDIS_OPEN_BLOCK NextGlobalOpen;
+
+};
+
+//
+// Routines to access packet flags
+//
+
+/*++
+
+VOID
+NdisSetSendFlags(
+ IN PNDIS_PACKET Packet,
+ IN UINT Flags
+ );
+
+--*/
+
+#define NdisSetSendFlags(_Packet,_Flags) \
+ (_Packet)->Private.Flags = (_Flags)
+
+/*++
+
+VOID
+NdisQuerySendFlags(
+ IN PNDIS_PACKET Packet,
+ OUT PUINT Flags
+ );
+
+--*/
+
+#define NdisQuerySendFlags(_Packet,_Flags) \
+ *(_Flags) = (_Packet)->Private.Flags
+
+
+//
+// Packet Pool
+//
+
+EXPORT
+VOID
+NdisAllocatePacketPool(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE PoolHandle,
+ IN UINT NumberOfDescriptors,
+ IN UINT ProtocolReservedLength
+ );
+
+// VOID
+// NdisFreePacketPool(
+// IN NDIS_HANDLE PoolHandle
+// );
+#define NdisFreePacketPool(PoolHandle) {\
+ NdisFreeSpinLock(&((PNDIS_PACKET_POOL)PoolHandle)->SpinLock);\
+ ExFreePool(PoolHandle); \
+}
+
+EXPORT
+VOID
+NdisAllocatePacket(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_PACKET * Packet,
+ IN NDIS_HANDLE PoolHandle
+ );
+
+// VOID
+// NdisFreePacket(
+// IN PNDIS_PACKET Packet
+// );
+#define NdisFreePacket(Packet) {\
+ NdisAcquireSpinLock(&(Packet)->Private.Pool->SpinLock); \
+ (Packet)->Private.Head = (PNDIS_BUFFER)(Packet)->Private.Pool->FreeList; \
+ (Packet)->Private.Pool->FreeList = (Packet); \
+ NdisReleaseSpinLock(&(Packet)->Private.Pool->SpinLock); \
+}
+
+
+// VOID
+// NdisReinitializePacket(
+// IN OUT PNDIS_PACKET Packet
+// );
+#define NdisReinitializePacket(Packet) { \
+ (Packet)->Private.Head = (PNDIS_BUFFER)NULL; \
+ (Packet)->Private.ValidCounts = FALSE; \
+}
+
+
+EXPORT
+VOID
+NdisInitializeTimer(
+ IN OUT PNDIS_TIMER Timer,
+ IN PNDIS_TIMER_FUNCTION TimerFunction,
+ IN PVOID FunctionContext
+ );
+
+/*++
+VOID
+NdisCancelTimer(
+ IN PNDIS_TIMER Timer,
+ OUT PBOOLEAN TimerCancelled
+ )
+--*/
+#define NdisCancelTimer(NdisTimer,TimerCancelled) \
+ (*(TimerCancelled) = KeCancelTimer(&((NdisTimer)->Timer)))
+
+//
+// Shared memory
+//
+
+EXPORT
+VOID
+NdisAllocateSharedMemory(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Length,
+ IN BOOLEAN Cached,
+ OUT PVOID *VirtualAddress,
+ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress
+ );
+
+EXPORT
+VOID
+NdisFreeSharedMemory(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Length,
+ IN BOOLEAN Cached,
+ IN PVOID VirtualAddress,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
+ );
+
+
+//
+// Requests used by Protocol Modules
+//
+
+EXPORT
+VOID
+NdisRegisterProtocol(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE NdisProtocolHandle,
+ IN PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics,
+ IN UINT CharacteristicsLength
+ );
+
+EXPORT
+VOID
+NdisDeregisterProtocol(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisProtocolHandle
+ );
+
+
+EXPORT
+VOID
+NdisOpenAdapter(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PNDIS_HANDLE NdisBindingHandle,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE NdisProtocolHandle,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_STRING AdapterName,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingInformation OPTIONAL
+ );
+
+
+EXPORT
+VOID
+NdisCloseAdapter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle
+ );
+
+
+// VOID
+// NdisSend(
+// OUT PNDIS_STATUS Status,
+// IN NDIS_HANDLE NdisBindingHandle,
+// IN PNDIS_PACKET Packet
+// );
+#define NdisSend(Status, \
+ NdisBindingHandle, \
+ Packet \
+ ) \
+{\
+ *(Status) = \
+ (((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->SendHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->MacBindingHandle, \
+ (Packet)); \
+}
+
+
+// VOID
+// NdisTransferData(
+// OUT PNDIS_STATUS Status,
+// IN NDIS_HANDLE NdisBindingHandle,
+// IN NDIS_HANDLE MacReceiveContext,
+// IN UINT ByteOffset,
+// IN UINT BytesToTransfer,
+// IN OUT PNDIS_PACKET Packet,
+// OUT PUINT BytesTransferred
+// );
+#define NdisTransferData( \
+ Status, \
+ NdisBindingHandle, \
+ MacReceiveContext, \
+ ByteOffset, \
+ BytesToTransfer, \
+ Packet, \
+ BytesTransferred \
+ ) \
+{\
+ *(Status) = \
+ (((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->TransferDataHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->MacBindingHandle, \
+ (MacReceiveContext), \
+ (ByteOffset), \
+ (BytesToTransfer), \
+ (Packet), \
+ (BytesTransferred)); \
+}
+
+
+// VOID
+// NdisReset(
+// OUT PNDIS_STATUS Status,
+// IN NDIS_HANDLE NdisBindingHandle
+// );
+#define NdisReset( \
+ Status, \
+ NdisBindingHandle \
+ ) \
+{ \
+ *(Status) = \
+ (((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->MacHandle->MacCharacteristics.ResetHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->MacBindingHandle); \
+}
+
+// VOID
+// NdisRequest(
+// OUT PNDIS_STATUS Status,
+// IN NDIS_HANDLE NdisBindingHandle,
+// IN PNDIS_REQUEST NdisRequest
+// );
+#define NdisRequest( \
+ Status,\
+ NdisBindingHandle, \
+ NdisRequest \
+ ) \
+{ \
+ *(Status) = \
+ (((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->MacHandle->MacCharacteristics.RequestHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->MacBindingHandle, \
+ (NdisRequest)); \
+}
+
+//
+// DMA operations.
+//
+
+EXPORT
+VOID
+NdisAllocateDmaChannel(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE NdisDmaHandle,
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PNDIS_DMA_DESCRIPTION DmaDescription,
+ IN ULONG MaximumLength
+ );
+
+EXPORT
+VOID
+NdisFreeDmaChannel(
+ IN PNDIS_HANDLE NdisDmaHandle
+ );
+
+EXPORT
+VOID
+NdisSetupDmaTransfer(
+ OUT PNDIS_STATUS Status,
+ IN PNDIS_HANDLE NdisDmaHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG Offset,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ );
+
+EXPORT
+VOID
+NdisCompleteDmaTransfer(
+ OUT PNDIS_STATUS Status,
+ IN PNDIS_HANDLE NdisDmaHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG Offset,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ );
+
+/*++
+ULONG
+NdisReadDmaCounter(
+ IN NDIS_HANDLE NdisDmaHandle
+ )
+--*/
+
+#define NdisReadDmaCounter(_NdisDmaHandle) \
+ HalReadDmaCounter(((PNDIS_DMA_BLOCK)(_NdisDmaHandle))->SystemAdapterObject)
+
+//
+// Requests Used by MAC Drivers
+//
+
+EXPORT
+VOID
+NdisRegisterMac(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE NdisMacHandle,
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN NDIS_HANDLE MacMacContext,
+ IN PNDIS_MAC_CHARACTERISTICS MacCharacteristics,
+ IN UINT CharacteristicsLength
+ );
+
+EXPORT
+VOID
+NdisDeregisterMac(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisMacHandle
+ );
+
+
+EXPORT
+NDIS_STATUS
+NdisRegisterAdapter(
+ OUT PNDIS_HANDLE NdisAdapterHandle,
+ IN NDIS_HANDLE NdisMacHandle,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN PNDIS_STRING AdapterName,
+ IN PVOID AdapterInformation
+ );
+
+EXPORT
+NDIS_STATUS
+NdisDeregisterAdapter(
+ IN NDIS_HANDLE NdisAdapterHandle
+ );
+
+EXPORT
+VOID
+NdisRegisterAdapterShutdownHandler(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PVOID ShutdownContext,
+ IN ADAPTER_SHUTDOWN_HANDLER ShutdownHandler
+ );
+
+EXPORT
+VOID
+NdisDeregisterAdapterShutdownHandler(
+ IN NDIS_HANDLE NdisAdapterHandle
+ );
+
+EXPORT
+VOID
+NdisReleaseAdapterResources(
+ IN NDIS_HANDLE NdisAdapterHandle
+ );
+
+EXPORT
+VOID
+NdisCompleteOpenAdapter(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS Status,
+ IN NDIS_STATUS OpenErrorStatus
+ );
+
+
+EXPORT
+VOID
+NdisCompleteCloseAdapter(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS Status
+ );
+
+
+// VOID
+// NdisCompleteSend(
+// IN NDIS_HANDLE NdisBindingContext,
+// IN PNDIS_PACKET Packet,
+// IN NDIS_STATUS Status
+// );
+#define NdisCompleteSend( \
+ NdisBindingContext, \
+ Packet, \
+ Status \
+ ) \
+{\
+ (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->SendCompleteHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext, \
+ (Packet), \
+ (Status)); \
+}
+
+
+// VOID
+// NdisCompleteTransferData(
+// IN NDIS_HANDLE NdisBindingContext,
+// IN PNDIS_PACKET Packet,
+// IN NDIS_STATUS Status,
+// IN UINT BytesTransferred
+// );
+#define NdisCompleteTransferData( \
+ NdisBindingContext, \
+ Packet, \
+ Status, \
+ BytesTransferred \
+ ) \
+{\
+ (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->TransferDataCompleteHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext, \
+ (Packet), \
+ (Status), \
+ (BytesTransferred)); \
+}
+
+// VOID
+// NdisCompleteReset(
+// IN NDIS_HANDLE NdisBindingContext,
+// IN NDIS_STATUS Status
+// );
+#define NdisCompleteReset( \
+ NdisBindingContext, \
+ Status \
+ ) \
+{ \
+ (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolHandle->ProtocolCharacteristics.ResetCompleteHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext, \
+ Status); \
+}
+
+
+// VOID
+// NdisCompleteRequest(
+// IN NDIS_HANDLE NdisBindingContext,
+// IN PNDIS_REQUEST NdisRequest,
+// IN NDIS_STATUS Status
+// );
+#define NdisCompleteRequest( \
+ NdisBindingContext, \
+ NdisRequest, \
+ Status) \
+{ \
+ (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolHandle->ProtocolCharacteristics.RequestCompleteHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext, \
+ NdisRequest, \
+ Status); \
+}
+
+// VOID
+// NdisIndicateReceive(
+// OUT PNDIS_STATUS Status,
+// IN NDIS_HANDLE NdisBindingContext,
+// IN NDIS_HANDLE MacReceiveContext,
+// IN PVOID HeaderBuffer,
+// IN UINT HeaderBufferSize,
+// IN PVOID LookaheadBuffer,
+// IN UINT LookaheadBufferSize,
+// IN UINT PacketSize
+// );
+#define NdisIndicateReceive( \
+ Status, \
+ NdisBindingContext, \
+ MacReceiveContext, \
+ HeaderBuffer, \
+ HeaderBufferSize, \
+ LookaheadBuffer, \
+ LookaheadBufferSize, \
+ PacketSize \
+ ) \
+{\
+ KIRQL oldIrql;\
+ KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );\
+ *(Status) = \
+ (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->PostNt31ReceiveHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext, \
+ (MacReceiveContext), \
+ (HeaderBuffer), \
+ (HeaderBufferSize), \
+ (LookaheadBuffer), \
+ (LookaheadBufferSize), \
+ (PacketSize)); \
+ KeLowerIrql( oldIrql );\
+}
+
+//
+// Used by the filter packages for indicating receives
+//
+
+#define FilterIndicateReceive( \
+ Status, \
+ NdisBindingContext, \
+ MacReceiveContext, \
+ HeaderBuffer, \
+ HeaderBufferSize, \
+ LookaheadBuffer, \
+ LookaheadBufferSize, \
+ PacketSize \
+ ) \
+{\
+ *(Status) = \
+ (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->PostNt31ReceiveHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext, \
+ (MacReceiveContext), \
+ (HeaderBuffer), \
+ (HeaderBufferSize), \
+ (LookaheadBuffer), \
+ (LookaheadBufferSize), \
+ (PacketSize)); \
+}
+
+
+// VOID
+// NdisIndicateReceiveComplete(
+// IN NDIS_HANDLE NdisBindingContext
+// );
+#define NdisIndicateReceiveComplete(NdisBindingContext) \
+{\
+ KIRQL oldIrql;\
+ KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );\
+ (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->PostNt31ReceiveCompleteHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext);\
+ KeLowerIrql( oldIrql );\
+}
+
+//
+// Used by the filter packages for indicating receive completion
+//
+
+#define FilterIndicateReceiveComplete(NdisBindingContext) \
+{\
+ (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->PostNt31ReceiveCompleteHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext);\
+}
+
+// VOID
+// NdisIndicateStatus(
+// IN NDIS_HANDLE NdisBindingContext,
+// IN NDIS_STATUS GeneralStatus,
+// IN PVOID StatusBuffer,
+// IN UINT StatusBufferSize
+// );
+#define NdisIndicateStatus( \
+ NdisBindingContext, \
+ GeneralStatus, \
+ StatusBuffer, \
+ StatusBufferSize \
+ ) \
+{\
+ (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolHandle->ProtocolCharacteristics.StatusHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext, \
+ (GeneralStatus), \
+ (StatusBuffer), \
+ (StatusBufferSize)); \
+}
+
+
+// VOID
+// NdisIndicateStatusComplete(
+// IN NDIS_HANDLE NdisBindingContext
+// );
+#define NdisIndicateStatusComplete( \
+ NdisBindingContext \
+ ) \
+{ \
+ (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolHandle->ProtocolCharacteristics.StatusCompleteHandler) ( \
+ ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext); \
+}
+
+EXPORT
+VOID
+NdisCompleteQueryStatistics(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS Status
+ );
+
+//
+// Interlocked support functions
+//
+
+/*++
+
+VOID
+NdisInterlockedAddUlong(
+ IN PULONG Addend,
+ IN ULONG Increment,
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+--*/
+
+#define NdisInterlockedAddUlong(_Addend, _Increment, _SpinLock) \
+ ExInterlockedAddUlong(_Addend, _Increment, &(_SpinLock)->SpinLock)
+
+/*++
+
+PLIST_ENTRY
+NdisInterlockedInsertHeadList(
+ IN PLIST_ENTRY ListHead,
+ IN PLIST_ENTRY ListEntry,
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+--*/
+
+#define NdisInterlockedInsertHeadList(_ListHead, _ListEntry, _SpinLock) \
+ ExInterlockedInsertHeadList(_ListHead, _ListEntry, &(_SpinLock)->SpinLock)
+
+/*++
+
+PLIST_ENTRY
+NdisInterlockedInsertTailList(
+ IN PLIST_ENTRY ListHead,
+ IN PLIST_ENTRY ListEntry,
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+--*/
+
+#define NdisInterlockedInsertTailList(_ListHead, _ListEntry, _SpinLock) \
+ ExInterlockedInsertTailList(_ListHead, _ListEntry, &(_SpinLock)->SpinLock)
+
+/*++
+
+PLIST_ENTRY
+NdisInterlockedRemoveHeadList(
+ IN PLIST_ENTRY ListHead,
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+--*/
+
+#define NdisInterlockedRemoveHeadList(_ListHead, _SpinLock) \
+ ExInterlockedRemoveHeadList(_ListHead, &(_SpinLock)->SpinLock)
+
+/*++
+
+VOID
+NdisAdjustBufferLength(
+ IN PNDIS_BUFFER Buffer,
+ IN UINT Length
+ );
+
+--*/
+
+#define NdisAdjustBufferLength(Buffer, Length) \
+ (((Buffer)->ByteCount) = (Length))
+
+//
+// Operating System Requests
+//
+
+EXPORT
+VOID
+NdisMapIoSpace(
+ OUT PNDIS_STATUS Status,
+ OUT PVOID * VirtualAddress,
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress,
+ IN UINT Length
+ );
+
+#if defined(_ALPHA_)
+
+/*++
+VOID
+NdisUnmapIoSpace(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PVOID VirtualAddress,
+ IN UINT Length
+ )
+--*/
+#define NdisUnmapIoSpace(Handle,VirtualAddress,Length) {}
+
+#else
+
+/*++
+VOID
+NdisUnmapIoSpace(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PVOID VirtualAddress,
+ IN UINT Length
+ )
+--*/
+#define NdisUnmapIoSpace(Handle,VirtualAddress,Length) \
+ MmUnmapIoSpace((VirtualAddress), (Length));
+
+#endif
+
+EXPORT
+VOID
+NdisInitializeInterrupt(
+ OUT PNDIS_STATUS Status,
+ IN OUT PNDIS_INTERRUPT Interrupt,
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PNDIS_INTERRUPT_SERVICE InterruptServiceRoutine,
+ IN PVOID InterruptContext,
+ IN PNDIS_DEFERRED_PROCESSING DeferredProcessingRoutine,
+ IN UINT InterruptVector,
+ IN UINT InterruptLevel,
+ IN BOOLEAN SharedInterrupt,
+ IN NDIS_INTERRUPT_MODE InterruptMode
+ );
+
+EXPORT
+VOID
+NdisRemoveInterrupt(
+ IN PNDIS_INTERRUPT Interrupt
+ );
+
+/*++
+BOOLEAN
+NdisSynchronizeWithInterrupt(
+ IN PNDIS_INTERRUPT Interrupt,
+ IN PVOID SynchronizeFunction,
+ IN PVOID SynchronizeContext
+ )
+--*/
+
+#define NdisSynchronizeWithInterrupt(Interrupt,Function,Context) \
+ KeSynchronizeExecution( \
+ (Interrupt)->InterruptObject,\
+ (PKSYNCHRONIZE_ROUTINE)Function,\
+ Context \
+ )
+
+//
+// Physical Mapping
+//
+
+//
+// VOID
+// NdisStartBufferPhysicalMapping(
+// IN NDIS_HANDLE NdisAdapterHandle,
+// IN PNDIS_BUFFER Buffer,
+// IN ULONG PhysicalMapRegister,
+// IN BOOLEAN WriteToDevice,
+// OUT PNDIS_PHYSICAL_ADDRESS_UNIT PhysicalAddressArray,
+// OUT PUINT ArraySize
+// );
+//
+
+#define NdisStartBufferPhysicalMapping( \
+ _NdisAdapterHandle, \
+ _Buffer, \
+ _PhysicalMapRegister, \
+ _Write, \
+ _PhysicalAddressArray, \
+ _ArraySize \
+ ) \
+{ \
+ PNDIS_ADAPTER_BLOCK _AdaptP = (PNDIS_ADAPTER_BLOCK)(_NdisAdapterHandle); \
+ PHYSICAL_ADDRESS _LogicalAddress; \
+ PUCHAR _VirtualAddress; \
+ ULONG _LengthRemaining; \
+ ULONG _LengthMapped; \
+ UINT _CurrentArrayLocation; \
+ _VirtualAddress = MmGetMdlVirtualAddress(_Buffer); \
+ _LengthRemaining = MmGetMdlByteCount(_Buffer); \
+ _CurrentArrayLocation = 0; \
+ while (_LengthRemaining > 0) { \
+ _LengthMapped = _LengthRemaining; \
+ _LogicalAddress = IoMapTransfer( \
+ NULL, \
+ _Buffer, \
+ _AdaptP->MapRegisters[_PhysicalMapRegister].MapRegister, \
+ _VirtualAddress, \
+ &_LengthMapped, \
+ _Write); \
+ _PhysicalAddressArray[_CurrentArrayLocation].PhysicalAddress = _LogicalAddress; \
+ _PhysicalAddressArray[_CurrentArrayLocation].Length = _LengthMapped; \
+ _LengthRemaining -= _LengthMapped; \
+ _VirtualAddress += _LengthMapped; \
+ ++_CurrentArrayLocation; \
+ } \
+ _AdaptP->MapRegisters[_PhysicalMapRegister].WriteToDevice = _Write; \
+ *(_ArraySize) = _CurrentArrayLocation; \
+}
+
+
+//
+// VOID
+// NdisCompleteBufferPhysicalMapping(
+// IN NDIS_HANDLE NdisAdapterHandle,
+// IN PNDIS_BUFFER Buffer,
+// IN ULONG PhysicalMapRegister
+// );
+//
+
+#define NdisCompleteBufferPhysicalMapping( \
+ NdisAdapterHandle, \
+ Buffer, \
+ PhysicalMapRegister \
+ ) \
+{ \
+ PNDIS_ADAPTER_BLOCK _AdaptP = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle; \
+ IoFlushAdapterBuffers( \
+ NULL, \
+ Buffer, \
+ _AdaptP->MapRegisters[PhysicalMapRegister].MapRegister, \
+ MmGetMdlVirtualAddress(Buffer), \
+ MmGetMdlByteCount(Buffer), \
+ _AdaptP->MapRegisters[PhysicalMapRegister].WriteToDevice); \
+}
diff --git a/private/ntos/ndis/ndis30/ndismain.h b/private/ntos/ndis/ndis30/ndismain.h
new file mode 100644
index 000000000..b96557a19
--- /dev/null
+++ b/private/ntos/ndis/ndis30/ndismain.h
@@ -0,0 +1,1976 @@
+//
+// Indicate that we're building for NT. NDIS_NT is always used for
+// miniport builds.
+//
+
+#define NDIS_NT 1
+
+#if defined(NDIS_DOS)
+#undef NDIS_DOS
+#endif
+
+
+//
+// Define status codes and event log codes.
+//
+
+#include <ntstatus.h>
+#include <netevent.h>
+
+//
+// Define a couple of extra types.
+//
+
+#if !defined(_WINDEF_) // these are defined in windows.h too
+typedef signed int INT, *PINT;
+typedef unsigned int UINT, *PUINT;
+#endif
+
+typedef UNICODE_STRING NDIS_STRING, *PNDIS_STRING;
+
+
+//
+// Portability extentions
+//
+
+#define NDIS_INIT_FUNCTION(_F) alloc_text(INIT,_F)
+#define NDIS_PAGABLE_FUNCTION(_F)
+
+
+//
+// This file contains the definition of an NDIS_OID as
+// well as #defines for all the current OID values.
+//
+
+#include <ntddndis.h>
+
+
+//
+// Ndis defines for configuration manager data structures
+//
+
+typedef CM_MCA_POS_DATA NDIS_MCA_POS_DATA, *PNDIS_MCA_POS_DATA;
+typedef CM_EISA_SLOT_INFORMATION NDIS_EISA_SLOT_INFORMATION,
+ *PNDIS_EISA_SLOT_INFORMATION;
+typedef CM_EISA_FUNCTION_INFORMATION NDIS_EISA_FUNCTION_INFORMATION,
+ *PNDIS_EISA_FUNCTION_INFORMATION;
+
+//
+// Define an exported function.
+//
+#if defined(NDIS_WRAPPER)
+#define EXPORT
+#else
+#define EXPORT DECLSPEC_IMPORT
+#endif
+
+//
+// Memory manipulation functions.
+//
+
+#define NdisMoveMemory(Destination,Source,Length) RtlCopyMemory(Destination,Source,Length)
+#define NdisZeroMemory(Destination,Length) RtlZeroMemory(Destination,Length)
+#define NdisRetrieveUlong(Destination,Source) RtlRetrieveUlong(Destination,Source)
+#define NdisStoreUlong(Destination,Value) RtlStoreUlong(Destination,Value)
+
+#define NDIS_STRING_CONST(x) {sizeof(L##x)-2, sizeof(L##x), L##x}
+
+//
+// On a MIPS machine, I/O mapped memory can't be accessed with
+// the Rtl routines.
+//
+
+#if defined(_M_IX86)
+
+#define NdisMoveMappedMemory(Destination,Source,Length) RtlCopyMemory(Destination,Source,Length)
+#define NdisZeroMappedMemory(Destination,Length) RtlZeroMemory(Destination,Length)
+
+#elif defined(_M_MRX000)
+
+#define NdisMoveMappedMemory(Destination,Source,Length) \
+{ \
+ PUCHAR _Src = (Source); \
+ PUCHAR _Dest = (Destination); \
+ PUCHAR _End = _Dest + (Length); \
+ while (_Dest < _End) { \
+ *_Dest++ = *_Src++; \
+ } \
+}
+#define NdisZeroMappedMemory(Destination,Length) \
+{ \
+ PUCHAR _Dest = (Destination); \
+ PUCHAR _End = _Dest + (Length); \
+ while (_Dest < _End) { \
+ *_Dest++ = 0; \
+ } \
+}
+
+#elif defined(_PPC_)
+
+#define NdisMoveMappedMemory(Destination,Source,Length) RtlCopyMemory32( Destination, Source, Length );
+#define NdisZeroMappedMemory(Destination,Length) \
+{ \
+ PUCHAR _Dest = (Destination); \
+ PUCHAR _End = _Dest + (Length); \
+ while (_Dest < _End) { \
+ *_Dest++ = 0; \
+ } \
+}
+
+#elif defined(_ALPHA_)
+
+#define NdisMoveMappedMemory(Destination,Source,Length) \
+{ \
+ PUCHAR _Src = (Source); \
+ PUCHAR _Dest = (Destination); \
+ PUCHAR _End = _Dest + (Length); \
+ while (_Dest < _End) \
+ { \
+ NdisReadRegisterUchar(_Src, _Dest); \
+ _Src++; \
+ _Dest++; \
+ } \
+}
+#define NdisZeroMappedMemory(Destination,Length) \
+{ \
+ PUCHAR _Dest = (Destination); \
+ PUCHAR _End = _Dest + (Length); \
+ while (_Dest < _End) { \
+ NdisWriteRegisterUchar(_Dest,0); \
+ _Dest++; \
+ } \
+}
+
+#endif
+
+
+//
+// On Mips and Intel systems, these are the same. On Alpha, they are different.
+//
+
+#if defined(_ALPHA_)
+
+#define NdisMoveToMappedMemory(Destination,Source,Length) WRITE_REGISTER_BUFFER_UCHAR(Destination,Source,Length)
+#define NdisMoveFromMappedMemory(Destination,Source,Length) READ_REGISTER_BUFFER_UCHAR(Source,Destination,Length)
+
+#else
+
+#define NdisMoveToMappedMemory(Destination,Source,Length) NdisMoveMappedMemory(Destination,Source,Length)
+#define NdisMoveFromMappedMemory(Destination,Source,Length) NdisMoveMappedMemory(Destination,Source,Length)
+
+#endif
+
+
+//
+// definition of the basic spin lock structure
+//
+
+typedef struct _NDIS_SPIN_LOCK {
+ KSPIN_LOCK SpinLock;
+ KIRQL OldIrql;
+} NDIS_SPIN_LOCK, * PNDIS_SPIN_LOCK;
+
+
+typedef PVOID NDIS_HANDLE, *PNDIS_HANDLE;
+
+typedef int NDIS_STATUS, *PNDIS_STATUS; // note default size
+
+#define NdisInterruptLatched Latched
+#define NdisInterruptLevelSensitive LevelSensitive
+typedef KINTERRUPT_MODE NDIS_INTERRUPT_MODE, *PNDIS_INTERRUPT_MODE;
+
+//
+// Configuration definitions
+//
+
+//
+// Possible data types
+//
+
+typedef enum _NDIS_PARAMETER_TYPE {
+ NdisParameterInteger,
+ NdisParameterHexInteger,
+ NdisParameterString,
+ NdisParameterMultiString
+} NDIS_PARAMETER_TYPE, *PNDIS_PARAMETER_TYPE;
+
+//
+// To store configuration information
+//
+typedef struct _NDIS_CONFIGURATION_PARAMETER {
+ NDIS_PARAMETER_TYPE ParameterType;
+ union {
+ ULONG IntegerData;
+ NDIS_STRING StringData;
+ } ParameterData;
+} NDIS_CONFIGURATION_PARAMETER, *PNDIS_CONFIGURATION_PARAMETER;
+
+
+//
+// Definitions for the "ProcessorType" keyword
+//
+typedef enum _NDIS_PROCESSOR_TYPE {
+ NdisProcessorX86,
+ NdisProcessorMips,
+ NdisProcessorAlpha,
+ NdisProcessorPpc
+} NDIS_PROCESSOR_TYPE, *PNDIS_PROCESSOR_TYPE;
+
+//
+// Definitions for the "Environment" keyword
+//
+typedef enum _NDIS_ENVIRONMENT_TYPE {
+ NdisEnvironmentWindows,
+ NdisEnvironmentWindowsNt
+} NDIS_ENVIRONMENT_TYPE, *PNDIS_ENVIRONMENT_TYPE;
+
+
+//
+// Possible Hardware Architecture. Define these to
+// match the HAL INTERFACE_TYPE enum.
+//
+typedef enum _NDIS_INTERFACE_TYPE {
+ NdisInterfaceInternal = Internal,
+ NdisInterfaceIsa = Isa,
+ NdisInterfaceEisa = Eisa,
+ NdisInterfaceMca = MicroChannel,
+ NdisInterfaceTurboChannel = TurboChannel,
+ NdisInterfacePci = PCIBus,
+ NdisInterfacePcMcia = PCMCIABus
+} NDIS_INTERFACE_TYPE, *PNDIS_INTERFACE_TYPE;
+
+//
+// Definition for shutdown handler
+//
+
+typedef
+VOID
+(*ADAPTER_SHUTDOWN_HANDLER) (
+ IN PVOID ShutdownContext
+ );
+
+//
+// Stuff for PCI configuring
+//
+
+typedef CM_PARTIAL_RESOURCE_LIST NDIS_RESOURCE_LIST, *PNDIS_RESOURCE_LIST;
+
+
+//
+// The structure passed up on a WAN_LINE_UP indication
+//
+
+typedef struct _NDIS_WAN_LINE_UP {
+ ULONG LinkSpeed; // 100 bps units
+ ULONG MaximumTotalSize; // suggested max for send packets
+ NDIS_WAN_QUALITY Quality;
+ USHORT SendWindow; // suggested by the MAC
+ UCHAR Address[1]; // variable length, depends on address type
+} NDIS_WAN_LINE_UP, *PNDIS_WAN_LINE_UP;
+
+//
+// The structure passed up on a WAN_LINE_DOWN indication
+//
+
+typedef struct _NDIS_WAN_LINE_DOWN {
+ UCHAR Address[1]; // variable length, depends on address type
+} NDIS_WAN_LINE_DOWN, *PNDIS_WAN_LINE_DOWN;
+
+//
+// The structure passed up on a WAN_FRAGMENT indication
+//
+
+typedef struct _NDIS_WAN_FRAGMENT {
+ UCHAR Address[1]; // variable length, depends on address type
+} NDIS_WAN_FRAGMENT, *PNDIS_WAN_FRAGMENT;
+
+
+//
+// DMA Channel information
+//
+typedef struct _NDIS_DMA_DESCRIPTION {
+ BOOLEAN DemandMode;
+ BOOLEAN AutoInitialize;
+ BOOLEAN DmaChannelSpecified;
+ DMA_WIDTH DmaWidth;
+ DMA_SPEED DmaSpeed;
+ ULONG DmaPort;
+ ULONG DmaChannel;
+} NDIS_DMA_DESCRIPTION, *PNDIS_DMA_DESCRIPTION;
+
+//
+// Internal structure representing an NDIS DMA channel
+//
+typedef struct _NDIS_DMA_BLOCK {
+ PVOID MapRegisterBase;
+ KEVENT AllocationEvent;
+ PADAPTER_OBJECT SystemAdapterObject;
+ BOOLEAN InProgress;
+} NDIS_DMA_BLOCK, *PNDIS_DMA_BLOCK;
+
+
+//
+// Ndis Buffer is actually an Mdl
+//
+typedef MDL NDIS_BUFFER, * PNDIS_BUFFER;
+
+//
+// Include an incomplete type for NDIS_PACKET structure so that
+// function types can refer to a type to be defined later.
+//
+struct _NDIS_PACKET;
+
+//
+// packet pool definition
+//
+typedef struct _NDIS_PACKET_POOL {
+ NDIS_SPIN_LOCK SpinLock;
+ struct _NDIS_PACKET *FreeList; // linked list of free slots in pool
+ UINT PacketLength; // amount needed in each packet
+ UCHAR Buffer[1]; // actual pool memory
+} NDIS_PACKET_POOL, * PNDIS_PACKET_POOL;
+
+
+//
+// wrapper-specific part of a packet
+//
+
+typedef struct _NDIS_PACKET_PRIVATE {
+ UINT PhysicalCount; // number of physical pages in packet.
+ UINT TotalLength; // Total amount of data in the packet.
+ PNDIS_BUFFER Head; // first buffer in the chain
+ PNDIS_BUFFER Tail; // last buffer in the chain
+
+ // if Head is NULL the chain is empty; Tail doesn't have to be NULL also
+
+ PNDIS_PACKET_POOL Pool; // so we know where to free it back to
+ UINT Count;
+ ULONG Flags;
+ BOOLEAN ValidCounts;
+} NDIS_PACKET_PRIVATE, * PNDIS_PACKET_PRIVATE;
+
+
+//
+// packet definition
+//
+
+typedef struct _NDIS_PACKET {
+ NDIS_PACKET_PRIVATE Private;
+
+ union {
+
+ struct {
+ UCHAR MiniportReserved[8];
+ UCHAR WrapperReserved[8];
+ };
+
+ struct {
+ UCHAR MacReserved[16];
+ };
+
+ };
+
+ UCHAR ProtocolReserved[1];
+
+} NDIS_PACKET, * PNDIS_PACKET;
+
+//
+// Request types used by NdisRequest; constants are added for
+// all entry points in the MAC, for those that want to create
+// their own internal requests.
+//
+
+typedef enum _NDIS_REQUEST_TYPE {
+ NdisRequestQueryInformation,
+ NdisRequestSetInformation,
+ NdisRequestQueryStatistics,
+ NdisRequestOpen,
+ NdisRequestClose,
+ NdisRequestSend,
+ NdisRequestTransferData,
+ NdisRequestReset,
+ NdisRequestGeneric1,
+ NdisRequestGeneric2,
+ NdisRequestGeneric3,
+ NdisRequestGeneric4
+} NDIS_REQUEST_TYPE, *PNDIS_REQUEST_TYPE;
+
+
+//
+// Structure of requests sent via NdisRequest
+//
+
+typedef struct _NDIS_REQUEST {
+ UCHAR MacReserved[16];
+ NDIS_REQUEST_TYPE RequestType;
+ union _DATA {
+
+ struct _QUERY_INFORMATION {
+ NDIS_OID Oid;
+ PVOID InformationBuffer;
+ UINT InformationBufferLength;
+ UINT BytesWritten;
+ UINT BytesNeeded;
+ } QUERY_INFORMATION;
+
+ struct _SET_INFORMATION {
+ NDIS_OID Oid;
+ PVOID InformationBuffer;
+ UINT InformationBufferLength;
+ UINT BytesRead;
+ UINT BytesNeeded;
+ } SET_INFORMATION;
+
+ } DATA;
+
+} NDIS_REQUEST, *PNDIS_REQUEST;
+
+//
+// Definitions for physical address.
+//
+
+typedef PHYSICAL_ADDRESS NDIS_PHYSICAL_ADDRESS, *PNDIS_PHYSICAL_ADDRESS;
+typedef struct _NDIS_PHYSICAL_ADDRESS_UNIT {
+ NDIS_PHYSICAL_ADDRESS PhysicalAddress;
+ UINT Length;
+} NDIS_PHYSICAL_ADDRESS_UNIT, *PNDIS_PHYSICAL_ADDRESS_UNIT;
+
+
+/*++
+
+ULONG
+NdisGetPhysicalAddressHigh(
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
+ );
+
+--*/
+
+#define NdisGetPhysicalAddressHigh(_PhysicalAddress)\
+ ((_PhysicalAddress).HighPart)
+
+/*++
+
+VOID
+NdisSetPhysicalAddressHigh(
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress,
+ IN ULONG Value
+ );
+
+--*/
+
+#define NdisSetPhysicalAddressHigh(_PhysicalAddress, _Value)\
+ ((_PhysicalAddress).HighPart) = (_Value)
+
+
+/*++
+
+ULONG
+NdisGetPhysicalAddressLow(
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
+ );
+
+--*/
+
+#define NdisGetPhysicalAddressLow(_PhysicalAddress) \
+ ((_PhysicalAddress).LowPart)
+
+
+/*++
+
+VOID
+NdisSetPhysicalAddressLow(
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress,
+ IN ULONG Value
+ );
+
+--*/
+
+#define NdisSetPhysicalAddressLow(_PhysicalAddress, _Value) \
+ ((_PhysicalAddress).LowPart) = (_Value)
+
+//
+// Macro to initialize an NDIS_PHYSICAL_ADDRESS constant
+//
+
+#define NDIS_PHYSICAL_ADDRESS_CONST(_Low, _High) \
+ { (ULONG)(_Low), (LONG)(_High) }
+
+
+//
+// block used for references...
+//
+
+typedef struct _REFERENCE {
+ NDIS_SPIN_LOCK SpinLock;
+ USHORT ReferenceCount;
+ BOOLEAN Closing;
+} REFERENCE, * PREFERENCE;
+
+
+//
+// This holds a map register entry.
+//
+
+typedef struct _MAP_REGISTER_ENTRY {
+ PVOID MapRegister;
+ BOOLEAN WriteToDevice;
+} MAP_REGISTER_ENTRY, * PMAP_REGISTER_ENTRY;
+
+//
+// Types of Memory (not mutually exclusive)
+//
+
+#define NDIS_MEMORY_CONTIGUOUS 0x00000001
+#define NDIS_MEMORY_NONCACHED 0x00000002
+
+//
+// Open options
+//
+#define NDIS_OPEN_RECEIVE_NOT_REENTRANT 0x00000001
+
+//
+// NDIS_STATUS values
+//
+
+#define NDIS_STATUS_SUCCESS ((NDIS_STATUS) STATUS_SUCCESS)
+#define NDIS_STATUS_PENDING ((NDIS_STATUS) STATUS_PENDING)
+#define NDIS_STATUS_NOT_RECOGNIZED ((NDIS_STATUS)0x00010001L)
+#define NDIS_STATUS_NOT_COPIED ((NDIS_STATUS)0x00010002L)
+#define NDIS_STATUS_NOT_ACCEPTED ((NDIS_STATUS)0x00010003L)
+
+#define NDIS_STATUS_ONLINE ((NDIS_STATUS)0x40010003L)
+#define NDIS_STATUS_RESET_START ((NDIS_STATUS)0x40010004L)
+#define NDIS_STATUS_RESET_END ((NDIS_STATUS)0x40010005L)
+#define NDIS_STATUS_RING_STATUS ((NDIS_STATUS)0x40010006L)
+#define NDIS_STATUS_CLOSED ((NDIS_STATUS)0x40010007L)
+#define NDIS_STATUS_WAN_LINE_UP ((NDIS_STATUS)0x40010008L)
+#define NDIS_STATUS_WAN_LINE_DOWN ((NDIS_STATUS)0x40010009L)
+#define NDIS_STATUS_WAN_FRAGMENT ((NDIS_STATUS)0x4001000AL)
+
+#define NDIS_STATUS_NOT_RESETTABLE ((NDIS_STATUS)0x80010001L)
+#define NDIS_STATUS_SOFT_ERRORS ((NDIS_STATUS)0x80010003L)
+#define NDIS_STATUS_HARD_ERRORS ((NDIS_STATUS)0x80010004L)
+
+#define NDIS_STATUS_FAILURE ((NDIS_STATUS) STATUS_UNSUCCESSFUL)
+#define NDIS_STATUS_RESOURCES ((NDIS_STATUS) \
+ STATUS_INSUFFICIENT_RESOURCES)
+#define NDIS_STATUS_CLOSING ((NDIS_STATUS)0xC0010002L)
+#define NDIS_STATUS_BAD_VERSION ((NDIS_STATUS)0xC0010004L)
+#define NDIS_STATUS_BAD_CHARACTERISTICS ((NDIS_STATUS)0xC0010005L)
+#define NDIS_STATUS_ADAPTER_NOT_FOUND ((NDIS_STATUS)0xC0010006L)
+#define NDIS_STATUS_OPEN_FAILED ((NDIS_STATUS)0xC0010007L)
+#define NDIS_STATUS_DEVICE_FAILED ((NDIS_STATUS)0xC0010008L)
+#define NDIS_STATUS_MULTICAST_FULL ((NDIS_STATUS)0xC0010009L)
+#define NDIS_STATUS_MULTICAST_EXISTS ((NDIS_STATUS)0xC001000AL)
+#define NDIS_STATUS_MULTICAST_NOT_FOUND ((NDIS_STATUS)0xC001000BL)
+#define NDIS_STATUS_REQUEST_ABORTED ((NDIS_STATUS)0xC001000CL)
+#define NDIS_STATUS_RESET_IN_PROGRESS ((NDIS_STATUS)0xC001000DL)
+#define NDIS_STATUS_CLOSING_INDICATING ((NDIS_STATUS)0xC001000EL)
+#define NDIS_STATUS_NOT_SUPPORTED ((NDIS_STATUS)STATUS_NOT_SUPPORTED)
+#define NDIS_STATUS_INVALID_PACKET ((NDIS_STATUS)0xC001000FL)
+#define NDIS_STATUS_OPEN_LIST_FULL ((NDIS_STATUS)0xC0010010L)
+#define NDIS_STATUS_ADAPTER_NOT_READY ((NDIS_STATUS)0xC0010011L)
+#define NDIS_STATUS_ADAPTER_NOT_OPEN ((NDIS_STATUS)0xC0010012L)
+#define NDIS_STATUS_NOT_INDICATING ((NDIS_STATUS)0xC0010013L)
+#define NDIS_STATUS_INVALID_LENGTH ((NDIS_STATUS)0xC0010014L)
+#define NDIS_STATUS_INVALID_DATA ((NDIS_STATUS)0xC0010015L)
+#define NDIS_STATUS_BUFFER_TOO_SHORT ((NDIS_STATUS)0xC0010016L)
+#define NDIS_STATUS_INVALID_OID ((NDIS_STATUS)0xC0010017L)
+#define NDIS_STATUS_ADAPTER_REMOVED ((NDIS_STATUS)0xC0010018L)
+#define NDIS_STATUS_UNSUPPORTED_MEDIA ((NDIS_STATUS)0xC0010019L)
+#define NDIS_STATUS_GROUP_ADDRESS_IN_USE ((NDIS_STATUS)0xC001001AL)
+#define NDIS_STATUS_FILE_NOT_FOUND ((NDIS_STATUS)0xC001001BL)
+#define NDIS_STATUS_ERROR_READING_FILE ((NDIS_STATUS)0xC001001CL)
+#define NDIS_STATUS_ALREADY_MAPPED ((NDIS_STATUS)0xC001001DL)
+#define NDIS_STATUS_RESOURCE_CONFLICT ((NDIS_STATUS)0xC001001EL)
+#define NDIS_STATUS_NO_CABLE ((NDIS_STATUS)0xC001001FL)
+
+#define NDIS_STATUS_TOKEN_RING_OPEN_ERROR ((NDIS_STATUS)0xC0011000L)
+
+
+//
+// used in error logging
+//
+
+#define NDIS_ERROR_CODE ULONG
+
+#define NDIS_ERROR_CODE_RESOURCE_CONFLICT EVENT_NDIS_RESOURCE_CONFLICT
+#define NDIS_ERROR_CODE_OUT_OF_RESOURCES EVENT_NDIS_OUT_OF_RESOURCE
+#define NDIS_ERROR_CODE_HARDWARE_FAILURE EVENT_NDIS_HARDWARE_FAILURE
+#define NDIS_ERROR_CODE_ADAPTER_NOT_FOUND EVENT_NDIS_ADAPTER_NOT_FOUND
+#define NDIS_ERROR_CODE_INTERRUPT_CONNECT EVENT_NDIS_INTERRUPT_CONNECT
+#define NDIS_ERROR_CODE_DRIVER_FAILURE EVENT_NDIS_DRIVER_FAILURE
+#define NDIS_ERROR_CODE_BAD_VERSION EVENT_NDIS_BAD_VERSION
+#define NDIS_ERROR_CODE_TIMEOUT EVENT_NDIS_TIMEOUT
+#define NDIS_ERROR_CODE_NETWORK_ADDRESS EVENT_NDIS_NETWORK_ADDRESS
+#define NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION EVENT_NDIS_UNSUPPORTED_CONFIGURATION
+#define NDIS_ERROR_CODE_INVALID_VALUE_FROM_ADAPTER EVENT_NDIS_INVALID_VALUE_FROM_ADAPTER
+#define NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER EVENT_NDIS_MISSING_CONFIGURATION_PARAMETER
+#define NDIS_ERROR_CODE_BAD_IO_BASE_ADDRESS EVENT_NDIS_BAD_IO_BASE_ADDRESS
+#define NDIS_ERROR_CODE_RECEIVE_SPACE_SMALL EVENT_NDIS_RECEIVE_SPACE_SMALL
+#define NDIS_ERROR_CODE_ADAPTER_DISABLED EVENT_NDIS_ADAPTER_DISABLED
+
+
+//
+// Ndis Spin Locks
+//
+
+#if BINARY_COMPATIBLE
+
+EXPORT
+VOID
+NdisAllocateSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+EXPORT
+VOID
+NdisFreeSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+EXPORT
+VOID
+NdisAcquireSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+EXPORT
+VOID
+NdisReleaseSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+EXPORT
+VOID
+NdisDprAcquireSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+EXPORT
+VOID
+NdisDprReleaseSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ );
+
+#else
+
+#define NdisAllocateSpinLock(_SpinLock) \
+ KeInitializeSpinLock(&(_SpinLock)->SpinLock)
+
+#define NdisFreeSpinLock(_SpinLock)
+
+#define NdisAcquireSpinLock(_SpinLock) \
+ KeAcquireSpinLock(&(_SpinLock)->SpinLock, &(_SpinLock)->OldIrql)
+
+#define NdisReleaseSpinLock(_SpinLock) \
+ KeReleaseSpinLock(&(_SpinLock)->SpinLock,(_SpinLock)->OldIrql)
+
+#define NdisDprAcquireSpinLock(_SpinLock) { \
+ KeAcquireSpinLockAtDpcLevel(&(_SpinLock)->SpinLock); \
+ (_SpinLock)->OldIrql = DISPATCH_LEVEL; \
+}
+
+#define NdisDprReleaseSpinLock(_SpinLock) \
+ KeReleaseSpinLockFromDpcLevel(&(_SpinLock)->SpinLock)
+
+#endif
+
+//
+// List manipulation
+//
+
+/*++
+
+VOID
+NdisInitializeListHead(
+ IN PLIST_ENTRY ListHead
+ );
+
+--*/
+#define NdisInitializeListHead(_ListHead) InitializeListHead(_ListHead)
+
+
+
+//
+// Configuration Requests
+//
+
+EXPORT
+VOID
+NdisOpenConfiguration(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE ConfigurationHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ );
+
+EXPORT
+VOID
+NdisReadConfiguration(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_CONFIGURATION_PARAMETER *ParameterValue,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING Keyword,
+ IN NDIS_PARAMETER_TYPE ParameterType
+ );
+
+EXPORT
+VOID
+NdisWriteConfiguration(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN PNDIS_STRING Keyword,
+ IN PNDIS_CONFIGURATION_PARAMETER ParameterValue
+ );
+
+EXPORT
+VOID
+NdisCloseConfiguration(
+ IN NDIS_HANDLE ConfigurationHandle
+ );
+
+EXPORT
+VOID
+NdisReadNetworkAddress(
+ OUT PNDIS_STATUS Status,
+ OUT PVOID * NetworkAddress,
+ OUT PUINT NetworkAddressLength,
+ IN NDIS_HANDLE ConfigurationHandle
+ );
+
+EXPORT
+VOID
+NdisReadBindingInformation(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_STRING * Binding,
+ IN NDIS_HANDLE ConfigurationHandle
+ );
+
+
+EXPORT
+VOID
+NdisReadEisaSlotInformation(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PUINT SlotNumber,
+ OUT PNDIS_EISA_FUNCTION_INFORMATION EisaData
+ );
+
+EXPORT
+VOID
+NdisReadEisaSlotInformationEx(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PUINT SlotNumber,
+ OUT PNDIS_EISA_FUNCTION_INFORMATION *EisaData,
+ OUT PUINT NumberOfFunctions
+ );
+
+EXPORT
+VOID
+NdisReadMcaPosInformation(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN PUINT ChannelNumber,
+ OUT PNDIS_MCA_POS_DATA McaData
+ );
+
+EXPORT
+ULONG
+NdisReadPciSlotInformation(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ );
+
+EXPORT
+ULONG
+NdisWritePciSlotInformation(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ );
+
+EXPORT
+NDIS_STATUS
+NdisPciAssignResources(
+ IN NDIS_HANDLE NdisMacHandle,
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SlotNumber,
+ OUT PNDIS_RESOURCE_LIST *AssignedResources
+ );
+
+//
+// Buffer Pool
+//
+
+EXPORT
+VOID
+NdisAllocateBufferPool(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE PoolHandle,
+ IN UINT NumberOfDescriptors
+ );
+
+EXPORT
+VOID
+NdisFreeBufferPool(
+ IN NDIS_HANDLE PoolHandle
+ );
+
+EXPORT
+VOID
+NdisAllocateBuffer(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_BUFFER * Buffer,
+ IN NDIS_HANDLE PoolHandle,
+ IN PVOID VirtualAddress,
+ IN UINT Length
+ );
+
+EXPORT
+VOID
+NdisCopyBuffer(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_BUFFER * Buffer,
+ IN NDIS_HANDLE PoolHandle,
+ IN PVOID MemoryDescriptor,
+ IN UINT Offset,
+ IN UINT Length
+ );
+
+
+#if BINARY_COMPATIBLE
+
+EXPORT
+VOID
+NdisFreeBuffer(
+ IN PNDIS_BUFFER Buffer
+ );
+
+EXPORT
+VOID
+NdisQueryBuffer(
+ IN PNDIS_BUFFER Buffer,
+ OUT PVOID *VirtualAddress OPTIONAL,
+ OUT PUINT Length
+ );
+
+EXPORT
+VOID
+NdisQueryBufferOffset(
+ IN PNDIS_BUFFER Buffer,
+ OUT PUINT Offset,
+ OUT PUINT Length
+ );
+
+#else
+
+#define NdisFreeBuffer(Buffer) IoFreeMdl(Buffer)
+
+#define NdisQueryBuffer(_Buffer, _VirtualAddress, _Length) \
+{ \
+ if ( ARGUMENT_PRESENT(_VirtualAddress) ) { \
+ *(PVOID *)(_VirtualAddress) = MmGetSystemAddressForMdl(_Buffer); \
+ } \
+ *(_Length) = MmGetMdlByteCount(_Buffer); \
+}
+
+#define NdisQueryBufferOffset(_Buffer, _Offset, _Length) \
+{ \
+ *(_Offset) = MmGetMdlByteOffset(_Buffer); \
+ *(_Length) = MmGetMdlByteCount(_Buffer); \
+}
+
+#endif
+
+
+//
+// This macro is used to determine how many physical pieces
+// an NDIS_BUFFER will take up when mapped.
+//
+
+#if BINARY_COMPATIBLE
+
+EXPORT
+ULONG
+NDIS_BUFFER_TO_SPAN_PAGES(
+ IN PNDIS_BUFFER Buffer
+ );
+
+EXPORT
+VOID
+NdisGetBufferPhysicalArraySize(
+ IN PNDIS_BUFFER Buffer,
+ OUT PUINT ArraySize
+ );
+
+#else
+
+#define NDIS_BUFFER_TO_SPAN_PAGES(_Buffer) \
+ (MmGetMdlByteCount(_Buffer)==0 ? \
+ 1 : \
+ (COMPUTE_PAGES_SPANNED(\
+ MmGetMdlVirtualAddress(_Buffer), \
+ MmGetMdlByteCount(_Buffer))))
+
+#define NdisGetBufferPhysicalArraySize(Buffer, ArraySize) \
+ (*(ArraySize) = NDIS_BUFFER_TO_SPAN_PAGES(Buffer))
+
+#endif
+
+/*++
+VOID
+NdisBufferGetSystemSpecific(
+ IN PNDIS_BUFFER Buffer,
+ OUT PVOID * SystemSpecific
+ );
+--*/
+
+#define NdisBufferGetSystemSpecific(Buffer, SystemSpecific) \
+ *(SystemSpecific) = (Buffer)
+
+
+/*++
+
+NDIS_BUFFER_LINKAGE(
+ IN PNDIS_BUFFER Buffer
+ );
+
+--*/
+
+#define NDIS_BUFFER_LINKAGE(Buffer) \
+ ((Buffer)->Next)
+
+
+/*++
+
+VOID
+NdisRecalculatePacketCounts(
+ IN OUT PNDIS_PACKET Packet
+ );
+
+--*/
+
+#define NdisRecalculatePacketCounts(Packet) { \
+ { \
+ PNDIS_BUFFER TmpBuffer = (Packet)->Private.Head; \
+ if (TmpBuffer) { \
+ while (TmpBuffer->Next) { \
+ TmpBuffer = TmpBuffer->Next; \
+ } \
+ (Packet)->Private.Tail = TmpBuffer; \
+ } \
+ (Packet)->Private.ValidCounts = FALSE; \
+ } \
+}
+
+
+/*++
+
+VOID
+NdisChainBufferAtFront(
+ IN OUT PNDIS_PACKET Packet,
+ IN OUT PNDIS_BUFFER Buffer
+ );
+
+--*/
+
+#define NdisChainBufferAtFront(Packet, Buffer) { \
+ PNDIS_BUFFER TmpBuffer = (Buffer); \
+\
+ for (;;) { \
+ if (TmpBuffer->Next == (PNDIS_BUFFER)NULL) \
+ break; \
+ TmpBuffer = TmpBuffer->Next; \
+ } \
+ if ((Packet)->Private.Head == (PNDIS_BUFFER)NULL) { \
+ (Packet)->Private.Tail = TmpBuffer; \
+ } \
+ TmpBuffer->Next = (Packet)->Private.Head; \
+ (Packet)->Private.Head = (Buffer); \
+ (Packet)->Private.ValidCounts = FALSE; \
+}
+
+/*++
+
+VOID
+NdisChainBufferAtBack(
+ IN OUT PNDIS_PACKET Packet,
+ IN OUT PNDIS_BUFFER Buffer
+ );
+
+--*/
+
+#define NdisChainBufferAtBack(Packet, Buffer) { \
+ PNDIS_BUFFER TmpBuffer = (Buffer); \
+\
+ for (;;) { \
+ if (TmpBuffer->Next == (PNDIS_BUFFER)NULL) \
+ break; \
+ TmpBuffer = TmpBuffer->Next; \
+ } \
+ if ((Packet)->Private.Head != (PNDIS_BUFFER)NULL) { \
+ (Packet)->Private.Tail->Next = (Buffer); \
+ } else { \
+ (Packet)->Private.Head = (Buffer); \
+ } \
+ (Packet)->Private.Tail = TmpBuffer; \
+ TmpBuffer->Next = (PNDIS_BUFFER)NULL; \
+ (Packet)->Private.ValidCounts = FALSE; \
+}
+
+EXPORT
+VOID
+NdisUnchainBufferAtFront(
+ IN OUT PNDIS_PACKET Packet,
+ OUT PNDIS_BUFFER * Buffer
+ );
+
+EXPORT
+VOID
+NdisUnchainBufferAtBack(
+ IN OUT PNDIS_PACKET Packet,
+ OUT PNDIS_BUFFER * Buffer
+ );
+
+
+/*++
+
+VOID
+NdisQueryPacket(
+ IN PNDIS_PACKET _Packet,
+ OUT PUINT _PhysicalBufferCount OPTIONAL,
+ OUT PUINT _BufferCount OPTIONAL,
+ OUT PNDIS_BUFFER * _FirstBuffer OPTIONAL,
+ OUT PUINT _TotalPacketLength OPTIONAL
+ );
+
+--*/
+
+#define NdisQueryPacket(_Packet, _PhysicalBufferCount, _BufferCount, _FirstBuffer, _TotalPacketLength) \
+{ \
+ \
+ if ((_FirstBuffer) != NULL) \
+ { \
+ PNDIS_BUFFER * __FirstBuffer = (_FirstBuffer); \
+ *(__FirstBuffer) = (_Packet)->Private.Head; \
+ } \
+ if ((_PhysicalBufferCount) || (_BufferCount) || (_TotalPacketLength)) { \
+ if (!(_Packet)->Private.ValidCounts) { \
+ PNDIS_BUFFER TmpBuffer = (_Packet)->Private.Head; \
+ UINT PTotalLength = 0, PPhysicalCount = 0, PAddedCount = 0; \
+ UINT PacketLength; \
+ \
+ while (TmpBuffer != (PNDIS_BUFFER)NULL) { \
+ NdisQueryBuffer(TmpBuffer, NULL, &PacketLength); \
+ PTotalLength += PacketLength; \
+ PPhysicalCount += NDIS_BUFFER_TO_SPAN_PAGES(TmpBuffer); \
+ ++PAddedCount; \
+ TmpBuffer = TmpBuffer->Next; \
+ } \
+ (_Packet)->Private.Count = PAddedCount; \
+ (_Packet)->Private.TotalLength = PTotalLength; \
+ (_Packet)->Private.PhysicalCount = PPhysicalCount; \
+ (_Packet)->Private.ValidCounts = TRUE; \
+ } \
+ if (_PhysicalBufferCount) \
+ { \
+ PUINT __PhysicalBufferCount = (_PhysicalBufferCount); \
+ *(__PhysicalBufferCount) = (_Packet)->Private.PhysicalCount; \
+ } \
+ if (_BufferCount) \
+ { \
+ PUINT __BufferCount = (_BufferCount); \
+ *(__BufferCount) = (_Packet)->Private.Count; \
+ } \
+ if (_TotalPacketLength) \
+ { \
+ PUINT __TotalPacketLength = (_TotalPacketLength); \
+ *(__TotalPacketLength) = (_Packet)->Private.TotalLength; \
+ } \
+ } \
+}
+
+
+/*++
+
+VOID
+NdisGetNextBuffer(
+ IN PNDIS_BUFFER CurrentBuffer,
+ OUT PNDIS_BUFFER * NextBuffer
+ );
+
+--*/
+
+#define NdisGetNextBuffer(CurrentBuffer, NextBuffer) {\
+ *(NextBuffer) = (CurrentBuffer)->Next; \
+}
+
+
+EXPORT
+VOID
+NdisCopyFromPacketToPacket(
+ IN PNDIS_PACKET Destination,
+ IN UINT DestinationOffset,
+ IN UINT BytesToCopy,
+ IN PNDIS_PACKET Source,
+ IN UINT SourceOffset,
+ OUT PUINT BytesCopied
+ );
+
+
+EXPORT
+NDIS_STATUS
+NdisAllocateMemory(
+ OUT PVOID *VirtualAddress,
+ IN UINT Length,
+ IN UINT MemoryFlags,
+ IN NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress
+ );
+
+EXPORT
+VOID
+NdisFreeMemory(
+ IN PVOID VirtualAddress,
+ IN UINT Length,
+ IN UINT MemoryFlags
+ );
+
+
+/*++
+VOID
+NdisStallExecution(
+ IN UINT MicrosecondsToStall
+ )
+--*/
+
+#define NdisStallExecution(MicroSecondsToStall) \
+ KeStallExecutionProcessor(MicroSecondsToStall)
+
+
+//
+// Simple I/O support
+//
+
+EXPORT
+VOID
+NdisOpenFile(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE FileHandle,
+ OUT PUINT FileLength,
+ IN PNDIS_STRING FileName,
+ IN NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress
+ );
+
+EXPORT
+VOID
+NdisCloseFile(
+ IN NDIS_HANDLE FileHandle
+ );
+
+EXPORT
+VOID
+NdisMapFile(
+ OUT PNDIS_STATUS Status,
+ OUT PVOID * MappedBuffer,
+ IN NDIS_HANDLE FileHandle
+ );
+
+EXPORT
+VOID
+NdisUnmapFile(
+ IN NDIS_HANDLE FileHandle
+ );
+
+
+//
+// Portability extensions
+//
+
+/*++
+VOID
+NdisFlushBuffer(
+ IN PNDIS_BUFFER Buffer,
+ IN BOOLEAN WriteToDevice
+ )
+--*/
+
+#define NdisFlushBuffer(Buffer,WriteToDevice) \
+ KeFlushIoBuffers((Buffer),!(WriteToDevice), TRUE)
+
+/*++
+ULONG
+NdisGetCacheFillSize(
+ )
+--*/
+#define NdisGetCacheFillSize() \
+ HalGetDmaAlignmentRequirement()
+
+//
+// This macro is used to convert a port number as the caller
+// thinks of it, to a port number as it should be passed to
+// READ/WRITE_PORT.
+//
+
+#define NDIS_PORT_TO_PORT(Handle,Port) (((PNDIS_ADAPTER_BLOCK)(Handle))->PortOffset + (Port))
+
+
+//
+// Write Port
+//
+
+/*++
+VOID
+NdisWritePortUchar(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Port,
+ IN UCHAR Data
+ )
+--*/
+#define NdisWritePortUchar(Handle,Port,Data) \
+ WRITE_PORT_UCHAR((PUCHAR)(NDIS_PORT_TO_PORT(Handle,Port)),(UCHAR)(Data))
+
+/*++
+VOID
+NdisWritePortUshort(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Port,
+ IN USHORT Data
+ )
+--*/
+#define NdisWritePortUshort(Handle,Port,Data) \
+ WRITE_PORT_USHORT((PUSHORT)(NDIS_PORT_TO_PORT(Handle,Port)),(USHORT)(Data))
+
+
+/*++
+VOID
+NdisWritePortUlong(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Port,
+ IN ULONG Data
+ )
+--*/
+#define NdisWritePortUlong(Handle,Port,Data) \
+ WRITE_PORT_ULONG((PULONG)(NDIS_PORT_TO_PORT(Handle,Port)),(ULONG)(Data))
+
+
+//
+// Write Port Buffers
+//
+
+/*++
+VOID
+NdisWritePortBufferUchar(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Port,
+ IN PUCHAR Buffer,
+ IN ULONG Length
+ )
+--*/
+#define NdisWritePortBufferUchar(Handle,Port,Buffer,Length) \
+ NdisRawWritePortBufferUchar(NDIS_PORT_TO_PORT((Handle),(Port)),(Buffer),(Length))
+
+/*++
+VOID
+NdisWritePortBufferUshort(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Port,
+ IN PUSHORT Buffer,
+ IN ULONG Length
+ )
+--*/
+#define NdisWritePortBufferUshort(Handle,Port,Buffer,Length) \
+ NdisRawWritePortBufferUshort(NDIS_PORT_TO_PORT((Handle),(Port)),(Buffer),(Length))
+
+
+/*++
+VOID
+NdisWritePortBufferUlong(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Port,
+ IN PULONG Buffer,
+ IN ULONG Length
+ )
+--*/
+#define NdisWritePortBufferUlong(Handle,Port,Buffer,Length) \
+ NdisRawWritePortBufferUlong(NDIS_PORT_TO_PORT((Handle),(Port)),(Buffer),(Length))
+
+
+//
+// Read Ports
+//
+
+/*++
+VOID
+NdisReadPortUchar(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Port,
+ OUT PUCHAR Data
+ )
+--*/
+#define NdisReadPortUchar(Handle,Port, Data) \
+ NdisRawReadPortUchar(NDIS_PORT_TO_PORT((Handle),(Port)),(Data))
+
+/*++
+VOID
+NdisReadPortUshort(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Port,
+ OUT PUSHORT Data
+ )
+--*/
+#define NdisReadPortUshort(Handle,Port,Data) \
+ NdisRawReadPortUshort(NDIS_PORT_TO_PORT((Handle),(Port)),(Data))
+
+
+/*++
+VOID
+NdisReadPortUlong(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Port,
+ OUT PULONG Data
+ )
+--*/
+#define NdisReadPortUlong(Handle,Port,Data) \
+ NdisRawReadPortUlong(NDIS_PORT_TO_PORT((Handle),(Port)),(Data))
+
+//
+// Read Buffer Ports
+//
+
+/*++
+VOID
+NdisReadPortBufferUchar(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Port,
+ OUT PUCHAR Buffer,
+ IN ULONG Length
+ )
+--*/
+#define NdisReadPortBufferUchar(Handle,Port,Buffer,Length) \
+ NdisRawReadPortBufferUchar(NDIS_PORT_TO_PORT((Handle),(Port)),(Buffer),(Length))
+
+/*++
+VOID
+NdisReadPortBufferUshort(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Port,
+ OUT PUSHORT Buffer,
+ IN ULONG Length
+ )
+--*/
+#define NdisReadPortBufferUshort(Handle,Port,Buffer,Length) \
+ NdisRawReadPortBufferUshort(NDIS_PORT_TO_PORT((Handle),(Port)),(Buffer),(Length))
+
+/*++
+VOID
+NdisReadPortBufferUlong(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Port,
+ OUT PULONG Buffer,
+ IN ULONG Length
+ )
+--*/
+#define NdisReadPortBufferUlong(Handle,Port,Buffer) \
+ NdisRawReadPortBufferUlong(NDIS_PORT_TO_PORT((Handle),(Port)),(Buffer),(Length))
+
+//
+// Raw Routines
+//
+
+//
+// Write Port Raw
+//
+
+/*++
+VOID
+NdisRawWritePortUchar(
+ IN ULONG Port,
+ IN UCHAR Data
+ )
+--*/
+#define NdisRawWritePortUchar(Port,Data) \
+ WRITE_PORT_UCHAR((PUCHAR)(Port),(UCHAR)(Data))
+
+/*++
+VOID
+NdisRawWritePortUshort(
+ IN ULONG Port,
+ IN USHORT Data
+ )
+--*/
+#define NdisRawWritePortUshort(Port,Data) \
+ WRITE_PORT_USHORT((PUSHORT)(Port),(USHORT)(Data))
+
+/*++
+VOID
+NdisRawWritePortUlong(
+ IN ULONG Port,
+ IN ULONG Data
+ )
+--*/
+#define NdisRawWritePortUlong(Port,Data) \
+ WRITE_PORT_ULONG((PULONG)(Port),(ULONG)(Data))
+
+
+//
+// Raw Write Port Buffers
+//
+
+/*++
+VOID
+NdisRawWritePortBufferUchar(
+ IN ULONG Port,
+ IN PUCHAR Buffer,
+ IN ULONG Length
+ )
+--*/
+#define NdisRawWritePortBufferUchar(Port,Buffer,Length) \
+ WRITE_PORT_BUFFER_UCHAR((PUCHAR)(Port),(PUCHAR)(Buffer),(Length))
+
+/*++
+VOID
+NdisRawWritePortBufferUshort(
+ IN ULONG Port,
+ IN PUSHORT Buffer,
+ IN ULONG Length
+ )
+--*/
+#if defined(_M_IX86)
+#define NdisRawWritePortBufferUshort(Port,Buffer,Length) \
+ WRITE_PORT_BUFFER_USHORT((PUSHORT)(Port),(PUSHORT)(Buffer),(Length))
+#else
+#define NdisRawWritePortBufferUshort(Port,Buffer,Length) \
+{ \
+ ULONG _Port = (ULONG)(Port); \
+ PUSHORT _Current = (Buffer); \
+ PUSHORT _End = _Current + (Length); \
+ for ( ; _Current < _End; ++_Current) { \
+ WRITE_PORT_USHORT((PUSHORT)_Port,*(UNALIGNED USHORT *)_Current); \
+ } \
+}
+#endif
+
+
+/*++
+VOID
+NdisRawWritePortBufferUlong(
+ IN ULONG Port,
+ IN PULONG Buffer,
+ IN ULONG Length
+ )
+--*/
+#if defined(_M_IX86)
+#define NdisRawWritePortBufferUlong(Port,Buffer,Length) \
+ WRITE_PORT_BUFFER_ULONG((PULONG)(Port),(PULONG)(Buffer),(Length))
+#else
+#define NdisRawWritePortBufferUlong(Port,Buffer,Length) \
+{ \
+ ULONG _Port = (ULONG)(Port); \
+ PULONG _Current = (Buffer); \
+ PULONG _End = _Current + (Length); \
+ for ( ; _Current < _End; ++_Current) { \
+ WRITE_PORT_ULONG((PULONG)_Port,*(UNALIGNED ULONG *)_Current); \
+ } \
+}
+#endif
+
+
+//
+// Raw Read Ports
+//
+
+/*++
+VOID
+NdisRawReadPortUchar(
+ IN ULONG Port,
+ OUT PUCHAR Data
+ )
+--*/
+#define NdisRawReadPortUchar(Port, Data) \
+ *(Data) = READ_PORT_UCHAR((PUCHAR)(Port))
+
+/*++
+VOID
+NdisRawReadPortUshort(
+ IN ULONG Port,
+ OUT PUSHORT Data
+ )
+--*/
+#define NdisRawReadPortUshort(Port,Data) \
+ *(Data) = READ_PORT_USHORT((PUSHORT)(Port))
+
+/*++
+VOID
+NdisRawReadPortUlong(
+ IN ULONG Port,
+ OUT PULONG Data
+ )
+--*/
+#define NdisRawReadPortUlong(Port,Data) \
+ *(Data) = READ_PORT_ULONG((PULONG)(Port))
+
+
+//
+// Raw Read Buffer Ports
+//
+
+/*++
+VOID
+NdisRawReadPortBufferUchar(
+ IN ULONG Port,
+ OUT PUCHAR Buffer,
+ IN ULONG Length
+ )
+--*/
+#define NdisRawReadPortBufferUchar(Port,Buffer,Length) \
+ READ_PORT_BUFFER_UCHAR((PUCHAR)(Port),(PUCHAR)(Buffer),(Length))
+
+
+/*++
+VOID
+NdisRawReadPortBufferUshort(
+ IN ULONG Port,
+ OUT PUSHORT Buffer,
+ IN ULONG Length
+ )
+--*/
+#if defined(_M_IX86)
+#define NdisRawReadPortBufferUshort(Port,Buffer,Length) \
+ READ_PORT_BUFFER_USHORT((PUSHORT)(Port),(PUSHORT)(Buffer),(Length))
+#else
+#define NdisRawReadPortBufferUshort(Port,Buffer,Length) \
+{ \
+ ULONG _Port = (ULONG)(Port); \
+ PUSHORT _Current = (Buffer); \
+ PUSHORT _End = _Current + (Length); \
+ for ( ; _Current < _End; ++_Current) { \
+ *(UNALIGNED USHORT *)_Current = READ_PORT_USHORT((PUSHORT)_Port); \
+ } \
+}
+#endif
+
+
+/*++
+VOID
+NdisRawReadPortBufferUlong(
+ IN ULONG Port,
+ OUT PULONG Buffer,
+ IN ULONG Length
+ )
+--*/
+#if defined(_M_IX86)
+#define NdisRawReadPortBufferUlong(Port,Buffer,Length) \
+ READ_PORT_BUFFER_ULONG((PULONG)(Port),(PULONG)(Buffer),(Length))
+#else
+#define NdisRawReadPortBufferUlong(Port,Buffer,Length) \
+{ \
+ ULONG _Port = (ULONG)(Port); \
+ PULONG _Current = (Buffer); \
+ PULONG _End = _Current + (Length); \
+ for ( ; _Current < _End; ++_Current) { \
+ *(UNALIGNED ULONG *)_Current = READ_PORT_ULONG((PULONG)_Port); \
+ } \
+}
+#endif
+
+
+//
+// Write Registers
+//
+
+/*++
+VOID
+NdisWriteRegisterUchar(
+ IN PUCHAR Register,
+ IN UCHAR Data
+ )
+--*/
+
+#if defined(_M_IX86)
+#define NdisWriteRegisterUchar(Register,Data) \
+ WRITE_REGISTER_UCHAR((Register),(Data))
+#else
+#define NdisWriteRegisterUchar(Register,Data) { \
+ WRITE_REGISTER_UCHAR((Register),(Data)); \
+ READ_REGISTER_UCHAR(Register); \
+ }
+#endif
+
+/*++
+VOID
+NdisWriteRegisterUshort(
+ IN PUSHORT Register,
+ IN USHORT Data
+ )
+--*/
+
+#if defined(_M_IX86)
+#define NdisWriteRegisterUshort(Register,Data) \
+ WRITE_REGISTER_USHORT((Register),(Data))
+#else
+#define NdisWriteRegisterUshort(Register,Data) { \
+ WRITE_REGISTER_USHORT((Register),(Data)); \
+ READ_REGISTER_USHORT(Register); \
+ }
+#endif
+
+/*++
+VOID
+NdisWriteRegisterUlong(
+ IN PULONG Register,
+ IN ULONG Data
+ )
+--*/
+
+#if defined(_M_IX86)
+#define NdisWriteRegisterUlong(Register,Data) \
+ WRITE_REGISTER_ULONG((Register),(Data))
+#else
+#define NdisWriteRegisterUlong(Register,Data) { \
+ WRITE_REGISTER_ULONG((Register),(Data)); \
+ READ_REGISTER_ULONG(Register); \
+ }
+#endif
+
+/*++
+VOID
+NdisReadRegisterUchar(
+ IN PUCHAR Register,
+ OUT PUCHAR Data
+ )
+--*/
+#if defined(_M_IX86)
+#define NdisReadRegisterUchar(Register,Data) \
+ *((PUCHAR)(Data)) = *(Register)
+#else
+#define NdisReadRegisterUchar(Register,Data) \
+ *(Data) = READ_REGISTER_UCHAR((PUCHAR)(Register))
+#endif
+
+/*++
+VOID
+NdisReadRegisterUshort(
+ IN PUSHORT Register,
+ OUT PUSHORT Data
+ )
+--*/
+#if defined(_M_IX86)
+#define NdisReadRegisterUshort(Register,Data) \
+ *((PUSHORT)(Data)) = *(Register)
+#else
+#define NdisReadRegisterUshort(Register,Data) \
+ *(Data) = READ_REGISTER_USHORT((PUSHORT)(Register))
+#endif
+
+/*++
+VOID
+NdisReadRegisterUlong(
+ IN PULONG Register,
+ OUT PULONG Data
+ )
+--*/
+#if defined(_M_IX86)
+#define NdisReadRegisterUlong(Register,Data) \
+ *((PULONG)(Data)) = *(Register)
+#else
+#define NdisReadRegisterUlong(Register,Data) \
+ *(Data) = READ_REGISTER_ULONG((PULONG)(Register))
+#endif
+
+#if BINARY_COMPATIBLE
+
+EXPORT
+BOOLEAN
+NdisEqualString(
+ IN PNDIS_STRING String1,
+ IN PNDIS_STRING String2,
+ IN BOOLEAN CaseInsensitive
+ );
+
+#else
+
+#define NdisEqualString(_String1,_String2,CaseInsensitive) \
+ RtlEqualUnicodeString((_String1), (_String2), CaseInsensitive)
+
+#endif
+
+EXPORT
+VOID
+NdisWriteErrorLogEntry(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN NDIS_ERROR_CODE ErrorCode,
+ IN ULONG NumberOfErrorValues,
+ ...
+ );
+
+#define NdisInitializeString(Destination,Source) \
+{\
+ PNDIS_STRING _D = (Destination);\
+ UCHAR *_S = (Source);\
+ WCHAR *_P;\
+ _D->Length = (strlen(_S)) * sizeof(WCHAR);\
+ _D->MaximumLength = _D->Length + sizeof(WCHAR);\
+ NdisAllocateMemory((PVOID *)&(_D->Buffer), _D->MaximumLength, 0, (-1));\
+ _P = _D->Buffer;\
+ while(*_S != '\0'){\
+ *_P = (WCHAR)(*_S);\
+ _S++;\
+ _P++;\
+ }\
+ *_P = UNICODE_NULL;\
+}
+
+#define NdisFreeString(String) NdisFreeMemory((String).Buffer, (String).MaximumLength, 0)
+
+#define NdisPrintString(String) DbgPrint("%ls",(String).Buffer)
+
+
+#if !defined(_ALPHA_)
+/*++
+
+ VOID
+ NdisCreateLookaheadBufferFromSharedMemory(
+ IN PVOID pSharedMemory,
+ IN UINT LookaheadLength,
+ OUT PVOID *pLookaheadBuffer
+ );
+
+--*/
+
+#define NdisCreateLookaheadBufferFromSharedMemory(_S, _L, _B) \
+ ((*(_B)) = (_S))
+
+/*++
+
+ VOID
+ NdisDestroyLookaheadBufferFromSharedMemory(
+ IN PVOID pLookaheadBuffer
+ );
+
+--*/
+
+#define NdisDestroyLookaheadBufferFromSharedMemory(_B)
+
+#else // Alpha
+
+EXPORT
+VOID
+NdisCreateLookaheadBufferFromSharedMemory(
+ IN PVOID pSharedMemory,
+ IN UINT LookaheadLength,
+ OUT PVOID *pLookaheadBuffer
+ );
+
+EXPORT
+VOID
+NdisDestroyLookaheadBufferFromSharedMemory(
+ IN PVOID pLookaheadBuffer
+ );
+
+#endif
+
+
+//
+// The following declarations are shared between ndismac.h and ndismini.h. They
+// are meant to be for internal use only. They should not be used directly by
+// miniport drivers.
+//
+
+//
+// declare these first since they point to each other
+//
+
+typedef struct _NDIS_WRAPPER_HANDLE NDIS_WRAPPER_HANDLE, * PNDIS_WRAPPER_HANDLE;
+typedef struct _NDIS_MAC_BLOCK NDIS_MAC_BLOCK, * PNDIS_MAC_BLOCK;
+typedef struct _NDIS_ADAPTER_BLOCK NDIS_ADAPTER_BLOCK, * PNDIS_ADAPTER_BLOCK;
+typedef struct _NDIS_PROTOCOL_BLOCK NDIS_PROTOCOL_BLOCK, * PNDIS_PROTOCOL_BLOCK;
+typedef struct _NDIS_OPEN_BLOCK NDIS_OPEN_BLOCK, * PNDIS_OPEN_BLOCK;
+
+//
+// Timers.
+//
+
+typedef
+VOID
+(*PNDIS_TIMER_FUNCTION) (
+ IN PVOID SystemSpecific1,
+ IN PVOID FunctionContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+typedef struct _NDIS_TIMER {
+ KTIMER Timer;
+ KDPC Dpc;
+} NDIS_TIMER, *PNDIS_TIMER;
+
+EXPORT
+VOID
+NdisSetTimer(
+ IN PNDIS_TIMER Timer,
+ IN UINT MillisecondsToDelay
+ );
+
+//
+// Function types for NDIS_PROTOCOL_CHARACTERISTICS
+//
+
+typedef
+VOID
+(*SEND_COMPLETE_HANDLER) (
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ );
+
+typedef
+VOID
+(*TRANSFER_DATA_COMPLETE_HANDLER) (
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ );
+
+typedef
+NDIS_STATUS
+(*RECEIVE_HANDLER) (
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookAheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+typedef
+VOID
+(*RECEIVE_COMPLETE_HANDLER) (
+ IN NDIS_HANDLE ProtocolBindingContext
+ );
+
+//
+// Wrapper initialization and termination.
+//
+
+EXPORT
+VOID
+NdisInitializeWrapper(
+ OUT PNDIS_HANDLE NdisWrapperHandle,
+ IN PVOID SystemSpecific1,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+EXPORT
+VOID
+NdisTerminateWrapper(
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN PVOID SystemSpecific
+ );
+
+//
+// Shared memory
+//
+
+#define NdisUpdateSharedMemory(_H, _L, _V, _P)
+
+//
+// System processor count
+//
+
+EXPORT
+CCHAR
+NdisSystemProcessorCount(
+ VOID
+ );
+
+//
+// Override bus number
+//
+
+EXPORT
+VOID
+NdisOverrideBusNumber(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN NDIS_HANDLE MiniportAdapterHandle OPTIONAL,
+ IN ULONG BusNumber
+ );
+
+
+EXPORT
+VOID
+NdisImmediateReadPortUchar(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ OUT PUCHAR Data
+ );
+
+EXPORT
+VOID
+NdisImmediateReadPortUshort(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ OUT PUSHORT Data
+ );
+
+EXPORT
+VOID
+NdisImmediateReadPortUlong(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ OUT PULONG Data
+ );
+
+EXPORT
+VOID
+NdisImmediateWritePortUchar(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ IN UCHAR Data
+ );
+
+EXPORT
+VOID
+NdisImmediateWritePortUshort(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ IN USHORT Data
+ );
+
+EXPORT
+VOID
+NdisImmediateWritePortUlong(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ IN ULONG Data
+ );
+
+EXPORT
+ULONG
+NdisImmediateReadPciSlotInformation(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ );
+
+EXPORT
+ULONG
+NdisImmediateWritePciSlotInformation(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ );
+
diff --git a/private/ntos/ndis/ndis30/ndismini.h b/private/ntos/ndis/ndis30/ndismini.h
new file mode 100644
index 000000000..38892897d
--- /dev/null
+++ b/private/ntos/ndis/ndis30/ndismini.h
@@ -0,0 +1,1216 @@
+#include <afilter.h>
+#include <efilter.h>
+#include <tfilter.h>
+#include <ffilter.h>
+
+#define NDIS_M_MAX_MULTI_LIST 32
+#define NDIS_M_MAX_LOOKAHEAD 526
+
+//
+// declare these first since they point to each other
+//
+
+typedef struct _NDIS_M_DRIVER_BLOCK NDIS_M_DRIVER_BLOCK, * PNDIS_M_DRIVER_BLOCK;
+typedef struct _NDIS_MINIPORT_BLOCK NDIS_MINIPORT_BLOCK, * PNDIS_MINIPORT_BLOCK;
+typedef struct _NDIS_M_PROTOCOL_BLOCK NDIS_M_PROTOCOL_BLOCK, * PNDIS_M_PROTOCOL_BLOCK;
+typedef struct _NDIS_M_OPEN_BLOCK NDIS_M_OPEN_BLOCK, * PNDIS_M_OPEN_BLOCK;
+
+
+//
+// Function types for NDIS_MINIPORT_CHARACTERISTICS
+//
+
+
+typedef
+BOOLEAN
+(*W_CHECK_FOR_HANG_HANDLER) (
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+typedef
+VOID
+(*W_DISABLE_INTERRUPT_HANDLER) (
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+typedef
+VOID
+(*W_ENABLE_INTERRUPT_HANDLER) (
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+typedef
+VOID
+(*W_HALT_HANDLER) (
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+typedef
+VOID
+(*W_HANDLE_INTERRUPT_HANDLER) (
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+typedef
+NDIS_STATUS
+(*W_INITIALIZE_HANDLER) (
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ );
+
+typedef
+VOID
+(*W_ISR_HANDLER) (
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueMiniportHandleInterrupt,
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+typedef
+NDIS_STATUS
+(*W_QUERY_INFORMATION_HANDLER) (
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ );
+
+typedef
+NDIS_STATUS
+(*W_RECONFIGURE_HANDLER) (
+ OUT PNDIS_STATUS OpenErrorStatus,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ );
+
+typedef
+NDIS_STATUS
+(*W_RESET_HANDLER) (
+ OUT PBOOLEAN AddressingReset,
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+typedef
+NDIS_STATUS
+(*W_SEND_HANDLER) (
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet,
+ IN UINT Flags
+ );
+
+typedef
+NDIS_STATUS
+(*W_SET_INFORMATION_HANDLER) (
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ );
+
+typedef
+NDIS_STATUS
+(*W_TRANSFER_DATA_HANDLER) (
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ );
+
+typedef struct _NDIS_MINIPORT_CHARACTERISTICS {
+ UCHAR MajorNdisVersion;
+ UCHAR MinorNdisVersion;
+ UINT Reserved;
+ W_CHECK_FOR_HANG_HANDLER CheckForHangHandler;
+ W_DISABLE_INTERRUPT_HANDLER DisableInterruptHandler;
+ W_ENABLE_INTERRUPT_HANDLER EnableInterruptHandler;
+ W_HALT_HANDLER HaltHandler;
+ W_HANDLE_INTERRUPT_HANDLER HandleInterruptHandler;
+ W_INITIALIZE_HANDLER InitializeHandler;
+ W_ISR_HANDLER ISRHandler;
+ W_QUERY_INFORMATION_HANDLER QueryInformationHandler;
+ W_RECONFIGURE_HANDLER ReconfigureHandler;
+ W_RESET_HANDLER ResetHandler;
+ W_SEND_HANDLER SendHandler;
+ W_SET_INFORMATION_HANDLER SetInformationHandler;
+ W_TRANSFER_DATA_HANDLER TransferDataHandler;
+} NDIS_MINIPORT_CHARACTERISTICS, *PNDIS_MINIPORT_CHARACTERISTICS;
+
+//
+// one of these per Driver
+//
+
+struct _NDIS_M_DRIVER_BLOCK {
+ PNDIS_MINIPORT_BLOCK MiniportQueue; // queue of mini-ports for this driver
+ NDIS_HANDLE MiniportIdField;
+
+ REFERENCE Ref; // contains spinlock for MiniportQueue
+ UINT Length; // of this NDIS_DRIVER_BLOCK structure
+ NDIS_MINIPORT_CHARACTERISTICS MiniportCharacteristics; // handler addresses
+ PNDIS_WRAPPER_HANDLE NdisDriverInfo; // Driver information.
+ PNDIS_M_DRIVER_BLOCK NextDriver;
+ PNDIS_MAC_BLOCK FakeMac;
+ KEVENT MiniportsRemovedEvent; // used to find when all mini-ports are gone.
+ BOOLEAN Unloading; // TRUE if unloading
+
+};
+
+typedef struct _NDIS_MINIPORT_INTERRUPT {
+ PKINTERRUPT InterruptObject;
+ KSPIN_LOCK DpcCountLock;
+ PVOID MiniportIdField;
+ W_ISR_HANDLER MiniportIsr;
+ W_HANDLE_INTERRUPT_HANDLER MiniportDpc;
+ KDPC InterruptDpc;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ UCHAR DpcCount;
+ BOOLEAN Filler1;
+
+ //
+ // This is used to tell when all the Dpcs for the adapter are completed.
+ //
+
+ KEVENT DpcsCompletedEvent;
+
+ BOOLEAN SharedInterrupt;
+ BOOLEAN IsrRequested;
+
+} NDIS_MINIPORT_INTERRUPT, *PNDIS_MINIPORT_INTERRUPT;
+
+
+typedef struct _NDIS_MINIPORT_TIMER {
+ KTIMER Timer;
+ KDPC Dpc;
+ PNDIS_TIMER_FUNCTION MiniportTimerFunction;
+ PVOID MiniportTimerContext;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ struct _NDIS_MINIPORT_TIMER *NextDeferredTimer;
+} NDIS_MINIPORT_TIMER, *PNDIS_MINIPORT_TIMER;
+
+//
+// Pending NdisOpenAdapter() structure (for miniports only).
+//
+
+typedef struct _MINIPORT_PENDING_OPEN *PMINIPORT_PENDING_OPEN;
+
+typedef struct _MINIPORT_PENDING_OPEN {
+
+ PMINIPORT_PENDING_OPEN NextPendingOpen;
+ PNDIS_HANDLE NdisBindingHandle;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PVOID NewOpenP;
+ PVOID FileObject;
+ NDIS_HANDLE NdisProtocolHandle;
+ NDIS_HANDLE ProtocolBindingContext;
+ PNDIS_STRING AdapterName;
+ UINT OpenOptions;
+ PSTRING AddressingInformation;
+ BOOLEAN UsingEncapsulation;
+} MINIPORT_PENDING_OPEN;
+
+
+//
+// one of these per mini-port registered on a Driver
+//
+
+struct _NDIS_MINIPORT_BLOCK {
+ ULONG Flags; // used to distinquish between MACs and mini-ports
+ PDEVICE_OBJECT DeviceObject; // created by the wrapper
+ PNDIS_M_DRIVER_BLOCK DriverHandle; // pointer to our Driver block
+ NDIS_HANDLE MiniportAdapterContext; // context when calling mini-port functions
+ NDIS_STRING MiniportName; // how mini-port refers to us
+ PNDIS_M_OPEN_BLOCK OpenQueue; // queue of opens for this mini-port
+ PNDIS_MINIPORT_BLOCK NextMiniport; // used by driver's MiniportQueue
+ REFERENCE Ref; // contains spinlock for OpenQueue
+ BOOLEAN NormalInterrupts;
+ BOOLEAN ProcessingDeferred; // TRUE if processing deferred operations
+
+ //
+ // Synchronization stuff.
+ //
+ // The boolean is used to lock out several DPCs from running at the
+ // same time. The difficultly is if DPC A releases the spin lock
+ // and DPC B tries to run, we want to defer B until after A has
+ // exited.
+ //
+ BOOLEAN LockAcquired;
+ NDIS_SPIN_LOCK Lock;
+ PNDIS_MINIPORT_INTERRUPT Interrupt;
+
+ //
+ // Stuff that got deferred.
+ //
+ BOOLEAN RunDpc;
+ BOOLEAN Timeout;
+ BOOLEAN InAddDriver;
+ BOOLEAN InInitialize;
+ PNDIS_MINIPORT_TIMER RunTimer;
+ NDIS_TIMER DpcTimer;
+ NDIS_TIMER WakeUpDpcTimer;
+
+ //
+ // Holds media specific information
+ //
+ PETH_FILTER EthDB;
+ PTR_FILTER TrDB;
+ PFDDI_FILTER FddiDB;
+ PARC_FILTER ArcDB;
+ NDIS_MEDIUM MediaType;
+
+ UCHAR TrResetRing;
+ UCHAR ArcnetAddress;
+ BOOLEAN ArcnetBroadcastSet;
+ BOOLEAN SendCompleteCalled;
+
+ PVOID WrapperContext;
+
+ NDIS_HANDLE ArcnetBufferPool;
+ PARC_BUFFER_LIST ArcnetFreeBufferList;
+ PARC_BUFFER_LIST ArcnetUsedBufferList;
+
+ //
+ // Resource information
+ //
+ PCM_RESOURCE_LIST Resources;
+
+ //
+ // contains mini-port information
+ //
+ ULONG BusNumber;
+ NDIS_INTERFACE_TYPE BusType;
+ NDIS_INTERFACE_TYPE AdapterType;
+ BOOLEAN Master;
+
+ //
+ // Holds the map registers for this mini-port.
+ //
+ BOOLEAN Dma32BitAddresses;
+ PMAP_REGISTER_ENTRY MapRegisters;
+ ULONG PhysicalMapRegistersNeeded;
+ ULONG MaximumPhysicalMapping;
+
+ //
+ // These two are used temporarily while allocating
+ // the map registers.
+ //
+ KEVENT AllocationEvent;
+ UINT CurrentMapRegister;
+ PADAPTER_OBJECT SystemAdapterObject;
+
+ //
+ // Send information
+ //
+ PNDIS_PACKET FirstPacket; // This pointer serves two purposes;
+ // it is the head of the queue of ALL
+ // packets that have been sent to
+ // the miniport, it is also the head
+ // of the packets that have been sent
+ // down to the miniport by the wrapper.
+ PNDIS_PACKET LastPacket; // This is tail pointer for the global
+ // packet queue and this is the tail
+ // pointer to the queue of packets
+ // waiting to be sent to the miniport.
+ PNDIS_PACKET FirstPendingPacket; // This is head of the queue of packets
+ // waiting to be sent to miniport.
+ PNDIS_PACKET LastMiniportPacket; // This is the tail pointer of the
+ // queue of packets that have been
+ // sent to the miniport by the wrapper.
+ ULONG SendResourcesAvailable;
+ PNDIS_PACKET DeadPacket; // This pointer is used by the wake-up
+ // dpc to make sure that a packet that
+ // was sent to the miniport has been
+ // completed with-in a decent amount
+ // of time.
+ BOOLEAN AlreadyLoopedBack; // This flag is set if a packet that
+ // is waiting to be sent to the
+ // miniport has already been looped-
+ // back;
+
+
+ //
+ // Transfer data information
+ //
+ PNDIS_PACKET FirstTDPacket;
+ PNDIS_PACKET LastTDPacket;
+ PNDIS_PACKET LoopbackPacket;
+ UINT LoopbackPacketHeaderSize;
+
+ //
+ // Reset information
+ //
+ PNDIS_M_OPEN_BLOCK ResetRequested;
+ PNDIS_M_OPEN_BLOCK ResetInProgress;
+
+ //
+ // RequestInformation
+ //
+ KEVENT RequestEvent;
+ PNDIS_REQUEST FirstPendingRequest;
+ PNDIS_REQUEST LastPendingRequest;
+ PNDIS_REQUEST MiniportRequest;
+ NDIS_REQUEST InternalRequest;
+ NDIS_STATUS RequestStatus;
+ UINT MaximumLongAddresses;
+ UINT MaximumShortAddresses;
+ UINT CurrentLookahead;
+ UINT MaximumLookahead;
+ UINT MacOptions;
+ ULONG SupportedPacketFilters;
+ BOOLEAN NeedToUpdateEthAddresses;
+ BOOLEAN NeedToUpdatePacketFilter;
+ BOOLEAN NeedToUpdateFunctionalAddress;
+ BOOLEAN NeedToUpdateGroupAddress;
+ BOOLEAN NeedToUpdateFddiLongAddresses;
+ BOOLEAN NeedToUpdateFddiShortAddresses;
+ BOOLEAN RunDoRequests;
+ BOOLEAN ProcessOddDeferredStuff;
+ UCHAR MulticastBuffer[NDIS_M_MAX_MULTI_LIST][6];
+ UCHAR LookaheadBuffer[NDIS_M_MAX_LOOKAHEAD];
+
+ BOOLEAN BeingRemoved; // TRUE if mini-port is being removed
+ BOOLEAN HaltingMiniport; // TRUE if mini-port halt handler needs to be called
+
+ //
+ // Temp stuff for using the old NDIS functions
+ //
+ ULONG ChannelNumber;
+
+ PMINIPORT_PENDING_OPEN FirstPendingOpen;
+ PMINIPORT_PENDING_OPEN LastPendingOpen;
+ BOOLEAN PendingRequestTimeout;
+};
+
+#define MINIPORT_LOCK_ACQUIRED(_Miniport) ((_Miniport)->LockAcquired)
+
+
+//
+// one of these per open on an mini-port/protocol
+//
+
+struct _NDIS_M_OPEN_BLOCK {
+ PNDIS_M_DRIVER_BLOCK DriverHandle; // pointer to our driver
+ PNDIS_MINIPORT_BLOCK MiniportHandle; // pointer to our mini-port
+ PNDIS_PROTOCOL_BLOCK ProtocolHandle; // pointer to our protocol
+ PNDIS_OPEN_BLOCK FakeOpen; // Pointer to fake open block
+ NDIS_HANDLE ProtocolBindingContext; // context when calling ProtXX funcs
+ NDIS_HANDLE MiniportAdapterContext; // context when calling MiniportXX funcs
+ PNDIS_M_OPEN_BLOCK MiniportNextOpen; // used by mini-port's OpenQueue
+ PFILE_OBJECT FileObject; // created by operating system
+ BOOLEAN Closing; // TRUE when removing this struct
+ BOOLEAN UsingEthEncapsulation; // TRUE if running 802.3 on 878.2
+ NDIS_HANDLE CloseRequestHandle; // 0 indicates an internal close
+ NDIS_HANDLE FilterHandle;
+ NDIS_SPIN_LOCK SpinLock; // guards Closing
+ ULONG References;
+ UINT CurrentLookahead;
+ ULONG ProtocolOptions;
+
+ //
+ // These are optimizations for getting to driver routines. They are not
+ // necessary, but are here to save a dereference through the Driver block.
+ //
+
+ W_SEND_HANDLER SendHandler;
+ W_TRANSFER_DATA_HANDLER TransferDataHandler;
+
+ //
+ // These are optimizations for getting to PROTOCOL routines. They are not
+ // necessary, but are here to save a dereference through the PROTOCOL block.
+ //
+
+ SEND_COMPLETE_HANDLER SendCompleteHandler;
+ TRANSFER_DATA_COMPLETE_HANDLER TransferDataCompleteHandler;
+ RECEIVE_HANDLER ReceiveHandler;
+ RECEIVE_COMPLETE_HANDLER ReceiveCompleteHandler;
+
+};
+
+//
+// NOTE: THIS STRUCTURE MUST, MUST, MUST ALIGN WITH THE
+// NDIS_USER_OPEN_CONTEXT STRUCTURE defined in the wrapper.
+//
+typedef struct _NDIS_M_USER_OPEN_CONTEXT {
+ PDEVICE_OBJECT DeviceObject;
+ PNDIS_MINIPORT_BLOCK MiniportBlock;
+ ULONG OidCount;
+ PNDIS_OID OidArray;
+} NDIS_M_USER_OPEN_CONTEXT, *PNDIS_M_USER_OPEN_CONTEXT;
+
+
+typedef struct _NDIS_REQUEST_RESERVED {
+ PNDIS_REQUEST Next;
+ struct _NDIS_M_OPEN_BLOCK * Open;
+} NDIS_REQUEST_RESERVED, *PNDIS_REQUEST_RESERVED;
+
+#define PNDIS_RESERVED_FROM_PNDIS_REQUEST(_request) \
+ ((PNDIS_REQUEST_RESERVED)((_request)->MacReserved))
+
+
+BOOLEAN
+NdisMIsr(
+ IN PKINTERRUPT KInterrupt,
+ IN PVOID Context
+ );
+
+VOID
+NdisMDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+VOID
+NdisMDpcTimer(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+VOID
+NdisMWakeUpDpc(
+ PKDPC Dpc,
+ PVOID Context,
+ PVOID SystemContext1,
+ PVOID SystemContext2
+ );
+
+NDIS_STATUS
+NdisMChangeEthAddresses(
+ IN UINT OldAddressCount,
+ IN CHAR OldAddresses[][6],
+ IN UINT NewAddressCount,
+ IN CHAR NewAddresses[][6],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+NDIS_STATUS
+NdisMChangeClass(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+VOID
+NdisMCloseAction(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+NDIS_STATUS
+NdisMChangeFunctionalAddress(
+ IN TR_FUNCTIONAL_ADDRESS OldFunctionalAddress,
+ IN TR_FUNCTIONAL_ADDRESS NewFunctionalAddress,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+NDIS_STATUS
+NdisMChangeGroupAddress(
+ IN TR_FUNCTIONAL_ADDRESS OldGroupAddress,
+ IN TR_FUNCTIONAL_ADDRESS NewGroupAddress,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+NDIS_STATUS
+NdisMChangeFddiAddresses(
+ IN UINT oldLongAddressCount,
+ IN CHAR oldLongAddresses[][6],
+ IN UINT newLongAddressCount,
+ IN CHAR newLongAddresses[][6],
+ IN UINT oldShortAddressCount,
+ IN CHAR oldShortAddresses[][2],
+ IN UINT newShortAddressCount,
+ IN CHAR newShortAddresses[][2],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+NDIS_STATUS
+NdisMSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+NDIS_STATUS
+NdisMTransferData(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+NDIS_STATUS
+NdisMArcTransferData(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+NDIS_STATUS
+NdisMReset(
+ IN NDIS_HANDLE NdisBindingHandle
+ );
+
+NDIS_STATUS
+NdisMRequest(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+
+//
+// Operating System Requests
+//
+
+EXPORT
+NDIS_STATUS
+NdisMAllocateMapRegisters(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT DmaChannel,
+ IN BOOLEAN Dma32BitAddresses,
+ IN ULONG PhysicalMapRegistersNeeded,
+ IN ULONG MaximumPhysicalMapping
+ );
+
+EXPORT
+VOID
+NdisMFreeMapRegisters(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ );
+
+EXPORT
+NDIS_STATUS
+NdisMRegisterIoPortRange(
+ OUT PVOID *PortOffset,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT InitialPort,
+ IN UINT NumberOfPorts
+ );
+
+EXPORT
+VOID
+NdisMDeregisterIoPortRange(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT InitialPort,
+ IN UINT NumberOfPorts,
+ IN PVOID PortOffset
+ );
+
+EXPORT
+NDIS_STATUS
+NdisMMapIoSpace(
+ OUT PVOID * VirtualAddress,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress,
+ IN UINT Length
+ );
+
+EXPORT
+VOID
+NdisMUnmapIoSpace(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PVOID VirtualAddress,
+ IN UINT Length
+ );
+
+EXPORT
+NDIS_STATUS
+NdisMRegisterInterrupt(
+ OUT PNDIS_MINIPORT_INTERRUPT Interrupt,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT InterruptVector,
+ IN UINT InterruptLevel,
+ IN BOOLEAN RequestIsr,
+ IN BOOLEAN SharedInterrupt,
+ IN NDIS_INTERRUPT_MODE InterruptMode
+ );
+
+EXPORT
+VOID
+NdisMDeregisterInterrupt(
+ IN PNDIS_MINIPORT_INTERRUPT Interrupt
+ );
+
+EXPORT
+BOOLEAN
+NdisMSynchronizeWithInterrupt(
+ IN PNDIS_MINIPORT_INTERRUPT Interrupt,
+ IN PVOID SynchronizeFunction,
+ IN PVOID SynchronizeContext
+ );
+
+
+EXPORT
+NDIS_STATUS
+NdisMQueryAdapterResources(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PNDIS_RESOURCE_LIST ResourceList,
+ IN OUT PUINT BufferSize
+ );
+
+//
+// Timers
+//
+
+/*++
+VOID
+NdisMSetTimer(
+ IN PNDIS_MINIPORT_TIMER Timer,
+ IN UINT MillisecondsToDelay
+ );
+--*/
+#define NdisMSetTimer(_Timer, _Delay) NdisSetTimer((PNDIS_TIMER)(_Timer), _Delay)
+
+EXPORT
+VOID
+NdisMInitializeTimer(
+ IN OUT PNDIS_MINIPORT_TIMER Timer,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_TIMER_FUNCTION TimerFunction,
+ IN PVOID FunctionContext
+ );
+
+EXPORT
+VOID
+NdisMCancelTimer(
+ IN PNDIS_MINIPORT_TIMER Timer,
+ OUT PBOOLEAN TimerCancelled
+ );
+
+//
+// Physical Mapping
+//
+
+#define NdisMStartBufferPhysicalMappingMacro( \
+ _MiniportAdapterHandle, \
+ _Buffer, \
+ _PhysicalMapRegister, \
+ _Write, \
+ _PhysicalAddressArray, \
+ _ArraySize \
+ ) \
+{ \
+ PNDIS_MINIPORT_BLOCK _Miniport = (PNDIS_MINIPORT_BLOCK)(_MiniportAdapterHandle); \
+ PHYSICAL_ADDRESS _LogicalAddress; \
+ PUCHAR _VirtualAddress; \
+ ULONG _LengthRemaining; \
+ ULONG _LengthMapped; \
+ UINT _CurrentArrayLocation; \
+ _VirtualAddress = MmGetMdlVirtualAddress(_Buffer); \
+ _LengthRemaining = MmGetMdlByteCount(_Buffer); \
+ _CurrentArrayLocation = 0; \
+ while (_LengthRemaining > 0) { \
+ _LengthMapped = _LengthRemaining; \
+ _LogicalAddress = \
+ IoMapTransfer( \
+ NULL, \
+ (_Buffer), \
+ _Miniport->MapRegisters[_PhysicalMapRegister].MapRegister, \
+ _VirtualAddress, \
+ &_LengthMapped, \
+ (_Write)); \
+ (_PhysicalAddressArray)[_CurrentArrayLocation].PhysicalAddress = _LogicalAddress; \
+ (_PhysicalAddressArray)[_CurrentArrayLocation].Length = _LengthMapped; \
+ _LengthRemaining -= _LengthMapped; \
+ _VirtualAddress += _LengthMapped; \
+ ++_CurrentArrayLocation; \
+ } \
+ _Miniport->MapRegisters[_PhysicalMapRegister].WriteToDevice = (_Write); \
+ *(_ArraySize) = _CurrentArrayLocation; \
+}
+
+#if BINARY_COMPATIBLE
+
+EXPORT
+VOID
+NdisMStartBufferPhysicalMapping(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG PhysicalMapRegister,
+ IN BOOLEAN WriteToDevice,
+ OUT PNDIS_PHYSICAL_ADDRESS_UNIT PhysicalAddressArray,
+ OUT PUINT ArraySize
+ );
+
+#else
+
+#define NdisMStartBufferPhysicalMapping( \
+ _MiniportAdapterHandle, \
+ _Buffer, \
+ _PhysicalMapRegister, \
+ _Write, \
+ _PhysicalAddressArray, \
+ _ArraySize \
+ ) \
+ NdisMStartBufferPhysicalMappingMacro( \
+ (_MiniportAdapterHandle), \
+ (_Buffer), \
+ (_PhysicalMapRegister), \
+ (_Write), \
+ (_PhysicalAddressArray), \
+ (_ArraySize) \
+ )
+
+#endif
+
+#define NdisMCompleteBufferPhysicalMappingMacro( \
+ _MiniportAdapterHandle, \
+ _Buffer, \
+ _PhysicalMapRegister \
+ ) { \
+ PNDIS_MINIPORT_BLOCK _Miniport = (PNDIS_MINIPORT_BLOCK)(_MiniportAdapterHandle); \
+ IoFlushAdapterBuffers( \
+ NULL, \
+ _Buffer, \
+ _Miniport->MapRegisters[_PhysicalMapRegister].MapRegister, \
+ MmGetMdlVirtualAddress(_Buffer), \
+ MmGetMdlByteCount(_Buffer), \
+ _Miniport->MapRegisters[_PhysicalMapRegister].WriteToDevice); \
+}
+
+#if BINARY_COMPATIBLE
+
+EXPORT
+VOID
+NdisMCompleteBufferPhysicalMapping(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG PhysicalMapRegister
+ );
+
+#else
+
+#define NdisMCompleteBufferPhysicalMapping( \
+ _MiniportAdapterHandle, \
+ _Buffer, \
+ _PhysicalMapRegister \
+ ) \
+ NdisMCompleteBufferPhysicalMappingMacro( \
+ (_MiniportAdapterHandle), \
+ (_Buffer), \
+ (_PhysicalMapRegister) \
+ )
+
+#endif
+
+//
+// Shared memory
+//
+
+EXPORT
+VOID
+NdisMAllocateSharedMemory(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN ULONG Length,
+ IN BOOLEAN Cached,
+ OUT PVOID *VirtualAddress,
+ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress
+ );
+
+/*++
+VOID
+NdisMUpdateSharedMemory(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN ULONG Length,
+ IN PVOID VirtualAddress,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
+ )
+--*/
+#define NdisMUpdateSharedMemory(_H, _L, _V, _P) NdisUpdateSharedMemory(_H, _L, _V, _P)
+
+
+EXPORT
+VOID
+NdisMFreeSharedMemory(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN ULONG Length,
+ IN BOOLEAN Cached,
+ IN PVOID VirtualAddress,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
+ );
+
+
+//
+// DMA operations.
+//
+
+EXPORT
+NDIS_STATUS
+NdisMRegisterDmaChannel(
+ OUT PNDIS_HANDLE MiniportDmaHandle,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT DmaChannel,
+ IN BOOLEAN Dma32BitAddresses,
+ IN PNDIS_DMA_DESCRIPTION DmaDescription,
+ IN ULONG MaximumLength
+ );
+
+
+EXPORT
+VOID
+NdisMDeregisterDmaChannel(
+ IN PNDIS_HANDLE MiniportDmaHandle
+ );
+
+/*++
+VOID
+NdisMSetupDmaTransfer(
+ OUT PNDIS_STATUS Status,
+ IN PNDIS_HANDLE MiniportDmaHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG Offset,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ )
+--*/
+#define NdisMSetupDmaTransfer(_S, _H, _B, _O, _L, _M_) \
+ NdisSetupDmaTransfer(_S, _H, _B, _O, _L, _M_)
+
+/*++
+VOID
+NdisMCompleteDmaTransfer(
+ OUT PNDIS_STATUS Status,
+ IN PNDIS_HANDLE MiniportDmaHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG Offset,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ )
+--*/
+#define NdisMCompleteDmaTransfer(_S, _H, _B, _O, _L, _M_) \
+ NdisCompleteDmaTransfer(_S, _H, _B, _O, _L, _M_)
+
+EXPORT
+ULONG
+NdisMReadDmaCounter(
+ IN NDIS_HANDLE MiniportDmaHandle
+ );
+
+
+//
+// Requests Used by Miniport Drivers
+//
+
+
+#define NdisMInitializeWrapper(_a,_b,_c,_d) NdisInitializeWrapper((_a),(_b),(_c),(_d))
+
+EXPORT
+NDIS_STATUS
+NdisMRegisterMiniport(
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN PNDIS_MINIPORT_CHARACTERISTICS MiniportCharacteristics,
+ IN UINT CharacteristicsLength
+ );
+
+EXPORT
+VOID
+NdisMSetAttributes(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN BOOLEAN BusMaster,
+ IN NDIS_INTERFACE_TYPE AdapterType
+ );
+
+EXPORT
+VOID
+NdisMSendComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ );
+
+EXPORT
+VOID
+NdisMSendResourcesAvailable(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ );
+
+EXPORT
+VOID
+NdisMTransferDataComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ );
+
+EXPORT
+VOID
+NdisMResetComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_STATUS Status,
+ IN BOOLEAN AddressingReset
+ );
+
+EXPORT
+VOID
+NdisMSetInformationComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_STATUS Status
+ );
+
+EXPORT
+VOID
+NdisMQueryInformationComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_STATUS Status
+ );
+
+
+/*++
+
+VOID
+NdisMEthIndicateReceive(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+--*/
+#define NdisMEthIndicateReceive( _H, _C, _B, _SZ, _L, _LSZ, _PSZ ) \
+{ \
+ ASSERT(MINIPORT_LOCK_ACQUIRED((PNDIS_MINIPORT_BLOCK)(_H))); \
+ EthFilterDprIndicateReceive( \
+ ((PNDIS_MINIPORT_BLOCK)(_H))->EthDB, \
+ _C, \
+ _B, \
+ _B, \
+ _SZ, \
+ _L, \
+ _LSZ, \
+ _PSZ \
+ ); \
+}
+
+/*++
+
+VOID
+NdisMTrIndicateReceive(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+--*/
+#define NdisMTrIndicateReceive( _H, _C, _B, _SZ, _L, _LSZ, _PSZ ) \
+{ \
+ ASSERT(MINIPORT_LOCK_ACQUIRED((PNDIS_MINIPORT_BLOCK)(_H))); \
+ TrFilterDprIndicateReceive( \
+ ((PNDIS_MINIPORT_BLOCK)(_H))->TrDB, \
+ _C, \
+ _B, \
+ _SZ, \
+ _L, \
+ _LSZ, \
+ _PSZ \
+ ); \
+}
+
+/*++
+
+VOID
+NdisMFddiIndicateReceive(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+--*/
+
+#define NdisMFddiIndicateReceive( _H, _C, _B, _SZ, _L, _LSZ, _PSZ ) \
+{ \
+ ASSERT(MINIPORT_LOCK_ACQUIRED((PNDIS_MINIPORT_BLOCK)(_H))); \
+ \
+ FddiFilterDprIndicateReceive( \
+ ((PNDIS_MINIPORT_BLOCK)(_H))->FddiDB, \
+ _C, \
+ (PUCHAR)_B + 1, \
+ ((((PUCHAR)_B)[0] & 0x40) ? FDDI_LENGTH_OF_LONG_ADDRESS \
+ : FDDI_LENGTH_OF_SHORT_ADDRESS), \
+ _B, \
+ _SZ, \
+ _L, \
+ _LSZ, \
+ _PSZ \
+ ); \
+}
+
+/*++
+
+VOID
+NdisMArcIndicateReceive(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PUCHAR pRawHeader, // Pointer to Arcnet frame header
+ IN PUCHAR pData, // Pointer to data portion of Arcnet frame
+ IN UINT Length // Data Length
+ )
+
+--*/
+#define NdisMArcIndicateReceive( _H, _HD, _D, _SZ) \
+{ \
+ ASSERT(MINIPORT_LOCK_ACQUIRED((PNDIS_MINIPORT_BLOCK)(_H))); \
+ ArcFilterDprIndicateReceive( \
+ ((PNDIS_MINIPORT_BLOCK)(_H))->ArcDB, \
+ _HD, \
+ _D, \
+ _SZ \
+ ); \
+}
+
+//
+// Used only internally by the wrapper and filter package.
+//
+VOID
+NdisMArcIndicateEthEncapsulatedReceive(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PVOID HeaderBuffer,
+ IN PVOID DataBuffer,
+ IN UINT Length
+ );
+
+
+
+
+/*++
+
+VOID
+NdisMEthIndicateReceiveComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ );
+
+--*/
+
+#define NdisMEthIndicateReceiveComplete( _H ) \
+{ \
+ PNDIS_MINIPORT_BLOCK _M_ = (PNDIS_MINIPORT_BLOCK)_H; \
+ ASSERT(MINIPORT_LOCK_ACQUIRED(_M_)); \
+ EthFilterDprIndicateReceiveComplete(_M_->EthDB); \
+}
+
+/*++
+
+VOID
+NdisMTrIndicateReceiveComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ );
+
+--*/
+
+#define NdisMTrIndicateReceiveComplete( _H ) \
+{ \
+ PNDIS_MINIPORT_BLOCK _M_ = (PNDIS_MINIPORT_BLOCK)_H; \
+ ASSERT(MINIPORT_LOCK_ACQUIRED(_M_)); \
+ TrFilterDprIndicateReceiveComplete(_M_->TrDB); \
+}
+
+/*++
+
+VOID
+NdisMFddiIndicateReceiveComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ );
+
+--*/
+
+#define NdisMFddiIndicateReceiveComplete( _H ) \
+{ \
+ PNDIS_MINIPORT_BLOCK _M_ = (PNDIS_MINIPORT_BLOCK)_H; \
+ ASSERT(MINIPORT_LOCK_ACQUIRED(_M_)); \
+ FddiFilterDprIndicateReceiveComplete(_M_->FddiDB); \
+}
+
+/*++
+
+VOID
+NdisMArcIndicateReceiveComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ );
+
+--*/
+
+#define NdisMArcIndicateReceiveComplete( _H ) \
+{ \
+ PNDIS_MINIPORT_BLOCK _M_ = (PNDIS_MINIPORT_BLOCK)_H; \
+ ASSERT(MINIPORT_LOCK_ACQUIRED(_M_)); \
+ \
+ if ( _M_->EthDB ) { \
+ EthFilterDprIndicateReceiveComplete(_M_->EthDB); \
+ } \
+ \
+ ArcFilterDprIndicateReceiveComplete(_M_->ArcDB); \
+}
+
+EXPORT
+VOID
+NdisMIndicateStatus(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ );
+
+EXPORT
+VOID
+NdisMIndicateStatusComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ );
+
+EXPORT
+VOID
+NdisMRegisterAdapterShutdownHandler(
+ IN NDIS_HANDLE MiniportHandle,
+ IN PVOID ShutdownContext,
+ IN ADAPTER_SHUTDOWN_HANDLER ShutdownHandler
+ );
+
+EXPORT
+VOID
+NdisMDeregisterAdapterShutdownHandler(
+ IN NDIS_HANDLE MiniportHandle
+ );
+
+EXPORT
+NDIS_STATUS
+NdisMPciAssignResources(
+ IN NDIS_HANDLE MiniportHandle,
+ IN ULONG SlotNumber,
+ IN PNDIS_RESOURCE_LIST *AssignedResources
+ );
+
+
diff --git a/private/ntos/ndis/ndis30/precomp.h b/private/ntos/ndis/ndis30/precomp.h
new file mode 100644
index 000000000..9521fc237
--- /dev/null
+++ b/private/ntos/ndis/ndis30/precomp.h
@@ -0,0 +1,6 @@
+#include "wrapper.h"
+
+#include <afilter.h>
+#include <efilter.h>
+#include <ffilter.h>
+#include <tfilter.h>
diff --git a/private/ntos/ndis/ndis30/sources b/private/ntos/ndis/ndis30/sources
new file mode 100644
index 000000000..1d31c6f72
--- /dev/null
+++ b/private/ntos/ndis/ndis30/sources
@@ -0,0 +1,59 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+NT_UP=0
+
+TARGETNAME=ndis
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=EXPORT_DRIVER
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+INCLUDES=..\..\inc
+C_DEFINES= $(C_DEFINES) -DNDIS_WRAPPER -D_NTDRIVER_
+
+NTPROFILEINPUT=yes
+
+
+SOURCES= \
+ miniport.c \
+ wrapper.c \
+ minisub.c \
+ afilter.c \
+ efilter.c \
+ tfilter.c \
+ ffilter.c \
+ ndis.rc
+
+PRECOMPILED_INCLUDE=precomp.h
+PRECOMPILED_PCH=precomp.pch
+PRECOMPILED_OBJ=precomp.obj
+
+DLLDEF=obj\*\ndis.def
+
+NTTARGETFILE0=obj\$(TARGET_DIRECTORY)\ndis.def
+
diff --git a/private/ntos/ndis/ndis30/tfilter.c b/private/ntos/ndis/ndis30/tfilter.c
new file mode 100644
index 000000000..6d0b98a82
--- /dev/null
+++ b/private/ntos/ndis/ndis30/tfilter.c
@@ -0,0 +1,2119 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ tfilter.c
+
+Abstract:
+
+ This module implements a set of library routines to handle packet
+ filtering for NDIS MAC drivers.
+
+Author:
+
+ Anthony V. Ercolano (Tonye) 03-Aug-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+ Adam Barr (adamba) 19-Mar-1991
+
+ - Modified for Token-Ring
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+//
+// 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);
+
+//
+// ZZZ NonPortable definitions.
+//
+#define AllocPhys(s, l) NdisAllocateMemory((PVOID *)(s), (l), 0, HighestAcceptableMax)
+#define FreePhys(s, l) NdisFreeMemory((PVOID)(s), (l), 0)
+
+#define RetrieveUlong(Destination, Source)\
+{\
+ PUCHAR _S = (Source);\
+ *(Destination) = ((ULONG)(*_S) << 24) | \
+ ((ULONG)(*(_S+1)) << 16) | \
+ ((ULONG)(*(_S+2)) << 8) | \
+ ((ULONG)(*(_S+3)));\
+}
+
+#ifdef NDIS_NT
+#define MoveMemory(Destination,Source,Length) RtlMoveMemory(Destination,Source,Length)
+#define ZeroMemory(Destination,Length) RtlZeroMemory(Destination,Length)
+#endif
+
+#ifdef NDIS_DOS
+#define MoveMemory(Destination,Source,Length) \
+{\
+ int _i = Length;\
+ while( _i--) ((PUCHAR)(Destination))[_i] = ((PUCHAR)(Source))[_i]; \
+}
+
+#define ZeroMemory(Destination,Length) \
+{\
+ int _i = Length;\
+ while (_i--) ((PUCHAR)(Destination))[_i] = 0;\
+}
+#endif
+
+//
+// Used in case we have to call TrChangeFunctionalAddress or
+// TrChangeGroupAddress with a NULL address.
+//
+static CHAR NullFunctionalAddress[4] = { 0x00 };
+
+
+//
+// Maximum number of supported opens
+//
+#define TR_FILTER_MAX_OPENS 32
+
+
+
+#if DBG
+extern BOOLEAN NdisCheckBadDrivers;
+#endif
+
+//VOID
+//CLEAR_BIT_IN_MASK(
+// IN UINT Offset,
+// IN OUT PULONG MaskToClear
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Clear a bit in the bitmask pointed to by the parameter.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to altered.
+//
+// MaskToClear - Pointer to the mask to be adjusted.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+//
+#define CLEAR_BIT_IN_MASK(Offset,MaskToClear) *MaskToClear &= (~(1 << Offset))
+
+//VOID
+//SET_BIT_IN_MASK(
+// IN UINT Offset,
+// IN OUT PULONG MaskToSet
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Set a bit in the bitmask pointed to by the parameter.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to altered.
+//
+// MaskToSet - Pointer to the mask to be adjusted.
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+#define SET_BIT_IN_MASK(Offset,MaskToSet) *MaskToSet |= (1 << Offset)
+
+//BOOLEAN
+//IS_BIT_SET_IN_MASK(
+// IN UINT Offset,
+// IN ULONG MaskToTest
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Tests if a particular bit in the bitmask pointed to by the parameter is
+// set.
+//
+//Arguments:
+//
+// Offset - The offset (from 0) of the bit to test.
+//
+// MaskToTest - The mask to be tested.
+//
+//Return Value:
+//
+// Returns TRUE if the bit is set.
+//
+//--*/
+#define IS_BIT_SET_IN_MASK(Offset,MaskToTest) \
+((MaskToTest & (1 << Offset))?(TRUE):(FALSE))
+
+//
+// VOID
+// TR_FILTER_ALLOC_OPEN(
+// IN PTR_FILTER Filter,
+// OUT PUINT FilterIndex
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Allocates an open block. This only allocate the index, not memory for
+// the open block.
+//
+//Arguments:
+//
+// Filter - DB from which to allocate the space
+//
+// FilterIndex - pointer to place to store the index.
+//
+//Return Value:
+//
+// FilterIndex of the new open
+//
+//--*/
+#define TR_FILTER_ALLOC_OPEN(Filter, FilterIndex)\
+{\
+ UINT i; \
+ for (i=0; i < TR_FILTER_MAX_OPENS; i++) { \
+ if (IS_BIT_SET_IN_MASK(i,(Filter)->FreeBindingMask)) { \
+ *(FilterIndex) = i; \
+ CLEAR_BIT_IN_MASK(i, &((Filter)->FreeBindingMask)); \
+ break; \
+ } \
+ } \
+}
+
+//
+// VOID
+// TR_FILTER_FREE_OPEN(
+// IN PTR_FILTER Filter,
+// IN PTR_BINDING_INFO LocalOpen
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Frees an open block. Also frees the memory associated with the open.
+//
+//Arguments:
+//
+// Filter - DB from which to allocate the space
+//
+// FilterIndex - Index to free
+//
+//Return Value:
+//
+// FilterIndex of the new open
+//
+//--*/
+#define TR_FILTER_FREE_OPEN(Filter, LocalOpen)\
+{\
+ SET_BIT_IN_MASK(((LocalOpen)->FilterIndex), &((Filter)->FreeBindingMask)); \
+ FreePhys((LocalOpen), sizeof(TR_BINDING_INFO));\
+}
+
+NDIS_SPIN_LOCK TrReferenceLock = {0};
+KEVENT TrPagedInEvent = {0};
+ULONG TrReferenceCount = 0;
+PVOID TrImageHandle = {0};
+
+VOID
+TrInitializePackage(VOID)
+{
+ NdisAllocateSpinLock(&TrReferenceLock);
+ KeInitializeEvent(
+ &TrPagedInEvent,
+ NotificationEvent,
+ FALSE
+ );
+}
+
+VOID
+TrReferencePackage(VOID)
+{
+
+ ACQUIRE_SPIN_LOCK(&TrReferenceLock);
+
+ TrReferenceCount++;
+
+ if (TrReferenceCount == 1) {
+
+ KeResetEvent(
+ &TrPagedInEvent
+ );
+
+ RELEASE_SPIN_LOCK(&TrReferenceLock);
+
+ //
+ // Page in all the functions
+ //
+ TrImageHandle = MmLockPagableCodeSection(TrCreateFilter);
+
+ //
+ // Signal to everyone to go
+ //
+ KeSetEvent(
+ &TrPagedInEvent,
+ 0L,
+ FALSE
+ );
+
+ } else {
+
+ RELEASE_SPIN_LOCK(&TrReferenceLock);
+
+ //
+ // Wait for everything to be paged in
+ //
+ KeWaitForSingleObject(
+ &TrPagedInEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ NULL
+ );
+
+ }
+
+}
+
+VOID
+TrDereferencePackage(VOID)
+{
+ ACQUIRE_SPIN_LOCK(&TrReferenceLock);
+
+ TrReferenceCount--;
+
+ if (TrReferenceCount == 0) {
+
+ RELEASE_SPIN_LOCK(&TrReferenceLock);
+
+ //
+ // Page out all the functions
+ //
+ MmUnlockPagableImageSection(TrImageHandle);
+
+ } else {
+
+ RELEASE_SPIN_LOCK(&TrReferenceLock);
+
+ }
+
+}
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGENDST, TrShouldAddressLoopBack)
+#pragma alloc_text(PAGENDST, TrFilterDprIndicateReceiveComplete)
+#pragma alloc_text(PAGENDST, TrFilterIndicateReceiveComplete)
+#pragma alloc_text(PAGENDST, TrFilterDprIndicateReceive)
+#pragma alloc_text(PAGENDST, TrFilterIndicateReceive)
+#pragma alloc_text(PAGENDST, TrFilterAdjust)
+#pragma alloc_text(PAGENDST, TrChangeGroupAddress)
+#pragma alloc_text(PAGENDST, TrChangeFunctionalAddress)
+#pragma alloc_text(PAGENDST, TrDeleteFilterOpenAdapter)
+#pragma alloc_text(PAGENDST, TrNoteFilterOpenAdapter)
+#pragma alloc_text(PAGENDST, TrCreateFilter)
+
+#endif
+
+
+
+
+BOOLEAN
+TrCreateFilter(
+ IN TR_ADDRESS_CHANGE AddressChangeAction,
+ IN TR_GROUP_CHANGE GroupChangeAction,
+ IN TR_FILTER_CHANGE FilterChangeAction,
+ IN TR_DEFERRED_CLOSE CloseAction,
+ IN PUCHAR AdapterAddress,
+ IN PNDIS_SPIN_LOCK Lock,
+ OUT PTR_FILTER *Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to create and initialize the filter database.
+
+Arguments:
+
+ AddressChangeAction - Action routine to call when the ORing together
+ of the functional address desired by all the bindings had changed.
+
+ GroupChangeAction - Action routine to call when the group address
+ desired by all the bindings had changed.
+
+ FilterChangeAction - Action routine to call when a binding sets or clears
+ a particular filter class and it is the first or only binding using
+ the filter class.
+
+ CloseAction - This routine is called if a binding closes while
+ it is being indicated to via NdisIndicateReceive. It will be
+ called upon return from NdisIndicateReceive.
+
+ AdapterAddress - the address of the adapter associated with this filter
+ database.
+
+ Lock - Pointer to the lock that should be held when mutual exclusion
+ is required.
+
+ Filter - A pointer to a TR_FILTER. This is what is allocated and
+ created by this routine.
+
+Return Value:
+
+ If the function returns false then one of the parameters exceeded
+ what the filter was willing to support.
+
+--*/
+
+{
+
+ PTR_FILTER LocalFilter;
+ NDIS_STATUS AllocStatus;
+
+
+ //
+ // Allocate the database and it's associated arrays.
+ //
+
+ AllocStatus = AllocPhys(&LocalFilter, sizeof(TR_FILTER));
+ *Filter = LocalFilter;
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+ return FALSE;
+ }
+
+ TrReferencePackage();
+
+ ZeroMemory(
+ LocalFilter,
+ sizeof(TR_FILTER)
+ );
+
+
+ LocalFilter->GroupReferences = 0;
+ LocalFilter->GroupAddress = 0;
+ LocalFilter->OpenList = NULL;
+ LocalFilter->FreeBindingMask = (ULONG)-1;
+
+ LocalFilter->Lock = Lock;
+
+ TR_COPY_NETWORK_ADDRESS(LocalFilter->AdapterAddress, AdapterAddress);
+ LocalFilter->AddressChangeAction = AddressChangeAction;
+ LocalFilter->GroupChangeAction = GroupChangeAction;
+ LocalFilter->FilterChangeAction = FilterChangeAction;
+ LocalFilter->CloseAction = CloseAction;
+
+ return TRUE;
+}
+
+//
+// NOTE : THIS ROUTINE CANNOT BE PAGEABLE
+//
+
+VOID
+TrDeleteFilter(
+ IN PTR_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to delete the memory associated with a filter
+ database. Note that this routines *ASSUMES* that the database
+ has been cleared of any active filters.
+
+Arguments:
+
+ Filter - A pointer to a TR_FILTER to be deleted.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ASSERT(Filter->OpenList == NULL);
+
+ FreePhys(Filter, sizeof(TR_FILTER));
+
+ TrDereferencePackage();
+
+}
+
+
+BOOLEAN
+TrNoteFilterOpenAdapter(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE NdisBindingContext,
+ OUT PNDIS_HANDLE NdisFilterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to add a new binding to the filter database.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE DATABASE IS LOCKED WHEN
+ IT IS CALLED.
+
+Arguments:
+
+ Filter - A pointer to the previously created and initialized filter
+ database.
+
+ MacBindingHandle - The MAC supplied value to the protocol in response
+ to a call to MacOpenAdapter.
+
+ NdisBindingContext - An NDIS supplied value to the call to MacOpenAdapter.
+
+ NdisFilterHandle - A pointer to the open block.
+
+Return Value:
+
+ Will return false if creating a new filter index will cause the maximum
+ number of filter indexes to be exceeded.
+
+--*/
+
+{
+ NDIS_STATUS AllocStatus;
+
+ //
+ // Will hold the value of the filter index so that we
+ // need not indirectly address through pointer parameter.
+ //
+ UINT LocalIndex;
+
+ //
+ // This new open
+ //
+ PTR_BINDING_INFO LocalOpen;
+
+ PNDIS_OPEN_BLOCK NdisOpen = (PNDIS_OPEN_BLOCK)NdisBindingContext;
+
+ if (Filter->FreeBindingMask == 0) {
+
+ return FALSE;
+
+ }
+
+ AllocStatus = AllocPhys(
+ &LocalOpen,
+ sizeof(TR_BINDING_INFO)
+ );
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Get place for the open and insert it.
+ //
+
+ TR_FILTER_ALLOC_OPEN(Filter, &LocalIndex);
+
+ LocalOpen->NextOpen = Filter->OpenList;
+
+ if (Filter->OpenList != NULL) {
+ Filter->OpenList->PrevOpen = LocalOpen;
+ }
+
+ LocalOpen->PrevOpen = NULL;
+
+ Filter->OpenList = LocalOpen;
+
+ LocalOpen->References = 1;
+ LocalOpen->FilterIndex = (UCHAR)LocalIndex;
+ LocalOpen->MacBindingHandle = MacBindingHandle;
+ LocalOpen->NdisBindingContext = NdisBindingContext;
+ LocalOpen->UsingGroupAddress = FALSE;
+ LocalOpen->PacketFilters = 0;
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ LocalOpen->FunctionalAddress = (TR_FUNCTIONAL_ADDRESS)0;
+
+ *NdisFilterHandle = (PTR_BINDING_INFO)LocalOpen;
+
+ return TRUE;
+
+}
+
+
+NDIS_STATUS
+TrDeleteFilterOpenAdapter(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ When an adapter is being closed this routine should
+ be called to delete knowledge of the adapter from
+ the filter database. This routine is likely to call
+ action routines associated with clearing filter classes
+ and addresses.
+
+ NOTE: THIS ROUTINE SHOULD ****NOT**** BE CALLED IF THE ACTION
+ ROUTINES FOR DELETING THE FILTER CLASSES OR THE FUNCTIONAL ADDRESSES
+ HAVE ANY POSSIBILITY OF RETURNING A STATUS OTHER THAN NDIS_STATUS_PENDING
+ OR NDIS_STATUS_SUCCESS. WHILE THESE ROUTINES WILL NOT BUGCHECK IF
+ SUCH A THING IS DONE, THE CALLER WILL PROBABLY FIND IT DIFFICULT
+ TO CODE A CLOSE ROUTINE!
+
+ NOTE: THIS ROUTINE ASSUMES THAT IT IS CALLED WITH THE LOCK HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - A pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routines,
+ this will be passed to it.
+
+Return Value:
+
+ If action routines are called by the various address and filtering
+ routines the this routine will likely return the status returned
+ by those routines. The exception to this rule is noted below.
+
+ Given that the filter and address deletion routines return a status
+ NDIS_STATUS_PENDING or NDIS_STATUS_SUCCESS this routine will then
+ try to return the filter index to the freelist. If the routine
+ detects that this binding is currently being indicated to via
+ NdisIndicateReceive, this routine will return a status of
+ NDIS_STATUS_CLOSING_INDICATING.
+
+--*/
+
+{
+
+ //
+ // Holds the status returned from the packet filter and address
+ // deletion routines. Will be used to return the status to
+ // the caller of this routine.
+ //
+ NDIS_STATUS StatusToReturn;
+
+ PTR_BINDING_INFO LocalOpen = (PTR_BINDING_INFO)NdisFilterHandle;
+
+ StatusToReturn = TrFilterAdjust(
+ Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ (UINT)0,
+ FALSE
+ );
+
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS ||
+ StatusToReturn == NDIS_STATUS_PENDING) {
+
+ NDIS_STATUS StatusToReturn2;
+
+ StatusToReturn2 = TrChangeFunctionalAddress(
+ Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ NullFunctionalAddress,
+ FALSE
+ );
+
+ if (StatusToReturn2 != NDIS_STATUS_SUCCESS) {
+
+ StatusToReturn = StatusToReturn2;
+
+
+ }
+
+ }
+
+ if (((StatusToReturn == NDIS_STATUS_SUCCESS) ||
+ (StatusToReturn == NDIS_STATUS_PENDING)) &&
+ (LocalOpen->UsingGroupAddress)) {
+
+ Filter->GroupReferences--;
+
+ LocalOpen->UsingGroupAddress = FALSE;
+
+ if (Filter->GroupReferences == 0) {
+
+ NDIS_STATUS StatusToReturn2;
+
+ StatusToReturn2 = TrChangeGroupAddress(
+ Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ NullFunctionalAddress,
+ FALSE
+ );
+
+ if (StatusToReturn2 != NDIS_STATUS_SUCCESS) {
+
+ StatusToReturn = StatusToReturn2;
+
+ }
+
+ }
+
+ }
+
+ if ((StatusToReturn == NDIS_STATUS_SUCCESS) ||
+ (StatusToReturn == NDIS_STATUS_PENDING)) {
+
+ //
+ // If this is the last reference to the open - remove it.
+ //
+
+ if ((--(LocalOpen->References)) == 0) {
+
+ //
+ // Remove it from the list of opens.
+ //
+
+ if (LocalOpen->NextOpen != NULL) {
+
+ LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen;
+
+ }
+
+ if (LocalOpen->PrevOpen != NULL) {
+
+ LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen;
+
+ } else {
+
+ Filter->OpenList = LocalOpen->NextOpen;
+
+ }
+
+ //
+ // Check if we need to clean up an IndicateReceiveComplete
+ //
+
+ if (LocalOpen->ReceivedAPacket) {
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ }
+
+ //
+ // Destroy it.
+ //
+
+ TR_FILTER_FREE_OPEN(Filter, LocalOpen);
+
+ } else {
+
+ //
+ // Let the caller know that this "reference" to the open
+ // is still "active". The close action routine will be
+ // called upon return from NdisIndicateReceive.
+ //
+
+ StatusToReturn = NDIS_STATUS_CLOSING_INDICATING;
+
+ }
+
+ }
+
+ return StatusToReturn;
+
+}
+
+
+NDIS_STATUS
+TrChangeFunctionalAddress(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN CHAR FunctionalAddressArray[TR_LENGTH_OF_FUNCTIONAL],
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ The ChangeFunctionalAddress routine will call an action
+ routine when the overall functional address for the adapter
+ has changed.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the functional address
+ for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - A pointer to the open
+
+ NdisRequest - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ FunctionalAddress - The new functional address for this binding.
+
+ Set - A boolean that determines whether the filter classes
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ //
+ // Holds the functional address as a longword.
+ //
+ TR_FUNCTIONAL_ADDRESS FunctionalAddress;
+
+ //
+ // Contains the value of the combined functional address before
+ // it is adjusted.
+ //
+ UINT OldCombined = Filter->CombinedFunctionalAddress;
+
+ //
+ // Pointer to the open.
+ //
+ PTR_BINDING_INFO LocalOpen = (PTR_BINDING_INFO)NdisFilterHandle;
+
+ //
+ // Contains the value of the particlar open's packet filters
+ // prior to the change. We save this in case the action
+ // routine (if called) returns an "error" status.
+ //
+ UINT OldFunctionalAddress =
+ LocalOpen->FunctionalAddress;
+
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfAdjust;
+
+ //
+ // Simple iteration variable.
+ //
+ PTR_BINDING_INFO OpenList;
+
+
+ //
+ // Convert the 32 bits of the address to a longword.
+ //
+ RetrieveUlong(&FunctionalAddress, FunctionalAddressArray);
+
+ //
+ // Set the new filter information for the open.
+ //
+
+ LocalOpen->FunctionalAddress = FunctionalAddress;
+
+ //
+ // We always have to reform the compbined filter since
+ // this filter index may have been the only filter index
+ // to use a particular bit.
+ //
+
+ for (
+ OpenList = Filter->OpenList,Filter->CombinedFunctionalAddress = 0;
+ OpenList != NULL;
+ OpenList = OpenList->NextOpen
+ ) {
+
+ Filter->CombinedFunctionalAddress |=
+ OpenList->FunctionalAddress;
+
+ }
+
+ if (OldCombined != Filter->CombinedFunctionalAddress) {
+
+ StatusOfAdjust = Filter->AddressChangeAction(
+ OldCombined,
+ Filter->CombinedFunctionalAddress,
+ LocalOpen->MacBindingHandle,
+ NdisRequest,
+ Set
+ );
+
+ if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) &&
+ (StatusOfAdjust != NDIS_STATUS_PENDING)) {
+
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+
+ LocalOpen->FunctionalAddress = OldFunctionalAddress;
+ Filter->CombinedFunctionalAddress = OldCombined;
+
+ }
+
+ } else {
+
+ StatusOfAdjust = NDIS_STATUS_SUCCESS;
+
+ }
+
+ return StatusOfAdjust;
+
+}
+
+
+NDIS_STATUS
+TrChangeGroupAddress(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN CHAR GroupAddressArray[TR_LENGTH_OF_FUNCTIONAL],
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ The ChangeGroupAddress routine will call an action
+ routine when the overall group address for the adapter
+ has changed.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the group address
+ for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - A pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ GroupAddressArray - The new group address for this binding.
+
+ Set - A boolean that determines whether the filter classes
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ //
+ // Holds the Group address as a longword.
+ //
+ TR_FUNCTIONAL_ADDRESS GroupAddress;
+
+ PTR_BINDING_INFO LocalOpen = (PTR_BINDING_INFO)NdisFilterHandle;
+
+ UINT OldGroupAddress = Filter->GroupAddress;
+ UINT OldReferenceCount = Filter->GroupReferences;
+
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfAdjust;
+
+ //
+ // Convert the 32 bits of the address to a longword.
+ //
+ RetrieveUlong(&GroupAddress, GroupAddressArray);
+
+ //
+ // See if this is a deletion
+ //
+ if ((GroupAddressArray[0] == NullFunctionalAddress[0]) &&
+ (GroupAddressArray[1] == NullFunctionalAddress[1]) &&
+ (GroupAddressArray[2] == NullFunctionalAddress[2]) &&
+ (GroupAddressArray[3] == NullFunctionalAddress[3])) {
+
+ if (LocalOpen->UsingGroupAddress) {
+
+ Filter->GroupReferences--;
+
+ LocalOpen->UsingGroupAddress = FALSE;
+
+ if (Filter->GroupReferences != 0) {
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ } else if (Filter->GroupReferences != 0) {
+
+ return(NDIS_STATUS_GROUP_ADDRESS_IN_USE);
+
+ } else {
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ } else {
+
+ //
+ // See if this address is already the current address.
+ //
+
+ if (GroupAddress == Filter->GroupAddress) {
+
+ if (LocalOpen->UsingGroupAddress) {
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ if (Filter->GroupReferences != 0) {
+
+ LocalOpen->UsingGroupAddress = TRUE;
+
+ Filter->GroupReferences++;
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ } else {
+
+ if (Filter->GroupReferences > 1) {
+
+ return(NDIS_STATUS_GROUP_ADDRESS_IN_USE);
+
+ }
+
+ if ((Filter->GroupReferences == 1) && !(LocalOpen->UsingGroupAddress)) {
+
+ return(NDIS_STATUS_GROUP_ADDRESS_IN_USE);
+
+ }
+
+ if ((Filter->GroupReferences == 1) && (LocalOpen->UsingGroupAddress)) {
+
+ //
+ // Remove old reference
+ //
+
+ Filter->GroupReferences--;
+ LocalOpen->UsingGroupAddress = FALSE;
+
+ }
+
+ }
+
+ }
+
+ //
+ // Set the new filter information for the open.
+ //
+
+ Filter->GroupAddress = GroupAddress;
+
+ StatusOfAdjust = Filter->GroupChangeAction(
+ OldGroupAddress,
+ Filter->GroupAddress,
+ LocalOpen->MacBindingHandle,
+ NdisRequest,
+ Set
+ );
+
+ if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) &&
+ (StatusOfAdjust != NDIS_STATUS_PENDING)) {
+
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+
+ Filter->GroupAddress = OldGroupAddress;
+ Filter->GroupReferences = OldReferenceCount;
+
+ } else if (GroupAddress == 0x00000000) {
+
+ LocalOpen->UsingGroupAddress = FALSE;
+ Filter->GroupReferences = 0;
+
+ } else {
+
+ LocalOpen->UsingGroupAddress = TRUE;
+
+ Filter->GroupReferences = 1;
+
+ }
+
+ return StatusOfAdjust;
+
+}
+
+
+NDIS_STATUS
+TrFilterAdjust(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT FilterClasses,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ The FilterAdjust routine will call an action routine when a
+ particular filter class is changes from not being used by any
+ binding to being used by at least one binding or vice versa.
+
+ If the action routine returns a value other than pending or
+ success then this routine has no effect on the packet filters
+ for the open or for the adapter as a whole.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+Arguments:
+
+ Filter - A pointer to the filter database.
+
+ NdisFilterHandle - A pointer to the open.
+
+ NdisRequest - If it is necessary to call the action routine,
+ this will be passed to it.
+
+ FilterClasses - The filter classes that are to be added or
+ deleted.
+
+ Set - A boolean that determines whether the filter classes
+ are being adjusted due to a set or because of a close. (The filtering
+ routines don't care, the MAC might.)
+
+Return Value:
+
+ If it calls the action routine then it will return the
+ status returned by the action routine. If the status
+ returned by the action routine is anything other than
+ NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
+ will be returned to the state it was in upon entrance to this
+ routine.
+
+ If the action routine is not called this routine will return
+ the following statum:
+
+ NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
+ the combined mask of all bindings packet filters.
+
+--*/
+
+{
+ //
+ // Contains the value of the combined filter classes before
+ // it is adjusted.
+ //
+ UINT OldCombined = Filter->CombinedPacketFilter;
+
+ //
+ // Pointer to the open
+ //
+ PTR_BINDING_INFO LocalOpen = (PTR_BINDING_INFO)NdisFilterHandle;
+
+ //
+ // Contains the value of the particlar opens packet filters
+ // prior to the change. We save this incase the action
+ // routine (if called) returns an "error" status.
+ //
+ UINT OldOpenFilters = LocalOpen->PacketFilters;
+
+ //
+ // Holds the status returned to the user of this routine, if the
+ // action routine is not called then the status will be success,
+ // otherwise, it is whatever the action routine returns.
+ //
+ NDIS_STATUS StatusOfAdjust;
+
+ //
+ // Simple iteration variable.
+ //
+ PTR_BINDING_INFO OpenList;
+
+ //
+ // Set the new filter information for the open.
+ //
+
+ LocalOpen->PacketFilters = FilterClasses;
+
+ //
+ // We always have to reform the compbined filter since
+ // this filter index may have been the only filter index
+ // to use a particular bit.
+ //
+
+ for (
+ OpenList = Filter->OpenList,Filter->CombinedPacketFilter = 0;
+ OpenList != NULL;
+ OpenList = OpenList->NextOpen
+ ) {
+
+ Filter->CombinedPacketFilter |=
+ OpenList->PacketFilters;
+
+ }
+
+ if (OldCombined != Filter->CombinedPacketFilter) {
+
+ StatusOfAdjust = Filter->FilterChangeAction(
+ OldCombined,
+ Filter->CombinedPacketFilter,
+ LocalOpen->MacBindingHandle,
+ NdisRequest,
+ Set
+ );
+
+ if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) &&
+ (StatusOfAdjust != NDIS_STATUS_PENDING)) {
+
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+
+ LocalOpen->PacketFilters = OldOpenFilters;
+ Filter->CombinedPacketFilter = OldCombined;
+
+ }
+
+ } else {
+
+ StatusOfAdjust = NDIS_STATUS_SUCCESS;
+
+ }
+
+ return StatusOfAdjust;
+
+}
+
+
+VOID
+TrFilterIndicateReceive(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate a packet to
+ all bindings. The packet will be filtered so that only the
+ appropriate bindings will receive the packet.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ MacReceiveContext - A MAC supplied context value that must be
+ returned by the protocol if it calls MacTransferData.
+
+ HeaderBuffer - A virtual address of the virtually contiguous
+ buffer containing the MAC header of the packet.
+
+ HeaderBufferSize - An unsigned integer indicating the size of
+ the header buffer, in bytes.
+
+ LookaheadBuffer - A virtual address of the virtually contiguous
+ buffer containing the first LookaheadBufferSize bytes of data
+ of the packet. The packet buffer is valid only within the current
+ call to the receive event handler.
+
+ LookaheadBufferSize - An unsigned integer indicating the size of
+ the lookahead buffer, in bytes.
+
+ PacketSize - An unsigned integer indicating the size of the received
+ packet, in bytes. This number has nothing to do with the lookahead
+ buffer, but indicates how large the arrived packet is so that a
+ subsequent MacTransferData request can be made to transfer the entire
+ packet as necessary.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ KIRQL oldIrql;
+ KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ TrFilterDprIndicateReceive(
+ Filter,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize
+ );
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ KeLowerIrql( oldIrql );
+ return;
+}
+
+
+VOID
+TrFilterDprIndicateReceive(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate a packet to
+ all bindings. The packet will be filtered so that only the
+ appropriate bindings will receive the packet.
+
+ Called at DPC_LEVEL.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ MacReceiveContext - A MAC supplied context value that must be
+ returned by the protocol if it calls MacTransferData.
+
+ HeaderBuffer - A virtual address of the virtually contiguous
+ buffer containing the MAC header of the packet.
+
+ HeaderBufferSize - An unsigned integer indicating the size of
+ the header buffer, in bytes.
+
+ LookaheadBuffer - A virtual address of the virtually contiguous
+ buffer containing the first LookaheadBufferSize bytes of data
+ of the packet. The packet buffer is valid only within the current
+ call to the receive event handler.
+
+ LookaheadBufferSize - An unsigned integer indicating the size of
+ the lookahead buffer, in bytes.
+
+ PacketSize - An unsigned integer indicating the size of the received
+ packet, in bytes. This number has nothing to do with the lookahead
+ buffer, but indicates how large the arrived packet is so that a
+ subsequent MacTransferData request can be made to transfer the entire
+ packet as necessary.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // The destination address in the lookahead buffer.
+ //
+ PCHAR DestinationAddress = (PCHAR)HeaderBuffer + 2;
+
+ //
+ // The source address in the lookahead buffer.
+ //
+ PCHAR SourceAddress = (PCHAR)HeaderBuffer + 8;
+
+ //
+ // Will hold the type of address that we know we've got.
+ //
+ UINT AddressType;
+
+ //
+ // TRUE if the packet is source routing packet.
+ //
+ BOOLEAN IsSourceRouting;
+
+ //
+ // The functional address as a longword, if the packet
+ // is addressed to one.
+ //
+ TR_FUNCTIONAL_ADDRESS FunctionalAddress;
+
+ //
+ // Will hold the status of indicating the receive packet.
+ // ZZZ For now this isn't used.
+ //
+ NDIS_STATUS StatusOfReceive;
+
+ //
+ // Will hold the open being indicated.
+ //
+ PTR_BINDING_INFO LocalOpen;
+
+ //
+ // Will hold the filter classes of the binding being indicated.
+ //
+ UINT BindingFilters;
+
+ //
+ // Holds intersection of open filters and this packet's type
+ //
+ UINT IntersectionOfFilters;
+
+ //
+ // If the packet is a runt packet, then only indicate to PROMISCUOUS
+ //
+
+ if ( HeaderBufferSize >= 14 && PacketSize != 0 ) {
+
+ //
+ // Holds the result of address determinations.
+ //
+ BOOLEAN ResultOfAddressCheck;
+
+ TR_IS_SOURCE_ROUTING(
+ SourceAddress,
+ &IsSourceRouting
+ );
+
+ //
+ // First check if it *at least* has the functional address bit.
+ //
+
+ TR_IS_NOT_DIRECTED(
+ DestinationAddress,
+ &ResultOfAddressCheck
+ );
+
+ if (ResultOfAddressCheck) {
+
+ //
+ // It is at least a functional address. Check to see if
+ // it is a broadcast address.
+ //
+
+ TR_IS_BROADCAST(
+ DestinationAddress,
+ &ResultOfAddressCheck
+ );
+
+ if (ResultOfAddressCheck) {
+
+#if DBG
+
+if (NdisCheckBadDrivers) {
+
+ if (!(Filter->CombinedPacketFilter & NDIS_PACKET_TYPE_BROADCAST)) {
+
+ //
+ // We should never receive directed packets
+ // to someone else unless in p-mode.
+ //
+ DbgPrint("NDIS: Bad driver, indicating broadcast\n");
+ DbgPrint("NDIS: packets when not set to.\n");
+ DbgBreakPoint();
+
+ }
+
+}
+
+#endif
+
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+
+ } else {
+
+ TR_IS_GROUP(
+ DestinationAddress,
+ &ResultOfAddressCheck
+ );
+
+ if (ResultOfAddressCheck) {
+
+ AddressType = NDIS_PACKET_TYPE_GROUP;
+
+ } else {
+
+ AddressType = NDIS_PACKET_TYPE_FUNCTIONAL;
+
+ }
+
+ RetrieveUlong(&FunctionalAddress,
+ (DestinationAddress + 2));
+
+
+ }
+
+ } else {
+
+ //
+ // Verify that the address is directed to the adapter. We
+ // have to check for this because of the following senario.
+ //
+ // Adapter A is in promiscuous mode.
+ // Adapter B only wants directed packets to this adapter.
+ //
+ // The MAC will indicate *all* packets.
+ //
+ // The filter package needs to filter directed packets to
+ // other adapters from ones directed to this adapter.
+ //
+
+ if (Filter->CombinedPacketFilter &
+ (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_SOURCE_ROUTING)) {
+
+ //
+ // The result of comparing an element of the address
+ // array and the multicast address.
+ //
+ // Result < 0 Implies the adapter address is greater.
+ // Result > 0 Implies the address is greater.
+ // Result = 0 Implies that the they are equal.
+ //
+ INT Result;
+
+ TR_COMPARE_NETWORK_ADDRESSES_EQ(
+ Filter->AdapterAddress,
+ DestinationAddress,
+ &Result
+ );
+
+ if (Result == 0) {
+
+ AddressType = NDIS_PACKET_TYPE_DIRECTED;
+
+ } else {
+
+ //
+ // This will cause binding that only want a specific
+ // address type to not be indicated.
+ //
+
+ AddressType = 0;
+
+ }
+
+ } else {
+
+#if DBG
+
+if (NdisCheckBadDrivers) {
+
+ //
+ // The result of comparing an element of the address
+ // array and the multicast address.
+ //
+ // Result < 0 Implies the adapter address is greater.
+ // Result > 0 Implies the address is greater.
+ // Result = 0 Implies that the they are equal.
+ //
+ INT Result;
+
+ TR_COMPARE_NETWORK_ADDRESSES_EQ(
+ Filter->AdapterAddress,
+ DestinationAddress,
+ &Result
+ );
+
+ if (Result != 0) {
+
+ //
+ // We should never receive directed packets
+ // to someone else unless in p-mode.
+ //
+ DbgPrint("NDIS: Bad driver, indicating packets\n");
+ DbgPrint("NDIS: to another station when not in\n");
+ DbgPrint("NDIS: promiscuous mode.\n");
+ DbgBreakPoint();
+
+
+ }
+
+}
+
+#endif
+
+ AddressType = NDIS_PACKET_TYPE_DIRECTED;
+
+ }
+
+ }
+
+ } else {
+
+ //
+ // Runt Packet
+ //
+
+ AddressType = NDIS_PACKET_TYPE_PROMISCUOUS;
+ IsSourceRouting = FALSE;
+
+ }
+
+ //
+ // We need to aquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+
+ LocalOpen = Filter->OpenList;
+
+ while (LocalOpen != NULL) {
+
+ BindingFilters = LocalOpen->PacketFilters;
+ IntersectionOfFilters = BindingFilters & AddressType;
+
+ //
+ // Can check directed and broadcast at the same time, just
+ // mask off all but those two bits in BindingFilters and
+ // then see if one of them corresponds to AddressType.
+ //
+
+ if (IntersectionOfFilters &
+ (NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST)) {
+
+ goto IndicatePacket;
+
+ }
+
+ //
+ // if the binding wants functional packets and the packet
+ // is a functional packet and it's in the list of addresses
+ // it will get the packet.
+ //
+
+ if (IntersectionOfFilters & NDIS_PACKET_TYPE_FUNCTIONAL) {
+
+ //
+ // See if the bit from the frame's address is also
+ // part of this bindings registered functional address.
+ //
+ if (FunctionalAddress &
+ LocalOpen->FunctionalAddress) {
+
+ goto IndicatePacket;
+
+ }
+
+ }
+
+ //
+ // if the binding wants all functional packets and the packet
+ // has a functional address it will get the packet
+ //
+
+ if ((AddressType & NDIS_PACKET_TYPE_FUNCTIONAL) &&
+ (BindingFilters & NDIS_PACKET_TYPE_ALL_FUNCTIONAL)) {
+
+ goto IndicatePacket;
+
+ }
+
+ //
+ // If the packet is a group packet and the binding is using the
+ // group address then it will get the packet.
+ //
+
+ if ((AddressType & NDIS_PACKET_TYPE_GROUP) &&
+ (BindingFilters & NDIS_PACKET_TYPE_GROUP) &&
+ (LocalOpen->UsingGroupAddress)) {
+
+ goto IndicatePacket;
+
+ }
+
+ //
+ // if this is a source routing packet and the binding
+ // wants it, indicate it.
+ //
+
+ if ((BindingFilters & NDIS_PACKET_TYPE_SOURCE_ROUTING) &&
+ IsSourceRouting) {
+
+ goto IndicatePacket;
+
+ }
+
+ //
+ // if the binding is promiscuous then it will get the packet
+ //
+
+ if (BindingFilters & NDIS_PACKET_TYPE_PROMISCUOUS) {
+
+ goto IndicatePacket;
+
+ }
+
+ //
+ // Nothing satisfied, so don't indicate the packet to
+ // this binding.
+ //
+
+ goto GetNextBinding;
+
+IndicatePacket:;
+
+ LocalOpen->References++;
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ //
+ // Indicate the packet to the binding.
+ //
+
+ FilterIndicateReceive(
+ &StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize
+ );
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ if ((--(LocalOpen->References)) == 0) {
+
+ PTR_BINDING_INFO NextOpen = LocalOpen->NextOpen;
+
+ //
+ // This binding is shutting down.
+ //
+
+
+ //
+ // Remove it from the list of opens.
+ //
+
+ if (LocalOpen->NextOpen != NULL) {
+
+ LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen;
+
+ }
+
+ if (LocalOpen->PrevOpen != NULL) {
+
+ LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen;
+
+ } else {
+
+ Filter->OpenList = LocalOpen->NextOpen;
+
+ }
+
+ //
+ // Call the IndicateComplete routine.
+ //
+
+ if (LocalOpen->ReceivedAPacket) {
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ }
+
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+
+ Filter->CloseAction(
+ LocalOpen->MacBindingHandle
+ );
+
+ TR_FILTER_FREE_OPEN(Filter, LocalOpen);
+
+ LocalOpen = NextOpen;
+
+ continue;
+
+ }
+
+GetNextBinding:
+
+ LocalOpen = LocalOpen->NextOpen;
+
+ }
+
+}
+
+
+VOID
+TrFilterIndicateReceiveComplete(
+ IN PTR_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate that the receive
+ process is done and to indicate to all protocols which received
+ a packet that receive is complete.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ KIRQL oldIrql;
+ KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ TrFilterDprIndicateReceiveComplete(
+ Filter
+ );
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ KeLowerIrql( oldIrql );
+ return;
+}
+
+
+VOID
+TrFilterDprIndicateReceiveComplete(
+ IN PTR_FILTER Filter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the MAC to indicate that the receive
+ process is done and to indicate to all protocols which received
+ a packet that receive is complete.
+
+ Called at DPC_LEVEL.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Pointer to currently indicated binding.
+ //
+ PTR_BINDING_INFO LocalOpen;
+
+ //
+ // We need to aquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+
+ LocalOpen = Filter->OpenList;
+
+ while (LocalOpen != NULL) {
+
+ LocalOpen->References++;
+
+ if (LocalOpen->ReceivedAPacket) {
+
+ //
+ // Indicate the binding.
+ //
+
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ }
+
+ if ((--(LocalOpen->References)) == 0) {
+
+ //
+ // This binding is shutting down.
+ //
+
+ PTR_BINDING_INFO NextOpen = LocalOpen->NextOpen;
+
+ //
+ // Remove it from the list.
+ //
+
+ if (LocalOpen->NextOpen != NULL) {
+
+ LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen;
+
+ }
+
+ if (LocalOpen->PrevOpen != NULL) {
+
+ LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen;
+
+ } else {
+
+ Filter->OpenList = LocalOpen->NextOpen;
+
+ }
+
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+
+ Filter->CloseAction(
+ LocalOpen->MacBindingHandle
+ );
+
+ TR_FILTER_FREE_OPEN(Filter, LocalOpen);
+
+ LocalOpen = NextOpen;
+
+ } else {
+
+ LocalOpen = LocalOpen->NextOpen;
+
+ }
+
+ }
+
+}
+
+
+BOOLEAN
+TrShouldAddressLoopBack(
+ IN PTR_FILTER Filter,
+ IN CHAR DestinationAddress[TR_LENGTH_OF_ADDRESS],
+ IN CHAR SourceAddress[TR_LENGTH_OF_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ Do a quick check to see whether the input address should
+ loopback.
+
+ NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
+
+ NOTE: THIS ROUTINE DOES NOT CHECK THE SPECIAL CASE OF SOURCE
+ EQUALS DESTINATION.
+
+Arguments:
+
+ Filter - Pointer to the filter database.
+
+ Address - A network address to check for loopback.
+
+
+Return Value:
+
+ Returns TRUE if the address is *likely* to need loopback. It
+ will return FALSE if there is *no* chance that the address would
+ require loopback.
+
+--*/
+{
+
+ //
+ // Holds the result of address determinations.
+ //
+ BOOLEAN ResultOfAddressCheck;
+
+ BOOLEAN IsSourceRouting;
+
+ UINT CombinedFilters;
+
+ ULONG GroupAddress;
+
+ //
+ // Convert the 32 bits of the address to a longword.
+ //
+ RetrieveUlong(&GroupAddress, (SourceAddress + 2));
+
+ //
+ // Check if the destination is a preexisting group address
+ //
+
+ TR_IS_GROUP(
+ SourceAddress,
+ &ResultOfAddressCheck
+ );
+
+ if ((ResultOfAddressCheck) &&
+ (GroupAddress == Filter->GroupAddress) &&
+ (Filter->GroupReferences != 0)) {
+
+ return(TRUE);
+
+ }
+
+
+ CombinedFilters = TR_QUERY_FILTER_CLASSES(Filter);
+
+ if ((!CombinedFilters) || (CombinedFilters & NDIS_PACKET_TYPE_PROMISCUOUS)) {
+
+ return FALSE;
+
+ }
+
+ TR_IS_SOURCE_ROUTING(
+ SourceAddress,
+ &IsSourceRouting
+ );
+
+ if (IsSourceRouting && (CombinedFilters & NDIS_PACKET_TYPE_SOURCE_ROUTING)) {
+
+ return TRUE;
+
+ }
+
+ //
+ // First check if it *at least* has the functional address bit.
+ //
+
+ TR_IS_NOT_DIRECTED(
+ DestinationAddress,
+ &ResultOfAddressCheck
+ );
+
+ if (ResultOfAddressCheck) {
+
+ //
+ // It is at least a functional address. Check to see if
+ // it is a broadcast address.
+ //
+
+ TR_IS_BROADCAST(
+ DestinationAddress,
+ &ResultOfAddressCheck
+ );
+
+ if (ResultOfAddressCheck) {
+
+ if (CombinedFilters & NDIS_PACKET_TYPE_BROADCAST) {
+
+ return TRUE;
+
+ } else {
+
+ return FALSE;
+
+ }
+
+ } else {
+
+ if (CombinedFilters &
+ (NDIS_PACKET_TYPE_ALL_FUNCTIONAL |
+ NDIS_PACKET_TYPE_FUNCTIONAL)) {
+
+ return TRUE;
+
+ } else {
+
+ return FALSE;
+
+ }
+
+ }
+
+ } else {
+
+ //
+ // Directed address never loops back.
+ //
+
+ return FALSE;
+
+ }
+
+}
diff --git a/private/ntos/ndis/ndis30/tfilter.h b/private/ntos/ndis/ndis30/tfilter.h
new file mode 100644
index 000000000..ea7b0a20d
--- /dev/null
+++ b/private/ntos/ndis/ndis30/tfilter.h
@@ -0,0 +1,558 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ tfilter.h
+
+Abstract:
+
+ Header file for the address filtering library for NDIS MAC's.
+
+Author:
+
+ Anthony V. Ercolano (tonye) creation-date 3-Aug-1990
+
+Environment:
+
+ Runs in the context of a single MAC driver.
+
+Notes:
+
+ None.
+
+Revision History:
+
+ Adam Barr (adamba) 19-Mar-1991
+
+ - Modified for Token-Ring
+
+--*/
+
+#ifndef _TR_FILTER_DEFS_
+#define _TR_FILTER_DEFS_
+
+#define TR_LENGTH_OF_FUNCTIONAL 4
+#define TR_LENGTH_OF_ADDRESS 6
+
+
+//
+// Only the low 32 bits of the functional/group address
+// are needed since the upper 16 bits is always c0-00.
+//
+typedef ULONG TR_FUNCTIONAL_ADDRESS;
+typedef ULONG TR_GROUP_ADDRESS;
+
+
+
+//
+//
+#define TR_IS_NOT_DIRECTED(Address, Result) \
+{ \
+ PUCHAR _A = Address; \
+ PBOOLEAN _R = Result; \
+ *_R = (BOOLEAN)(_A[0] & ((UCHAR)0x80));\
+}
+
+//
+//
+#define TR_IS_FUNCTIONAL(Address, Result) \
+{ \
+ PUCHAR _A = Address; \
+ PBOOLEAN _R = Result; \
+ *_R = (BOOLEAN)((_A[0] & ((UCHAR)0x80)) &&\
+ !(_A[2] & ((UCHAR)0x80))); \
+}
+
+//
+//
+#define TR_IS_GROUP(Address, Result) \
+{ \
+ PUCHAR _A = Address; \
+ PBOOLEAN _R = Result; \
+ *_R = (BOOLEAN)(_A[0] & _A[2] & ((UCHAR)0x80)); \
+}
+
+//
+//
+#define TR_IS_SOURCE_ROUTING(Address, Result) \
+{ \
+ PUCHAR _A = Address; \
+ PBOOLEAN _R = Result; \
+ *_R = (BOOLEAN)(_A[0] >> 7);\
+}
+
+
+//
+// Check whether an address is broadcast.
+//
+#define TR_IS_BROADCAST(Address, Result) \
+{ \
+ PUCHAR _A = Address; \
+ PBOOLEAN _R = Result; \
+ *_R = (BOOLEAN)((((_A[0] == ((UCHAR)0xff)) && \
+ (_A[1] == ((UCHAR)0xff))) || \
+ ((_A[0] == ((UCHAR)0xc0)) && \
+ (_A[1] == ((UCHAR)0x00)))) && \
+ (_A[2] == ((UCHAR)0xff)) && \
+ (_A[3] == ((UCHAR)0xff)) && \
+ (_A[4] == ((UCHAR)0xff)) && \
+ (_A[5] == ((UCHAR)0xff))); \
+}
+
+
+//
+// This macro will compare network addresses.
+//
+// A - Is a network address.
+//
+// B - Is a network address.
+//
+// Result - The result of comparing two network address.
+//
+// Result < 0 Implies the B address is greater.
+// Result > 0 Implies the A element is greater.
+// Result = 0 Implies equality.
+//
+// Note that this is an arbitrary ordering. There is not
+// defined relation on network addresses. This is ad-hoc!
+//
+//
+#define TR_COMPARE_NETWORK_ADDRESSES(A, B, Result) \
+{ \
+ PUCHAR _A = (PUCHAR)(A); \
+ PUCHAR _B = (PUCHAR)(B); \
+ if ( *(ULONG UNALIGNED *)&_A[2] > \
+ *(ULONG UNALIGNED *)&_B[2] ) { \
+ *Result = 1; \
+ } else if ( *(ULONG UNALIGNED *)&_A[2] < \
+ *(ULONG UNALIGNED *)&_B[2] ) { \
+ *Result = (UINT)-1; \
+ } else if ( *(USHORT UNALIGNED *)_A > \
+ *(USHORT UNALIGNED *)_B ) { \
+ *Result = 1; \
+ } else if ( *(USHORT UNALIGNED *)_A < \
+ *(USHORT UNALIGNED *)_B ) { \
+ *Result = (UINT)-1; \
+ } else { \
+ *Result = 0; \
+ } \
+}
+
+//
+// This macro will compare network addresses.
+//
+// A - Is a network address.
+//
+// B - Is a network address.
+//
+// Result - The result of comparing two network address.
+//
+// Result != 0 Implies inequality.
+// Result == 0 Implies equality.
+//
+//
+#define TR_COMPARE_NETWORK_ADDRESSES_EQ(A,B,Result) \
+{ \
+ PUCHAR _A = (PUCHAR)(A); \
+ PUCHAR _B = (PUCHAR)(B); \
+ if ( ( *(ULONG UNALIGNED *)&_A[2] == \
+ *(ULONG UNALIGNED *)&_B[2] ) && \
+ ( *(USHORT UNALIGNED *)_A == \
+ *(USHORT UNALIGNED *)_B ) ) { \
+ *Result = 0; \
+ } else { \
+ *Result = 1; \
+ } \
+}
+
+
+//
+// This macro is used to copy from one network address to
+// another.
+//
+#define TR_COPY_NETWORK_ADDRESS(D, S) \
+{ \
+ PCHAR _D = (D); \
+ PCHAR _S = (S); \
+ _D[0] = _S[0]; \
+ _D[1] = _S[1]; \
+ _D[2] = _S[2]; \
+ _D[3] = _S[3]; \
+ _D[4] = _S[4]; \
+ _D[5] = _S[5]; \
+}
+
+
+//
+//UINT
+//TR_QUERY_FILTER_CLASSES(
+// IN PTR_FILTER Filter
+// )
+//
+// This macro returns the currently enabled filter classes.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define TR_QUERY_FILTER_CLASSES(Filter) ((Filter)->CombinedPacketFilter)
+
+
+//
+//UINT
+//TR_QUERY_PACKET_FILTER(
+// IN PTR_FILTER Filter,
+// IN NDIS_HANDLE NdisFilterHandle
+// )
+//
+// This macro returns the currently enabled filter classes for a specific
+// open instance.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define TR_QUERY_PACKET_FILTER(Filter, NdisFilterHandle) \
+ (((PTR_BINDING_INFO)NdisFilterHandle)->PacketFilters)
+
+
+
+//
+//UINT
+//TR_QUERY_FILTER_ADDRESSES(
+// IN PTR_FILTER Filter
+// )
+//
+// This macro returns the currently enabled functional address.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define TR_QUERY_FILTER_ADDRESSES(Filter) ((Filter)->CombinedFunctionalAddress)
+
+
+
+//
+//UINT
+//TR_QUERY_FILTER_GROUP(
+// IN PTR_FILTER Filter
+// )
+//
+// This macro returns the currently enabled Group address.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define TR_QUERY_FILTER_Group(Filter) ((Filter)->GroupAddress)
+#define TR_QUERY_FILTER_GROUP(Filter) ((Filter)->GroupAddress)
+
+
+
+//
+//UINT
+//TR_QUERY_FILTER_BINDING_ADDRESS(
+// IN PTR_FILTER Filter
+// IN NDIS_HANDLE NdisFilterHandle,
+// )
+//
+// This macro returns the currently desired functional addresses
+// for the specified binding.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define TR_QUERY_FILTER_BINDING_ADDRESS(Filter, NdisFilterHandle) \
+ (((PTR_BINDING_INFO)NdisFilterHandle)->FunctionalAddress)
+
+
+
+
+//
+//BOOLEAN
+//TR_QUERY_FILTER_BINDING_GROUP(
+// IN PTR_FILTER Filter
+// IN NDIS_HANDLE NdisFilterHandle,
+// )
+//
+// This macro returns TRUE if the specified binding is using the
+// current group address.
+//
+// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD.
+//
+#define TR_QUERY_FILTER_BINDING_GROUP(Filter, NdisFilterHandle) \
+ (((PTR_BINDING_INFO)NdisFilterHandle)->UsingGroupAddress)
+
+
+//
+// An action routine type. The routines are called
+// when a filter type is set for the first time or
+// no more bindings require a particular type of filter.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+NDIS_STATUS
+(*TR_FILTER_CHANGE)(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+//
+// This action routine is called when the functional address
+// for the card has changed. It is passed the old functional
+// address as well as the new one.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+NDIS_STATUS
+(*TR_ADDRESS_CHANGE)(
+ IN TR_FUNCTIONAL_ADDRESS OldFunctionalAddress,
+ IN TR_FUNCTIONAL_ADDRESS NewFunctionalAddress,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+
+//
+// This action routine is called when the group address
+// for the card has changed. It is passed the old group
+// address as well as the new one.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+NDIS_STATUS
+(*TR_GROUP_CHANGE)(
+ IN TR_GROUP_ADDRESS OldGroupAddress,
+ IN TR_GROUP_ADDRESS NewGroupAddress,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+
+
+//
+// This action routine is called when the mac requests a close for
+// a particular binding *WHILE THE BINDING IS BEING INDICATED TO
+// THE PROTOCOL*. The filtering package can't get rid of the open
+// right away. So this routine will be called as soon as the
+// NdisIndicateReceive returns.
+//
+// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED.
+//
+typedef
+VOID
+(*TR_DEFERRED_CLOSE)(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+
+//
+// The binding info is threaded on two lists. When
+// the binding is free it is on a single freelist.
+//
+// When the binding is being used it is on a doubly linked
+// index list.
+//
+typedef struct _TR_BINDING_INFO {
+ NDIS_HANDLE MacBindingHandle;
+ NDIS_HANDLE NdisBindingContext;
+ UINT PacketFilters;
+ TR_FUNCTIONAL_ADDRESS FunctionalAddress;
+ struct _TR_BINDING_INFO *NextOpen;
+ struct _TR_BINDING_INFO *PrevOpen;
+ UINT References;
+ UCHAR FilterIndex;
+ BOOLEAN UsingGroupAddress;
+ BOOLEAN ReceivedAPacket;
+} TR_BINDING_INFO,*PTR_BINDING_INFO;
+
+//
+// An opaque type that contains a filter database.
+// The MAC need not know how it is structured.
+//
+typedef struct _TR_FILTER {
+
+ //
+ // Spin lock used to protect the filter from multiple accesses.
+ //
+ PNDIS_SPIN_LOCK Lock;
+
+ //
+ // ORing together of all the FunctionalAddresses.
+ //
+ TR_FUNCTIONAL_ADDRESS CombinedFunctionalAddress;
+
+ //
+ // Current group address in use.
+ //
+ TR_FUNCTIONAL_ADDRESS GroupAddress;
+
+ //
+ // Reference count on group address;
+ //
+ UINT GroupReferences;
+
+ //
+ // Combination of all the filters of all the open bindings.
+ //
+ UINT CombinedPacketFilter;
+
+ //
+ // Pointer to list of current opens.
+ //
+ PTR_BINDING_INFO OpenList;
+
+ //
+ // Address of the adapter associated with this filter.
+ //
+ UCHAR AdapterAddress[TR_LENGTH_OF_ADDRESS];
+
+ //
+ // Action routines to be invoked on notable changes in the filter.
+ //
+ TR_ADDRESS_CHANGE AddressChangeAction;
+ TR_GROUP_CHANGE GroupChangeAction;
+ TR_FILTER_CHANGE FilterChangeAction;
+ TR_DEFERRED_CLOSE CloseAction;
+
+ //
+ // Bit mask of opens that are available.
+ //
+ ULONG FreeBindingMask;
+
+} TR_FILTER,*PTR_FILTER;
+
+//
+// Only for internal wrapper use.
+//
+VOID
+TrInitializePackage(
+ VOID
+ );
+
+VOID
+TrReferencePackage(
+ VOID
+ );
+
+VOID
+TrDereferencePackage(
+ VOID
+ );
+
+//
+// Exported functions
+//
+EXPORT
+BOOLEAN
+TrCreateFilter(
+ IN TR_ADDRESS_CHANGE AddressChangeAction,
+ IN TR_GROUP_CHANGE GroupChangeAction,
+ IN TR_FILTER_CHANGE FilterChangeAction,
+ IN TR_DEFERRED_CLOSE CloseAction,
+ IN PUCHAR AdapterAddress,
+ IN PNDIS_SPIN_LOCK Lock,
+ OUT PTR_FILTER *Filter
+ );
+
+EXPORT
+VOID
+TrDeleteFilter(
+ IN PTR_FILTER Filter
+ );
+
+EXPORT
+BOOLEAN
+TrNoteFilterOpenAdapter(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE NdisBindingContext,
+ OUT PNDIS_HANDLE NdisFilterHandle
+ );
+
+EXPORT
+NDIS_STATUS
+TrDeleteFilterOpenAdapter(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+EXPORT
+NDIS_STATUS
+TrChangeFunctionalAddress(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN CHAR FunctionalAddressArray[TR_LENGTH_OF_FUNCTIONAL],
+ IN BOOLEAN Set
+ );
+
+EXPORT
+NDIS_STATUS
+TrChangeGroupAddress(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN CHAR GroupAddressArray[TR_LENGTH_OF_FUNCTIONAL],
+ IN BOOLEAN Set
+ );
+
+EXPORT
+BOOLEAN
+TrShouldAddressLoopBack(
+ IN PTR_FILTER Filter,
+ IN CHAR DestinationAddress[TR_LENGTH_OF_ADDRESS],
+ IN CHAR SourceAddress[TR_LENGTH_OF_ADDRESS]
+ );
+
+EXPORT
+NDIS_STATUS
+TrFilterAdjust(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE NdisFilterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT FilterClasses,
+ IN BOOLEAN Set
+ );
+
+EXPORT
+VOID
+TrFilterIndicateReceive(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+EXPORT
+VOID
+TrFilterDprIndicateReceive(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+EXPORT
+VOID
+TrFilterIndicateReceiveComplete(
+ IN PTR_FILTER Filter
+ );
+
+EXPORT
+VOID
+TrFilterDprIndicateReceiveComplete(
+ IN PTR_FILTER Filter
+ );
+
+
+#endif // _TR_FILTER_DEFS_
diff --git a/private/ntos/ndis/ndis30/wrapper.c b/private/ntos/ndis/ndis30/wrapper.c
new file mode 100644
index 000000000..9373647c4
--- /dev/null
+++ b/private/ntos/ndis/ndis30/wrapper.c
@@ -0,0 +1,17480 @@
+/*++
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ wrapper.c
+
+Abstract:
+
+ NDIS wrapper functions
+
+Author:
+
+ Adam Barr (adamba) 11-Jul-1990
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ 26-Feb-1991 JohnsonA Added Debugging Code
+ 10-Jul-1991 JohnsonA Implement revised Ndis Specs
+
+--*/
+
+
+#include <precomp.h>
+#pragma hdrstop
+
+#include <stdarg.h>
+
+//
+// The following are counters used for debugging
+//
+
+#if NDISDBG
+BOOLEAN NdisChkErrorFlag=TRUE; // parameter checking on
+int NdisMsgLevel=TRACE_ALL; // no trace
+#endif
+
+PNDIS_MAC_BLOCK NdisMacList = (PNDIS_MAC_BLOCK)NULL;
+NDIS_SPIN_LOCK NdisMacListLock = {0};
+
+BOOLEAN NdisInitialInitNeeded = TRUE;
+BOOLEAN NdisUpOnlyEventLogged = FALSE;
+
+//
+// Global variables for tracking memory allocated for shared memory
+//
+ERESOURCE SharedMemoryResource = {0};
+
+//
+// Global variables for tracking on NT 3.1 protocols that do not
+// use any of the filter packages.
+//
+PNDIS_OPEN_BLOCK GlobalOpenList = NULL;
+NDIS_SPIN_LOCK GlobalOpenListLock = {0};
+
+//
+// Debug variable for filter packages
+//
+#if DBG
+BOOLEAN NdisCheckBadDrivers = FALSE;
+
+extern NDIS_SPIN_LOCK PacketLogSpinLock;
+#endif
+
+//
+// Arcnet specific stuff
+//
+#define WRAPPER_ARC_BUFFERS 8
+#define WRAPPER_ARC_HEADER_SIZE 4
+
+//
+// Define constants used internally to identify regular opens from
+// query global statistics ones.
+//
+
+#define NDIS_OPEN_INTERNAL 1
+#define NDIS_OPEN_QUERY_STATISTICS 2
+
+//
+// This is the structure pointed to by the FsContext of an
+// open used for query statistics.
+//
+// NOTE: THIS STRUCTURE MUST, MUST, MUST ALIGN WITH THE
+// NDIS_M_USER_OPEN_CONTEXT STRUCTURE!!!
+//
+
+typedef struct _NDIS_USER_OPEN_CONTEXT {
+ PDEVICE_OBJECT DeviceObject;
+ PNDIS_ADAPTER_BLOCK AdapterBlock;
+ ULONG OidCount;
+ PNDIS_OID OidArray;
+} NDIS_USER_OPEN_CONTEXT, *PNDIS_USER_OPEN_CONTEXT;
+
+//
+// An active query single statistic request.
+//
+
+typedef struct _NDIS_QUERY_GLOBAL_REQUEST {
+ PIRP Irp;
+ NDIS_REQUEST Request;
+} NDIS_QUERY_GLOBAL_REQUEST, *PNDIS_QUERY_GLOBAL_REQUEST;
+
+
+//
+// An active query all statistics request.
+//
+
+typedef struct _NDIS_QUERY_ALL_REQUEST {
+ PIRP Irp;
+ NDIS_REQUEST Request;
+ NDIS_STATUS NdisStatus;
+ KEVENT Event;
+} NDIS_QUERY_ALL_REQUEST, *PNDIS_QUERY_ALL_REQUEST;
+
+
+//
+// An temporary request used during an open.
+//
+
+typedef struct _NDIS_QUERY_OPEN_REQUEST {
+ PIRP Irp;
+ NDIS_REQUEST Request;
+ NDIS_STATUS NdisStatus;
+ KEVENT Event;
+} NDIS_QUERY_OPEN_REQUEST, *PNDIS_QUERY_OPEN_REQUEST;
+
+
+//
+// Used to queue configuration parameters
+//
+
+typedef struct _NDIS_CONFIGURATION_PARAMETER_QUEUE {
+ struct _NDIS_CONFIGURATION_PARAMETER_QUEUE* Next;
+ NDIS_CONFIGURATION_PARAMETER Parameter;
+} NDIS_CONFIGURATION_PARAMETER_QUEUE, *PNDIS_CONFIGURATION_PARAMETER_QUEUE;
+
+//
+// Configuration Handle
+//
+
+typedef struct _NDIS_CONFIGURATION_HANDLE {
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable;
+ PNDIS_CONFIGURATION_PARAMETER_QUEUE ParameterList;
+} NDIS_CONFIGURATION_HANDLE, *PNDIS_CONFIGURATION_HANDLE;
+
+//
+// This is used during addadapter/miniportinitialize so that when the
+// driver calls any NdisImmediatexxx routines we can access its driverobj.
+//
+typedef struct _NDIS_WRAPPER_CONFIGURATION_HANDLE
+{
+ RTL_QUERY_REGISTRY_TABLE ParametersQueryTable[4];
+ PDRIVER_OBJECT DriverObject;
+}
+ NDIS_WRAPPER_CONFIGURATION_HANDLE,
+ *PNDIS_WRAPPER_CONFIGURATION_HANDLE;
+
+//
+// Describes an open NDIS file
+//
+
+typedef struct _NDIS_FILE_DESCRIPTOR {
+ PVOID Data;
+ NDIS_SPIN_LOCK Lock;
+ BOOLEAN Mapped;
+} NDIS_FILE_DESCRIPTOR, *PNDIS_FILE_DESCRIPTOR;
+
+//
+// IRP handlers established on behalf of NDIS devices by
+// the wrapper.
+//
+
+NTSTATUS
+NdisCreateIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+NTSTATUS
+NdisDeviceControlIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+NTSTATUS
+NdisCloseIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+NTSTATUS
+NdisSuccessIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+
+NTSTATUS
+NdisQueryOidList(
+ PNDIS_USER_OPEN_CONTEXT OpenContext,
+ PIRP Irp
+ );
+
+NTSTATUS
+NdisMQueryOidList(
+ PNDIS_M_USER_OPEN_CONTEXT OpenContext,
+ PIRP Irp
+ );
+
+VOID
+NdisLastCountRemovedFunction(
+ IN struct _KDPC *Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+
+BOOLEAN
+NdisQueueOpenOnProtocol(
+ IN PNDIS_OPEN_BLOCK OpenP,
+ IN PNDIS_PROTOCOL_BLOCK ProtP
+ );
+
+NDIS_STATUS
+MiniportAdjustMaximumLookahead(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+BOOLEAN
+NdisMKillOpen(
+ PNDIS_OPEN_BLOCK OldOpenP
+ );
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+NDIS_STATUS
+NdisMacReceiveHandler(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+VOID
+NdisMacReceiveCompleteHandler(
+ IN NDIS_HANDLE NdisBindingContext
+ );
+
+PNDIS_OPEN_BLOCK
+GetOpenBlockFromProtocolBindingContext(
+ IN NDIS_HANDLE ProtocolBindingContext
+ );
+
+NTSTATUS
+NdisShutdown(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+VOID
+NdisUnload(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+BOOLEAN
+NdisIsr(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID Context
+ );
+
+VOID
+NdisDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+VOID
+NdisOpenConfiguration(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE ConfigurationHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ );
+
+NTSTATUS
+WrapperSaveParameters(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+VOID
+NdisReadNetworkAddress(
+ OUT PNDIS_STATUS Status,
+ OUT PVOID * NetworkAddress,
+ OUT PUINT NetworkAddressLength,
+ IN NDIS_HANDLE ConfigurationHandle
+ );
+
+VOID
+NdisReadEisaSlotInformation(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PUINT SlotNumber,
+ OUT PNDIS_EISA_FUNCTION_INFORMATION EisaData
+ );
+
+VOID
+NdisReadEisaSlotInformationEx(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PUINT SlotNumber,
+ OUT PNDIS_EISA_FUNCTION_INFORMATION *EisaData,
+ OUT PUINT NumberOfFunctions
+ );
+
+VOID
+NdisReadMcaPosInformation(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PUINT ChannelNumber,
+ OUT PNDIS_MCA_POS_DATA McaData
+ );
+
+NDIS_STATUS
+NdisCallDriverAddAdapter(
+ IN PNDIS_MAC_BLOCK NewMacP
+ );
+
+NDIS_STATUS
+NdisMWanSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE NdisLinkHandle,
+ IN PVOID Packet
+ );
+
+
+CCHAR NdisMacAdapterDpcTargetProcessor = -1;
+
+//
+// Routines for dealing with making the MAC specific routines pagable
+//
+
+NDIS_SPIN_LOCK NdisMacReferenceLock = {0};
+KEVENT NdisMacPagedInEvent = {0};
+ULONG NdisMacReferenceCount = 0;
+PVOID NdisMacImageHandle = {0};
+
+VOID
+NdisMacInitializePackage(VOID)
+{
+ //
+ // Allocate the spin lock
+ //
+ NdisAllocateSpinLock(&NdisMacReferenceLock);
+
+ //
+ // Initialize the "in page" event.
+ //
+ KeInitializeEvent(
+ &NdisMacPagedInEvent,
+ NotificationEvent,
+ FALSE
+ );
+}
+
+VOID
+NdisMacReferencePackage(VOID)
+{
+
+ //
+ // Grab the spin lock
+ //
+ ACQUIRE_SPIN_LOCK(&NdisMacReferenceLock);
+
+ //
+ // Increment the reference count
+ //
+ NdisMacReferenceCount++;
+
+ if (NdisMacReferenceCount == 1) {
+
+ //
+ // We are the first reference. Page everything in.
+ //
+
+ //
+ // Clear the event
+ //
+ KeResetEvent(
+ &NdisMacPagedInEvent
+ );
+
+ //
+ // Set the spin lock free
+ //
+ RELEASE_SPIN_LOCK(&NdisMacReferenceLock);
+
+ //
+ // Page in all the functions
+ //
+ NdisMacImageHandle = MmLockPagableCodeSection(NdisIsr);
+
+ //
+ // Signal to everyone to go
+ //
+ KeSetEvent(
+ &NdisMacPagedInEvent,
+ 0L,
+ FALSE
+ );
+
+ } else {
+
+ //
+ // Set the spin lock free
+ //
+ RELEASE_SPIN_LOCK(&NdisMacReferenceLock);
+
+ //
+ // Wait for everything to be paged in
+ //
+ KeWaitForSingleObject(
+ &NdisMacPagedInEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ NULL
+ );
+
+ }
+
+}
+
+VOID
+NdisMacDereferencePackage(VOID)
+{
+
+ //
+ // Get the spin lock
+ //
+ ACQUIRE_SPIN_LOCK(&NdisMacReferenceLock);
+
+ NdisMacReferenceCount--;
+
+ if (NdisMacReferenceCount == 0) {
+
+ //
+ // Let next one in
+ //
+ RELEASE_SPIN_LOCK(&NdisMacReferenceLock);
+
+ //
+ // Page out all the functions
+ //
+ MmUnlockPagableImageSection(NdisMacImageHandle);
+
+ } else {
+
+ //
+ // Let next one in
+ //
+ RELEASE_SPIN_LOCK(&NdisMacReferenceLock);
+
+ }
+
+}
+
+
+
+//
+// Routines for dealing with making the initialization routines pagable
+//
+
+NDIS_SPIN_LOCK NdisInitReferenceLock = {0};
+KEVENT NdisInitPagedInEvent = {0};
+ULONG NdisInitReferenceCount = 0;
+PVOID NdisInitImageHandle = {0};
+
+VOID
+NdisInitInitializePackage(VOID)
+{
+ //
+ // Allocate the spin lock
+ //
+ NdisAllocateSpinLock(&NdisInitReferenceLock);
+
+ //
+ // Initialize the "in page" event.
+ //
+ KeInitializeEvent(
+ &NdisInitPagedInEvent,
+ NotificationEvent,
+ FALSE
+ );
+}
+
+VOID
+NdisInitReferencePackage(VOID)
+{
+
+ //
+ // Grab the spin lock
+ //
+ ACQUIRE_SPIN_LOCK(&NdisInitReferenceLock);
+
+ //
+ // Increment the reference count
+ //
+ NdisInitReferenceCount++;
+
+ if (NdisInitReferenceCount == 1) {
+
+ //
+ // We are the first reference. Page everything in.
+ //
+
+ //
+ // Clear the event
+ //
+ KeResetEvent(
+ &NdisInitPagedInEvent
+ );
+
+ //
+ // Set the spin lock free
+ //
+ RELEASE_SPIN_LOCK(&NdisInitReferenceLock);
+
+ //
+ // Page in all the functions
+ //
+ NdisInitImageHandle = MmLockPagableCodeSection(NdisReadConfiguration);
+
+ //
+ // Signal to everyone to go
+ //
+ KeSetEvent(
+ &NdisInitPagedInEvent,
+ 0L,
+ FALSE
+ );
+
+ } else {
+
+ //
+ // Set the spin lock free
+ //
+ RELEASE_SPIN_LOCK(&NdisInitReferenceLock);
+
+ //
+ // Wait for everything to be paged in
+ //
+ KeWaitForSingleObject(
+ &NdisInitPagedInEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ NULL
+ );
+
+ }
+
+}
+
+VOID
+NdisInitDereferencePackage(VOID)
+{
+
+ //
+ // Get the spin lock
+ //
+ ACQUIRE_SPIN_LOCK(&NdisInitReferenceLock);
+
+ NdisInitReferenceCount--;
+
+ if (NdisInitReferenceCount == 0) {
+
+ //
+ // Let next one in
+ //
+ RELEASE_SPIN_LOCK(&NdisInitReferenceLock);
+
+ //
+ // Page out all the functions
+ //
+ MmUnlockPagableImageSection(NdisInitImageHandle);
+
+ } else {
+
+ //
+ // Let next one in
+ //
+ RELEASE_SPIN_LOCK(&NdisInitReferenceLock);
+
+ }
+}
+
+
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGENDSI, NdisPciAssignResources)
+#pragma alloc_text(PAGENDSI, NdisReadMcaPosInformation)
+#pragma alloc_text(PAGENDSI, NdisReadEisaSlotInformationEx)
+#pragma alloc_text(PAGENDSI, NdisReadEisaSlotInformation)
+#pragma alloc_text(PAGENDSI, NdisCallDriverAddAdapter)
+#pragma alloc_text(PAGENDSW, NdisDereferenceMac)
+#pragma alloc_text(PAGENDSW, NdisDereferenceAdapter)
+#pragma alloc_text(PAGENDSW, NdisKillAdapter)
+#pragma alloc_text(PAGENDSW, NdisDeQueueAdapterOnMac)
+#pragma alloc_text(PAGENDSW, NdisQueueAdapterOnMac)
+#pragma alloc_text(PAGENDSW, NdisKillOpen)
+#pragma alloc_text(PAGENDSW, NdisKillOpenAndNotifyProtocol)
+#pragma alloc_text(PAGENDSW, NdisCloseIrpHandler)
+#pragma alloc_text(PAGENDSW, NdisCompleteQueryStatistics)
+#pragma alloc_text(PAGENDSW, NdisQueryOidList)
+#pragma alloc_text(PAGENDSW, NdisFinishOpen)
+#pragma alloc_text(PAGENDSW, NdisCompleteCloseAdapter)
+#pragma alloc_text(PAGENDSW, NdisCompleteOpenAdapter)
+#pragma alloc_text(PAGENDSI, NdisRegisterAdapterShutdownHandler)
+#pragma alloc_text(PAGENDSI, NdisRegisterAdapter)
+#pragma alloc_text(PAGENDSI, NdisInitializeWrapper)
+#pragma alloc_text(PAGENDSW, NdisMacReceiveCompleteHandler)
+#pragma alloc_text(PAGENDSW, NdisMacReceiveHandler)
+#pragma alloc_text(PAGENDSW, GetOpenBlockFromProtocolBindingContext)
+#pragma alloc_text(PAGENDSI, NdisAllocateDmaChannel)
+#pragma alloc_text(PAGENDSW, NdisShutdown)
+#pragma alloc_text(PAGENDSW, NdisUnload)
+#pragma alloc_text(PAGENDSI, NdisInitializeInterrupt)
+#pragma alloc_text(PAGENDSW, NdisDpc)
+#pragma alloc_text(PAGENDSW, NdisIsr)
+#pragma alloc_text(PAGENDSI, NdisMapIoSpace)
+#pragma alloc_text(PAGENDSI, NdisReadNetworkAddress)
+#pragma alloc_text(PAGENDSI, NdisCloseConfiguration)
+#pragma alloc_text(PAGENDSI, NdisReadConfiguration)
+#pragma alloc_text(PAGENDSI, WrapperSaveParameters)
+#pragma alloc_text(PAGENDSI, NdisOpenConfiguration)
+#pragma alloc_text(PAGENDSI, NdisOverrideBusNumber)
+#pragma alloc_text(INIT, DriverEntry)
+
+#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);
+
+#if defined(_ALPHA_)
+
+typedef struct _NDIS_LOOKAHEAD_ELEMENT {
+
+ ULONG Length;
+ struct _NDIS_LOOKAHEAD_ELEMENT *Next;
+
+} NDIS_LOOKAHEAD_ELEMENT, *PNDIS_LOOKAHEAD_ELEMENT;
+
+NDIS_SPIN_LOCK NdisLookaheadBufferLock = {0};
+ULONG NdisLookaheadBufferLength = 0;
+PNDIS_LOOKAHEAD_ELEMENT NdisLookaheadBufferList = NULL;
+
+#endif
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ Temporary entry point needed to initialize the NDIS wrapper driver.
+
+Arguments:
+
+ DriverObject - Pointer to the driver object created by the system.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(RegistryPath);
+
+ return STATUS_SUCCESS;
+
+} // DriverEntry
+
+
+NDIS_STATUS
+NdisInitialInit(
+ IN PDRIVER_OBJECT Driver OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+ This routine is used for all one time initialization of NDIS variables.
+ It seems that DriverEntry is *not* called for ndis.sys due to its type.
+
+Arguments:
+
+ Driver - Optional pointer to an NT driver object. Used to log an error,
+ if necessary.
+
+Return Value:
+
+ NTSTATUS - Status of initialization. Currently, this routine can only
+ fail if built for UP and loaded on MP.
+
+--*/
+
+{
+ Driver;
+
+ if (NdisInitialInitNeeded) {
+
+#if defined(UP_DRIVER)
+ //
+ // If built for UP, ensure that this is a UP system.
+ //
+
+ if (*KeNumberProcessors != 1) {
+
+ if (ARGUMENT_PRESENT(Driver) && !NdisUpOnlyEventLogged) {
+
+ //
+ // Log an error
+ //
+
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+
+ errorLogEntry = IoAllocateErrorLogEntry( Driver, sizeof(IO_ERROR_LOG_PACKET) );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->ErrorCode = EVENT_UP_DRIVER_ON_MP;
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+ errorLogEntry->NumberOfStrings = 0;
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ NdisUpOnlyEventLogged = TRUE;
+ }
+
+ }
+
+ return NDIS_STATUS_BAD_VERSION; //!!! better status?
+ }
+
+#endif // defined(UP_DRIVER)
+
+ NdisInitialInitNeeded = FALSE;
+ NdisAllocateSpinLock(&NdisMacListLock);
+
+ ArcInitializePackage();
+ EthInitializePackage();
+ FddiInitializePackage();
+ TrInitializePackage();
+ MiniportInitializePackage();
+ NdisInitInitializePackage();
+ NdisMacInitializePackage();
+
+#if defined(_ALPHA_)
+ NdisAllocateSpinLock(&NdisLookaheadBufferLock);
+#endif
+
+ ExInitializeResource(&SharedMemoryResource);
+
+ NdisAllocateSpinLock(&GlobalOpenListLock);
+
+#if DBG
+ NdisAllocateSpinLock(&PacketLogSpinLock);
+#endif
+ }
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+//
+// Configuration Requests
+//
+
+VOID
+NdisOpenConfiguration(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE ConfigurationHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to open the parameter subkey of the
+ adapter registry tree.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ ConfigurationHandle - Returns a handle which is used in calls to
+ NdisReadConfiguration and NdisCloseConfiguration.
+
+ WrapperConfigurationContext - a handle pointing to an RTL_QUERY_REGISTRY_TABLE
+ that is set up for this driver's parameters.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Handle to be returned
+ //
+ PNDIS_CONFIGURATION_HANDLE HandleToReturn;
+
+
+ //
+ // Allocate the configuration handle
+ //
+
+ *Status = NdisAllocateMemory(
+ (PVOID*) &HandleToReturn,
+ sizeof(NDIS_CONFIGURATION_HANDLE),
+ 0,
+ HighestAcceptableMax);
+
+ if (*Status != NDIS_STATUS_SUCCESS) {
+ return;
+ }
+
+ HandleToReturn->KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ HandleToReturn->ParameterList = NULL;
+ *ConfigurationHandle = (NDIS_HANDLE) HandleToReturn;
+
+ return;
+}
+
+
+NTSTATUS
+WrapperSaveParameters(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called with the value for a specified parameter. It allocates
+ memory to hold the data and copies it over.
+
+Arguments:
+
+ ValueName - The name of the value (ignored).
+
+ ValueType - The type of the value.
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - Points to the head of the parameter chain.
+
+ EntryContext - A pointer to
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ NDIS_STATUS Status;
+
+ //
+ // Obtain the actual configuration handle structure
+ //
+
+ PNDIS_CONFIGURATION_HANDLE NdisConfigHandle =
+ (PNDIS_CONFIGURATION_HANDLE)Context;
+
+ //
+ // Where the user wants a pointer returned to the data.
+ //
+
+ PNDIS_CONFIGURATION_PARAMETER *ParameterValue =
+ (PNDIS_CONFIGURATION_PARAMETER *)EntryContext;
+
+ //
+ // Use this to link parameters allocated to this open
+ //
+
+ PNDIS_CONFIGURATION_PARAMETER_QUEUE ParameterNode;
+
+
+
+ //
+ // Allocate our parameter node
+ //
+
+ Status = NdisAllocateMemory(
+ (PVOID*)&ParameterNode,
+ sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE),
+ 0,
+ HighestAcceptableMax);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ return (NTSTATUS)Status;
+ }
+
+
+ *ParameterValue = &ParameterNode->Parameter;
+
+ //
+ // Map registry datatypes to ndis data types
+ //
+
+ if (ValueType == REG_DWORD) {
+
+ //
+ // The registry says that the data is in a dword boundary.
+ //
+
+ (*ParameterValue)->ParameterType = NdisParameterInteger;
+ (*ParameterValue)->ParameterData.IntegerData =
+ *((PULONG) ValueData);
+
+ } else if ((ValueType == REG_SZ) || (ValueType == REG_MULTI_SZ)) {
+
+ (*ParameterValue)->ParameterType =
+ (ValueType == REG_SZ) ? NdisParameterString : NdisParameterMultiString;
+
+ (*ParameterValue)->ParameterData.StringData.Buffer =
+ ExAllocatePoolWithTag(NonPagedPool, ValueLength, ' DN');
+
+ if (((*ParameterValue)->ParameterData.StringData.Buffer) == NULL) {
+ NdisFreeMemory (ParameterNode, sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE), 0);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory ((*ParameterValue)->ParameterData.StringData.Buffer,
+ ValueData, ValueLength);
+ (*ParameterValue)->ParameterData.StringData.Length = (USHORT)ValueLength;
+ (*ParameterValue)->ParameterData.StringData.MaximumLength = (USHORT)ValueLength;
+
+ //
+ // Special fix; if a string ends in a NULL and that is included
+ // in the length, remove it.
+ //
+
+ if (ValueType == REG_SZ) {
+ if ((((PUCHAR)ValueData)[ValueLength-1] == 0) &&
+ (((PUCHAR)ValueData)[ValueLength-2] == 0)) {
+ (*ParameterValue)->ParameterData.StringData.Length -= 2;
+ }
+ }
+
+ } else {
+
+ NdisFreeMemory(
+ ParameterNode,
+ sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE),
+ 0
+ );
+
+ return STATUS_OBJECT_NAME_NOT_FOUND;
+
+ }
+
+
+ //
+ // Queue this parameter node
+ //
+
+ ParameterNode->Next = NdisConfigHandle->ParameterList;
+ NdisConfigHandle->ParameterList = ParameterNode;
+
+ return STATUS_SUCCESS;
+
+}
+
+
+VOID
+NdisReadConfiguration(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_CONFIGURATION_PARAMETER *ParameterValue,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING Keyword,
+ IN NDIS_PARAMETER_TYPE ParameterType
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to read the parameter for a configuration
+ keyword from the configuration database.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ ParameterValue - Returns the value for this keyword.
+
+ ConfigurationHandle - Handle returned by NdisOpenConfiguration. Points
+ to the parameter subkey.
+
+ Keyword - The keyword to search for.
+
+ ParameterType - Ignored on NT, specifies the type of the value.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // Status of our requests
+ //
+ NTSTATUS RegistryStatus;
+
+ //
+ // There are some built-in parameters which can always be
+ // read, even if not present in the registry. This is the
+ // number of them.
+ //
+
+#define BUILT_IN_COUNT 2
+
+ //
+ // The names of the built-in parameters.
+ //
+
+ static NDIS_STRING BuiltInStrings[BUILT_IN_COUNT] =
+ { NDIS_STRING_CONST ("Environment"),
+ NDIS_STRING_CONST ("ProcessorType") };
+
+ //
+ // The values to return for the built-in parameters.
+ //
+
+ static NDIS_CONFIGURATION_PARAMETER BuiltInParameters[BUILT_IN_COUNT] =
+ { { NdisParameterInteger, NdisEnvironmentWindowsNt },
+ { NdisParameterInteger,
+#if defined(_M_IX86)
+ NdisProcessorX86
+#elif defined(_M_MRX000)
+ NdisProcessorMips
+#elif defined(_ALPHA_)
+ NdisProcessorAlpha
+#else
+ NdisProcessorPpc
+#endif
+ } };
+
+
+ //
+ // Holds a null-terminated version of the keyword.
+ //
+ PWSTR KeywordBuffer;
+
+ //
+ // index variable
+ //
+ UINT i;
+
+ //
+ // Obtain the actual configuration handle structure
+ //
+ PNDIS_CONFIGURATION_HANDLE NdisConfigHandle =
+ (PNDIS_CONFIGURATION_HANDLE) ConfigurationHandle;
+
+
+
+ //
+ // First check if this is one of the built-in parameters.
+ //
+
+ for (i = 0; i < BUILT_IN_COUNT; i++) {
+ if (RtlEqualUnicodeString(Keyword, &BuiltInStrings[i], TRUE)) {
+ *Status = NDIS_STATUS_SUCCESS;
+ *ParameterValue = &BuiltInParameters[i];
+ return;
+ }
+ }
+
+
+ //
+ // Allocate room for a null-terminated version of the keyword
+ //
+
+ KeywordBuffer = (PWSTR)ExAllocatePoolWithTag(
+ NonPagedPool,
+ Keyword->Length + sizeof(WCHAR),
+ ' DN');
+ if (KeywordBuffer == NULL) {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+ RtlCopyMemory (KeywordBuffer, Keyword->Buffer, Keyword->Length);
+ *(PWCHAR)(((PUCHAR)KeywordBuffer)+Keyword->Length) = (WCHAR)L'\0';
+
+
+ //
+ // Finish initializing the table for this query.
+ //
+
+ NdisConfigHandle->KeyQueryTable[1].Name = KeywordBuffer;
+ NdisConfigHandle->KeyQueryTable[1].EntryContext = ParameterValue;
+
+ //
+ // Get the value from the registry; this chains it on to the
+ // parameter list at NdisConfigHandle.
+ //
+
+ RegistryStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ NdisConfigHandle->KeyQueryTable[3].Name,
+ NdisConfigHandle->KeyQueryTable,
+ NdisConfigHandle, // context
+ NULL);
+
+
+ ExFreePool (KeywordBuffer); // no longer needed
+
+ if (!NT_SUCCESS(RegistryStatus)) {
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+ return;
+
+}
+
+
+VOID
+NdisWriteConfiguration(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING Keyword,
+ PNDIS_CONFIGURATION_PARAMETER ParameterValue
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to write a parameter to the configuration database.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ ConfigurationHandle - Handle passed to the driver's AddAdapter routine.
+
+ Keyword - The keyword to set.
+
+ ParameterValue - Specifies the new value for this keyword.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // Status of our requests
+ //
+ NTSTATUS RegistryStatus;
+
+ //
+ // The ConfigurationHandle is really a pointer to a registry query table.
+ //
+ PNDIS_CONFIGURATION_HANDLE NdisConfigHandle =
+ (PNDIS_CONFIGURATION_HANDLE) ConfigurationHandle;
+
+ //
+ // The name of the Parameters key.
+ //
+ PWSTR Parameters = L"\\Parameters";
+ ULONG ParametersLength = (wcslen(Parameters) + 1) * sizeof(WCHAR);
+
+ ULONG DriverLength = wcslen(NdisConfigHandle->KeyQueryTable[3].Name) * sizeof(WCHAR);
+
+ //
+ // Holds a null-terminated version of the name of the Parameters key.
+ //
+ PWSTR KeyNameBuffer;
+
+ //
+ // Holds a null-terminated version of the keyword.
+ //
+ PWSTR KeywordBuffer;
+
+ //
+ // Variables describing the parameter value.
+ //
+ PVOID ValueData;
+ ULONG ValueLength;
+ ULONG ValueType;
+
+ //
+ // Get the value data.
+ //
+ if ( ParameterValue->ParameterType == NdisParameterInteger ) {
+ ValueData = &ParameterValue->ParameterData.IntegerData;
+ ValueLength = sizeof(ParameterValue->ParameterData.IntegerData);
+ ValueType = REG_DWORD;
+ } else if ( (ParameterValue->ParameterType == NdisParameterString) ||
+ (ParameterValue->ParameterType == NdisParameterMultiString) ) {
+ ValueData = ParameterValue->ParameterData.StringData.Buffer;
+ ValueLength = ParameterValue->ParameterData.StringData.Length;
+ ValueType = ParameterValue->ParameterType == NdisParameterString ?
+ REG_SZ : REG_MULTI_SZ;
+ } else {
+ *Status = NDIS_STATUS_NOT_SUPPORTED;
+ return;
+ }
+
+ //
+ // Allocate room for the Parameters key name (e.g., L"Elnk3\Parameters").
+ //
+
+ KeyNameBuffer = (PWSTR)ExAllocatePoolWithTag(
+ NonPagedPool,
+ DriverLength + ParametersLength,
+ ' DN');
+ if (KeyNameBuffer == NULL) {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ RtlCopyMemory (KeyNameBuffer, NdisConfigHandle->KeyQueryTable[3].Name, DriverLength);
+ RtlCopyMemory ((PCHAR)KeyNameBuffer + DriverLength, Parameters, ParametersLength);
+
+ //
+ // Allocate room for a null-terminated version of the keyword
+ //
+
+ KeywordBuffer = (PWSTR)ExAllocatePoolWithTag(
+ NonPagedPool,
+ Keyword->Length + sizeof(WCHAR),
+ ' DN');
+ if (KeywordBuffer == NULL) {
+ ExFreePool (KeyNameBuffer);
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ RtlCopyMemory (KeywordBuffer, Keyword->Buffer, Keyword->Length);
+ *(PWCHAR)((PUCHAR)KeywordBuffer+Keyword->Length) = (WCHAR)L'\0';
+
+ //
+ // Write the value to the registry.
+ //
+
+ RegistryStatus = RtlWriteRegistryValue(
+ RTL_REGISTRY_SERVICES,
+ KeyNameBuffer,
+ KeywordBuffer,
+ ValueType,
+ ValueData,
+ ValueLength
+ );
+
+ ExFreePool (KeywordBuffer); // no longer needed
+ ExFreePool (KeyNameBuffer);
+
+ if (!NT_SUCCESS(RegistryStatus)) {
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+ return;
+
+}
+
+
+
+VOID
+NdisCloseConfiguration(
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to close a configuration database opened by
+ NdisOpenConfiguration.
+
+Arguments:
+
+ ConfigurationHandle - Handle returned by NdisOpenConfiguration.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Obtain the actual configuration handle structure
+ //
+ PNDIS_CONFIGURATION_HANDLE NdisConfigHandle =
+ (PNDIS_CONFIGURATION_HANDLE) ConfigurationHandle;
+
+ //
+ // Pointer to a parameter node
+ //
+ PNDIS_CONFIGURATION_PARAMETER_QUEUE ParameterNode;
+
+ //
+ // deallocate the parameter nodes
+ //
+
+ ParameterNode = NdisConfigHandle->ParameterList;
+
+ while (ParameterNode != NULL) {
+
+ NdisConfigHandle->ParameterList = ParameterNode->Next;
+
+ if ((ParameterNode->Parameter.ParameterType == NdisParameterString) ||
+ (ParameterNode->Parameter.ParameterType == NdisParameterMultiString)) {
+ ExFreePool (ParameterNode->Parameter.ParameterData.StringData.Buffer);
+ }
+
+ NdisFreeMemory(
+ ParameterNode,
+ sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE),
+ 0
+ );
+
+ ParameterNode = NdisConfigHandle->ParameterList;
+ }
+
+ NdisFreeMemory(
+ ConfigurationHandle,
+ sizeof(NDIS_CONFIGURATION_HANDLE),
+ 0);
+}
+
+
+
+VOID
+NdisReadNetworkAddress(
+ OUT PNDIS_STATUS Status,
+ OUT PVOID * NetworkAddress,
+ OUT PUINT NetworkAddressLength,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to read the "NetworkAddress" parameter
+ from the configuration database. It reads the value as a
+ string separated by hyphens, then converts it to a binary
+ array and stores the result.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ NetworkAddress - Returns a pointer to the address.
+
+ NetworkAddressLength - Returns the length of the address.
+
+ ConfigurationHandle - Handle returned by NdisOpenConfiguration. Points
+ to the parameter subkey.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Convert the handle to its real value
+ //
+
+ PNDIS_CONFIGURATION_HANDLE NdisConfigHandle =
+ (PNDIS_CONFIGURATION_HANDLE) ConfigurationHandle;
+
+ //
+ // Variables used in reading the data from the registry
+ //
+
+ NTSTATUS NtStatus;
+ PWSTR NetworkAddressString = L"NetworkAddress";
+ PNDIS_CONFIGURATION_PARAMETER ParameterValue;
+
+ //
+ // Variables used in converting the address
+ //
+
+ UCHAR ConvertArray[3];
+ PWSTR CurrentReadLoc;
+ PWSTR AddressEnd;
+ PUCHAR CurrentWriteLoc;
+ UINT TotalBytesRead;
+ ULONG TempUlong;
+ ULONG AddressLength;
+
+
+ //
+ // Finish initializing the table for this query.
+ //
+
+ NdisConfigHandle->KeyQueryTable[1].Name = NetworkAddressString;
+ NdisConfigHandle->KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ //
+ // Get the value from the registry; this chains it on to the
+ // parameter list at NdisConfigHandle.
+ //
+
+ NtStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ NdisConfigHandle->KeyQueryTable[3].Name,
+ NdisConfigHandle->KeyQueryTable,
+ NdisConfigHandle, // context
+ NULL);
+
+ if (NtStatus != NDIS_STATUS_SUCCESS) {
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ if (ParameterValue->ParameterType != NdisParameterString) {
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+
+ //
+ // Now convert the address to binary (we do this
+ // in-place, since this allows us to use the memory
+ // already allocated which is automatically freed
+ // by NdisCloseConfiguration).
+ //
+
+ ConvertArray[2] = '\0';
+ CurrentReadLoc = (PWSTR)ParameterValue->ParameterData.StringData.Buffer;
+ CurrentWriteLoc = (PUCHAR)CurrentReadLoc;
+ TotalBytesRead = ParameterValue->ParameterData.StringData.Length;
+ AddressEnd = CurrentReadLoc + (TotalBytesRead / sizeof(WCHAR));
+ AddressLength = 0;
+
+ while ((CurrentReadLoc+2) <= AddressEnd) {
+
+ //
+ // Copy the current two-character value into ConvertArray
+ //
+
+ ConvertArray[0] = (UCHAR)(*(CurrentReadLoc++));
+ ConvertArray[1] = (UCHAR)(*(CurrentReadLoc++));
+
+ //
+ // Convert it to a Ulong and update
+ //
+
+ NtStatus = RtlCharToInteger (
+ ConvertArray,
+ 16,
+ &TempUlong);
+
+ if (!NT_SUCCESS(NtStatus)) {
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ *(CurrentWriteLoc++) = (UCHAR)TempUlong;
+ ++AddressLength;
+
+ //
+ // If the next character is a hyphen, skip it.
+ //
+
+ if (CurrentReadLoc < AddressEnd) {
+ if (*CurrentReadLoc == (WCHAR)L'-') {
+ ++CurrentReadLoc;
+ }
+ }
+ }
+
+
+ *Status = STATUS_SUCCESS;
+ *NetworkAddress = ParameterValue->ParameterData.StringData.Buffer;
+ *NetworkAddressLength = AddressLength;
+
+}
+
+
+VOID
+NdisReadBindingInformation(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_STRING * Binding,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to read the binding information for
+ this adapter from the configuration database. The value
+ returned is a pointer to a string containing the bind
+ that matches the export for the current AddAdapter call.
+
+ This function is meant for NDIS drivers that are layered
+ on top of other NDIS drivers. Binding would be passed to
+ NdisOpenAdapter as the AdapterName.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ Binding - Returns the binding data.
+
+ ConfigurationHandle - Handle returned by NdisOpenConfiguration. Points
+ to the parameter subkey.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Convert the handle to its real value
+ //
+
+ PNDIS_CONFIGURATION_HANDLE NdisConfigHandle =
+ (PNDIS_CONFIGURATION_HANDLE) ConfigurationHandle;
+
+ //
+ // Use this to link parameters allocated to this open
+ //
+
+ PNDIS_CONFIGURATION_PARAMETER_QUEUE ParameterNode;
+
+
+ //
+ // For layered drivers, this points to the binding. For
+ // non-layered drivers, it is NULL. This is set up before
+ // the call to AddAdapter.
+ //
+
+ if (NdisConfigHandle->KeyQueryTable[3].EntryContext == NULL) {
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+
+ //
+ // Allocate our parameter node
+ //
+
+ *Status = NdisAllocateMemory(
+ (PVOID*)&ParameterNode,
+ sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE),
+ 0,
+ HighestAcceptableMax);
+
+ if (*Status != NDIS_STATUS_SUCCESS) {
+ return;
+ }
+
+
+ //
+ // We set this to Integer because if we set it to String
+ // then CloseConfiguration would try to free the string,
+ // which we don't want.
+ //
+
+ ParameterNode->Parameter.ParameterType = NdisParameterInteger;
+
+ RtlInitUnicodeString(
+ &ParameterNode->Parameter.ParameterData.StringData,
+ NdisConfigHandle->KeyQueryTable[3].EntryContext);
+
+ //
+ // Queue this parameter node
+ //
+
+ ParameterNode->Next = NdisConfigHandle->ParameterList;
+ NdisConfigHandle->ParameterList = ParameterNode;
+
+ *Binding = &ParameterNode->Parameter.ParameterData.StringData;
+ *Status = NDIS_STATUS_SUCCESS;
+
+}
+
+//
+// Packet and Buffer requests
+//
+
+
+VOID
+NdisAllocatePacketPool(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE PoolHandle,
+ IN UINT NumberOfDescriptors,
+ IN UINT ProtocolReservedLength
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes a packet pool. All packets are the same
+ size for a given pool (as determined by ProtocolReservedLength),
+ so a simple linked list of free packets is set up initially.
+
+Arguments:
+
+ Status - Returns the final status (always NDIS_STATUS_SUCCESS).
+ PoolHandle - Returns a pointer to the pool.
+ NumberOfDescriptors - Number of packet descriptors needed.
+ ProtocolReservedLength - How long the ProtocolReserved field
+ should be for packets in this pool.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_PACKET_POOL TmpPool;
+ PUCHAR FreeEntry;
+ UINT PacketLength;
+ UINT i;
+
+ //
+ // Set up the size of packets in this pool (rounded
+ // up to sizeof(ULONG) for alignment).
+ //
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("==>NdisAllocatePacketPool\n");
+
+ PacketLength = sizeof(NDIS_PACKET) - 1 + ProtocolReservedLength;
+ PacketLength = ((PacketLength+(sizeof(ULONG)-1)) / sizeof(ULONG))
+ * sizeof(ULONG);
+
+ //
+ // Allocate space needed
+ //
+ TmpPool = (PNDIS_PACKET_POOL) ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(NDIS_PACKET_POOL) +
+ PacketLength * NumberOfDescriptors -
+ 1,
+ 'ppDN'
+ );
+
+ if (TmpPool == NULL) {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ TmpPool->PacketLength = PacketLength;
+
+ //
+ // First entry in free list is at beginning of pool space.
+ //
+
+ TmpPool->FreeList = (PNDIS_PACKET)TmpPool->Buffer;
+ FreeEntry = TmpPool->Buffer;
+
+ for (i = 1; i < NumberOfDescriptors; i++) {
+
+ //
+ // Each entry is linked to the "packet" PacketLength bytes
+ // ahead of it, using the Private.Head field.
+ //
+
+ ((PNDIS_PACKET)FreeEntry)->Private.Head =
+ (PNDIS_BUFFER)(FreeEntry + PacketLength);
+ FreeEntry += PacketLength;
+ }
+
+ //
+ // Final free list entry.
+ //
+
+ ((PNDIS_PACKET)FreeEntry)->Private.Head = (PNDIS_BUFFER)NULL;
+
+
+ NdisAllocateSpinLock(&TmpPool->SpinLock);
+
+ *Status = NDIS_STATUS_SUCCESS;
+ *PoolHandle = (NDIS_HANDLE)TmpPool;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisAllocatePacketPool\n");
+}
+
+
+
+VOID
+NdisAllocateBufferPool(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE PoolHandle,
+ IN UINT NumberOfDescriptors
+ )
+/*++
+
+Routine Description:
+
+ Initializes a block of storage so that buffer descriptors can be
+ allocated.
+
+Arguments:
+
+ Status - status of the request.
+ PoolHandle - handle that is used to specify the pool
+ NumberOfDescriptors - Number of buffer descriptors in the pool.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // A nop for NT
+ //
+ UNREFERENCED_PARAMETER(NumberOfDescriptors);
+ *PoolHandle = NULL;
+ *Status = NDIS_STATUS_SUCCESS;
+
+}
+
+VOID
+NdisFreeBufferPool(
+ IN NDIS_HANDLE PoolHandle
+ )
+/*++
+
+Routine Description:
+
+ Terminates usage of a buffer descriptor pool.
+
+Arguments:
+
+ PoolHandle - handle that is used to specify the pool
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(PoolHandle);
+}
+
+VOID
+NdisAllocateBuffer(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_BUFFER * Buffer,
+ IN NDIS_HANDLE PoolHandle,
+ IN PVOID VirtualAddress,
+ IN UINT Length
+ )
+/*++
+
+Routine Description:
+
+ Creates a buffer descriptor to describe a segment of virtual memory
+ allocated via NdisAllocateMemory (which always allocates nonpaged).
+
+Arguments:
+
+ Status - Status of the request.
+ Buffer - Pointer to the allocated buffer descriptor.
+ PoolHandle - Handle that is used to specify the pool.
+ VirtualAddress - The virtual address of the buffer.
+ Length - The Length of the buffer.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ UNREFERENCED_PARAMETER(PoolHandle);
+
+ if ((*Buffer = IoAllocateMdl(
+ VirtualAddress,
+ Length,
+ FALSE,
+ FALSE,
+ NULL
+ )) == NULL) {
+
+ *Status = NDIS_STATUS_FAILURE;
+
+ } else {
+
+ MmBuildMdlForNonPagedPool(*Buffer);
+ (*Buffer)->Next = NULL;
+ *Status = NDIS_STATUS_SUCCESS;
+
+ }
+
+}
+
+
+VOID
+NdisCopyBuffer(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_BUFFER * Buffer,
+ IN NDIS_HANDLE PoolHandle,
+ IN PVOID MemoryDescriptor,
+ IN UINT Offset,
+ IN UINT Length
+ )
+/*++
+
+Routine Description:
+
+ Used to create a buffer descriptor given a memory descriptor.
+
+Arguments:
+
+ Status - Status of the request.
+ Buffer - Pointer to the allocated buffer descriptor.
+ PoolHandle - Handle that is used to specify the pool.
+ MemoryDescriptor - Pointer to the descriptor of the source memory.
+ Offset - The Offset in the sources memory from which the copy is to
+ begin
+ Length - Number of Bytes to copy.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PNDIS_BUFFER SourceDescriptor = (PNDIS_BUFFER)MemoryDescriptor;
+ PVOID BaseVa = (((PUCHAR)MmGetMdlVirtualAddress(SourceDescriptor)) + Offset);
+
+ UNREFERENCED_PARAMETER(PoolHandle);
+
+ if ((*Buffer = IoAllocateMdl(
+ BaseVa,
+ Length,
+ FALSE,
+ FALSE,
+ NULL
+ )) == NULL ) {
+
+ *Status = NDIS_STATUS_FAILURE;
+
+ } else {
+
+ IoBuildPartialMdl(
+ SourceDescriptor,
+ *Buffer,
+ BaseVa,
+ Length);
+
+ (*Buffer)->Next = NULL;
+ *Status = NDIS_STATUS_SUCCESS;
+
+ }
+
+}
+
+
+VOID
+NdisAllocatePacket(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_PACKET * Packet,
+ IN NDIS_HANDLE PoolHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates a packet out of a packet pool.
+
+Arguments:
+
+ Status - Returns the final status.
+ Packet - Return a pointer to the packet.
+ PoolHandle - The packet pool to allocate from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_PACKET_POOL TmpPool = (PNDIS_PACKET_POOL)PoolHandle;
+
+ ACQUIRE_SPIN_LOCK(&TmpPool->SpinLock);
+
+
+ //
+ // See if any packets are on pool free list.
+ //
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisAllocatePacket\n");
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(PoolHandle)) {
+ NdisPrint1("AllocatePacket: NULL Pool address\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(PoolHandle)) {
+ NdisPrint1("AllocatePacket: Pool not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ if (TmpPool->FreeList == (PNDIS_PACKET)NULL) {
+
+ //
+ // No, cannot satisfy request.
+ //
+
+ RELEASE_SPIN_LOCK(&TmpPool->SpinLock);
+ *Status = NDIS_STATUS_RESOURCES;
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisAllocatePacket\n");
+ return;
+ }
+
+ //
+ // Yes, take free packet off head of list and return it.
+ //
+
+ *Packet = TmpPool->FreeList;
+ TmpPool->FreeList = (PNDIS_PACKET)(*Packet)->Private.Head;
+ RELEASE_SPIN_LOCK(&TmpPool->SpinLock);
+
+
+ //
+ // Clear packet elements.
+ //
+
+ RtlZeroMemory((PVOID)*Packet, TmpPool->PacketLength);
+ (*Packet)->Private.Head = (PNDIS_BUFFER)NULL; // don't need to set Tail
+ (*Packet)->Private.Pool = (PNDIS_PACKET_POOL)PoolHandle;
+ (*Packet)->Private.Count = 0;
+ (*Packet)->Private.PhysicalCount = 0;
+ (*Packet)->Private.TotalLength = 0;
+ (*Packet)->Private.ValidCounts = TRUE;
+
+ *Status = NDIS_STATUS_SUCCESS;
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisAllocatePacket\n");
+}
+
+
+VOID
+NdisUnchainBufferAtFront(
+ IN OUT PNDIS_PACKET Packet,
+ OUT PNDIS_BUFFER * Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ Takes a buffer off the front of a packet.
+
+Arguments:
+
+ Packet - The packet to be modified.
+ Buffer - Returns the packet on the front, or NULL.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ *Buffer = Packet->Private.Head;
+
+ //
+ // If packet is not empty, remove head buffer.
+ //
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisUnchainBufferAtFront\n");
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(Packet)) {
+ NdisPrint1("UnchainBufferAtFront: Null Packet Pointer\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(Packet)) {
+ NdisPrint1("UnchainBufferAtFront: Packet not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsPacket(Packet)) {
+ NdisPrint1("UnchainBufferAtFront: Illegal Packet Size\n");
+ DbgBreakPoint();
+ }
+ }
+
+ if (*Buffer != (PNDIS_BUFFER)NULL) {
+ Packet->Private.Head = (*Buffer)->Next; // may be NULL
+ (*Buffer)->Next = (PNDIS_BUFFER)NULL;
+ Packet->Private.ValidCounts = FALSE;
+ }
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisUnchainBufferAtFront\n");
+}
+
+VOID
+NdisUnchainBufferAtBack(
+ IN OUT PNDIS_PACKET Packet,
+ OUT PNDIS_BUFFER * Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ Takes a buffer off the end of a packet.
+
+Arguments:
+
+ Packet - The packet to be modified.
+ Buffer - Returns the packet on the end, or NULL.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_BUFFER TmpBufP = Packet->Private.Head;
+ PNDIS_BUFFER Result;
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisUnchainBufferAtBack\n");
+ IF_ERROR_CHK {
+ if (DbgIsNull(Packet)) {
+ NdisPrint1("UnchainBufferAtBack: Null Packet Pointer\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(Packet)) {
+ NdisPrint1("UnchainBufferAtBack: Packet not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsPacket(Packet)) {
+ NdisPrint1("UnchainBufferAtBack: Illegal Packet Size\n");
+ DbgBreakPoint();
+ }
+ }
+ if (TmpBufP != (PNDIS_BUFFER)NULL) {
+
+ //
+ // The packet is not empty, return the tail buffer.
+ //
+
+ Result = Packet->Private.Tail;
+ if (TmpBufP == Result) {
+
+ //
+ // There was only one buffer on the queue.
+ //
+
+ Packet->Private.Head = (PNDIS_BUFFER)NULL;
+ } else {
+
+ //
+ // Determine the new tail buffer.
+ //
+
+ while (TmpBufP->Next != Result) {
+ TmpBufP = TmpBufP->Next;
+ }
+ Packet->Private.Tail = TmpBufP;
+ TmpBufP->Next = NULL;
+ }
+
+ Result->Next = (PNDIS_BUFFER)NULL;
+ Packet->Private.ValidCounts = FALSE;
+ } else {
+
+ //
+ // Packet is empty.
+ //
+
+ Result = (PNDIS_BUFFER)NULL;
+ }
+
+ *Buffer = Result;
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisUnchainBufferAtBack\n");
+}
+
+
+
+VOID
+NdisCopyFromPacketToPacket(
+ IN PNDIS_PACKET Destination,
+ IN UINT DestinationOffset,
+ IN UINT BytesToCopy,
+ IN PNDIS_PACKET Source,
+ IN UINT SourceOffset,
+ OUT PUINT BytesCopied
+ )
+
+/*++
+
+Routine Description:
+
+ Copy from an ndis packet to an ndis packet.
+
+Arguments:
+
+ Destination - The packet should be copied in to.
+
+ DestinationOffset - The offset from the beginning of the packet
+ into which the data should start being placed.
+
+ BytesToCopy - The number of bytes to copy from the source packet.
+
+ Source - The ndis packet from which to copy data.
+
+ SourceOffset - The offset from the start of the packet from which
+ to start copying data.
+
+ BytesCopied - The number of bytes actually copied from the source
+ packet. This can be less than BytesToCopy if the source or destination
+ packet is too short.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ //
+ // Holds the count of the number of ndis buffers comprising the
+ // destination packet.
+ //
+ UINT DestinationBufferCount;
+
+ //
+ // Holds the count of the number of ndis buffers comprising the
+ // source packet.
+ //
+ UINT SourceBufferCount;
+
+ //
+ // Points to the buffer into which we are putting data.
+ //
+ PNDIS_BUFFER DestinationCurrentBuffer;
+
+ //
+ // Points to the buffer from which we are extracting data.
+ //
+ PNDIS_BUFFER SourceCurrentBuffer;
+
+ //
+ // Holds the virtual address of the current destination buffer.
+ //
+ PVOID DestinationVirtualAddress;
+
+ //
+ // Holds the virtual address of the current source buffer.
+ //
+ PVOID SourceVirtualAddress;
+
+ //
+ // Holds the length of the current destination buffer.
+ //
+ UINT DestinationCurrentLength;
+
+ //
+ // Holds the length of the current source buffer.
+ //
+ UINT SourceCurrentLength;
+
+ //
+ // Keep a local variable of BytesCopied so we aren't referencing
+ // through a pointer.
+ //
+ UINT LocalBytesCopied = 0;
+
+ //
+ // Take care of boundary condition of zero length copy.
+ //
+
+ *BytesCopied = 0;
+ if (!BytesToCopy) return;
+
+ //
+ // Get the first buffer of the destination.
+ //
+
+ NdisQueryPacket(
+ Destination,
+ NULL,
+ &DestinationBufferCount,
+ &DestinationCurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (!DestinationBufferCount) return;
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ //
+ // Get the first buffer of the source.
+ //
+
+ NdisQueryPacket(
+ Source,
+ NULL,
+ &SourceBufferCount,
+ &SourceCurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (!SourceBufferCount) return;
+
+ NdisQueryBuffer(
+ SourceCurrentBuffer,
+ &SourceVirtualAddress,
+ &SourceCurrentLength
+ );
+
+ while (LocalBytesCopied < BytesToCopy) {
+
+ //
+ // Check to see whether we've exhausted the current destination
+ // buffer. If so, move onto the next one.
+ //
+
+ if (!DestinationCurrentLength) {
+
+ NdisGetNextBuffer(
+ DestinationCurrentBuffer,
+ &DestinationCurrentBuffer
+ );
+
+ if (!DestinationCurrentBuffer) {
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.)
+ //
+
+ break;
+
+ }
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+ continue;
+
+ }
+
+
+ //
+ // Check to see whether we've exhausted the current source
+ // buffer. If so, move onto the next one.
+ //
+
+ if (!SourceCurrentLength) {
+
+ NdisGetNextBuffer(
+ SourceCurrentBuffer,
+ &SourceCurrentBuffer
+ );
+
+ if (!SourceCurrentBuffer) {
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.)
+ //
+
+ break;
+
+ }
+
+ NdisQueryBuffer(
+ SourceCurrentBuffer,
+ &SourceVirtualAddress,
+ &SourceCurrentLength
+ );
+ continue;
+
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (DestinationOffset) {
+
+ if (DestinationOffset > DestinationCurrentLength) {
+
+ //
+ // What we want isn't in this buffer.
+ //
+
+ DestinationOffset -= DestinationCurrentLength;
+ DestinationCurrentLength = 0;
+ continue;
+
+ } else {
+
+ DestinationVirtualAddress = (PCHAR)DestinationVirtualAddress
+ + DestinationOffset;
+ DestinationCurrentLength -= DestinationOffset;
+ DestinationOffset = 0;
+
+ }
+
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (SourceOffset) {
+
+ if (SourceOffset > SourceCurrentLength) {
+
+ //
+ // What we want isn't in this buffer.
+ //
+
+ SourceOffset -= SourceCurrentLength;
+ SourceCurrentLength = 0;
+ continue;
+
+ } else {
+
+ SourceVirtualAddress = (PCHAR)SourceVirtualAddress
+ + SourceOffset;
+ SourceCurrentLength -= SourceOffset;
+ SourceOffset = 0;
+
+ }
+
+ }
+
+ //
+ // Copy the data.
+ //
+
+ {
+
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ //
+ // Holds the amount desired remaining.
+ //
+ UINT Remaining = BytesToCopy - LocalBytesCopied;
+
+ AmountToMove =
+ ((SourceCurrentLength <= DestinationCurrentLength)?
+ (SourceCurrentLength):(DestinationCurrentLength));
+
+ AmountToMove = ((Remaining < AmountToMove)?
+ (Remaining):(AmountToMove));
+
+ RtlCopyMemory(
+ DestinationVirtualAddress,
+ SourceVirtualAddress,
+ AmountToMove
+ );
+
+ DestinationVirtualAddress =
+ (PCHAR)DestinationVirtualAddress + AmountToMove;
+ SourceVirtualAddress =
+ (PCHAR)SourceVirtualAddress + AmountToMove;
+
+ LocalBytesCopied += AmountToMove;
+ SourceCurrentLength -= AmountToMove;
+ DestinationCurrentLength -= AmountToMove;
+
+ }
+
+ }
+
+ *BytesCopied = LocalBytesCopied;
+
+}
+
+//
+// Operating System Requests
+//
+//
+
+
+VOID
+NdisMapIoSpace(
+ OUT PNDIS_STATUS Status,
+ OUT PVOID * VirtualAddress,
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress,
+ IN UINT Length
+ )
+/*++
+
+Routine Description:
+
+ Map virtual memory address space onto a physical address.
+
+Arguments:
+
+ Status - resulting status
+ VirtualAddress - resulting address in virtual space.
+ NdisAdapterHandle - value returned by NdisRegisterAdapter.
+ PhysicalAddress - Physical address.
+ Length - Size of requested memory mapping
+
+Return Value:
+
+ none.
+
+--*/
+{
+ ULONG addressSpace = 0;
+ ULONG NumberOfElements;
+ PHYSICAL_ADDRESS PhysicalTemp;
+ PCM_RESOURCE_LIST Resources;
+ BOOLEAN Conflict;
+ NTSTATUS NtStatus;
+ PNDIS_ADAPTER_BLOCK AdptrP = (PNDIS_ADAPTER_BLOCK)(NdisAdapterHandle);
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(NdisAdapterHandle);
+
+ //
+ // First check if any bus access is allowed
+ //
+
+ if ((((AdptrP->DeviceObject != NULL) ?
+ AdptrP->BusType :
+ Miniport->BusType) == (NDIS_INTERFACE_TYPE)-1) ||
+ (((AdptrP->DeviceObject != NULL) ?
+ AdptrP->BusNumber :
+ Miniport->BusNumber) == (ULONG)-1)) {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ //
+ // First check for resource conflict by expanding current resource list,
+ // adding in the mapped space, and then re-submitting the resource list.
+ //
+
+ if (((AdptrP->DeviceObject != NULL) ?
+ AdptrP->Resources :
+ Miniport->Resources) != NULL) {
+
+ NumberOfElements = ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->Resources->List[0].PartialResourceList.Count + 1:
+ Miniport->Resources->List[0].PartialResourceList.Count + 1);
+
+ } else {
+
+ NumberOfElements = 1;
+ }
+
+ //
+ // First check for resource conflict by expanding current resource list,
+ // adding in the mapped space, and then re-submitting the resource list.
+ //
+
+ Resources = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ NumberOfElements,
+ 'lrDN'
+ );
+
+ if (Resources == NULL) {
+
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+
+ }
+
+ if (((AdptrP->DeviceObject != NULL) ?
+ AdptrP->Resources :
+ Miniport->Resources) != NULL) {
+
+ RtlCopyMemory (Resources,
+ ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->Resources:
+ Miniport->Resources),
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ (NumberOfElements-1)
+ );
+ } else {
+
+ //
+ // Setup initial resource info -- NOTE: This is definitely a mini-port
+ //
+ ASSERT(AdptrP->DeviceObject == NULL);
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = Miniport->AdapterType;
+ Resources->List[0].BusNumber = Miniport->BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ }
+
+ //
+ // Setup memory
+ //
+
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type =
+ CmResourceTypeMemory;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition =
+ CmResourceShareDeviceExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags =
+ CM_RESOURCE_MEMORY_READ_WRITE;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Memory.Start =
+ PhysicalAddress;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Memory.Length =
+ Length;
+ Resources->List[0].PartialResourceList.Count++;
+
+
+ //
+ // Make the call
+ //
+
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->MacHandle->NdisMacInfo->NdisWrapperDriver :
+ Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver),
+ NULL,
+ 0,
+ ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->DeviceObject:
+ Miniport->DeviceObject),
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ Resources->List[0].PartialResourceList.Count,
+ TRUE,
+ &Conflict
+ );
+
+ //
+ // Check for conflict.
+ //
+
+ if (((AdptrP->DeviceObject != NULL) ?
+ AdptrP->Resources :
+ Miniport->Resources) != NULL) {
+ ExFreePool(((AdptrP->DeviceObject != NULL) ?
+ AdptrP->Resources:
+ Miniport->Resources));
+ }
+
+ if (AdptrP->DeviceObject != NULL) {
+ AdptrP->Resources = Resources;
+ } else {
+ Miniport->Resources = Resources;
+ }
+
+ if (Conflict || (NtStatus != STATUS_SUCCESS)) {
+
+
+ if (Conflict) {
+
+
+ //
+ // Log an error
+ //
+
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ volatile ULONG i;
+ ULONG StringSize;
+ PUCHAR Place;
+ PWCH baseFileName;
+ WCHAR Character;
+ ULONG Value;
+
+ baseFileName = ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.Buffer :
+ Miniport->MiniportName.Buffer);
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+
+ for ( i = 0;
+ i < ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.Length :
+ Miniport->MiniportName.Length) / sizeof(WCHAR);
+ i++ ) {
+
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+
+ if ( ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.Buffer[i] :
+ Miniport->MiniportName.Buffer[i]) == OBJ_NAME_PATH_SEPARATOR ) {
+ baseFileName = ((AdptrP->DeviceObject != NULL) ?
+ &(AdptrP->AdapterName.Buffer[++i]):
+ &(Miniport->MiniportName.Buffer[++i]));
+ }
+
+ }
+
+ StringSize = ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.MaximumLength :
+ Miniport->MiniportName.MaximumLength) -
+ (((ULONG)baseFileName) -
+ ((AdptrP->DeviceObject != NULL) ?
+ ((ULONG)AdptrP->AdapterName.Buffer) :
+ ((ULONG)Miniport->MiniportName.Buffer)));
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->DeviceObject:
+ Miniport->DeviceObject),
+ (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize +
+ 34) // wstrlen("FFFFFFFFFFFFFFFF") * sizeof(WHCAR) + sizeof(UNICODE_NULL)
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_MEMORY_CONFLICT;
+
+ //
+ // store the time
+ //
+
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+
+ //
+ // Set string information
+ //
+
+ if (StringSize != 0) {
+
+ errorLogEntry->NumberOfStrings = 1;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+
+ RtlCopyMemory (
+ ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET),
+ (PVOID)baseFileName,
+ StringSize
+ );
+
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize;
+
+ } else {
+
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET);
+
+ errorLogEntry->NumberOfStrings = 0;
+
+ }
+
+ errorLogEntry->NumberOfStrings++;
+
+ //
+ // Put in memory address
+ //
+
+ for (StringSize = 0; StringSize < 2; StringSize++) {
+
+ if (StringSize == 0) {
+
+ //
+ // Do high part
+ //
+
+ Value = NdisGetPhysicalAddressHigh(PhysicalAddress);
+
+ } else {
+
+ //
+ // Do Low part
+ //
+
+ Value = NdisGetPhysicalAddressLow(PhysicalAddress);
+
+ }
+
+ //
+ // Convert value
+ //
+
+ for (i = 1; i <= (sizeof(ULONG) * 2); i++) {
+
+ switch ((Value >> (((sizeof(ULONG) * 2) - i) * 4)) & 0x0F) {
+
+ case 0:
+ Character = L'0';
+ break;
+ case 1:
+ Character = L'1';
+ break;
+ case 2:
+ Character = L'2';
+ break;
+ case 3:
+ Character = L'3';
+ break;
+ case 4:
+ Character = L'4';
+ break;
+ case 5:
+ Character = L'5';
+ break;
+ case 6:
+ Character = L'6';
+ break;
+ case 7:
+ Character = L'7';
+ break;
+ case 8:
+ Character = L'8';
+ break;
+ case 9:
+ Character = L'9';
+ break;
+ case 10:
+ Character = L'A';
+ break;
+ case 11:
+ Character = L'B';
+ break;
+ case 12:
+ Character = L'C';
+ break;
+ case 13:
+ Character = L'D';
+ break;
+ case 14:
+ Character = L'E';
+ break;
+ case 15:
+ Character = L'F';
+ break;
+ }
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ Place += sizeof(WCHAR);
+
+ }
+
+ }
+
+ Character = UNICODE_NULL;
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ //
+ // write it out
+ //
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+ *Status = NDIS_STATUS_RESOURCE_CONFLICT;
+ return;
+
+ }
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+
+ if ( !HalTranslateBusAddress(
+ ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->BusType:
+ Miniport->BusType),
+ ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->BusNumber :
+ Miniport->BusNumber),
+ PhysicalAddress,
+ &addressSpace,
+ &PhysicalTemp
+ ) ) {
+
+ //
+ // It would be nice to return a better status here, but we only get
+ // TRUE/FALSE back from HalTranslateBusAddress.
+ //
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ if (addressSpace == 0) {
+
+ //
+ // memory space
+ //
+
+ *VirtualAddress = MmMapIoSpace(PhysicalTemp, (Length), FALSE);
+
+ } else {
+
+ //
+ // I/O space
+ //
+
+ *VirtualAddress = (PVOID)(PhysicalTemp.LowPart);
+
+ }
+
+ if (*VirtualAddress == NULL) {
+ *Status = NDIS_STATUS_RESOURCES;
+ } else {
+ *Status = NDIS_STATUS_SUCCESS;
+ }
+}
+
+NDIS_STATUS
+NdisAllocateMemory(
+ OUT PVOID *VirtualAddress,
+ IN UINT Length,
+ IN UINT MemoryFlags,
+ IN NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress
+ )
+/*++
+
+Routine Description:
+
+ Allocate memory for use by a protocol or a MAC driver
+
+Arguments:
+
+ VirtualAddress - Returns a pointer to the allocated memory.
+ Length - Size of requested allocation in bytes.
+ MaximumPhysicalAddress - Highest addressable address of the allocated
+ memory.. 0 means highest system memory possible.
+ MemoryFlags - Bit mask that allows the caller to specify attributes
+ of the allocated memory. 0 means standard memory.
+
+ other options:
+
+ NDIS_MEMORY_CONTIGUOUS
+ NDIS_MEMORY_NONCACHED
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if successful.
+ NDIS_STATUS_FAILURE if not successful. *VirtualAddress will be NULL.
+
+
+--*/
+{
+ //
+ // Depending on the value of MemoryFlags, we allocate three different
+ // types of memory.
+ //
+
+ if (MemoryFlags == 0) {
+
+ *VirtualAddress = ExAllocatePoolWithTag(NonPagedPool, Length, 'maDN');
+
+ } else if (MemoryFlags & NDIS_MEMORY_NONCACHED) {
+
+ *VirtualAddress = MmAllocateNonCachedMemory(Length);
+
+ } else if (MemoryFlags & NDIS_MEMORY_CONTIGUOUS) {
+
+ *VirtualAddress = MmAllocateContiguousMemory(Length, HighestAcceptableAddress);
+
+ }
+
+ if (*VirtualAddress == NULL) {
+
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ return NDIS_STATUS_SUCCESS;
+
+}
+
+
+VOID
+NdisFreeMemory(
+ IN PVOID VirtualAddress,
+ IN UINT Length,
+ IN UINT MemoryFlags
+ )
+/*++
+
+Routine Description:
+
+ Releases memory allocated using NdisAllocateMemory.
+
+Arguments:
+
+ VirtualAddress - Pointer to the memory to be freed.
+ Length - Size of allocation in bytes.
+ MemoryFlags - Bit mask that allows the caller to specify attributes
+ of the allocated memory. 0 means standard memory.
+
+ other options:
+
+ NDIS_MEMORY_CONTIGUOUS
+ NDIS_MEMORY_NONCACHED
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Depending on the value of MemoryFlags, we allocate three free 3
+ // types of memory.
+ //
+
+ if (MemoryFlags == 0) {
+
+ ExFreePool(VirtualAddress);
+
+ } else if (MemoryFlags & NDIS_MEMORY_NONCACHED) {
+
+ MmFreeNonCachedMemory(VirtualAddress, Length);
+
+ } else if (MemoryFlags & NDIS_MEMORY_CONTIGUOUS) {
+
+ MmFreeContiguousMemory(VirtualAddress);
+
+ }
+
+}
+
+VOID
+NdisInitializeTimer(
+ IN OUT PNDIS_TIMER NdisTimer,
+ IN PNDIS_TIMER_FUNCTION TimerFunction,
+ IN PVOID FunctionContext
+ )
+/*++
+
+Routine Description:
+
+ Sets up an NdisTimer object, initializing the DPC in the timer to
+ the function and context.
+
+Arguments:
+
+ NdisTimer - the timer object.
+ TimerFunction - Routine to start.
+ FunctionContext - Context of TimerFunction.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ KeInitializeTimer(&(NdisTimer)->Timer);
+
+ //
+ // Initialize our dpc. If Dpc was previously initialized, this will
+ // reinitialize it.
+ //
+
+ KeInitializeDpc(
+ &NdisTimer->Dpc,
+ (PKDEFERRED_ROUTINE) TimerFunction,
+ FunctionContext
+ );
+
+ KeSetImportanceDpc(
+ &NdisTimer->Dpc,
+ LowImportance
+ );
+}
+
+
+VOID
+NdisSetTimer(
+ IN PNDIS_TIMER NdisTimer,
+ IN UINT MillisecondsToDelay
+ )
+/*++
+
+Routine Description:
+
+ Sets up TimerFunction to fire after MillisecondsToDelay.
+
+Arguments:
+
+ NdisTimer - the timer object.
+ MillisecondsToDelay - Amount of time before TimerFunction is started.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ LARGE_INTEGER FireUpTime;
+
+ FireUpTime.QuadPart = Int32x32To64((LONG)MillisecondsToDelay, -10000);
+
+ //
+ // Set the timer
+ //
+ KeSetTimer(
+ &NdisTimer->Timer,
+ FireUpTime,
+ &NdisTimer->Dpc
+ );
+}
+
+
+BOOLEAN
+NdisIsr(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ Handles ALL Mac interrupts, calling the appropriate Mac ISR and DPC
+ depending on the context.
+
+Arguments:
+
+ Interrupt - Interrupt object for the Mac.
+
+ Context - Really a pointer to the interrupt.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Get adapter from context.
+ //
+
+ PNDIS_INTERRUPT NdisInterrupt = (PNDIS_INTERRUPT)(Context);
+
+ BOOLEAN (*InterruptIsr)(PVOID) = (BOOLEAN (*) (PVOID))(NdisInterrupt->MacIsr);
+
+ UNREFERENCED_PARAMETER(Interrupt);
+
+ //
+ // Call MacIsr
+ //
+
+ if((*InterruptIsr)(NdisInterrupt->InterruptContext) != FALSE){
+
+ //
+ // Queue MacDpc if needed
+ //
+
+ Increment((PLONG)&NdisInterrupt->DpcCount,&NdisInterrupt->DpcCountLock);
+
+ if (!(KeInsertQueueDpc(&(NdisInterrupt->InterruptDpc),NULL,NULL))) {
+
+ //
+ // If the DPC was already queued, then we have an extra
+ // reference (we do it this way to ensure that the reference
+ // is added *before* the DPC is queued).
+ //
+
+ Decrement((PLONG)&NdisInterrupt->DpcCount,&NdisInterrupt->DpcCountLock);
+
+ if (NdisInterrupt->Removing && (NdisInterrupt->DpcCount==0)) {
+
+ //
+ // We need to queue a DPC to set the event because we
+ // can't do it from the ISR. We know that the interrupt
+ // DPC won't fire because the refcount is 0, so we reuse it.
+ //
+
+ KeInitializeDpc(
+ &NdisInterrupt->InterruptDpc,
+ NdisLastCountRemovedFunction,
+ (PVOID)(&NdisInterrupt->DpcsCompletedEvent)
+ );
+
+ //
+ // When NdisLastCountRemovedFunction runs it will set
+ // the event.
+ //
+
+ KeInsertQueueDpc (&(NdisInterrupt->InterruptDpc), NULL, NULL);
+
+ }
+ }
+
+ return TRUE;
+
+ }
+
+ return FALSE;
+
+}
+
+VOID
+NdisLastCountRemovedFunction(
+ IN struct _KDPC *Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+
+/*++
+
+Routine Description:
+
+ Queued from NdisIsr if the refcount is zero and we need to
+ set the event, since we can't do that from an ISR.
+
+Arguments:
+
+ Dpc - Will be NdisInterrupt->InterruptDpc.
+
+ DeferredContext - Points to the event to set.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UNREFERENCED_PARAMETER (Dpc);
+ UNREFERENCED_PARAMETER (SystemArgument1);
+ UNREFERENCED_PARAMETER (SystemArgument2);
+
+ KeSetEvent(
+ (PKEVENT)DeferredContext,
+ 0L,
+ FALSE
+ );
+}
+
+
+VOID
+NdisDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+/*++
+
+Routine Description:
+
+ Handles ALL Mac interrupt DPCs, calling the appropriate Mac DPC
+ depending on the context.
+
+Arguments:
+
+ Interrupt - Interrupt object for the Mac.
+
+ Context - Really a pointer to the Interrupt.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Get adapter from context.
+ //
+
+ PNDIS_INTERRUPT NdisInterrupt = (PNDIS_INTERRUPT)(InterruptContext);
+
+ VOID (*MacDpc)(PVOID) = (VOID (*) (PVOID))(NdisInterrupt->MacDpc);
+
+ //
+ // Call MacDpc
+ //
+
+ (*((PNDIS_DEFERRED_PROCESSING)MacDpc))(SystemSpecific1,
+ NdisInterrupt->InterruptContext,
+ SystemSpecific2,
+ SystemSpecific3
+ );
+
+ Decrement((PLONG)&NdisInterrupt->DpcCount,&NdisInterrupt->DpcCountLock);
+
+ if (NdisInterrupt->Removing && (NdisInterrupt->DpcCount==0)) {
+
+ KeSetEvent(
+ &NdisInterrupt->DpcsCompletedEvent,
+ 0L,
+ FALSE
+ );
+ }
+
+
+}
+
+
+VOID
+NdisInitializeInterrupt(
+ OUT PNDIS_STATUS Status,
+ IN OUT PNDIS_INTERRUPT NdisInterrupt,
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PNDIS_INTERRUPT_SERVICE InterruptServiceRoutine,
+ IN PVOID InterruptContext,
+ IN PNDIS_DEFERRED_PROCESSING DeferredProcessingRoutine,
+ IN UINT InterruptVector,
+ IN UINT InterruptLevel,
+ IN BOOLEAN SharedInterrupt,
+ IN NDIS_INTERRUPT_MODE InterruptMode
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes the interrupt and sets up the Dpc.
+
+Arguments:
+
+ Status - Status of this request.
+ InterruptDpc - The Dpc object corresponding to DeferredProcessingRoutine.
+ Interrupt - Points to driver allocated memory that the wrapper fills in
+ with information about the interrupt handler.
+ InterruptServiceRoutine - The ISR that is called for this interrupt.
+ InterruptContext - Value passed to the ISR.
+ DeferredProcessingRoutine - The DPC queued by the ISR.
+ InterruptVector - Interrupt number used by the ISR.
+ InterruptMode - Type of interrupt the adapter generates.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ NTSTATUS NtStatus;
+ PNDIS_ADAPTER_BLOCK AdptrP = (PNDIS_ADAPTER_BLOCK)(NdisAdapterHandle);
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(NdisAdapterHandle);
+ ULONG Vector;
+ ULONG NumberOfElements;
+ KIRQL Irql;
+ KAFFINITY InterruptAffinity;
+ PCM_RESOURCE_LIST Resources;
+ BOOLEAN Conflict;
+ BOOLEAN IsAMiniport;
+ PNDIS_MINIPORT_INTERRUPT MiniportInterrupt = (PNDIS_MINIPORT_INTERRUPT)(NdisInterrupt);
+
+ IsAMiniport = (AdptrP->DeviceObject == NULL);
+
+ //
+ // First check if any bus access is allowed
+ //
+
+ if (((IsAMiniport ?
+ Miniport->BusType:
+ AdptrP->BusType) == (NDIS_INTERFACE_TYPE)-1) ||
+ ((IsAMiniport ?
+ Miniport->BusNumber:
+ AdptrP->BusNumber) == (ULONG)-1)) {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ //
+ // First check for resource conflict by expanding current resource list,
+ // adding in the interrupt, and then re-submitting the resource list.
+ //
+
+ if ((IsAMiniport ?
+ Miniport->Resources:
+ AdptrP->Resources) != NULL) {
+
+ NumberOfElements = (IsAMiniport ?
+ Miniport->Resources->List[0].PartialResourceList.Count + 1 :
+ AdptrP->Resources->List[0].PartialResourceList.Count + 1);
+
+ } else {
+
+ NumberOfElements = 1;
+ }
+
+ Resources = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ NumberOfElements,
+ 'lrDN'
+ );
+
+ if (Resources == NULL) {
+
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+
+ }
+
+ if ((IsAMiniport ?
+ Miniport->Resources :
+ AdptrP->Resources) != NULL) {
+
+ RtlCopyMemory (Resources,
+ (IsAMiniport ?
+ Miniport->Resources :
+ AdptrP->Resources),
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ (NumberOfElements - 1)
+ );
+
+ } else {
+
+ //
+ // Setup initial resource info
+ //
+ ASSERT(IsAMiniport);
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = Miniport->AdapterType;
+ Resources->List[0].BusNumber = Miniport->BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ }
+
+ //
+ // Setup interrupt
+ //
+
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type =
+ CmResourceTypeInterrupt;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition =
+ SharedInterrupt ? CmResourceShareShared : CmResourceShareDeviceExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags =
+ (InterruptMode == NdisInterruptLatched) ?
+ CM_RESOURCE_INTERRUPT_LATCHED :
+ CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Interrupt.Level =
+ InterruptLevel;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Interrupt.Vector =
+ InterruptVector;
+ Resources->List[0].PartialResourceList.Count++;
+
+ //
+ // Make the call
+ //
+
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ (IsAMiniport ?
+ Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver :
+ AdptrP->MacHandle->NdisMacInfo->NdisWrapperDriver),
+ NULL,
+ 0,
+ (IsAMiniport ?
+ Miniport->DeviceObject :
+ AdptrP->DeviceObject),
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ Resources->List[0].PartialResourceList.Count,
+ TRUE,
+ &Conflict
+ );
+
+ //
+ // Check for conflict.
+ //
+
+ if ((IsAMiniport ?
+ Miniport->Resources:
+ AdptrP->Resources) != NULL) {
+ ExFreePool((IsAMiniport ?
+ Miniport->Resources:
+ AdptrP->Resources));
+ }
+
+ if (IsAMiniport) {
+
+ Miniport->Resources = Resources;
+
+ } else {
+
+ AdptrP->Resources = Resources;
+
+
+ }
+ if (Conflict || (NtStatus != STATUS_SUCCESS)) {
+
+ if (Conflict) {
+
+ //
+ // Log an error
+ //
+
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ ULONG i;
+ ULONG StringSize;
+ PUCHAR Place;
+ PWCH baseFileName;
+ WCHAR Character;
+ ULONG Value;
+
+ baseFileName = ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.Buffer :
+ Miniport->MiniportName.Buffer);
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+
+ for ( i = 0;
+ i < ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.Length :
+ Miniport->MiniportName.Length) / sizeof(WCHAR);
+ i++ ) {
+
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+
+ if ( ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.Buffer[i] :
+ Miniport->MiniportName.Buffer[i]) == OBJ_NAME_PATH_SEPARATOR ) {
+ baseFileName = ((AdptrP->DeviceObject != NULL) ?
+ &(AdptrP->AdapterName.Buffer[++i]):
+ &(Miniport->MiniportName.Buffer[++i]));
+ }
+
+ }
+
+ StringSize = ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.MaximumLength :
+ Miniport->MiniportName.MaximumLength) -
+ (((ULONG)baseFileName) -
+ ((AdptrP->DeviceObject != NULL) ?
+ ((ULONG)AdptrP->AdapterName.Buffer) :
+ ((ULONG)Miniport->MiniportName.Buffer)));
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (IsAMiniport ?
+ Miniport->DeviceObject :
+ AdptrP->DeviceObject),
+ (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize +
+ 6) // wstrlen("99") * sizeof(WHCAR) + sizeof(UNICODE_NULL)
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_INTERRUPT_CONFLICT;
+
+ //
+ // store the time
+ //
+
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+
+ //
+ // Set string information
+ //
+
+ if (StringSize != 0) {
+
+ errorLogEntry->NumberOfStrings = 1;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+
+ RtlCopyMemory (
+ ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET),
+ (PVOID)baseFileName,
+ StringSize
+ );
+
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize;
+
+ } else {
+
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET);
+
+ errorLogEntry->NumberOfStrings = 0;
+
+ }
+
+ errorLogEntry->NumberOfStrings++;
+
+ //
+ // Put in interrupt level
+ //
+
+ Value = InterruptLevel;
+
+ //
+ // Convert value
+ //
+ // I couldn't think of a better way to do this (with some
+ // loop). If you find one, plz put it in.
+ //
+
+ if (Value > 9) {
+
+ switch (Value / 10) {
+
+ case 0:
+ Character = L'0';
+ break;
+ case 1:
+ Character = L'1';
+ break;
+ case 2:
+ Character = L'2';
+ break;
+ case 3:
+ Character = L'3';
+ break;
+ case 4:
+ Character = L'4';
+ break;
+ case 5:
+ Character = L'5';
+ break;
+ case 6:
+ Character = L'6';
+ break;
+ case 7:
+ Character = L'7';
+ break;
+ case 8:
+ Character = L'8';
+ break;
+ case 9:
+ Character = L'9';
+ break;
+ }
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ Place += sizeof(WCHAR);
+
+ Value -= 10;
+
+ }
+
+ switch (Value) {
+
+ case 0:
+ Character = L'0';
+ break;
+ case 1:
+ Character = L'1';
+ break;
+ case 2:
+ Character = L'2';
+ break;
+ case 3:
+ Character = L'3';
+ break;
+ case 4:
+ Character = L'4';
+ break;
+ case 5:
+ Character = L'5';
+ break;
+ case 6:
+ Character = L'6';
+ break;
+ case 7:
+ Character = L'7';
+ break;
+ case 8:
+ Character = L'8';
+ break;
+ case 9:
+ Character = L'9';
+ break;
+ }
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ Place += sizeof(WCHAR);
+
+ Character = UNICODE_NULL;
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ //
+ // write it out
+ //
+
+ IoWriteErrorLogEntry(errorLogEntry);
+ }
+
+ *Status = NDIS_STATUS_RESOURCE_CONFLICT;
+ return;
+
+ }
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ //
+ // We must do this stuff first because if we connect the
+ // interrupt first then an interrupt could occur before
+ // the MacISR is recorded in the Ndis interrupt structure.
+ //
+
+ if (IsAMiniport) {
+
+ KeInitializeSpinLock(&(MiniportInterrupt->DpcCountLock));
+ Miniport->Interrupt = MiniportInterrupt;
+ MiniportInterrupt->DpcCount = 0;
+ MiniportInterrupt->MiniportIdField = NULL;
+ MiniportInterrupt->Miniport = Miniport;
+ MiniportInterrupt->MiniportIsr = Miniport->DriverHandle->MiniportCharacteristics.ISRHandler;
+ MiniportInterrupt->MiniportDpc = Miniport->DriverHandle->MiniportCharacteristics.HandleInterruptHandler;
+ MiniportInterrupt->SharedInterrupt = SharedInterrupt;
+ MiniportInterrupt->IsrRequested = (BOOLEAN)DeferredProcessingRoutine;
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ } else {
+
+ NdisInterrupt->MacIsr = InterruptServiceRoutine;
+ NdisInterrupt->MacDpc = DeferredProcessingRoutine;
+ NdisInterrupt->InterruptContext = InterruptContext;
+ KeInitializeSpinLock(&(NdisInterrupt->DpcCountLock));
+ NdisInterrupt->DpcCount = 0;
+ NdisInterrupt->Removing = FALSE;
+
+ }
+
+ //
+ // This is used to tell when all Dpcs are completed after the
+ // interrupt has been removed.
+ //
+
+ KeInitializeEvent(
+ (IsAMiniport ?
+ &MiniportInterrupt->DpcsCompletedEvent :
+ &NdisInterrupt->DpcsCompletedEvent),
+ NotificationEvent,
+ FALSE
+ );
+
+ //
+ // Initialize our dpc.
+ //
+
+ if (NdisMacAdapterDpcTargetProcessor < 0) {
+ NdisMacAdapterDpcTargetProcessor = (**(PCCHAR *)&KeNumberProcessors) - 1;
+ }
+
+ if (IsAMiniport) {
+
+ KeInitializeDpc(
+ &MiniportInterrupt->InterruptDpc,
+ (PKDEFERRED_ROUTINE) NdisMDpc,
+ MiniportInterrupt
+ );
+
+ KeSetImportanceDpc(
+ &MiniportInterrupt->InterruptDpc,
+ LowImportance
+ );
+
+ KeSetTargetProcessorDpc (
+ &MiniportInterrupt->InterruptDpc,
+ NdisMacAdapterDpcTargetProcessor
+ );
+ } else {
+
+ KeInitializeDpc(
+ &NdisInterrupt->InterruptDpc,
+ (PKDEFERRED_ROUTINE) NdisDpc,
+ NdisInterrupt
+ );
+
+ KeSetImportanceDpc(
+ &NdisInterrupt->InterruptDpc,
+ LowImportance
+ );
+
+ KeSetTargetProcessorDpc (
+ &NdisInterrupt->InterruptDpc,
+ NdisMacAdapterDpcTargetProcessor
+ );
+ }
+
+ NdisMacAdapterDpcTargetProcessor -= 1;
+
+ //
+ // Get the system interrupt vector and IRQL.
+ //
+
+ Vector = HalGetInterruptVector(
+ (IsAMiniport ?
+ Miniport->BusType :
+ AdptrP->BusType), // InterfaceType
+ (IsAMiniport ?
+ Miniport->BusNumber :
+ AdptrP->BusNumber), // BusNumber
+ (ULONG)InterruptLevel, // BusInterruptLevel
+ (ULONG)InterruptVector, // BusInterruptVector
+ &Irql, // Irql
+ &InterruptAffinity
+ );
+
+ if (IsAMiniport) {
+
+ NtStatus = IoConnectInterrupt(
+ &MiniportInterrupt->InterruptObject,
+ (PKSERVICE_ROUTINE)NdisMIsr,
+ MiniportInterrupt,
+ NULL,
+ Vector,
+ Irql,
+ Irql,
+ (KINTERRUPT_MODE)InterruptMode,
+ SharedInterrupt,
+ InterruptAffinity,
+ FALSE
+ );
+
+ } else {
+
+ NtStatus = IoConnectInterrupt(
+ &NdisInterrupt->InterruptObject,
+ (PKSERVICE_ROUTINE)NdisIsr,
+ NdisInterrupt,
+ NULL,
+ Vector,
+ Irql,
+ Irql,
+ (KINTERRUPT_MODE)InterruptMode,
+ SharedInterrupt,
+ InterruptAffinity,
+ FALSE
+ );
+ }
+
+
+ if (!NT_SUCCESS(NtStatus)) {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+}
+
+VOID
+NdisRemoveInterrupt(
+ IN PNDIS_INTERRUPT Interrupt
+ )
+/*++
+
+Routine Description:
+
+ Removes the interrupt, will not return until all interrupts and
+ interrupt dpcs are completed.
+
+Arguments:
+
+ Interrupt - Points to driver allocated memory that the wrapper filled
+ with information about the interrupt handler.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_INTERRUPT MiniportInterrupt = (PNDIS_MINIPORT_INTERRUPT)Interrupt;
+
+ if (MiniportInterrupt->MiniportIdField == NULL) {
+
+ MiniportInterrupt->Miniport->BeingRemoved = TRUE;
+
+ } else {
+
+ Interrupt->Removing = TRUE;
+
+ }
+
+ //
+ // Now we disconnect the interrupt. NOTE: they are aligned in both structures
+ //
+
+ IoDisconnectInterrupt(
+ Interrupt->InterruptObject
+ );
+
+ //
+ // Right now we know that any Dpcs that may fire are counted.
+ // We don't have to guard this with a spin lock because the
+ // Dpc will set the event if if completes first, or we may
+ // wait for a little while for it to complete.
+ //
+
+ if (Interrupt->DpcCount > 0) {
+
+ //
+ // Now we wait for all dpcs to complete.
+ //
+
+ KeWaitForSingleObject(
+ &Interrupt->DpcsCompletedEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PTIME)NULL
+ );
+
+ KeResetEvent(
+ &Interrupt->DpcsCompletedEvent
+ );
+
+
+ }
+
+}
+
+
+
+VOID
+NdisUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+/*++
+
+Routine Description:
+
+ This routine is called when a driver is supposed to unload. Ndis
+ converts this into a set of calls to MacRemoveAdapter() for each
+ adapter that the Mac has open. When the last adapter deregisters
+ itself it will call MacUnload().
+
+Arguments:
+
+ DriverObject - the driver object for the mac that is to unload.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MAC_BLOCK MacP;
+ PNDIS_ADAPTER_BLOCK Adapter, NextAdapter;
+
+ ACQUIRE_SPIN_LOCK(&NdisMacListLock);
+
+ //
+ // Search for the MacP
+ //
+
+ MacP = NdisMacList;
+
+ while (MacP != (PNDIS_MAC_BLOCK)NULL) {
+
+ if (MacP->NdisMacInfo->NdisWrapperDriver == DriverObject) {
+
+ break;
+
+ }
+
+ MacP = MacP->NextMac;
+
+ }
+
+ RELEASE_SPIN_LOCK(&NdisMacListLock);
+
+ if (MacP == (PNDIS_MAC_BLOCK)NULL) {
+
+ //
+ // It is already gone. Just return.
+ //
+
+ return;
+
+ }
+
+ MacP->Unloading = TRUE;
+
+
+ //
+ // Now call MACRemoveAdapter() for each Adapter.
+ //
+
+ Adapter = MacP->AdapterQueue;
+
+ while (Adapter != (PNDIS_ADAPTER_BLOCK)NULL) {
+
+ NextAdapter = Adapter->NextAdapter; // since queue may change
+
+ (MacP->MacCharacteristics.RemoveAdapterHandler)(
+ Adapter->MacAdapterContext
+ );
+
+ //
+ // If a shutdown handler was registered then deregister it.
+ //
+ NdisDeregisterAdapterShutdownHandler(Adapter);
+
+ Adapter = NextAdapter;
+
+ }
+
+
+ //
+ // Wait for all adapters to be gonzo.
+ //
+
+ KeWaitForSingleObject(
+ &MacP->AdaptersRemovedEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PTIME)NULL
+ );
+
+ KeResetEvent(
+ &MacP->AdaptersRemovedEvent
+ );
+
+
+ //
+ // Now call the MACUnload routine
+ //
+
+ (MacP->MacCharacteristics.UnloadMacHandler)(MacP->MacMacContext);
+
+
+ //
+ // Now remove the last reference (this will remove it from the list)
+ //
+ ASSERT(MacP->Ref.ReferenceCount == 1);
+
+ NdisDereferenceMac(MacP);
+}
+
+
+NTSTATUS
+NdisShutdown(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ The "shutdown handler" for the SHUTDOWN Irp. Will call the Ndis
+ shutdown routine, if one is registered.
+
+Arguments:
+
+ DeviceObject - The adapter's device object.
+ Irp - The IRP.
+
+Return Value:
+
+ Always STATUS_SUCCESS.
+
+--*/
+
+{
+ PNDIS_WRAPPER_CONTEXT WrapperContext = (PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension;
+ PNDIS_ADAPTER_BLOCK Miniport = (PNDIS_ADAPTER_BLOCK)(WrapperContext + 1);
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisShutdown\n");
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(Irp)) {
+ NdisPrint1(": Null Irp\n");
+ DbgBreakPoint();
+ }
+
+ if (!DbgIsNonPaged(Irp)) {
+ NdisPrint1(": Irp not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+
+ }
+
+ if (WrapperContext->ShutdownHandler != NULL) {
+
+ //
+ // Call the shutdown routine
+ //
+
+ WrapperContext->ShutdownHandler(WrapperContext->ShutdownContext);
+ }
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisShutdown\n");
+
+ return STATUS_SUCCESS;
+}
+
+VOID
+NdisAllocateSharedMemory(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Length,
+ IN BOOLEAN Cached,
+ OUT PVOID *VirtualAddress,
+ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates memory to be shared between the driver and the adapter.
+
+Arguments:
+
+ NdisAdapterHandle - handle returned by NdisRegisterAdapter.
+ Length - Length of the memory to allocate.
+ Cached - TRUE if memory is to be cached.
+ VirtualAddress - Returns the virtual address of the memory,
+ or NULL if the memory cannot be allocated.
+ PhysicalAddress - Returns the physical address of the memory.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG Alignment;
+ PNDIS_ADAPTER_BLOCK AdaptP = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle;
+ PADAPTER_OBJECT SystemAdapterObject;
+ PNDIS_WRAPPER_CONTEXT WrapperContext;
+ PULONG Page;
+ ULONG Type;
+
+ //
+ // Get interesting information from the adapter/miniport.
+ //
+
+ if ( AdaptP->DeviceObject != NULL ) {
+ SystemAdapterObject = AdaptP->SystemAdapterObject;
+ WrapperContext = AdaptP->WrapperContext;
+ } else {
+ SystemAdapterObject = Miniport->SystemAdapterObject;
+ WrapperContext = Miniport->WrapperContext;
+ }
+
+ //
+ // Non-busmasters shouldn't call this routine.
+ //
+
+ if (SystemAdapterObject == NULL) {
+ *VirtualAddress = NULL;
+ KdPrint(("NDIS: You are not a busmaster\n"));
+ return;
+ }
+
+ //
+ // Compute allocation size by aligning to the proper boundary.
+ //
+
+ ASSERT(Length != 0);
+
+ Alignment = HalGetDmaAlignmentRequirement();
+ if (sizeof(ULONG) > Alignment) {
+ Alignment = sizeof(ULONG);
+ }
+
+ Length = (Length + Alignment - 1) & ~(Alignment - 1);
+
+ //
+ // Check to determine is there is enough room left in the current page
+ // to satisfy the allocation.
+ //
+
+ Type = Cached ? 1 : 0;
+ ExAcquireResourceExclusive(&SharedMemoryResource, TRUE);
+ if (WrapperContext->SharedMemoryLeft[Type] < Length) {
+ if ((Length + sizeof(ULONG)) >= PAGE_SIZE) {
+
+ //
+ // The allocation is greater than a page.
+ //
+
+ *VirtualAddress = HalAllocateCommonBuffer(
+ SystemAdapterObject,
+ Length,
+ PhysicalAddress,
+ Cached);
+
+ ExReleaseResource(&SharedMemoryResource);
+ return;
+ }
+
+ //
+ // Allocate a new page for shared alocation.
+ //
+
+ WrapperContext->SharedMemoryPage[Type] =
+ HalAllocateCommonBuffer(
+ SystemAdapterObject,
+ PAGE_SIZE,
+ &WrapperContext->SharedMemoryAddress[Type],
+ Cached);
+
+ if (WrapperContext->SharedMemoryPage[Type] == NULL) {
+ WrapperContext->SharedMemoryLeft[Type] = 0;
+ *VirtualAddress = NULL;
+ ExReleaseResource(&SharedMemoryResource);
+ return;
+ }
+
+ //
+ // Initialize the reference count in the last ULONG of the page.
+ //
+
+ Page = (PULONG)WrapperContext->SharedMemoryPage[Type];
+ Page[(PAGE_SIZE / sizeof(ULONG)) - 1] = 0;
+ WrapperContext->SharedMemoryLeft[Type] = PAGE_SIZE - sizeof(ULONG);
+ }
+
+ //
+ // Increment the reference count, set the address of the allocation,
+ // compute the physical address, and reduce the space remaining.
+ //
+
+ Page = (PULONG)WrapperContext->SharedMemoryPage[Type];
+ Page[(PAGE_SIZE / sizeof(ULONG)) - 1] += 1;
+ *VirtualAddress = (PVOID)((PUCHAR)Page +
+ (PAGE_SIZE - sizeof(ULONG) - WrapperContext->SharedMemoryLeft[Type]));
+
+#if !defined(BUILD_FOR_3_1)
+ PhysicalAddress->QuadPart = WrapperContext->SharedMemoryAddress[Type].QuadPart +
+ ((ULONG)*VirtualAddress & (PAGE_SIZE - 1));
+#else
+ *PhysicalAddress = RtlLargeIntegerAdd(
+ WrapperContext->SharedMemoryAddress[Type],
+ RtlConvertUlongToLargeInteger((ULONG)*VirtualAddress & (PAGE_SIZE - 1))
+ );
+#endif
+
+ WrapperContext->SharedMemoryLeft[Type] -= Length;
+ ExReleaseResource(&SharedMemoryResource);
+ return;
+}
+
+
+#undef NdisUpdateSharedMemory
+
+VOID
+NdisUpdateSharedMemory(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Length,
+ IN PVOID VirtualAddress,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Ensures that the data to be read from a shared memory region is
+ fully up-to-date.
+
+Arguments:
+
+ NdisAdapterHandle - handle returned by NdisRegisterAdapter.
+ Length - The length of the shared memory.
+ VirtualAddress - Virtual address returned by NdisAllocateSharedMemory.
+ PhysicalAddress - The physical address returned by NdisAllocateSharedMemory.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // There is no underlying HAL routine for this anymore,
+ // it is not needed. This is macro'd to nothing in the
+ // header file now. This is there for backward compatibility
+
+ NdisAdapterHandle; Length; VirtualAddress; PhysicalAddress;
+
+}
+
+
+VOID
+NdisFreeSharedMemory(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Length,
+ IN BOOLEAN Cached,
+ IN PVOID VirtualAddress,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates memory to be shared between the driver and the adapter.
+
+Arguments:
+
+ NdisAdapterHandle - handle returned by NdisRegisterAdapter.
+ Length - Length of the memory to allocate.
+ Cached - TRUE if memory was allocated cached.
+ VirtualAddress - Virtual address returned by NdisAllocateSharedMemory.
+ PhysicalAddress - The physical address returned by NdisAllocateSharedMemory.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG Alignment;
+ PNDIS_ADAPTER_BLOCK AdaptP = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle;
+ PADAPTER_OBJECT SystemAdapterObject;
+ PNDIS_WRAPPER_CONTEXT WrapperContext;
+ PULONG Page;
+ ULONG Type;
+
+ //
+ // Get interesting information from the adapter/miniport.
+ //
+
+ if ( AdaptP->DeviceObject != NULL ) {
+ SystemAdapterObject = AdaptP->SystemAdapterObject;
+ WrapperContext = AdaptP->WrapperContext;
+ } else {
+ SystemAdapterObject = Miniport->SystemAdapterObject;
+ WrapperContext = Miniport->WrapperContext;
+ }
+
+ //
+ // Non-busmasters shouldn't call this routine.
+ //
+
+ ASSERT(SystemAdapterObject != NULL);
+
+ //
+ // Compute allocation size by aligning to the proper boundary.
+ //
+
+ ASSERT(Length != 0);
+
+ Alignment = HalGetDmaAlignmentRequirement();
+ if (sizeof(ULONG) > Alignment) {
+ Alignment = sizeof(ULONG);
+ }
+
+ Length = (Length + Alignment - 1) & ~(Alignment - 1);
+
+ //
+ // Free the specified memory.
+ //
+
+ ExAcquireResourceExclusive(&SharedMemoryResource, TRUE);
+ if ((Length + sizeof(ULONG)) >= PAGE_SIZE) {
+
+ //
+ // The allocation is greater than a page free the page directly.
+ //
+
+ HalFreeCommonBuffer(
+ SystemAdapterObject,
+ Length,
+ PhysicalAddress,
+ VirtualAddress,
+ Cached);
+
+ } else {
+
+ //
+ // Decrement the reference count and if the result is zero, then free
+ // the page.
+ //
+
+ Page = (PULONG)((ULONG)VirtualAddress & ~(PAGE_SIZE - 1));
+ Page[(PAGE_SIZE / sizeof(ULONG)) - 1] -= 1;
+ if (Page[(PAGE_SIZE / sizeof(ULONG)) - 1] == 0) {
+
+ //
+ // Compute the physical address of the page and free it.
+ //
+
+ PhysicalAddress.LowPart &= ~(PAGE_SIZE - 1);
+ HalFreeCommonBuffer(
+ SystemAdapterObject,
+ PAGE_SIZE,
+ PhysicalAddress,
+ Page,
+ Cached);
+
+ Type = Cached ? 1 : 0;
+ if ((PVOID)Page == WrapperContext->SharedMemoryPage[Type]) {
+ WrapperContext->SharedMemoryLeft[Type] = 0;
+ WrapperContext->SharedMemoryPage[Type] = NULL;
+ }
+ }
+ }
+
+ ExReleaseResource(&SharedMemoryResource);
+ return;
+}
+
+
+IO_ALLOCATION_ACTION
+NdisDmaExecutionRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is an execution routine for AllocateAdapterChannel,
+ if is called when an adapter channel allocated by NdisAllocate
+ DmaChannel is available.
+
+Arguments:
+
+ DeviceObject - The device object of the adapter.
+
+ Irp - ??.
+
+ MapRegisterBase - The address of the first translation table
+ assigned to us.
+
+ Context - A pointer to the NDIS_DMA_BLOCK in question.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_DMA_BLOCK DmaBlock = (PNDIS_DMA_BLOCK)Context;
+
+ UNREFERENCED_PARAMETER (Irp);
+ UNREFERENCED_PARAMETER (DeviceObject);
+
+
+ //
+ // Save the map register base.
+ //
+
+ DmaBlock->MapRegisterBase = MapRegisterBase;
+
+ //
+ // This will free the thread that is waiting for this callback.
+ //
+
+ KeSetEvent(
+ &DmaBlock->AllocationEvent,
+ 0L,
+ FALSE
+ );
+
+ return KeepObject;
+}
+
+
+
+VOID
+NdisAllocateDmaChannel(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE NdisDmaHandle,
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PNDIS_DMA_DESCRIPTION DmaDescription,
+ IN ULONG MaximumLength
+ )
+
+/*++
+
+Routine Description:
+
+ Sets up a DMA channel for future DMA operations.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ NdisDmaHandle - Returns a handle used to specify this channel to
+ future operations.
+
+ NdisAdapterHandle - handle returned by NdisRegisterAdapter.
+
+ DmaDescription - Details of the DMA channel.
+
+ MaximumLength - The maximum length DMA transfer that will be done
+ using this channel.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // For registering this set of resources
+ //
+ PCM_RESOURCE_LIST Resources;
+ BOOLEAN Conflict;
+
+ //
+ // Needed to call HalGetAdapter.
+ //
+ DEVICE_DESCRIPTION DeviceDescription;
+
+ //
+ // Returned by HalGetAdapter.
+ //
+ PADAPTER_OBJECT AdapterObject;
+
+ //
+ // Map registers needed per channel.
+ //
+ ULONG MapRegistersNeeded;
+
+ //
+ // Map registers allowed per channel.
+ //
+ ULONG MapRegistersAllowed;
+
+ //
+ // Saves the structure we allocate for this channel.
+ //
+ PNDIS_DMA_BLOCK DmaBlock;
+
+ //
+ // Convert the handle to our internal structure.
+ PNDIS_ADAPTER_BLOCK AdapterBlock =
+ (PNDIS_ADAPTER_BLOCK) NdisAdapterHandle;
+
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) NdisAdapterHandle;
+ BOOLEAN IsAMiniport;
+
+ //
+ // Save our IRQL when we raise it to call IoAllocateAdapterChannel.
+ //
+ KIRQL OldIrql;
+ ULONG NumberOfElements;
+
+ NTSTATUS NtStatus;
+
+ LARGE_INTEGER TimeoutValue;
+
+ IsAMiniport = (AdapterBlock->DeviceObject == NULL);
+
+ //
+ // First check if any bus access is allowed
+ //
+
+ if (((IsAMiniport ?
+ Miniport->BusType :
+ AdapterBlock->BusType) == (NDIS_INTERFACE_TYPE)-1) ||
+ ((IsAMiniport ?
+ Miniport->BusNumber :
+ AdapterBlock->BusNumber) == (ULONG)-1)) {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ //
+ // First check for resource conflict by expanding current resource list,
+ // adding in the mapped space, and then re-submitting the resource list.
+ //
+
+ if ((IsAMiniport ? Miniport->Resources : AdapterBlock->Resources) != NULL) {
+
+ NumberOfElements =
+ (IsAMiniport ?
+ Miniport->Resources->List[0].PartialResourceList.Count :
+ AdapterBlock->Resources->List[0].PartialResourceList.Count) + 1;
+
+ } else {
+
+ NumberOfElements = 1;
+ }
+
+ //
+ // First check for resource conflict by expanding current resource list,
+ // adding in the mapped space, and then re-submitting the resource list.
+ //
+
+ Resources = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ NumberOfElements,
+ 'lrDN'
+ );
+
+ if (Resources == NULL) {
+
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+
+ }
+
+ if ((IsAMiniport ? Miniport->Resources : AdapterBlock->Resources) != NULL) {
+
+ RtlCopyMemory (Resources,
+ (IsAMiniport ? Miniport->Resources : AdapterBlock->Resources),
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ (NumberOfElements - 1)
+ );
+ } else {
+
+ //
+ // Setup initial resource info
+ //
+ ASSERT(IsAMiniport);
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = Miniport->AdapterType;
+ Resources->List[0].BusNumber = Miniport->BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ }
+
+ //
+ // Setup DMA Channel
+ //
+
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type =
+ CmResourceTypeDma;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition =
+ CmResourceShareDeviceExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags =
+ 0;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Dma.Channel =
+ (IsAMiniport ? Miniport->ChannelNumber :
+ (DmaDescription->DmaChannelSpecified ?
+ DmaDescription->DmaChannel : AdapterBlock->ChannelNumber));
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Dma.Port =
+ DmaDescription->DmaPort;
+ Resources->List[0].PartialResourceList.Count++;
+
+
+ //
+ // Make the call
+ //
+
+ *Status = IoReportResourceUsage(
+ NULL,
+ (IsAMiniport ?
+ Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver :
+ AdapterBlock->MacHandle->NdisMacInfo->NdisWrapperDriver),
+ NULL,
+ 0,
+ (IsAMiniport ? Miniport->DeviceObject : AdapterBlock->DeviceObject),
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ Resources->List[0].PartialResourceList.Count,
+ TRUE,
+ &Conflict
+ );
+
+ if ((IsAMiniport ? Miniport->Resources : AdapterBlock->Resources) != NULL) {
+
+ ExFreePool((IsAMiniport ? Miniport->Resources : AdapterBlock->Resources));
+
+ }
+
+ if (IsAMiniport) {
+
+ Miniport->Resources = Resources;
+
+ } else {
+
+ AdapterBlock->Resources = Resources;
+
+ }
+
+ //
+ // Check for conflict.
+ //
+
+ if (Conflict || (*Status != STATUS_SUCCESS)) {
+
+
+ if (Conflict) {
+
+
+ //
+ // Log an error
+ //
+
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ ULONG i;
+ ULONG StringSize;
+ PUCHAR Place;
+ PWCH baseFileName;
+ WCHAR Character;
+ ULONG Value;
+
+ baseFileName = (IsAMiniport ?
+ Miniport->MiniportName.Buffer :
+ AdapterBlock->AdapterName.Buffer);
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+
+ for ( i = 0;
+ i < (IsAMiniport ? Miniport->MiniportName.Length :
+ AdapterBlock->AdapterName.Length)
+ / sizeof(WCHAR);
+ i++ ) {
+
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+
+ if ((IsAMiniport ?
+ Miniport->MiniportName.Buffer[i] :
+ AdapterBlock->AdapterName.Buffer[i]) == OBJ_NAME_PATH_SEPARATOR ) {
+
+ baseFileName = (IsAMiniport ?
+ &(Miniport->MiniportName.Buffer[++i]) :
+ &(AdapterBlock->AdapterName.Buffer[++i]));
+
+ }
+
+ }
+
+ StringSize = (IsAMiniport ?
+ Miniport->MiniportName.MaximumLength :
+ AdapterBlock->AdapterName.MaximumLength) -
+ (((ULONG)baseFileName) -
+ (IsAMiniport ?
+ ((ULONG)Miniport->MiniportName.Buffer) :
+ ((ULONG)AdapterBlock->AdapterName.Buffer)));
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (IsAMiniport ?
+ Miniport->DeviceObject :
+ AdapterBlock->DeviceObject),
+ (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize +
+ 6) // wstrlen("99") * sizeof(WHCAR) + sizeof(UNICODE_NULL)
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_DMA_CONFLICT;
+
+ //
+ // store the time
+ //
+
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+
+ //
+ // Set string information
+ //
+
+ if (StringSize != 0) {
+
+ errorLogEntry->NumberOfStrings = 1;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+
+ RtlCopyMemory (
+ ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET),
+ (PVOID)baseFileName,
+ StringSize
+ );
+
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize;
+
+ } else {
+
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET);
+
+ errorLogEntry->NumberOfStrings = 0;
+
+ }
+
+ errorLogEntry->NumberOfStrings++;
+
+ //
+ // Put in dma channel
+ //
+
+ Value = (IsAMiniport ? Miniport->ChannelNumber :
+ AdapterBlock->ChannelNumber);
+
+ //
+ // Convert value
+ //
+ // I couldn't think of a better way to do this (with some
+ // loop). If you find one, plz put it in.
+ //
+
+ if (Value > 9) {
+
+ switch (Value / 10) {
+
+ case 0:
+ Character = L'0';
+ break;
+ case 1:
+ Character = L'1';
+ break;
+ case 2:
+ Character = L'2';
+ break;
+ case 3:
+ Character = L'3';
+ break;
+ case 4:
+ Character = L'4';
+ break;
+ case 5:
+ Character = L'5';
+ break;
+ case 6:
+ Character = L'6';
+ break;
+ case 7:
+ Character = L'7';
+ break;
+ case 8:
+ Character = L'8';
+ break;
+ case 9:
+ Character = L'9';
+ break;
+ }
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ Place += sizeof(WCHAR);
+
+ Value -= 10;
+
+ }
+
+ switch (Value) {
+
+ case 0:
+ Character = L'0';
+ break;
+ case 1:
+ Character = L'1';
+ break;
+ case 2:
+ Character = L'2';
+ break;
+ case 3:
+ Character = L'3';
+ break;
+ case 4:
+ Character = L'4';
+ break;
+ case 5:
+ Character = L'5';
+ break;
+ case 6:
+ Character = L'6';
+ break;
+ case 7:
+ Character = L'7';
+ break;
+ case 8:
+ Character = L'8';
+ break;
+ case 9:
+ Character = L'9';
+ break;
+ }
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ Place += sizeof(WCHAR);
+
+ Character = UNICODE_NULL;
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ //
+ // write it out
+ //
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+ *Status = NDIS_STATUS_RESOURCE_CONFLICT;
+ return;
+
+ }
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ //
+ // Set up the device description; zero it out in case its
+ // size changes.
+ //
+
+ RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
+
+ DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
+ DeviceDescription.Master = (IsAMiniport ? Miniport->Master : FALSE);
+ DeviceDescription.ScatterGather = (IsAMiniport ? Miniport->Master : FALSE);
+ DeviceDescription.DemandMode = DmaDescription->DemandMode;
+ DeviceDescription.AutoInitialize = DmaDescription->AutoInitialize;
+ DeviceDescription.Dma32BitAddresses = (IsAMiniport ? Miniport->Dma32BitAddresses : FALSE);
+ DeviceDescription.BusNumber = (IsAMiniport ? Miniport->BusNumber : AdapterBlock->BusNumber);
+ DeviceDescription.DmaChannel = (IsAMiniport ? Miniport->ChannelNumber :
+ (DmaDescription->DmaChannelSpecified ?
+ DmaDescription->DmaChannel : AdapterBlock->ChannelNumber));
+ DeviceDescription.InterfaceType = (IsAMiniport ? Miniport->BusType : AdapterBlock->BusType);
+ DeviceDescription.DmaWidth = DmaDescription->DmaWidth;
+ DeviceDescription.DmaSpeed = DmaDescription->DmaSpeed;
+ DeviceDescription.MaximumLength = MaximumLength;
+ DeviceDescription.DmaPort = DmaDescription->DmaPort;
+
+
+ MapRegistersNeeded = ((MaximumLength - 2) / PAGE_SIZE) + 2;
+
+ //
+ // Get the adapter object.
+ //
+
+ AdapterObject = HalGetAdapter (&DeviceDescription, &MapRegistersAllowed);
+
+ if ((AdapterObject == NULL) || (MapRegistersAllowed < MapRegistersNeeded)) {
+
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+
+ //
+ // Allocate storage for our DMA block.
+ //
+
+ DmaBlock = (PNDIS_DMA_BLOCK)ExAllocatePoolWithTag (NonPagedPool, sizeof(NDIS_DMA_BLOCK), 'bdDN');
+
+ if (DmaBlock == (PNDIS_DMA_BLOCK)NULL) {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+
+ //
+ // Use this event to tell us when NdisAllocationExecutionRoutine
+ // has been called.
+ //
+
+ KeInitializeEvent(
+ &DmaBlock->AllocationEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ //
+ // We save this to call IoFreeAdapterChannel later.
+ //
+
+ DmaBlock->SystemAdapterObject = AdapterObject;
+
+
+ //
+ // Now allocate the adapter channel.
+ //
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NtStatus = IoAllocateAdapterChannel(
+ AdapterObject,
+ (IsAMiniport ? Miniport->DeviceObject : AdapterBlock->DeviceObject),
+ MapRegistersNeeded,
+ NdisDmaExecutionRoutine,
+ (PVOID)DmaBlock
+ );
+
+ KeLowerIrql(OldIrql);
+
+ if (!NT_SUCCESS(NtStatus)) {
+ NdisPrint2("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus);
+ ExFreePool (DmaBlock);
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ TimeoutValue.QuadPart = Int32x32To64(2 * 1000, -10000);
+
+ //
+ // NdisDmaExecutionRoutine will set this event
+ // when it has been called.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &DmaBlock->AllocationEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ NdisPrint2("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus);
+ ExFreePool (DmaBlock);
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+
+ }
+
+ KeResetEvent(
+ &DmaBlock->AllocationEvent
+ );
+
+
+ //
+ // We now have the DMA channel allocated, we are done.
+ //
+
+ DmaBlock->InProgress = FALSE;
+
+ *NdisDmaHandle = (NDIS_HANDLE)DmaBlock;
+ *Status = NDIS_STATUS_SUCCESS;
+
+}
+
+
+VOID
+NdisFreeDmaChannel(
+ IN PNDIS_HANDLE NdisDmaHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Frees a DMA channel allocated with NdisAllocateDmaChannel.
+
+Arguments:
+
+ NdisDmaHandle - Handle returned by NdisAllocateDmaChannel, indicating the
+ DMA channel that is to be freed.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ KIRQL OldIrql;
+ PNDIS_DMA_BLOCK DmaBlock = (PNDIS_DMA_BLOCK)NdisDmaHandle;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ IoFreeAdapterChannel (DmaBlock->SystemAdapterObject);
+ KeLowerIrql(OldIrql);
+
+ ExFreePool (DmaBlock);
+
+}
+
+
+VOID
+NdisSetupDmaTransfer(
+ OUT PNDIS_STATUS Status,
+ IN PNDIS_HANDLE NdisDmaHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG Offset,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ )
+
+/*++
+
+Routine Description:
+
+ Sets up the host DMA controller for a DMA transfer. The
+ DMA controller is set up to transfer the specified MDL.
+ Since we register all DMA channels as non-scatter/gather,
+ IoMapTransfer will ensure that the entire MDL is
+ in a single logical piece for transfer.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ NdisDmaHandle - Handle returned by NdisAllocateDmaChannel.
+
+ Buffer - An NDIS_BUFFER which describes the host memory involved in the
+ transfer.
+
+ Offset - An offset within buffer where the transfer should
+ start.
+
+ Length - The length of the transfer. VirtualAddress plus Length must not
+ extend beyond the end of the buffer.
+
+ WriteToDevice - TRUE for a download operation (host to adapter); FALSE
+ for an upload operation (adapter to host).
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PNDIS_DMA_BLOCK DmaBlock = (PNDIS_DMA_BLOCK)NdisDmaHandle;
+ PHYSICAL_ADDRESS LogicalAddress;
+ ULONG LengthMapped;
+
+
+ //
+ // Make sure another request is not in progress.
+ //
+
+ if (DmaBlock->InProgress) {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ DmaBlock->InProgress = TRUE;
+
+ //
+ // Use IoMapTransfer to set up the transfer.
+ //
+
+ LengthMapped = Length;
+
+ LogicalAddress = IoMapTransfer(
+ DmaBlock->SystemAdapterObject,
+ (PMDL)Buffer,
+ DmaBlock->MapRegisterBase,
+ (PUCHAR)(MmGetMdlVirtualAddress(Buffer)) + Offset,
+ &LengthMapped,
+ WriteToDevice
+ );
+
+ if (LengthMapped != Length) {
+
+ //
+ // Somehow the request could not be mapped competely,
+ // this should not happen for a non-scatter/gather adapter.
+ //
+
+ (VOID)IoFlushAdapterBuffers(
+ DmaBlock->SystemAdapterObject,
+ (PMDL)Buffer,
+ DmaBlock->MapRegisterBase,
+ (PUCHAR)(MmGetMdlVirtualAddress(Buffer)) + Offset,
+ LengthMapped,
+ WriteToDevice
+ );
+
+ DmaBlock->InProgress = FALSE;
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+}
+
+
+VOID
+NdisCompleteDmaTransfer(
+ OUT PNDIS_STATUS Status,
+ IN PNDIS_HANDLE NdisDmaHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG Offset,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ )
+
+/*++
+
+Routine Description:
+
+ Completes a previously started DMA transfer.
+
+Arguments:
+
+ Status - Returns the status of the transfer.
+
+ NdisDmaHandle - Handle returned by NdisAllocateDmaChannel.
+
+ Buffer - An NDIS_BUFFER which was passed to NdisSetupDmaTransfer.
+
+ Offset - the offset passed to NdisSetupDmaTransfer.
+
+ Length - The length passed to NdisSetupDmaTransfer.
+
+ WriteToDevice - TRUE for a download operation (host to adapter); FALSE
+ for an upload operation (adapter to host).
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_DMA_BLOCK DmaBlock = (PNDIS_DMA_BLOCK)NdisDmaHandle;
+ BOOLEAN Successful;
+
+ Successful = IoFlushAdapterBuffers(
+ DmaBlock->SystemAdapterObject,
+ (PMDL)Buffer,
+ DmaBlock->MapRegisterBase,
+ (PUCHAR)(MmGetMdlVirtualAddress(Buffer)) + Offset,
+ Length,
+ WriteToDevice);
+
+ *Status = (Successful ? NDIS_STATUS_SUCCESS : NDIS_STATUS_RESOURCES);
+ DmaBlock->InProgress = FALSE;
+
+}
+
+//
+// Requests used by protocol modules
+//
+//
+
+VOID
+NdisRegisterProtocol(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE NdisProtocolHandle,
+ IN PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics,
+ IN UINT CharacteristicsLength
+ )
+
+/*++
+
+Routine Description:
+
+ Register an NDIS protocol.
+
+Arguments:
+
+ Status - Returns the final status.
+ NdisProtocolHandle - Returns a handle referring to this protocol.
+ ProtocolCharacteritics - The NDIS_PROTOCOL_CHARACTERISTICS table.
+ CharacteristicsLength - The length of ProtocolCharacteristics.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_PROTOCOL_BLOCK NewProtP;
+ UINT MemNeeded;
+
+ //
+ // Do any initial initialization that may be necessary. Note: this
+ // routine will notice if this is the second or later call to it.
+ //
+ *Status = NdisInitialInit( NULL );
+ if (!NT_SUCCESS(*Status)) {
+ return;
+ }
+
+ //
+ // Check that this is an NDIS 3.1 protocol.
+ //
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("==>NdisRegisterProtocol\n");
+ IF_ERROR_CHK {
+ if (DbgIsNull(ProtocolCharacteristics->OpenAdapterCompleteHandler)) {
+ NdisPrint1("RegisterProtocol: OpenAdapterCompleteHandler Null\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolCharacteristics->CloseAdapterCompleteHandler)) {
+ NdisPrint1("RegisterProtocol: CloseAdapterCompleteHandler Null\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolCharacteristics->SendCompleteHandler)) {
+ NdisPrint1("RegisterProtocol: SendCompleteHandler Null\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolCharacteristics->TransferDataCompleteHandler)) {
+ NdisPrint1("RegisterProtocol: TransferDataCompleteHandler Null\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolCharacteristics->ResetCompleteHandler)) {
+ NdisPrint1("RegisterProtocol: ResetCompleteHandler Null\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolCharacteristics->RequestCompleteHandler)) {
+ NdisPrint1("RegisterProtocol: RequestCompleteHandler Null\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolCharacteristics->ReceiveHandler)) {
+ NdisPrint1("RegisterProtocol: ReceiveHandler Null\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolCharacteristics->ReceiveCompleteHandler)) {
+ NdisPrint1("RegisterProtocol: ReceiveCompleteHandler Null\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolCharacteristics->StatusHandler)) {
+ NdisPrint1("RegisterProtocol: StatusHandler Null\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolCharacteristics->StatusCompleteHandler)) {
+ NdisPrint1("RegisterProtocol: StatusCompleteHandler Null\n");
+ DbgBreakPoint();
+ }
+ }
+
+
+ if (ProtocolCharacteristics->MajorNdisVersion != 3 ||
+ ProtocolCharacteristics->MinorNdisVersion != 0) {
+ *Status = NDIS_STATUS_BAD_VERSION;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterProtocol\n");
+ return;
+ }
+
+
+ //
+ // Check that CharacteristicsLength is enough.
+ //
+
+ if (CharacteristicsLength < sizeof(NDIS_PROTOCOL_CHARACTERISTICS)) {
+ *Status = NDIS_STATUS_BAD_CHARACTERISTICS;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterProtocol\n");
+ return;
+ }
+
+
+ //
+ // Allocate memory for the NDIS protocol block.
+ //
+
+ MemNeeded = sizeof(NDIS_PROTOCOL_BLOCK);
+ NewProtP = (PNDIS_PROTOCOL_BLOCK)ExAllocatePoolWithTag(NonPagedPool, MemNeeded, 'bpDN');
+ if (NewProtP == (PNDIS_PROTOCOL_BLOCK)NULL) {
+ *Status = NDIS_STATUS_RESOURCES;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterProtocol\n");
+ return;
+ }
+ RtlZeroMemory(NewProtP, sizeof(NDIS_PROTOCOL_BLOCK));
+
+ NewProtP->Length = MemNeeded;
+
+ //
+ // Copy over the characteristics table.
+ //
+
+ RtlCopyMemory((PVOID)&NewProtP->ProtocolCharacteristics,
+ (PVOID)ProtocolCharacteristics, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
+
+#if NDISDBG
+ IF_TRACE(TRACE_IMPT) NdisPrint2(" Protocol: %s\n",ProtocolCharacteristics->Name);
+#endif
+
+ //
+ // No opens for this protocol yet.
+ //
+
+ NewProtP->OpenQueue = (PNDIS_OPEN_BLOCK)NULL;
+
+ NdisInitializeRef(&NewProtP->Ref);
+ *NdisProtocolHandle = (NDIS_HANDLE)NewProtP;
+ *Status = NDIS_STATUS_SUCCESS;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterProtocol\n");
+}
+
+VOID
+NdisDeregisterProtocol(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisProtocolHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Deregisters an NDIS protocol.
+
+Arguments:
+
+ Status - Returns the final status.
+ NdisProtocolHandle - The handle returned by NdisRegisterProtocol.
+
+Return Value:
+
+ None.
+
+Note:
+
+ This will kill all the opens for this protocol.
+
+--*/
+
+{
+
+ PNDIS_PROTOCOL_BLOCK OldProtP = (PNDIS_PROTOCOL_BLOCK)NdisProtocolHandle;
+
+ //
+ // If the protocol is already closing, return.
+ //
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisDeregisterProtocol\n");
+ NdisPrint2(" Protocol: %wZ\n",&OldProtP->ProtocolCharacteristics.Name);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(NdisProtocolHandle)) {
+ NdisPrint1("DeregisterProtocol: Null Handle\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(NdisProtocolHandle)) {
+ NdisPrint1("DeregisterProtocol: Handle not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ if (!NdisCloseRef(&OldProtP->Ref)) {
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeregisterProtocol\n");
+ return;
+ }
+
+
+ //
+ // Kill all the opens for this protocol.
+ //
+
+ while (OldProtP->OpenQueue != (PNDIS_OPEN_BLOCK)NULL) {
+
+ //
+ // This removes it from the protocol's OpenQueue etc.
+ //
+
+ NdisKillOpenAndNotifyProtocol(OldProtP->OpenQueue);
+ }
+
+ NdisDereferenceProtocol(OldProtP);
+
+ *Status = NDIS_STATUS_SUCCESS;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeregisterProtocol\n");
+}
+
+
+NDIS_STATUS
+NdisMacReceiveHandler(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+{
+ PNDIS_OPEN_BLOCK Open;
+ NDIS_STATUS Status;
+ KIRQL oldIrql;
+
+ KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
+
+ //
+ // Find protocol binding context and get associated open for it.
+ //
+ Open = GetOpenBlockFromProtocolBindingContext(ProtocolBindingContext);
+ ASSERT(Open != NULL);
+
+ Status =
+ (Open->PostNt31ReceiveHandler) (
+ ProtocolBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize);
+
+ KeLowerIrql( oldIrql );
+ return Status;
+}
+
+
+VOID
+NdisMacReceiveCompleteHandler(
+ IN NDIS_HANDLE ProtocolBindingContext
+ )
+{
+ PNDIS_OPEN_BLOCK Open;
+ KIRQL oldIrql;
+ KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
+
+ //
+ // Find protocol binding context and get associated open for it.
+ //
+ Open = GetOpenBlockFromProtocolBindingContext(ProtocolBindingContext);
+ ASSERT(Open != NULL);
+
+ (Open->PostNt31ReceiveCompleteHandler) (
+ ProtocolBindingContext
+ );
+ KeLowerIrql( oldIrql );
+ return;
+}
+
+PNDIS_OPEN_BLOCK
+GetOpenBlockFromProtocolBindingContext(
+ IN NDIS_HANDLE ProtocolBindingContext
+ )
+{
+ PNDIS_OPEN_BLOCK TmpOpen;
+ PNDIS_OPEN_BLOCK PrvOpen = NULL;
+
+ ACQUIRE_SPIN_LOCK(&GlobalOpenListLock);
+
+ TmpOpen = GlobalOpenList;
+
+ while (TmpOpen != NULL) {
+
+ if (TmpOpen->ProtocolBindingContext == ProtocolBindingContext) {
+
+ if (TmpOpen != GlobalOpenList) {
+
+ //
+ // Put this one at the front of the list
+ //
+
+ PrvOpen->NextGlobalOpen = TmpOpen->NextGlobalOpen;
+ TmpOpen->NextGlobalOpen = GlobalOpenList;
+ GlobalOpenList = TmpOpen;
+
+
+ }
+
+ RELEASE_SPIN_LOCK(&GlobalOpenListLock);
+
+ return(TmpOpen);
+
+ }
+
+ PrvOpen = TmpOpen;
+ TmpOpen = TmpOpen->NextGlobalOpen;
+
+ }
+
+ RELEASE_SPIN_LOCK(&GlobalOpenListLock);
+
+ return((PNDIS_OPEN_BLOCK)NULL);
+
+}
+
+VOID
+MiniportOpenAdapter(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PNDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE NdisProtocolHandle,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_STRING AdapterName,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingInformation,
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_OPEN_BLOCK NewOpenP,
+ IN PFILE_OBJECT FileObject,
+ IN BOOLEAN UsingEncapsulation
+ )
+/*++
+
+Routine Description:
+
+ This routine handles opening a miniport either directly from NdisOpenAdapter()
+ of from our deferred processing routine if the open had to pend.
+
+ NOTE: Must be called with spin lock held.
+ NOTE: Must be called with lock acquired flag set.
+
+Arguments:
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_M_OPEN_BLOCK MiniportOpen;
+ PNDIS_MAC_BLOCK FakeMac;
+ BOOLEAN FilterOpen;
+ PNDIS_PROTOCOL_BLOCK TmpProtP;
+
+ ASSERT( MINIPORT_LOCK_ACQUIRED(Miniport) );
+
+ if (!NdisReferenceMiniport(Miniport)) {
+
+ //
+ // The adapter is closing.
+ //
+
+ ObDereferenceObject((PVOID)FileObject);
+ ExFreePool((PVOID)NewOpenP);
+
+ *Status = NDIS_STATUS_CLOSING;
+
+ return;
+ }
+
+ //
+ // Increment the protocol's reference count.
+ //
+
+ TmpProtP = (PNDIS_PROTOCOL_BLOCK)NdisProtocolHandle;
+
+ if (!NdisReferenceProtocol(TmpProtP)) {
+
+ //
+ // The protocol is closing.
+ //
+
+ NdisDereferenceMiniport(Miniport);
+ ObDereferenceObject((PVOID)FileObject);
+ ExFreePool((PVOID)NewOpenP);
+ *Status = NDIS_STATUS_CLOSING;
+ return;
+ }
+
+
+ //
+ // Now allocate a complete set of MAC structures for the protocol
+ // and set them up to transfer to the Miniport handler routines.
+ //
+
+ if (Miniport->DriverHandle->FakeMac == NULL) {
+
+ FakeMac = (PNDIS_MAC_BLOCK)ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(NDIS_MAC_BLOCK),
+ ' DN'
+ );
+
+ if (FakeMac == NULL) {
+ ObDereferenceObject((PVOID)FileObject);
+ NdisDereferenceMiniport(Miniport);
+ NdisDereferenceProtocol(TmpProtP);
+ ExFreePool((PVOID)NewOpenP);
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ RtlZeroMemory(FakeMac, sizeof(NDIS_MAC_BLOCK));
+ Miniport->DriverHandle->FakeMac = FakeMac;
+ FakeMac->MacCharacteristics.OpenAdapterHandler = NULL;
+ FakeMac->MacCharacteristics.CloseAdapterHandler = NULL;
+ FakeMac->MacCharacteristics.SendHandler = NdisMSend;
+ FakeMac->MacCharacteristics.ResetHandler = NdisMReset;
+ FakeMac->MacCharacteristics.RequestHandler = NdisMRequest;
+ FakeMac->MacCharacteristics.QueryGlobalStatisticsHandler = NULL;
+ FakeMac->MacCharacteristics.UnloadMacHandler = NULL;
+ FakeMac->MacCharacteristics.AddAdapterHandler = NULL;
+ FakeMac->MacCharacteristics.RemoveAdapterHandler = NULL;
+
+ //
+ // If transfer data calls don't pend then we'll use the faster
+ // NdisMTransferDataSync().
+ //
+
+ if ( (Miniport->MacOptions & NDIS_MAC_OPTION_TRANSFERS_NOT_PEND) != 0 ) {
+ FakeMac->MacCharacteristics.TransferDataHandler = NdisMTransferDataSync;
+ } else {
+ FakeMac->MacCharacteristics.TransferDataHandler = NdisMTransferData;
+ }
+
+ //
+ // Keep the SendHandler the same for WAN miniports
+ //
+
+ if (Miniport->MediaType == NdisMediumWan) {
+
+ FakeMac->MacCharacteristics.SendHandler =
+ (PVOID)Miniport->DriverHandle->MiniportCharacteristics.SendHandler;
+ }
+
+ } else {
+
+ FakeMac = Miniport->DriverHandle->FakeMac;
+
+ }
+
+ //
+ // Allocate an open within the Miniport context
+ //
+ MiniportOpen = (PNDIS_M_OPEN_BLOCK)ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(NDIS_M_OPEN_BLOCK),
+ ' DN'
+ );
+
+ if (MiniportOpen == (PNDIS_M_OPEN_BLOCK)NULL) {
+ ObDereferenceObject((PVOID)FileObject);
+ NdisDereferenceMiniport(Miniport);
+ NdisDereferenceProtocol(TmpProtP);
+ ExFreePool((PVOID)NewOpenP);
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ NdisZeroMemory(MiniportOpen, sizeof(NDIS_M_OPEN_BLOCK));
+
+ MiniportOpen->DriverHandle = Miniport->DriverHandle;
+ MiniportOpen->MiniportHandle = Miniport;
+ MiniportOpen->ProtocolHandle = TmpProtP;
+ MiniportOpen->FakeOpen = NewOpenP;
+ MiniportOpen->ProtocolBindingContext = ProtocolBindingContext;
+ MiniportOpen->MiniportAdapterContext = Miniport->MiniportAdapterContext;
+ MiniportOpen->FileObject = FileObject;
+ MiniportOpen->Closing = FALSE;
+ MiniportOpen->CloseRequestHandle = 0;
+ MiniportOpen->CurrentLookahead = Miniport->CurrentLookahead;
+
+ NdisAllocateSpinLock(&(MiniportOpen->SpinLock));
+
+ MiniportOpen->References = 1;
+ MiniportOpen->UsingEthEncapsulation = UsingEncapsulation;
+ MiniportOpen->SendHandler =
+ Miniport->DriverHandle->MiniportCharacteristics.SendHandler;
+ MiniportOpen->TransferDataHandler =
+ Miniport->DriverHandle->MiniportCharacteristics.TransferDataHandler;
+ MiniportOpen->SendCompleteHandler =
+ TmpProtP->ProtocolCharacteristics.SendCompleteHandler;
+ MiniportOpen->TransferDataCompleteHandler =
+ TmpProtP->ProtocolCharacteristics.TransferDataCompleteHandler;
+ MiniportOpen->ReceiveHandler =
+ TmpProtP->ProtocolCharacteristics.ReceiveHandler;
+ MiniportOpen->ReceiveCompleteHandler =
+ TmpProtP->ProtocolCharacteristics.ReceiveCompleteHandler;
+
+ //
+ // Set up the elements of the open structure.
+ //
+
+ NdisAllocateSpinLock(&NewOpenP->SpinLock);
+ NewOpenP->Closing = FALSE;
+
+ NewOpenP->AdapterHandle = (NDIS_HANDLE) Miniport;
+ NewOpenP->ProtocolHandle = TmpProtP;
+ NewOpenP->ProtocolBindingContext = ProtocolBindingContext;
+ NewOpenP->MacBindingHandle = (NDIS_HANDLE)MiniportOpen;
+
+ //
+ // for speed, instead of having to use AdapterHandle->MacHandle
+ //
+ NewOpenP->MacHandle = (NDIS_HANDLE)FakeMac;
+
+ //
+ // for even more speed....
+ //
+
+ if (Miniport->MediaType == NdisMediumArcnet878_2) {
+
+ NewOpenP->TransferDataHandler = NdisMArcTransferData;
+
+ } else {
+
+ if ( (Miniport->MacOptions & NDIS_MAC_OPTION_TRANSFERS_NOT_PEND) != 0 ) {
+ NewOpenP->TransferDataHandler = NdisMTransferDataSync;
+ } else {
+ NewOpenP->TransferDataHandler = NdisMTransferData;
+ }
+ }
+
+ NewOpenP->SendHandler = NdisMSend;
+
+ //
+ // For WAN miniports, the send handler is different
+ //
+
+ if ( Miniport->MediaType == NdisMediumWan ) {
+
+ NewOpenP->SendHandler = (PVOID)NdisMWanSend;
+ }
+
+ NewOpenP->SendCompleteHandler = TmpProtP->ProtocolCharacteristics.SendCompleteHandler;
+ NewOpenP->TransferDataCompleteHandler = TmpProtP->ProtocolCharacteristics.TransferDataCompleteHandler;
+ NewOpenP->ReceiveHandler = TmpProtP->ProtocolCharacteristics.ReceiveHandler;
+ NewOpenP->ReceiveCompleteHandler = TmpProtP->ProtocolCharacteristics.ReceiveCompleteHandler;
+ NewOpenP->PostNt31ReceiveHandler = TmpProtP->ProtocolCharacteristics.ReceiveHandler;
+ NewOpenP->PostNt31ReceiveCompleteHandler = TmpProtP->ProtocolCharacteristics.ReceiveCompleteHandler;
+
+ //
+ // Save a pointer to the file object in the open...
+ //
+
+ NewOpenP->FileObject = FileObject;
+
+ //
+ // ...and a pointer to the open in the file object.
+ //
+
+ FileObject->FsContext = (PVOID)NewOpenP;
+
+ *NdisBindingHandle = (NDIS_HANDLE)NewOpenP;
+
+ //
+ // Insert the open into the filter package
+ //
+
+ switch (Miniport->MediaType) {
+
+ case NdisMediumArcnet878_2:
+
+ if ( !UsingEncapsulation ) {
+
+ FilterOpen = ArcNoteFilterOpenAdapter(
+ Miniport->ArcDB,
+ MiniportOpen,
+ (NDIS_HANDLE)NewOpenP,
+ &MiniportOpen->FilterHandle
+ );
+
+ break;
+ }
+
+ //
+ // If we're using ethernet encapsulation then
+ // we simply fall through to the ethernet stuff.
+ //
+
+ case NdisMedium802_3:
+
+ FilterOpen = EthNoteFilterOpenAdapter(
+ Miniport->EthDB,
+ MiniportOpen,
+ (NDIS_HANDLE)NewOpenP,
+ &MiniportOpen->FilterHandle
+ );
+ break;
+
+ case NdisMedium802_5:
+
+ FilterOpen = TrNoteFilterOpenAdapter(
+ Miniport->TrDB,
+ MiniportOpen,
+ (NDIS_HANDLE)NewOpenP,
+ &MiniportOpen->FilterHandle
+ );
+ break;
+
+ case NdisMediumFddi:
+
+ FilterOpen = FddiNoteFilterOpenAdapter(
+ Miniport->FddiDB,
+ MiniportOpen,
+ (NDIS_HANDLE)NewOpenP,
+ &MiniportOpen->FilterHandle
+ );
+ break;
+
+
+ case NdisMediumWan:
+ //
+ // Bogus non-NULL value
+ //
+
+ FilterOpen = 1;
+ break;
+ }
+
+ //
+ // Check for an open filter failure.
+ //
+
+ if ( !FilterOpen ) {
+
+ //
+ // Something went wrong, clean up and exit.
+ //
+
+ ObDereferenceObject((PVOID)FileObject);
+ NdisDereferenceMiniport(Miniport);
+ NdisDereferenceProtocol(TmpProtP);
+ ExFreePool((PVOID)MiniportOpen);
+ ExFreePool((PVOID)NewOpenP);
+ *Status = NDIS_STATUS_OPEN_FAILED;
+ return;
+
+ }
+
+ NdisQueueOpenOnProtocol(NewOpenP, TmpProtP);
+
+ //
+ // Everything has been filled in. Synchronize access to the
+ // adapter block and link the new open adapter in.
+ //
+
+ MiniportOpen->MiniportNextOpen = Miniport->OpenQueue;
+ Miniport->OpenQueue = MiniportOpen;
+
+ //
+ // NOTE: This must be called at DPC_LEVEL, which it is.
+ //
+ MiniportAdjustMaximumLookahead(Miniport);
+
+ *Status = NDIS_STATUS_SUCCESS;
+}
+
+
+VOID
+MiniportFinishPendingOpens(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+/*++
+
+Routine Description:
+
+ Handles any pending NdisOpenAdapter() calls for miniports.
+
+ NOTE: Must be called with spin lock held.
+
+ NOTE: Must be called with lock acquired flag set.
+
+Arguments:
+
+ Miniport.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PMINIPORT_PENDING_OPEN MiniportPendingOpen;
+ NDIS_STATUS Status;
+ NDIS_STATUS OpenErrorStatus;
+
+ while( Miniport->FirstPendingOpen != NULL ) {
+
+ MiniportPendingOpen = Miniport->FirstPendingOpen;
+
+ //
+ // Do the open again.
+ //
+
+ MiniportOpenAdapter(
+ &Status,
+ &OpenErrorStatus,
+ MiniportPendingOpen->NdisBindingHandle,
+ MiniportPendingOpen->NdisProtocolHandle,
+ MiniportPendingOpen->ProtocolBindingContext,
+ MiniportPendingOpen->AdapterName,
+ MiniportPendingOpen->OpenOptions,
+ MiniportPendingOpen->AddressingInformation,
+ MiniportPendingOpen->Miniport,
+ MiniportPendingOpen->NewOpenP,
+ MiniportPendingOpen->FileObject,
+ MiniportPendingOpen->UsingEncapsulation
+ );
+
+ //
+ // If the open didn't pend then call the NdisCompleteOpenAdapter(),
+ //
+
+ if ( Status != NDIS_STATUS_PENDING ) {
+
+ PNDIS_OPEN_BLOCK OpenP = MiniportPendingOpen->NewOpenP;
+
+ (OpenP->ProtocolHandle->ProtocolCharacteristics.OpenAdapterCompleteHandler) (
+ OpenP->ProtocolBindingContext,
+ Status,
+ OpenErrorStatus
+ );
+ }
+
+ //
+ // Get the next pending open.
+ //
+
+ Miniport->FirstPendingOpen = MiniportPendingOpen->NextPendingOpen;
+
+ //
+ // We're done with this pending open context.
+ //
+
+ NdisFreeMemory(
+ MiniportPendingOpen,
+ sizeof(MINIPORT_PENDING_OPEN),
+ 0
+ );
+
+ }
+}
+
+
+
+UCHAR NdisInternalEaName[4] = "NDIS";
+UCHAR NdisInternalEaValue[8] = "INTERNAL";
+
+VOID
+NdisOpenAdapter(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PNDIS_HANDLE NdisBindingHandle,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE NdisProtocolHandle,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_STRING AdapterName,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingInformation OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ Opens a connection between a protocol and an adapter (MAC).
+
+Arguments:
+
+ Status - Returns the final status.
+ NdisBindingHandle - Returns a handle referring to this open.
+ SelectedMediumIndex - Index in MediumArray of the medium type that
+ the MAC wishes to be viewed as.
+ MediumArray - Array of medium types which a protocol supports.
+ MediumArraySize - Number of elements in MediumArray.
+ NdisProtocolHandle - The handle returned by NdisRegisterProtocol.
+ ProtocolBindingContext - A context for indications.
+ AdapterName - The name of the adapter to open.
+ OpenOptions - bit mask.
+ AddressingInformation - Information passed to MacOpenAdapter.
+
+Return Value:
+
+ None.
+
+Note:
+
+ This function opens the adapter which will cause an IRP_MJ_CREATE
+ to be sent to the adapter, which is ignored. However, after that we
+ can access the file object for the open, and fill it in as
+ appropriate. The work is done here rather than in the IRP_MJ_CREATE
+ handler because this avoids having to pass the parameters to
+ NdisOpenAdapter through to the adapter.
+
+--*/
+
+{
+ HANDLE FileHandle;
+ OBJECT_ATTRIBUTES ObjectAttr;
+ PFILE_OBJECT FileObject;
+ PDEVICE_OBJECT DeviceObject;
+ PNDIS_OPEN_BLOCK NewOpenP;
+ PNDIS_PROTOCOL_BLOCK TmpProtP;
+ PNDIS_ADAPTER_BLOCK TmpAdaptP;
+ NDIS_STATUS OpenStatus;
+ NTSTATUS NtOpenStatus;
+ IO_STATUS_BLOCK IoStatus;
+ PFILE_FULL_EA_INFORMATION OpenEa;
+ ULONG OpenEaLength;
+ BOOLEAN UsingEncapsulation;
+ KIRQL OldIrql;
+ BOOLEAN LocalLock;
+
+ //
+ // Allocate memory for the NDIS open block.
+ //
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisOpenAdapter\n");
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(NdisProtocolHandle)) {
+ NdisPrint1("OpenAdapter: Null ProtocolHandle\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(NdisProtocolHandle)) {
+ NdisPrint1("OpenAdapter: ProtocolHandle not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolBindingContext)) {
+ NdisPrint1("OpenAdapter: Null Context\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(ProtocolBindingContext)) {
+ NdisPrint1("OpenAdapter: Context not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ NewOpenP = (PNDIS_OPEN_BLOCK) ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(NDIS_OPEN_BLOCK),
+ 'boDN'
+ );
+
+ if (NewOpenP == (PNDIS_OPEN_BLOCK)NULL) {
+
+ *Status = NDIS_STATUS_RESOURCES;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n");
+
+ return;
+ }
+
+ RtlZeroMemory(NewOpenP, sizeof(NDIS_OPEN_BLOCK));
+
+ OpenEaLength = sizeof(FILE_FULL_EA_INFORMATION) +
+ sizeof(NdisInternalEaName) +
+ sizeof(NdisInternalEaValue);
+
+ OpenEa = ExAllocatePoolWithTag (NonPagedPool, OpenEaLength, ' DN');
+
+ if (OpenEa == NULL) {
+ ExFreePool (NewOpenP);
+ *Status = NDIS_STATUS_RESOURCES;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n");
+ return;
+ }
+
+ OpenEa->NextEntryOffset = 0;
+ OpenEa->Flags = 0;
+ OpenEa->EaNameLength = sizeof(NdisInternalEaName);
+ OpenEa->EaValueLength = sizeof(NdisInternalEaValue);
+
+ RtlCopyMemory(
+ OpenEa->EaName,
+ NdisInternalEaName,
+ sizeof(NdisInternalEaName)
+ );
+
+ RtlCopyMemory(
+ &OpenEa->EaName[OpenEa->EaNameLength+1],
+ NdisInternalEaValue,
+ sizeof(NdisInternalEaValue)
+ );
+
+
+ //
+ // Obtain a handle to the driver's file object.
+ //
+
+ InitializeObjectAttributes(
+ &ObjectAttr,
+ AdapterName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+
+
+ NtOpenStatus = ZwCreateFile(&FileHandle,
+ FILE_READ_DATA | FILE_WRITE_DATA,
+ &ObjectAttr,
+ &IoStatus,
+ (PLARGE_INTEGER) NULL, // allocation size
+ 0L, // file attributes
+ FILE_SHARE_READ | FILE_SHARE_WRITE, // share access
+ FILE_OPEN, // create disposition
+ 0, // create options
+ OpenEa,
+ OpenEaLength);
+
+
+ ExFreePool(OpenEa);
+
+ if (NtOpenStatus != STATUS_SUCCESS) {
+ ExFreePool((PVOID)NewOpenP);
+ *Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n");
+ return;
+ }
+
+
+ //
+ // Convert the file handle into a pointer to the adapter's
+ // file object.
+ //
+
+ ObReferenceObjectByHandle(FileHandle,
+ 0,
+ NULL,
+ KernelMode,
+ (PVOID *) &FileObject,
+ NULL
+ );
+
+ //
+ // Close the file handle, now that we have the object reference.
+ //
+
+ ZwClose(FileHandle);
+
+ //
+ // From the file object, obtain the device object.
+ //
+
+ DeviceObject = IoGetRelatedDeviceObject(FileObject);
+
+
+ //
+ // Increment the adapter's reference count.
+ //
+
+ TmpAdaptP = (PNDIS_ADAPTER_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1);
+
+ //
+ // Check if this is a Miniport or mac
+ //
+
+ if (TmpAdaptP->DeviceObject != DeviceObject) {
+
+ //
+ // It is a Miniport
+ //
+
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)TmpAdaptP;
+ ULONG i;
+
+ UsingEncapsulation = FALSE;
+
+ //
+ // Select the medium to use
+ //
+
+ for (i = 0; i < MediumArraySize; i++){
+
+ if (MediumArray[i] == Miniport->MediaType) {
+
+ break;
+
+ }
+
+ }
+
+ if (i == MediumArraySize){
+
+ //
+ // Check for ethernet encapsulation on Arcnet as
+ // a possible combination.
+ //
+ if (Miniport->MediaType == NdisMediumArcnet878_2) {
+
+ for (i = 0; i < MediumArraySize; i++){
+
+ if (MediumArray[i] == NdisMedium802_3) {
+ break;
+ }
+ }
+
+ if (i == MediumArraySize) {
+
+ *Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
+ return;
+
+ }
+
+ //
+ // encapsulated ethernet, so we add in the wrapper's
+ // ability to support (emulate) the multicast stuff
+ //
+
+ Miniport->SupportedPacketFilters |= (NDIS_PACKET_TYPE_MULTICAST |
+ NDIS_PACKET_TYPE_ALL_MULTICAST);
+
+ UsingEncapsulation = TRUE;
+
+ } else {
+
+ *Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
+ return;
+
+ }
+
+ }
+
+ *SelectedMediumIndex = i;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ //
+ // Lock the miniport. If the lock fails, then
+ // we must pend this open and try it later.
+ //
+
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ if ( LocalLock ) {
+
+ MiniportOpenAdapter(
+ Status,
+ OpenErrorStatus,
+ NdisBindingHandle,
+ NdisProtocolHandle,
+ ProtocolBindingContext,
+ AdapterName,
+ OpenOptions,
+ AddressingInformation,
+ Miniport,
+ NewOpenP,
+ FileObject,
+ UsingEncapsulation
+ );
+
+ } else {
+
+ PMINIPORT_PENDING_OPEN MiniportPendingOpen;
+
+ //
+ // Allocate some space for this pending structure.
+ // We free in after we call NdisOpenComplete.
+ //
+
+ *Status = NdisAllocateMemory(
+ (PVOID *) &MiniportPendingOpen,
+ sizeof(MINIPORT_PENDING_OPEN),
+ 0,
+ HighestAcceptableMax
+ );
+
+ if ( *Status == NDIS_STATUS_SUCCESS ) {
+
+ //
+ // Save off the parameters for this open so we can
+ // do the actual NdisOpenAdapter() later on.
+ //
+
+ MiniportPendingOpen->NextPendingOpen = NULL;
+ MiniportPendingOpen->NdisBindingHandle = NdisBindingHandle;
+ MiniportPendingOpen->NdisProtocolHandle = NdisProtocolHandle;
+ MiniportPendingOpen->ProtocolBindingContext = ProtocolBindingContext;
+ MiniportPendingOpen->AdapterName = AdapterName;
+ MiniportPendingOpen->OpenOptions = OpenOptions;
+ MiniportPendingOpen->AddressingInformation = AddressingInformation;
+ MiniportPendingOpen->Miniport = Miniport;
+ MiniportPendingOpen->NewOpenP = NewOpenP;
+ MiniportPendingOpen->FileObject = FileObject;
+ MiniportPendingOpen->UsingEncapsulation = UsingEncapsulation;
+
+ if ( Miniport->FirstPendingOpen == NULL ) {
+
+ Miniport->FirstPendingOpen = MiniportPendingOpen;
+
+ } else {
+
+ Miniport->LastPendingOpen->NextPendingOpen = MiniportPendingOpen;
+ }
+
+ Miniport->LastPendingOpen = MiniportPendingOpen;
+
+ //
+ // Make sure MiniportProcessDeferred() completes the open.
+ //
+
+ *Status = NDIS_STATUS_PENDING;
+
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ } else {
+
+ ObDereferenceObject((PVOID) FileObject);
+ ExFreePool((PVOID) NewOpenP);
+ }
+ }
+
+ //
+ // Unlock the miniport.
+ //
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ return;
+ }
+
+ //
+ // It is a mac
+ //
+
+ IF_TRACE(TRACE_IMPT) NdisPrint2("openadapter: adaptername=%s\n",TmpAdaptP->AdapterName.Buffer);
+ if (!NdisReferenceAdapter(TmpAdaptP)) {
+
+ //
+ // The adapter is closing.
+ //
+
+ ObDereferenceObject((PVOID)FileObject);
+ ExFreePool((PVOID)NewOpenP);
+ *Status = NDIS_STATUS_CLOSING;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n");
+ return;
+ }
+
+ //
+ // Increment the protocol's reference count.
+ //
+
+ TmpProtP = (PNDIS_PROTOCOL_BLOCK)NdisProtocolHandle;
+ if (!NdisReferenceProtocol(TmpProtP)) {
+
+ //
+ // The protocol is closing.
+ //
+
+ NdisDereferenceAdapter(TmpAdaptP);
+ ObDereferenceObject((PVOID)FileObject);
+ ExFreePool((PVOID)NewOpenP);
+ *Status = NDIS_STATUS_CLOSING;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n");
+ return;
+ }
+
+
+ //
+ // Set up the elements of the open structure.
+ //
+
+ NdisAllocateSpinLock(&NewOpenP->SpinLock);
+ NewOpenP->Closing = FALSE;
+
+ NewOpenP->AdapterHandle = TmpAdaptP;
+ NewOpenP->ProtocolHandle = TmpProtP;
+
+ //
+ // for speed, instead of having to use AdapterHandle->MacHandle
+ //
+ NewOpenP->MacHandle = TmpAdaptP->MacHandle;
+
+ //
+ // for even more speed....
+ //
+
+ NewOpenP->SendHandler = TmpAdaptP->MacHandle->MacCharacteristics.SendHandler;
+ NewOpenP->TransferDataHandler = TmpAdaptP->MacHandle->MacCharacteristics.TransferDataHandler;
+
+ NewOpenP->SendCompleteHandler = TmpProtP->ProtocolCharacteristics.SendCompleteHandler;
+ NewOpenP->TransferDataCompleteHandler = TmpProtP->ProtocolCharacteristics.TransferDataCompleteHandler;
+
+ //
+ // Now we have to fake some stuff to get all indications to happen
+ // at DPC_LEVEL. What we do is start the pointer at an NDIS function
+ // which will guarantee that it occurs.
+ //
+ // Then, by extending the OPEN structure and adding the real handlers
+ // at the end we can use these for drivers compiled with this header.
+ //
+ NewOpenP->ProtocolBindingContext = ProtocolBindingContext;
+ NewOpenP->PostNt31ReceiveHandler = TmpProtP->ProtocolCharacteristics.ReceiveHandler;
+ NewOpenP->PostNt31ReceiveCompleteHandler = TmpProtP->ProtocolCharacteristics.ReceiveCompleteHandler;
+ NewOpenP->ReceiveHandler = NdisMacReceiveHandler;
+ NewOpenP->ReceiveCompleteHandler = NdisMacReceiveCompleteHandler;
+
+ //
+ // Patch the open into the global list of macs
+ //
+ ACQUIRE_SPIN_LOCK(&GlobalOpenListLock);
+
+ NewOpenP->NextGlobalOpen = GlobalOpenList;
+ GlobalOpenList = NewOpenP;
+
+ RELEASE_SPIN_LOCK(&GlobalOpenListLock);
+
+
+ //
+ // Save a pointer to the file object in the open...
+ //
+
+ NewOpenP->FileObject = FileObject;
+
+ //
+ // ...and a pointer to the open in the file object.
+ //
+
+ FileObject->FsContext = (PVOID)NewOpenP;
+
+
+ *NdisBindingHandle = (NDIS_HANDLE)NewOpenP;
+
+
+ //
+ // Call MacOpenAdapter, see what we shall see...
+ //
+
+ OpenStatus = (TmpAdaptP->MacHandle->MacCharacteristics.OpenAdapterHandler) (
+ OpenErrorStatus,
+ &NewOpenP->MacBindingHandle,
+ SelectedMediumIndex,
+ MediumArray,
+ MediumArraySize,
+ (NDIS_HANDLE)NewOpenP,
+ TmpAdaptP->MacAdapterContext,
+ OpenOptions,
+ AddressingInformation
+ );
+
+ if ((OpenStatus == NDIS_STATUS_SUCCESS) && NdisFinishOpen(NewOpenP)) {
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ } else if (OpenStatus == NDIS_STATUS_PENDING) {
+
+ *Status = NDIS_STATUS_PENDING;
+
+ } else {
+
+ PNDIS_OPEN_BLOCK TmpOpen;
+
+ //
+ // Something went wrong, clean up and exit.
+ //
+
+ ACQUIRE_SPIN_LOCK(&GlobalOpenListLock);
+
+ if (GlobalOpenList == NewOpenP) {
+
+ GlobalOpenList = NewOpenP->NextGlobalOpen;
+
+ } else {
+
+ TmpOpen = GlobalOpenList;
+
+ while (TmpOpen->NextGlobalOpen != NewOpenP) {
+
+ TmpOpen = TmpOpen->NextGlobalOpen;
+
+ }
+
+ TmpOpen->NextGlobalOpen = NewOpenP->NextGlobalOpen;
+
+ }
+
+ RELEASE_SPIN_LOCK(&GlobalOpenListLock);
+
+ ObDereferenceObject((PVOID)FileObject);
+ NdisDereferenceAdapter(TmpAdaptP);
+ NdisDereferenceProtocol(TmpProtP);
+ ExFreePool((PVOID)NewOpenP);
+ *Status = NDIS_STATUS_OPEN_FAILED;
+ }
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n");
+ return;
+}
+
+
+VOID
+NdisCloseAdapter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Closes a connection between a protocol and an adapter (MAC).
+
+Arguments:
+
+ Status - Returns the final status.
+ NdisBindingHandle - The handle returned by NdisOpenAdapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_OPEN_BLOCK OpenP = ((PNDIS_OPEN_BLOCK)NdisBindingHandle);
+
+ if (OpenP->AdapterHandle->DeviceObject == NULL) {
+
+ //
+ // This is a Miniport
+ // This returns TRUE if it finished synchronously.
+ //
+
+ if (NdisMKillOpen(OpenP)) {
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ } else {
+
+ *Status = NDIS_STATUS_PENDING; // will complete later
+
+ }
+ return;
+ }
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisCloseAdapter\n");
+ NdisPrint3(" Protocol %wZ is closing Adapter %wZ\n",
+ &(OpenP->ProtocolHandle)->ProtocolCharacteristics.Name,
+ &(OpenP->AdapterHandle)->AdapterName);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(NdisBindingHandle)) {
+ NdisPrint1("OpenAdapter: Null BindingHandle\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(NdisBindingHandle)) {
+ NdisPrint1("OpenAdapter: BindingHandle not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ //
+ // This returns TRUE if it finished synchronously.
+ //
+
+ if (NdisKillOpen(OpenP)) {
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ } else {
+
+ *Status = NDIS_STATUS_PENDING; // will complete later
+
+ }
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisCloseAdapter\n");
+#undef OpenP
+}
+
+
+//
+// Requests Used by MAC Drivers
+//
+//
+
+
+
+VOID
+NdisInitializeWrapper(
+ OUT PNDIS_HANDLE NdisWrapperHandle,
+ IN PVOID SystemSpecific1,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+
+/*++
+
+Routine Description:
+
+ Called at the beginning of every MAC's initialization routine.
+
+Arguments:
+
+ NdisWrapperHandle - A MAC specific handle for the wrapper.
+
+ SystemSpecific1, a pointer to the driver object for the MAC.
+ SystemSpecific2, a PUNICODE_STRING containing the location of
+ the registry subtree for this driver.
+ SystemSpecific3, unused on NT.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS Status;
+
+ PNDIS_WRAPPER_HANDLE NdisMacInfo;
+
+ UNREFERENCED_PARAMETER (SystemSpecific3);
+
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("==>NdisInitializeWrapper\n");
+
+ Status = NdisAllocateMemory(
+ (PVOID*) (NdisWrapperHandle),
+ sizeof(NDIS_WRAPPER_HANDLE),
+ 0,
+ HighestAcceptableMax
+ );
+
+ if ( Status == NDIS_STATUS_SUCCESS ) {
+
+ NdisMacInfo = (PNDIS_WRAPPER_HANDLE) (*NdisWrapperHandle);
+ NdisMacInfo->NdisWrapperDriver = (PDRIVER_OBJECT) SystemSpecific1;
+ NdisMacInfo->NdisWrapperConfigurationHandle = (HANDLE) SystemSpecific2;
+
+ } else {
+
+ *NdisWrapperHandle = NULL;
+ }
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisInitializeWrapper\n");
+}
+
+VOID
+NdisTerminateWrapper(
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN PVOID SystemSpecific
+ )
+
+/*++
+
+Routine Description:
+
+ Called at the end of every MAC's termination routine.
+
+Arguments:
+
+ NdisWrapperHandle - The handle returned from NdisInitializeWrapper.
+
+ SystemSpecific - No defined value.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_WRAPPER_HANDLE NdisMacInfo = (PNDIS_WRAPPER_HANDLE)NdisWrapperHandle;
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("==>NdisTerminateWrapper\n");
+
+ UNREFERENCED_PARAMETER(SystemSpecific);
+
+
+ if (NdisMacInfo != NULL) {
+
+ NdisFreeMemory(NdisMacInfo, sizeof(NDIS_WRAPPER_HANDLE), 0);
+
+ }
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisTerminateWrapper\n");
+
+ return;
+}
+
+VOID
+NdisRegisterMac(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE NdisMacHandle,
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN NDIS_HANDLE MacMacContext,
+ IN PNDIS_MAC_CHARACTERISTICS MacCharacteristics,
+ IN UINT CharacteristicsLength
+ )
+
+/*++
+
+Routine Description:
+
+ Register an NDIS MAC.
+
+Arguments:
+
+ Status - Returns the final status.
+ NdisMacHandle - Returns a handle referring to this MAC.
+ NdisWrapperHandle - Handle returned by NdisInitializeWrapper.
+ MacMacContext - Context for calling MACUnloadMac and MACAddAdapter.
+ MacCharacteritics - The NDIS_MAC_CHARACTERISTICS table.
+ CharacteristicsLength - The length of MacCharacteristics.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_MAC_BLOCK NewMacP;
+ PNDIS_WRAPPER_HANDLE NdisMacInfo = (PNDIS_WRAPPER_HANDLE)(NdisWrapperHandle);
+ UINT MemNeeded;
+
+ //
+ // check that this is an NDIS 3.0 MAC.
+ //
+ IF_TRACE(TRACE_IMPT) NdisPrint1("==>NdisRegisterMac\n");
+
+ //
+ // Do any initial initialization that may be necessary. Note: this
+ // routine will notice if this is the second or later call to it.
+ //
+ *Status = NdisInitialInit( NdisMacInfo->NdisWrapperDriver );
+ if (!NT_SUCCESS(*Status)) {
+ return;
+ }
+
+ *NdisMacHandle = (NDIS_HANDLE)NULL;
+
+ if (NdisMacInfo == NULL) {
+
+ *Status = NDIS_STATUS_FAILURE;
+
+ return;
+
+ }
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(MacCharacteristics->OpenAdapterHandler)) {
+ NdisPrint1("RegisterMac: Null OpenAdapterHandler \n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(MacCharacteristics->CloseAdapterHandler)) {
+ NdisPrint1("RegisterMac: Null CloseAdapterHandler \n");
+ DbgBreakPoint();
+ }
+
+ if (DbgIsNull(MacCharacteristics->SendHandler)) {
+ NdisPrint1("RegisterMac: Null SendHandler \n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(MacCharacteristics->TransferDataHandler)) {
+ NdisPrint1("RegisterMac: Null TransferDataHandler \n");
+ DbgBreakPoint();
+ }
+
+ if (DbgIsNull(MacCharacteristics->ResetHandler)) {
+ NdisPrint1("RegisterMac: Null ResetHandler \n");
+ DbgBreakPoint();
+ }
+
+ if (DbgIsNull(MacCharacteristics->RequestHandler)) {
+ NdisPrint1("RegisterMac: Null RequestHandler \n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(MacCharacteristics->QueryGlobalStatisticsHandler)) {
+ NdisPrint1("RegisterMac: Null QueryGlobalStatisticsHandler \n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(MacCharacteristics->UnloadMacHandler)) {
+ NdisPrint1("RegisterMac: Null UnloadMacHandler \n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(MacCharacteristics->AddAdapterHandler)) {
+ NdisPrint1("RegisterMac: Null AddAdapterHandler \n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(MacCharacteristics->RemoveAdapterHandler)) {
+ NdisPrint1("RegisterMac: Null RemoveAdapterHandler \n");
+ DbgBreakPoint();
+ }
+ }
+
+ if (MacCharacteristics->MajorNdisVersion != 3 ||
+ MacCharacteristics->MinorNdisVersion != 0) {
+ *Status = NDIS_STATUS_BAD_VERSION;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterMac\n");
+ return;
+ }
+
+ //
+ // Check that CharacteristicsLength is enough.
+ //
+
+ if (CharacteristicsLength < sizeof(NDIS_MAC_CHARACTERISTICS)) {
+ NdisPrint3("char len = %d < %d\n",CharacteristicsLength,
+ sizeof(NDIS_MAC_CHARACTERISTICS));
+
+ *Status = NDIS_STATUS_BAD_CHARACTERISTICS;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterMac\n");
+ return;
+ }
+
+ //
+ // Allocate memory for the NDIS MAC block.
+ //
+ MemNeeded = sizeof(NDIS_MAC_BLOCK) + MacCharacteristics->Name.Length;
+ NewMacP = (PNDIS_MAC_BLOCK)ExAllocatePoolWithTag(NonPagedPool, MemNeeded, 'bmDN');
+ if (NewMacP == (PNDIS_MAC_BLOCK)NULL) {
+ *Status = NDIS_STATUS_RESOURCES;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterMac\n");
+ return;
+ }
+ RtlZeroMemory(NewMacP, sizeof(NDIS_MAC_BLOCK));
+
+ NewMacP->Length = MemNeeded;
+
+ //
+ // Copy over the characteristics table.
+ //
+
+ RtlCopyMemory((PVOID)&NewMacP->MacCharacteristics,
+ (PVOID)MacCharacteristics, sizeof(NDIS_MAC_CHARACTERISTICS));
+
+ //
+ // Move buffer pointer to correct location (extra space at the end of
+ // the characteristics table)
+ //
+
+ (NewMacP->MacCharacteristics).Name.Buffer =
+ (PWSTR)((PUCHAR)NewMacP + sizeof(NDIS_MAC_BLOCK));
+
+
+ //
+ // Copy String over.
+ //
+
+ RtlCopyMemory(
+ (NewMacP->MacCharacteristics).Name.Buffer,
+ (MacCharacteristics->Name).Buffer,
+ (MacCharacteristics->Name).Length
+ );
+
+ //
+ // No adapters yet registered for this MAC.
+ //
+
+ NewMacP->AdapterQueue = (PNDIS_ADAPTER_BLOCK)NULL;
+
+ NewMacP->MacMacContext = MacMacContext;
+
+ //
+ // Set up unload handler
+ //
+
+ NdisMacInfo->NdisWrapperDriver->DriverUnload = NdisUnload;
+
+ //
+ // Set up shutdown handler
+ //
+ NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_SHUTDOWN] = NdisShutdown;
+
+ //
+ // Set up the handlers for this driver (they all do nothing).
+ //
+
+ NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CREATE] = NdisCreateIrpHandler;
+ NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NdisDeviceControlIrpHandler;
+ NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CLEANUP] = NdisSuccessIrpHandler;
+ NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CLOSE] = NdisCloseIrpHandler;
+
+ NewMacP->NdisMacInfo = NdisMacInfo;
+
+ //
+ // Put MAC on global list.
+ //
+
+ ACQUIRE_SPIN_LOCK(&NdisMacListLock);
+
+ NewMacP->NextMac = NdisMacList;
+ NdisMacList = NewMacP;
+
+ RELEASE_SPIN_LOCK(&NdisMacListLock);
+
+ //
+ // Use this event to tell us when all adapters are removed from the mac
+ // during an unload
+ //
+
+ KeInitializeEvent(
+ &NewMacP->AdaptersRemovedEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ NewMacP->Unloading = FALSE;
+
+ NdisInitializeRef(&NewMacP->Ref);
+
+ *NdisMacHandle = (NDIS_HANDLE)NewMacP;
+
+ NdisInitReferencePackage();
+
+ if (NdisMacInfo->NdisWrapperConfigurationHandle) {
+
+ if (NdisCallDriverAddAdapter(NewMacP) == NDIS_STATUS_SUCCESS) {
+ *Status = NDIS_STATUS_SUCCESS;
+ } else {
+ *Status = NDIS_STATUS_FAILURE;
+ NdisDereferenceMac(NewMacP);
+ }
+ } else {
+ *Status = NDIS_STATUS_FAILURE;
+ }
+
+ NdisInitDereferencePackage();
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterMac\n");
+}
+
+
+VOID
+NdisDeregisterMac(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisMacHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Deregisters an NDIS MAC.
+
+Arguments:
+
+ Status - Returns the status of the request.
+ NdisMacHandle - The handle returned by NdisRegisterMac.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_MAC_BLOCK OldMacP = (PNDIS_MAC_BLOCK)NdisMacHandle;
+
+ //
+ // If the MAC is already closing, return.
+ //
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ if (OldMacP == NULL) {
+
+ return;
+ }
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisDeregisterMac\n");
+ NdisPrint2(" Mac %wZ being deregistered\n",&OldMacP->MacCharacteristics.Name);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(NdisMacHandle)) {
+ NdisPrint1("DeregisterMac: Null Handle\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(NdisMacHandle)) {
+ NdisPrint1("DeregisterMac: Handle not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ if (!NdisCloseRef(&OldMacP->Ref)) {
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeregisterMac\n");
+ return;
+ }
+
+
+ ASSERT(OldMacP->AdapterQueue == (PNDIS_ADAPTER_BLOCK)NULL);
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeregisterMac\n");
+}
+
+IO_ALLOCATION_ACTION
+NdisAllocationExecutionRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the execution routine for AllocateAdapterChannel,
+ if is called when the map registers have been assigned.
+
+Arguments:
+
+ DeviceObject - The device object of the adapter.
+
+ Irp - ??.
+
+ MapRegisterBase - The address of the first translation table
+ assigned to us.
+
+ Context - A pointer to the Adapter in question.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_ADAPTER_BLOCK AdaptP = (PNDIS_ADAPTER_BLOCK)Context;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)Context;
+
+ Irp; DeviceObject;
+
+ //
+ // Save this translation entry in the correct spot.
+ //
+
+ if (AdaptP->DeviceObject == NULL) {
+
+ Miniport->MapRegisters[Miniport->CurrentMapRegister].MapRegister = MapRegisterBase;
+
+ } else {
+
+ AdaptP->MapRegisters[AdaptP->CurrentMapRegister].MapRegister = MapRegisterBase;
+
+ }
+
+ //
+ // This will free the thread that is waiting for this callback.
+ //
+
+ KeSetEvent(
+ ((AdaptP->DeviceObject == NULL) ?
+ &Miniport->AllocationEvent :
+ &AdaptP->AllocationEvent),
+ 0L,
+ FALSE
+ );
+
+ return DeallocateObjectKeepRegisters;
+}
+
+
+
+NDIS_STATUS
+NdisRegisterAdapter(
+ OUT PNDIS_HANDLE NdisAdapterHandle,
+ IN NDIS_HANDLE NdisMacHandle,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN PNDIS_STRING AdapterName,
+ IN PVOID AdapterInformation
+ )
+
+/*++
+
+Routine Description:
+
+ Register an NDIS adapter.
+
+Arguments:
+
+ NdisAdapterHandle - Returns a handle referring to this adapter.
+ NdisMacHandle - A handle for a previously registered MAC.
+ MacAdapterContext - A context for calls into this MAC.
+ WrapperConfigurationContext - Context passed to MacAddAdapter.
+ AdapterName - The name the adapter should be registered under.
+ AdapterInformation - Contains adapter information. For future
+ use. NULL for the meantime. Storage for it
+ must be allocated by the caller.
+
+Return Value:
+
+ The final status.
+
+--*/
+
+{
+ PNDIS_ADAPTER_BLOCK NewAdaptP;
+ PDEVICE_OBJECT TmpDeviceP;
+ PNDIS_MAC_BLOCK TmpMacP;
+ NTSTATUS NtStatus;
+ NDIS_STRING NdisAdapterName;
+ PHYSICAL_ADDRESS PortAddress;
+ PHYSICAL_ADDRESS InitialPortAddress;
+ ULONG addressSpace;
+ PNDIS_ADAPTER_INFORMATION AdapterInfo = (PNDIS_ADAPTER_INFORMATION)AdapterInformation;
+ BOOLEAN Conflict;
+ PCM_RESOURCE_LIST Resources;
+ LARGE_INTEGER TimeoutValue;
+ BOOLEAN AllocateIndividualPorts = TRUE;
+ ULONG i;
+ ULONG BusNumber;
+ NDIS_INTERFACE_TYPE BusType;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisRegisterAdapter\n");
+ }
+
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(NdisMacHandle)) {
+ NdisPrint1("RegisterAdapter: Null Handle\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(NdisMacHandle)) {
+ NdisPrint1("RegisterAdapter: Handle not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(MacAdapterContext)) {
+ NdisPrint1("RegisterAdapter: Null Context\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(MacAdapterContext)) {
+ NdisPrint1("RegisterAdapter: Context not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ //
+ // Increment the MAC's refernce count.
+ //
+
+ if (!NdisReferenceMac((PNDIS_MAC_BLOCK)NdisMacHandle)) {
+
+ //
+ // The MAC is closing.
+ //
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_CLOSING;
+ }
+
+ //
+ // Allocate the string structure and space for the string. This
+ // must be allocated from nonpaged pool, because it is touched by
+ // NdisWriteErrorLogEntry, which may be called from DPC level.
+ //
+
+ NdisAdapterName.Buffer = (PWSTR)ExAllocatePoolWithTag(
+ NonPagedPool,
+ AdapterName->MaximumLength,
+ 'naDN'
+ );
+ if (NdisAdapterName.Buffer == NULL) {
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ NdisAdapterName.MaximumLength = AdapterName->MaximumLength;
+ NdisAdapterName.Length = AdapterName->Length;
+
+ RtlCopyMemory(NdisAdapterName.Buffer,
+ AdapterName->Buffer,
+ AdapterName->MaximumLength
+ );
+
+ //
+ // Create a device object for this adapter.
+ //
+
+ NtStatus = IoCreateDevice(
+ ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver,
+ sizeof(NDIS_ADAPTER_BLOCK) + sizeof(NDIS_WRAPPER_CONTEXT), // device extension size
+ AdapterName,
+ FILE_DEVICE_PHYSICAL_NETCARD,
+ 0,
+ FALSE, // exclusive flag
+ &TmpDeviceP
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ ExFreePool( NdisAdapterName.Buffer );
+ return NDIS_STATUS_DEVICE_FAILED;
+ }
+
+
+ //
+ // Initialize the NDIS adapter block in the device object extension
+ //
+ // *** NDIS_WRAPPER_CONTEXT has a higher alignment requirement than
+ // NDIS_ADAPTER_BLOCK, so we put it first in the extension.
+ //
+
+ ASSERT( (sizeof(NDIS_WRAPPER_CONTEXT) & 3) <= (sizeof(NDIS_ADAPTER_BLOCK) & 3) );
+
+ NewAdaptP = (PNDIS_ADAPTER_BLOCK)((PNDIS_WRAPPER_CONTEXT)TmpDeviceP->DeviceExtension + 1);
+ RtlZeroMemory(NewAdaptP, sizeof(NDIS_ADAPTER_BLOCK));
+
+ NewAdaptP->DeviceObject = TmpDeviceP;
+ NewAdaptP->MacHandle = TmpMacP = (PNDIS_MAC_BLOCK)NdisMacHandle;
+ NewAdaptP->MacAdapterContext = MacAdapterContext;
+ NewAdaptP->AdapterName = NdisAdapterName;
+ // NewAdaptP->OpenQueue = (PNDIS_OPEN_BLOCK)NULL;
+
+ NewAdaptP->WrapperContext = TmpDeviceP->DeviceExtension;
+
+ //
+ // Get the BusNumber and BusType from the context
+ //
+
+ if (((PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext)[3].DefaultType ==
+ (NDIS_INTERFACE_TYPE)-1) {
+
+ BusType = (NDIS_INTERFACE_TYPE)-1;
+
+ } else {
+
+ BusType = AdapterInfo->AdapterType;
+
+ }
+
+ BusNumber = ((PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext)[3].DefaultLength;
+
+ //
+ // Check that if there is no bus number or no bus type that the driver is not
+ // going to try to acquire any hardware resources
+ //
+
+ if ((BusType == (NDIS_INTERFACE_TYPE)-1) || (BusNumber == (ULONG)-1)) {
+
+ if ((AdapterInfo != NULL) &&
+ ((AdapterInfo->NumberOfPortDescriptors != 0) ||
+ (AdapterInfo->Master))) {
+
+ //
+ // Error out
+ //
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ return NDIS_STATUS_BAD_CHARACTERISTICS;
+
+ }
+
+ }
+
+ //
+ // Copy over any PCI assigned resources
+ //
+ if ((BusType == NdisInterfacePci) &&
+ (BusNumber != -1) &&
+ (AdapterInfo != NULL) &&
+ (TmpMacP->PciAssignedResources != NULL)) {
+
+ //
+ // Reassign old resources to this device
+ //
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver,
+ NULL,
+ 0,
+ NewAdaptP->DeviceObject,
+ TmpMacP->PciAssignedResources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ TmpMacP->PciAssignedResources->List[0].PartialResourceList.Count,
+ TRUE,
+ &Conflict
+ );
+
+ //
+ // Allocate a new buffer
+ //
+ Resources = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ (AdapterInfo->NumberOfPortDescriptors +
+ TmpMacP->PciAssignedResources->List[0].PartialResourceList.Count +
+ (((AdapterInfo->Master == TRUE) &&
+ (AdapterInfo->AdapterType == NdisInterfaceIsa))
+ ?1
+ :0)),
+ 'lrDN'
+ );
+
+ if (Resources == NULL) {
+
+ //
+ // Error out
+ //
+
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ ExFreePool( TmpMacP->PciAssignedResources );
+ NdisDereferenceMac(TmpMacP);
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ //
+ // Copy over old resource list
+ //
+ NdisMoveMemory(Resources,
+ TmpMacP->PciAssignedResources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ TmpMacP->PciAssignedResources->List[0].PartialResourceList.Count
+ );
+
+ TmpMacP->PciAssignedResources->Count = 0;
+
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver,
+ TmpMacP->PciAssignedResources,
+ sizeof(CM_RESOURCE_LIST),
+ NULL,
+ NULL,
+ 0,
+ TRUE,
+ &Conflict
+ );
+
+ ExFreePool( TmpMacP->PciAssignedResources);
+
+ TmpMacP->PciAssignedResources = NULL;
+
+ } else {
+
+ //
+ // Allocate a new buffer for non-pci devices
+ //
+ Resources = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ (AdapterInfo->NumberOfPortDescriptors +
+ (((AdapterInfo->Master == TRUE) &&
+ (AdapterInfo->AdapterType == NdisInterfaceIsa))
+ ?1
+ :0)),
+ 'lrDN'
+ );
+
+ if (Resources == NULL) {
+
+ //
+ // Error out
+ //
+
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ //
+ // Fix up counts for non-pci devices
+ //
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ }
+
+ //
+ // Setup resources for the ports
+ //
+
+ if ((BusType != (NDIS_INTERFACE_TYPE)-1) &&
+ (BusNumber != (ULONG)-1)) {
+
+ if (AdapterInfo != NULL) {
+
+ ULONG HighestPort;
+ ULONG LowestPort;
+
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = AdapterInfo->AdapterType;
+ Resources->List[0].BusNumber = BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+
+ NewAdaptP->Resources = Resources;
+ NewAdaptP->BusNumber = BusNumber;
+ NewAdaptP->BusType = BusType;
+ NewAdaptP->AdapterType = AdapterInfo->AdapterType;
+ NewAdaptP->Master = AdapterInfo->Master;
+
+ //
+ // NewAdaptP->InitialPort and NumberOfPorts refer to the
+ // union of all port mappings specified; the area must
+ // cover all possible ports. We scan the list, keeping track
+ // of the highest and lowest ports used.
+ //
+
+ if (AdapterInfo->NumberOfPortDescriptors > 0) {
+
+
+ //
+ // Setup port
+ //
+ LowestPort = AdapterInfo->PortDescriptors[0].InitialPort;
+ HighestPort = LowestPort + AdapterInfo->PortDescriptors[0].NumberOfPorts;
+
+ if (AdapterInfo->PortDescriptors[0].PortOffset == NULL) {
+
+ AllocateIndividualPorts = FALSE;
+
+ }
+
+ for (i = 0; i < AdapterInfo->NumberOfPortDescriptors; i++) {
+
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].Type =
+ CmResourceTypePort;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].ShareDisposition =
+ CmResourceShareDeviceExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].Flags =
+ (AdapterInfo->AdapterType == NdisInterfaceInternal)?
+ CM_RESOURCE_PORT_MEMORY : CM_RESOURCE_PORT_IO;
+#if !defined(BUILD_FOR_3_1)
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].u.Port.Start.QuadPart =
+ (ULONG)AdapterInfo->PortDescriptors[i].InitialPort;
+#else
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].u.Port.Start =
+ RtlConvertUlongToLargeInteger((ULONG)(AdapterInfo->PortDescriptors[i].InitialPort));
+#endif
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].u.Port.Length =
+ AdapterInfo->PortDescriptors[i].NumberOfPorts;
+
+ if (AdapterInfo->PortDescriptors[i].PortOffset == NULL) {
+
+ AllocateIndividualPorts = FALSE;
+
+ }
+
+ if (AdapterInfo->PortDescriptors[i].InitialPort < LowestPort) {
+ LowestPort = AdapterInfo->PortDescriptors[i].InitialPort;
+ }
+ if ((AdapterInfo->PortDescriptors[i].InitialPort +
+ AdapterInfo->PortDescriptors[i].NumberOfPorts) > HighestPort) {
+ HighestPort = AdapterInfo->PortDescriptors[i].InitialPort +
+ AdapterInfo->PortDescriptors[i].NumberOfPorts;
+ }
+ }
+
+ NewAdaptP->InitialPort = LowestPort;
+ NewAdaptP->NumberOfPorts = HighestPort - LowestPort;
+
+ } else {
+
+ NewAdaptP->NumberOfPorts = 0;
+
+ }
+
+ Resources->List[0].PartialResourceList.Count += AdapterInfo->NumberOfPortDescriptors;
+
+ } else {
+
+ //
+ // Error out
+ //
+
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ }
+
+ NewAdaptP->BeingRemoved = FALSE;
+
+ if ((BusType != (NDIS_INTERFACE_TYPE)-1) &&
+ (BusNumber != (ULONG)-1)) {
+
+ //
+ // Submit Resources
+ //
+
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver,
+ NULL,
+ 0,
+ NewAdaptP->DeviceObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ Resources->List[0].PartialResourceList.Count,
+ TRUE,
+ &Conflict
+ );
+
+ //
+ // Check for conflict.
+ //
+
+ if (Conflict || (NtStatus != STATUS_SUCCESS)) {
+
+ if (Conflict) {
+
+ //
+ // Log an error
+ //
+
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ ULONG StringSize;
+ PWCH baseFileName;
+
+ baseFileName = NewAdaptP->AdapterName.Buffer;
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+
+ for ( i = 0; i < NewAdaptP->AdapterName.Length / sizeof(WCHAR); i++ ) {
+
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+
+ if ( NewAdaptP->AdapterName.Buffer[i] == OBJ_NAME_PATH_SEPARATOR ) {
+ baseFileName = &(NewAdaptP->AdapterName.Buffer[++i]);
+ }
+
+ }
+
+ StringSize = NewAdaptP->AdapterName.MaximumLength -
+ (((ULONG)baseFileName) - ((ULONG)NewAdaptP->AdapterName.Buffer)) ;
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ TmpDeviceP,
+ (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize)
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_IO_PORT_CONFLICT;
+
+ //
+ // store the time
+ //
+
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+
+ //
+ // Set string information
+ //
+
+ if (StringSize != 0) {
+
+ errorLogEntry->NumberOfStrings = 1;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+
+ RtlCopyMemory (
+ ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET),
+ (PVOID)baseFileName,
+ StringSize
+ );
+
+ } else {
+
+ errorLogEntry->NumberOfStrings = 0;
+
+ }
+
+ //
+ // write it out
+ //
+
+ IoWriteErrorLogEntry(errorLogEntry);
+ }
+
+ //
+ // Free memory
+ //
+
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+
+ return(NDIS_STATUS_RESOURCE_CONFLICT);
+
+ }
+
+ //
+ // Free memory
+ //
+
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+
+
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // If port mapping is needed, we do that. If the result
+ // is in memory, we have to map it. We map only the
+ // ports specified in AdapterInformation; the default
+ // is to map the first 4K.
+ //
+ // Note that NumberOfPorts can only be 0 if AdapterInfo
+ // is provided and explicitly sets it to 0, so in that
+ // case it is OK to leave the adapter in a state where
+ // a call to NdisXXXPort will probably crash (because
+ // PortOffset will be undefined).
+ //
+
+ if (NewAdaptP->NumberOfPorts > 0) {
+
+ if (AllocateIndividualPorts) {
+
+ //
+ // We get here if we are supposed to allocate ports on an
+ // individual bases -- which implies that the driver will
+ // be using the Raw functions.
+ //
+ // Get the system physical address for this card. The card uses
+ // I/O space, except for "internal" Jazz devices which use
+ // memory space.
+ //
+
+ for (i = 0; i < AdapterInfo->NumberOfPortDescriptors; i++) {
+
+ addressSpace = (NewAdaptP->AdapterType == NdisInterfaceInternal) ? 0 : 1;
+
+ InitialPortAddress.LowPart = AdapterInfo->PortDescriptors[i].InitialPort;
+ InitialPortAddress.HighPart = 0;
+
+ if ( !HalTranslateBusAddress(
+ NewAdaptP->BusType, // InterfaceType
+ NewAdaptP->BusNumber, // BusNumber
+ InitialPortAddress, // Bus Address
+ &addressSpace, // AddressSpace
+ &PortAddress // Translated address
+ ) ) {
+
+ //
+ // Free memory
+ //
+
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+
+
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ if (addressSpace == 0) {
+
+ //
+ // memory space
+ //
+
+ *(AdapterInfo->PortDescriptors[i].PortOffset) = MmMapIoSpace(
+ PortAddress,
+ AdapterInfo->PortDescriptors[i].NumberOfPorts,
+ FALSE
+ );
+
+ if (*(AdapterInfo->PortDescriptors[i].PortOffset) == NULL) {
+
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ } else {
+
+ //
+ // I/O space
+ //
+
+ *(AdapterInfo->PortDescriptors[i].PortOffset) = (PUCHAR)PortAddress.LowPart;
+
+ }
+
+ }
+
+ } else {
+
+ //
+ // The driver will not use the Raw functions, only the
+ // old NdisRead and NdisWrite port functions.
+ //
+ // Get the system physical address for this card. The card uses
+ // I/O space, except for "internal" Jazz devices which use
+ // memory space.
+ //
+
+ addressSpace = (NewAdaptP->AdapterType == NdisInterfaceInternal) ? 0 : 1;
+ InitialPortAddress.LowPart = NewAdaptP->InitialPort;
+ InitialPortAddress.HighPart = 0;
+ if ( !HalTranslateBusAddress(
+ NewAdaptP->BusType, // InterfaceType
+ NewAdaptP->BusNumber, // BusNumber
+ InitialPortAddress, // Bus Address
+ &addressSpace, // AddressSpace
+ &PortAddress // Translated address
+ ) ) {
+
+ //
+ // Free memory
+ //
+
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+
+
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ if (addressSpace == 0) {
+
+ //
+ // memory space
+ //
+
+ NewAdaptP->InitialPortMapping = MmMapIoSpace(
+ PortAddress,
+ NewAdaptP->NumberOfPorts,
+ FALSE
+ );
+
+ if (NewAdaptP->InitialPortMapping == NULL) {
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ NewAdaptP->InitialPortMapped = TRUE;
+
+ } else {
+
+ //
+ // I/O space
+ //
+
+ NewAdaptP->InitialPortMapping = (PUCHAR)PortAddress.LowPart;
+ NewAdaptP->InitialPortMapped = FALSE;
+
+ }
+
+ //
+ // PortOffset holds the mapped address of port 0.
+ //
+
+ NewAdaptP->PortOffset = NewAdaptP->InitialPortMapping - NewAdaptP->InitialPort;
+
+ }
+
+ } else {
+
+ //
+ // Technically should not allow this, but do it until
+ // all drivers register their info correctly.
+ //
+
+ NewAdaptP->PortOffset = 0;
+
+ }
+
+ }
+
+ //
+ // If the driver want to be called back now, use
+ // supplied callback routine.
+ //
+
+ if ((AdapterInfo != NULL) && (AdapterInfo->ActivateCallback != NULL)) {
+
+ Status = (*(AdapterInfo->ActivateCallback))((NDIS_HANDLE)NewAdaptP,
+ MacAdapterContext,
+ AdapterInfo->DmaChannel
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Exit
+ //
+
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return Status;
+
+ }
+
+ }
+
+ //
+ // Set information from AdapterInformation. The call back
+ // routine can set these values.
+ //
+
+ NewAdaptP->ChannelNumber = AdapterInfo->DmaChannel;
+ NewAdaptP->PhysicalMapRegistersNeeded =
+ AdapterInfo->PhysicalMapRegistersNeeded;
+ NewAdaptP->MaximumPhysicalMapping =
+ AdapterInfo->MaximumPhysicalMapping;
+
+
+ //
+ // Check for resource conflic on DmaChannel.
+ //
+
+ if ((NewAdaptP->Master) &&
+ (BusType != (NDIS_INTERFACE_TYPE)-1) &&
+ (BusNumber != (ULONG)-1)) {
+
+ if (NewAdaptP->AdapterType == NdisInterfaceIsa) {
+
+ //
+ // Put the DMA channel in the resource list.
+ //
+
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type =
+ CmResourceTypeDma;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition =
+ CmResourceShareDeviceExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags =
+ 0;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Dma.Channel =
+ NewAdaptP->ChannelNumber;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Dma.Port =
+ 0;
+ Resources->List[0].PartialResourceList.Count++;
+
+ }
+
+ //
+ // Submit Resources
+ //
+
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver,
+ NULL,
+ 0,
+ NewAdaptP->DeviceObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ Resources->List[0].PartialResourceList.Count,
+ TRUE,
+ &Conflict
+ );
+
+ //
+ // Check for conflict.
+ //
+
+ if (Conflict || (NtStatus != STATUS_SUCCESS)) {
+
+ if (Conflict) {
+
+ //
+ // Log an error
+ //
+
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ ULONG StringSize;
+ PWCH baseFileName;
+
+ baseFileName = NewAdaptP->AdapterName.Buffer;
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+
+ for ( i = 0; i < NewAdaptP->AdapterName.Length / sizeof(WCHAR); i++ ) {
+
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+
+ if ( NewAdaptP->AdapterName.Buffer[i] == OBJ_NAME_PATH_SEPARATOR ) {
+ baseFileName = &(NewAdaptP->AdapterName.Buffer[++i]);
+ }
+
+ }
+
+ StringSize = NewAdaptP->AdapterName.MaximumLength -
+ (((ULONG)baseFileName) - ((ULONG)NewAdaptP->AdapterName.Buffer)) ;
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ TmpDeviceP,
+ (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize)
+ );
+
+ if (errorLogEntry != NULL) {
+
+ if ((NewAdaptP->Master) &&
+ (NewAdaptP->AdapterType == Isa)){
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_PORT_OR_DMA_CONFLICT;
+
+ } else {
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_IO_PORT_CONFLICT;
+
+ }
+
+ //
+ // store the time
+ //
+
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+
+ //
+ // Set string information
+ //
+
+ if (StringSize != 0) {
+
+ errorLogEntry->NumberOfStrings = 1;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+
+ RtlCopyMemory (
+ ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET),
+ (PVOID)baseFileName,
+ StringSize
+ );
+
+ } else {
+
+ errorLogEntry->NumberOfStrings = 0;
+
+ }
+
+ //
+ // write it out
+ //
+
+ IoWriteErrorLogEntry(errorLogEntry);
+ }
+
+ //
+ // Free memory
+ //
+
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+
+ return(NDIS_STATUS_RESOURCE_CONFLICT);
+
+ }
+
+ //
+ // Free memory
+ //
+
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+
+
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ }
+
+ //
+ // If the device is a busmaster, we get an adapter
+ // object for it.
+ // If map registers are needed, we loop, allocating an
+ // adapter channel for each map register needed.
+ //
+
+ if ((NewAdaptP->Master) &&
+ (BusType != (NDIS_INTERFACE_TYPE)-1) &&
+ (BusNumber != (ULONG)-1)) {
+
+ //
+ // This is needed by HalGetAdapter.
+ //
+ DEVICE_DESCRIPTION DeviceDescription;
+
+ //
+ // Returned by HalGetAdapter.
+ //
+ ULONG MapRegistersAllowed;
+
+ //
+ // Returned by HalGetAdapter.
+ //
+ PADAPTER_OBJECT AdapterObject;
+
+ //
+ // Map registers needed per channel.
+ //
+ ULONG MapRegistersPerChannel;
+
+ NTSTATUS Status;
+
+ //
+ // Allocate storage for holding the appropriate
+ // information for each map register.
+ //
+
+ NewAdaptP->MapRegisters = (PMAP_REGISTER_ENTRY)
+ ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(MAP_REGISTER_ENTRY) *
+ NewAdaptP->PhysicalMapRegistersNeeded,
+ 'rmDN');
+
+ if (NewAdaptP->MapRegisters == (PMAP_REGISTER_ENTRY)NULL) {
+
+ //
+ // Error out
+ //
+
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ //
+ // Use this event to tell us when NdisAllocationExecutionRoutine
+ // has been called.
+ //
+
+ KeInitializeEvent(
+ &NewAdaptP->AllocationEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+
+ //
+ // Set up the device description; zero it out in case its
+ // size changes.
+ //
+
+ RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
+
+ DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
+ DeviceDescription.Master = TRUE;
+ DeviceDescription.ScatterGather = TRUE;
+
+ DeviceDescription.BusNumber = NewAdaptP->BusNumber;
+ DeviceDescription.DmaChannel = NewAdaptP->ChannelNumber;
+ DeviceDescription.InterfaceType = NewAdaptP->AdapterType;
+
+ if (DeviceDescription.InterfaceType == NdisInterfaceIsa) {
+
+ //
+ // For ISA devices, the width is based on the DMA channel:
+ // 0-3 == 8 bits, 5-7 == 16 bits. Timing is compatibility
+ // mode.
+ //
+
+ if (NewAdaptP->ChannelNumber > 4) {
+ DeviceDescription.DmaWidth = Width16Bits;
+ } else {
+ DeviceDescription.DmaWidth = Width8Bits;
+ }
+ DeviceDescription.DmaSpeed = Compatible;
+
+ } else if ((DeviceDescription.InterfaceType == NdisInterfaceMca) ||
+ (DeviceDescription.InterfaceType == NdisInterfaceEisa) ||
+ (DeviceDescription.InterfaceType == NdisInterfacePci))
+ {
+ DeviceDescription.Dma32BitAddresses = AdapterInfo->Dma32BitAddresses;
+ DeviceDescription.DmaPort = 0;
+
+ }
+
+ DeviceDescription.MaximumLength = NewAdaptP->MaximumPhysicalMapping;
+
+
+ //
+ // Determine how many map registers we need per channel.
+ //
+
+ MapRegistersPerChannel =
+ ((NewAdaptP->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2;
+
+ //
+ // Get the adapter object.
+ //
+
+ AdapterObject = HalGetAdapter (&DeviceDescription, &MapRegistersAllowed);
+
+ if (AdapterObject == NULL) {
+
+ ExFreePool(Resources);
+ ExFreePool(NewAdaptP->MapRegisters);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ ASSERT (MapRegistersAllowed >= MapRegistersPerChannel);
+
+ //
+ // We save this to call IoFreeMapRegisters later.
+ //
+
+ NewAdaptP->SystemAdapterObject = AdapterObject;
+
+
+ //
+ // Now loop, allocating an adapter channel each time, then
+ // freeing everything but the map registers.
+ //
+
+ for (i=0; i<NewAdaptP->PhysicalMapRegistersNeeded; i++) {
+
+ NewAdaptP->CurrentMapRegister = i;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ Status = IoAllocateAdapterChannel(
+ AdapterObject,
+ NewAdaptP->DeviceObject,
+ MapRegistersPerChannel,
+ NdisAllocationExecutionRoutine,
+ (PVOID)NewAdaptP
+ );
+
+ KeLowerIrql(OldIrql);
+
+ if (!NT_SUCCESS(Status)) {
+
+#if DBG
+ DbgPrint("NDIS: Failed to load driver because of\n");
+ DbgPrint("NDIS: insufficient map registers.\n");
+ DbgPrint("NDIS: AllocateAdapterChannel: %lx\n", Status);
+#endif
+
+ ExFreePool(Resources);
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ for (; i != 0; i--) {
+ IoFreeMapRegisters(
+ NewAdaptP->SystemAdapterObject,
+ NewAdaptP->MapRegisters[i-1].MapRegister,
+ MapRegistersPerChannel
+ );
+ }
+
+ KeLowerIrql(OldIrql);
+
+ ExFreePool(NewAdaptP->MapRegisters);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ TimeoutValue.QuadPart = Int32x32To64(2 * 1000, -10000);
+
+ //
+ // NdisAllocationExecutionRoutine will set this event
+ // when it has gotten FirstTranslationEntry.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &NewAdaptP->AllocationEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ NdisPrint2("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus);
+ ExFreePool(Resources);
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ for (; i != 0; i--) {
+ IoFreeMapRegisters(
+ NewAdaptP->SystemAdapterObject,
+ NewAdaptP->MapRegisters[i-1].MapRegister,
+ MapRegistersPerChannel
+ );
+ }
+
+ KeLowerIrql(OldIrql);
+
+ ExFreePool(NewAdaptP->MapRegisters);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ return(NDIS_STATUS_RESOURCES);
+
+ }
+
+ KeResetEvent(
+ &NewAdaptP->AllocationEvent
+ );
+
+ }
+
+ }
+
+
+
+ NdisInitializeRef(&NewAdaptP->Ref);
+
+
+ if (!NdisQueueAdapterOnMac(NewAdaptP, TmpMacP)) {
+
+ //
+ // The MAC is closing, undo what we have done.
+ //
+
+ ExFreePool(Resources);
+ if (NewAdaptP->Master) {
+ ULONG MapRegistersPerChannel =
+ ((NewAdaptP->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2;
+
+ for (i=0; i<NewAdaptP->PhysicalMapRegistersNeeded; i++) {
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ IoFreeMapRegisters(
+ NewAdaptP->SystemAdapterObject,
+ NewAdaptP->MapRegisters[i].MapRegister,
+ MapRegistersPerChannel
+ );
+
+ KeLowerIrql(OldIrql);
+ }
+
+ ExFreePool(NewAdaptP->MapRegisters);
+ }
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_CLOSING;
+ }
+
+ NdisMacReferencePackage();
+
+ //
+ // Add an extra reference because the wrapper is using the MAC
+ //
+ NdisReferenceAdapter(NewAdaptP);
+
+ *NdisAdapterHandle = (NDIS_HANDLE)NewAdaptP;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+NDIS_STATUS
+NdisDeregisterAdapter(
+ IN NDIS_HANDLE NdisAdapterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Deregisters an NDIS adapter.
+
+Arguments:
+
+ NdisAdapterHandle - The handle returned by NdisRegisterAdapter.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS.
+
+--*/
+
+{
+
+ //
+ // KillAdapter does all the work.
+ //
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisDeregisterAdapter\n");
+ NdisPrint2(" Deregistering Adapter %s\n",
+ ((PNDIS_ADAPTER_BLOCK)NdisAdapterHandle)->AdapterName.Buffer);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(NdisAdapterHandle)) {
+ NdisPrint1("DeregisterAdapter: Null Handle\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(NdisAdapterHandle)) {
+ NdisPrint1("DeregisterAdapter: Handle not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ NdisKillAdapter((PNDIS_ADAPTER_BLOCK)NdisAdapterHandle);
+
+ //
+ // Remove reference from wrapper
+ //
+ NdisDereferenceAdapter((PNDIS_ADAPTER_BLOCK)NdisAdapterHandle);
+
+ NdisMacDereferencePackage();
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeregisterAdapter\n");
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+VOID
+NdisRegisterAdapterShutdownHandler(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PVOID ShutdownContext,
+ IN ADAPTER_SHUTDOWN_HANDLER ShutdownHandler
+ )
+
+/*++
+
+Routine Description:
+
+ Deregisters an NDIS adapter.
+
+Arguments:
+
+ NdisAdapterHandle - The handle returned by NdisRegisterAdapter.
+
+ ShutdownContext - Context to pass the the handler, when called.
+
+ ShutdownHandler - The Handler for the Adapter, to be called on shutdown.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS.
+
+--*/
+
+{
+ PNDIS_ADAPTER_BLOCK Adapter = (PNDIS_ADAPTER_BLOCK) NdisAdapterHandle;
+ PNDIS_WRAPPER_CONTEXT WrapperContext = Adapter->WrapperContext;
+
+ if (WrapperContext->ShutdownHandler == NULL) {
+
+ //
+ // Store information
+ //
+
+ WrapperContext->ShutdownHandler = ShutdownHandler;
+ WrapperContext->ShutdownContext = ShutdownContext;
+
+ //
+ // Register our shutdown handler for either a system shutdown
+ // notification or a bugcheck.
+ //
+
+ IoRegisterShutdownNotification(Adapter->DeviceObject);
+
+#if !defined(BUILD_FOR_3_1)
+ KeInitializeCallbackRecord(&WrapperContext->BugcheckCallbackRecord);
+
+ KeRegisterBugCheckCallback(
+ &WrapperContext->BugcheckCallbackRecord, // callback record.
+ (PVOID) NdisBugcheckHandler, // callback routine.
+ (PVOID) WrapperContext, // free form buffer.
+ sizeof(NDIS_WRAPPER_CONTEXT), // buffer size.
+ "Ndis mac" // component id.
+ );
+#endif
+
+ }
+}
+
+
+VOID
+NdisDeregisterAdapterShutdownHandler(
+ IN NDIS_HANDLE NdisAdapterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Deregisters an NDIS adapter.
+
+Arguments:
+
+ NdisAdapterHandle - The handle returned by NdisRegisterAdapter.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS.
+
+--*/
+
+{
+ PNDIS_ADAPTER_BLOCK Adapter = (PNDIS_ADAPTER_BLOCK) NdisAdapterHandle;
+ PNDIS_WRAPPER_CONTEXT WrapperContext = Adapter->WrapperContext;
+
+ if (WrapperContext->ShutdownHandler != NULL) {
+
+ //
+ // Clear information
+ //
+
+ WrapperContext->ShutdownHandler = NULL;
+
+ IoUnregisterShutdownNotification(Adapter->DeviceObject);
+
+#if !defined(BUILD_FOR_3_1)
+ KeDeregisterBugCheckCallback(&WrapperContext->BugcheckCallbackRecord);
+#endif
+
+ }
+}
+
+
+VOID
+NdisReleaseAdapterResources(
+ IN NDIS_HANDLE NdisAdapterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Informs the wrapper that the resources (such as interrupt,
+ I/O ports, etc.) have been shut down in some way such that
+ they will not interfere with other devices in the system.
+
+Arguments:
+
+ NdisAdapterHandle - The handle returned by NdisRegisterAdapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCM_RESOURCE_LIST Resources;
+ BOOLEAN Conflict;
+ NTSTATUS NtStatus;
+ PNDIS_ADAPTER_BLOCK AdptrP = (PNDIS_ADAPTER_BLOCK)(NdisAdapterHandle);
+
+ Resources = AdptrP->Resources;
+
+ //
+ // Clear count
+ //
+
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ //
+ // Make the call
+ //
+
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ AdptrP->MacHandle->NdisMacInfo->NdisWrapperDriver,
+ NULL,
+ 0,
+ AdptrP->DeviceObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ TRUE,
+ &Conflict
+ );
+
+
+ return;
+
+}
+
+
+VOID
+NdisWriteErrorLogEntry(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN NDIS_ERROR_CODE ErrorCode,
+ IN ULONG NumberOfErrorValues,
+ ...
+ )
+/*++
+
+Routine Description:
+
+ This function allocates an I/O error log record, fills it in and writes it
+ to the I/O error log.
+
+
+Arguments:
+
+ NdisAdapterHandle - points to the adapter block.
+
+ ErrorCode - Ndis code mapped to a string.
+
+ NumberOfErrorValues - number of ULONGS to store for the error.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+
+ va_list ArgumentPointer;
+
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ PNDIS_ADAPTER_BLOCK AdapterBlock = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle;
+ ULONG i;
+ ULONG StringSize;
+ PWCH baseFileName;
+
+ if (AdapterBlock == NULL) {
+
+ return;
+
+ }
+
+ if (AdapterBlock->DeviceObject != NULL) {
+ baseFileName = AdapterBlock->AdapterName.Buffer;
+ } else {
+ baseFileName = Miniport->MiniportName.Buffer;
+ }
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+
+ for ( i = 0;
+ i < ((AdapterBlock->DeviceObject != NULL) ?
+ AdapterBlock->AdapterName.Length :
+ Miniport->MiniportName.Length) / sizeof(WCHAR); i++ ) {
+
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+
+ if ( ((AdapterBlock->DeviceObject != NULL) ?
+ AdapterBlock->AdapterName.Buffer[i] :
+ Miniport->MiniportName.Buffer[i]) == OBJ_NAME_PATH_SEPARATOR ) {
+ baseFileName = ((AdapterBlock->DeviceObject != NULL) ?
+ &(AdapterBlock->AdapterName.Buffer[++i]) :
+ &(Miniport->MiniportName.Buffer[++i]));
+ }
+
+ }
+
+ StringSize = ((AdapterBlock->DeviceObject != NULL) ?
+ AdapterBlock->AdapterName.MaximumLength :
+ Miniport->MiniportName.MaximumLength) -
+ (((ULONG)baseFileName) -
+ ((AdapterBlock->DeviceObject != NULL) ?
+ ((ULONG)AdapterBlock->AdapterName.Buffer) :
+ ((ULONG)Miniport->MiniportName.Buffer))) ;
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ ((AdapterBlock->DeviceObject != NULL) ?
+ AdapterBlock->DeviceObject :
+ Miniport->DeviceObject),
+ (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
+ NumberOfErrorValues * sizeof(ULONG) +
+ StringSize)
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->ErrorCode = ErrorCode;
+
+ //
+ // store the time
+ //
+
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+
+ //
+ // Store Data
+ //
+
+ errorLogEntry->DumpDataSize = (USHORT)(NumberOfErrorValues * sizeof(ULONG));
+
+ va_start(ArgumentPointer, NumberOfErrorValues);
+
+ for (i = 0; i < NumberOfErrorValues; i++) {
+
+ errorLogEntry->DumpData[i] = va_arg(ArgumentPointer, ULONG);
+
+ }
+
+ va_end(ArgumentPointer);
+
+
+ //
+ // Set string information
+ //
+
+ if (StringSize != 0) {
+
+ errorLogEntry->NumberOfStrings = 1;
+ errorLogEntry->StringOffset =
+ sizeof(IO_ERROR_LOG_PACKET) +
+ NumberOfErrorValues * sizeof(ULONG);
+
+
+ RtlCopyMemory (
+ ((PUCHAR)errorLogEntry) +
+ (sizeof(IO_ERROR_LOG_PACKET) +
+ NumberOfErrorValues * sizeof(ULONG)),
+ (PVOID)baseFileName,
+ StringSize
+ );
+
+ } else {
+
+ errorLogEntry->NumberOfStrings = 0;
+
+ }
+
+ //
+ // write it out
+ //
+
+ IoWriteErrorLogEntry(errorLogEntry);
+ }
+
+}
+
+
+VOID
+NdisCompleteOpenAdapter(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS Status,
+ IN NDIS_STATUS OpenErrorStatus
+ )
+
+{
+ PNDIS_OPEN_BLOCK OpenP = (PNDIS_OPEN_BLOCK)NdisBindingContext;
+ PNDIS_OPEN_BLOCK TmpOpen;
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisCompleteOpenAdapter\n");
+ }
+ IF_ERROR_CHK {
+ if (!DbgIsNonPaged(NdisBindingContext)) {
+ NdisPrint1("NdisCompleteOpenAdapter: Handle not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(NdisBindingContext)) {
+ NdisPrint1("NdisCompleteOpenAdapter: Binding Context not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+ if (!NdisFinishOpen(OpenP)) {
+ Status = NDIS_STATUS_CLOSING;
+ }
+ }
+
+ (OpenP->ProtocolHandle->ProtocolCharacteristics.OpenAdapterCompleteHandler) (
+ OpenP->ProtocolBindingContext,
+ Status,
+ OpenErrorStatus
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Something went wrong, clean up and exit.
+ //
+
+ ACQUIRE_SPIN_LOCK(&GlobalOpenListLock);
+
+ if (GlobalOpenList == OpenP) {
+
+ GlobalOpenList = OpenP->NextGlobalOpen;
+
+ } else {
+
+ TmpOpen = GlobalOpenList;
+
+ while (TmpOpen->NextGlobalOpen != OpenP) {
+
+ TmpOpen = TmpOpen->NextGlobalOpen;
+
+ }
+
+ TmpOpen->NextGlobalOpen = OpenP->NextGlobalOpen;
+
+ }
+
+ RELEASE_SPIN_LOCK(&GlobalOpenListLock);
+
+ ObDereferenceObject((PVOID)OpenP->FileObject);
+ NdisDereferenceAdapter(OpenP->AdapterHandle);
+ NdisDereferenceProtocol(OpenP->ProtocolHandle);
+ ExFreePool((PVOID)OpenP);
+
+ }
+
+}
+
+
+VOID
+NdisCompleteCloseAdapter(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS Status
+ )
+
+{
+ PNDIS_OPEN_BLOCK Open = (PNDIS_OPEN_BLOCK) NdisBindingContext;
+ PNDIS_OPEN_BLOCK TmpOpen;
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisCompleteCloseAdapter\n");
+ }
+ IF_ERROR_CHK {
+ if (!DbgIsNonPaged(NdisBindingContext)) {
+ NdisPrint1("NdisCompleteCloseAdapter: Handle not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(NdisBindingContext)) {
+ NdisPrint1("NdisCompleteCloseAdapter: Binding Context not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.CloseAdapterCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Status
+ );
+
+ NdisDeQueueOpenOnAdapter(Open, Open->AdapterHandle);
+ NdisDeQueueOpenOnProtocol(Open, Open->ProtocolHandle);
+
+ NdisDereferenceProtocol(Open->ProtocolHandle);
+ NdisDereferenceAdapter(Open->AdapterHandle);
+ NdisFreeSpinLock(&Open->SpinLock);
+
+ //
+ // This sends an IRP_MJ_CLOSE IRP.
+ //
+
+ ObDereferenceObject((PVOID)(Open->FileObject));
+
+ //
+ // Remove from global list
+ //
+ ACQUIRE_SPIN_LOCK(&GlobalOpenListLock);
+
+ if (GlobalOpenList == Open) {
+
+ GlobalOpenList = Open->NextGlobalOpen;
+
+ } else {
+
+ TmpOpen = GlobalOpenList;
+
+ while (TmpOpen->NextGlobalOpen != Open) {
+
+ TmpOpen = TmpOpen->NextGlobalOpen;
+
+ }
+
+ TmpOpen->NextGlobalOpen = Open->NextGlobalOpen;
+
+ }
+
+ RELEASE_SPIN_LOCK(&GlobalOpenListLock);
+
+ ExFreePool((PVOID)(NdisBindingContext));
+}
+
+
+
+
+BOOLEAN
+NdisReferenceRef(
+ IN PREFERENCE RefP
+ )
+
+/*++
+
+Routine Description:
+
+ Adds a reference to an object.
+
+Arguments:
+
+ RefP - A pointer to the REFERENCE portion of the object.
+
+Return Value:
+
+ TRUE if the reference was added.
+ FALSE if the object was closing.
+
+--*/
+
+{
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisReferenceRef\n");
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(RefP)) {
+ NdisPrint1("NdisReferenceRef: NULL Reference address\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(RefP)) {
+ NdisPrint1("NdisReferenceRef: Reference not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ ACQUIRE_SPIN_LOCK(&RefP->SpinLock);
+
+ if (RefP->Closing) {
+ RELEASE_SPIN_LOCK(&RefP->SpinLock);
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisReferenceRef\n");
+ return FALSE;
+ }
+
+ ++(RefP->ReferenceCount);
+
+ RELEASE_SPIN_LOCK(&RefP->SpinLock);
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisReferenceRef\n");
+ return TRUE;
+}
+
+BOOLEAN
+NdisDereferenceRef(
+ PREFERENCE RefP
+ )
+
+/*++
+
+Routine Description:
+
+ Removes a reference to an object.
+
+Arguments:
+
+ RefP - A pointer to the REFERENCE portion of the object.
+
+Return Value:
+
+ TRUE if the reference count is now 0.
+ FALSE otherwise.
+
+--*/
+
+{
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisDereferenceRef\n");
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(RefP)) {
+ NdisPrint1("NdisDereferenceRef: NULL Reference address\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(RefP)) {
+ NdisPrint1("NdisDereferenceRef: Reference not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ ACQUIRE_SPIN_LOCK(&RefP->SpinLock);
+ --(RefP->ReferenceCount);
+ if (RefP->ReferenceCount == 0) {
+ RELEASE_SPIN_LOCK(&RefP->SpinLock);
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisDereferenceRef\n");
+ return TRUE;
+ }
+
+ RELEASE_SPIN_LOCK(&RefP->SpinLock);
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisDereferenceRef\n");
+ return FALSE;
+}
+
+
+VOID
+NdisInitializeRef(
+ PREFERENCE RefP
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize a reference count structure.
+
+Arguments:
+
+ RefP - The structure to be initialized.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisInitializeRef\n");
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(RefP)) {
+ NdisPrint1("NdisInitializeRef: NULL Reference address\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(RefP)) {
+ NdisPrint1("NdisInitializeRef: Reference not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ RefP->Closing = FALSE;
+ RefP->ReferenceCount = 1;
+ NdisAllocateSpinLock(&RefP->SpinLock);
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisInitializeRef\n");
+}
+
+BOOLEAN
+NdisCloseRef(
+ PREFERENCE RefP
+ )
+
+/*++
+
+Routine Description:
+
+ Closes a reference count structure.
+
+Arguments:
+
+ RefP - The structure to be closed.
+
+Return Value:
+
+ FALSE if it was already closing.
+ TRUE otherwise.
+
+--*/
+
+{
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisCloseRef\n");
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(RefP)) {
+ NdisPrint1("NdisCloseRef: NULL Reference address\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(RefP)) {
+ NdisPrint1("NdisCloseRef: Reference not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ ACQUIRE_SPIN_LOCK(&RefP->SpinLock);
+
+ if (RefP->Closing) {
+ RELEASE_SPIN_LOCK(&RefP->SpinLock);
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisCloseRef\n");
+ return FALSE;
+ }
+
+ RefP->Closing = TRUE;
+
+ RELEASE_SPIN_LOCK(&RefP->SpinLock);
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisCloseRef\n");
+ return TRUE;
+}
+
+
+
+BOOLEAN
+NdisQueueOpenOnProtocol(
+ IN PNDIS_OPEN_BLOCK OpenP,
+ IN PNDIS_PROTOCOL_BLOCK ProtP
+ )
+
+/*++
+
+Routine Description:
+
+ Attaches an open block to the list of opens for a protocol.
+
+Arguments:
+
+ OpenP - The open block to be queued.
+ ProtP - The protocol block to queue it to.
+
+Return Value:
+
+ TRUE if the operation is successful.
+ FALSE if the protocol is closing.
+
+--*/
+
+{
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisQueueOpenOnProtocol\n");
+ NdisPrint2(" Protocol: %wZ\n",&ProtP->ProtocolCharacteristics.Name);
+ }
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(OpenP)) {
+ NdisPrint1("NdisQueueOpenOnProtocol: Null Open Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(OpenP)) {
+ NdisPrint1("NdisQueueOpenOnProtocol: Open Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+
+ if (DbgIsNull(ProtP)) {
+ NdisPrint1("NdisQueueOpenOnProtocol: Null Protocol Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(ProtP)) {
+ NdisPrint1("NdisQueueOpenOnProtocol: Protocol Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+
+ }
+ ACQUIRE_SPIN_LOCK(&ProtP->Ref.SpinLock);
+
+ //
+ // Make sure the protocol is not closing.
+ //
+
+ if (ProtP->Ref.Closing) {
+ RELEASE_SPIN_LOCK(&ProtP->Ref.SpinLock);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueOpenOnProtocol\n");
+ return FALSE;
+ }
+
+
+ //
+ // Attach this open at the head of the queue.
+ //
+
+ OpenP->ProtocolNextOpen = ProtP->OpenQueue;
+ ProtP->OpenQueue = OpenP;
+
+
+ RELEASE_SPIN_LOCK(&ProtP->Ref.SpinLock);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueOpenOnProtocol\n");
+ return TRUE;
+}
+
+VOID
+NdisDeQueueOpenOnProtocol(
+ IN PNDIS_OPEN_BLOCK OpenP,
+ IN PNDIS_PROTOCOL_BLOCK ProtP
+ )
+
+/*++
+
+Routine Description:
+
+ Detaches an open block from the list of opens for a protocol.
+
+Arguments:
+
+ OpenP - The open block to be dequeued.
+ ProtP - The protocol block to dequeue it from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisDeQueueOpenOnProtocol\n");
+ NdisPrint2(" Protocol: %wZ\n",&ProtP->ProtocolCharacteristics.Name);
+ }
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(OpenP)) {
+ NdisPrint1("NdisDeQueueOpenOnProtocol: Null Open Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(OpenP)) {
+ NdisPrint1("NdisDeQueueOpenOnProtocol: Open Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+
+ if (DbgIsNull(ProtP)) {
+ NdisPrint1("NdisDeQueueOpenOnProtocol: Null Protocol Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(ProtP)) {
+ NdisPrint1("NdisDeQueueOpenOnProtocol: Protocol Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+
+ }
+
+ ACQUIRE_SPIN_LOCK(&ProtP->Ref.SpinLock);
+
+ //
+ // Find the open on the queue, and remove it.
+ //
+
+ if (ProtP->OpenQueue == OpenP) {
+ ProtP->OpenQueue = OpenP->ProtocolNextOpen;
+ } else {
+ PNDIS_OPEN_BLOCK PP = ProtP->OpenQueue;
+
+ while (PP->ProtocolNextOpen != OpenP) {
+ PP = PP->ProtocolNextOpen;
+ }
+
+ PP->ProtocolNextOpen = PP->ProtocolNextOpen->ProtocolNextOpen;
+ }
+
+ RELEASE_SPIN_LOCK(&ProtP->Ref.SpinLock);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeQueueOpenOnProtocol\n");
+}
+
+VOID
+NdisDeQueueOpenOnMiniport(
+ IN PNDIS_M_OPEN_BLOCK OpenP,
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Detaches an open block from the list of opens for a Miniport.
+
+Arguments:
+
+ OpenP - The open block to be dequeued.
+ Miniport - The Miniport block to dequeue it from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ACQUIRE_SPIN_LOCK(&Miniport->Ref.SpinLock);
+
+ OpenP->References--;
+
+ //
+ // Find the open on the queue, and remove it.
+ //
+
+ if (Miniport->OpenQueue == OpenP) {
+ Miniport->OpenQueue = OpenP->MiniportNextOpen;
+ } else {
+ PNDIS_M_OPEN_BLOCK PP = Miniport->OpenQueue;
+
+ while (PP->MiniportNextOpen != OpenP) {
+ PP = PP->MiniportNextOpen;
+ }
+
+ PP->MiniportNextOpen = PP->MiniportNextOpen->MiniportNextOpen;
+ }
+
+ RELEASE_SPIN_LOCK(&Miniport->Ref.SpinLock);
+}
+
+
+
+BOOLEAN
+NdisFinishOpen(
+ IN PNDIS_OPEN_BLOCK OpenP
+ )
+
+/*++
+
+Routine Description:
+
+ Performs the final functions of NdisOpenAdapter. Called when
+ MacOpenAdapter is done.
+
+Arguments:
+
+ OpenP - The open block to finish up.
+
+Return Value:
+
+ FALSE if the adapter or the protocol is closing.
+ TRUE otherwise.
+
+--*/
+
+{
+ //
+ // Add us to the adapter's queue of opens.
+ //
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisFinishOpen\n");
+ NdisPrint3(" Protocol %wZ is being bound to Adapter %wZ\n",
+ &(OpenP->ProtocolHandle)->ProtocolCharacteristics.Name,
+ &OpenP->AdapterHandle->AdapterName);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(OpenP)) {
+ NdisPrint1("NdisFinishOpen: Null Open Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(OpenP)) {
+ NdisPrint1("NdisFinishOpen: Open Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ if (!NdisQueueOpenOnAdapter(OpenP, OpenP->AdapterHandle)) {
+
+ //
+ // The adapter is closing.
+ //
+ // Call MacCloseAdapter(), don't worry about it completing.
+ //
+
+ (OpenP->MacHandle->MacCharacteristics.CloseAdapterHandler) (
+ OpenP->MacBindingHandle);
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisFinishOpen\n");
+ return FALSE;
+ }
+
+
+ //
+ // Add us to the protocol's queue of opens.
+ //
+
+ if (!NdisQueueOpenOnProtocol(OpenP, OpenP->ProtocolHandle)) {
+
+ //
+ // The protocol is closing.
+ //
+ // Call MacCloseAdapter(), don't worry about it completing.
+ //
+
+ (OpenP->MacHandle->MacCharacteristics.CloseAdapterHandler) (
+ OpenP->MacBindingHandle);
+
+ //
+ // Undo the queueing we just did.
+ //
+
+ NdisDeQueueOpenOnAdapter(OpenP, OpenP->AdapterHandle);
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisFinishOpen\n");
+ return FALSE;
+ }
+
+
+ //
+ // Both queueings succeeded.
+ //
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisFinishOpen\n");
+ return TRUE;
+}
+
+NTSTATUS
+NdisCreateIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ The handle for IRP_MJ_CREATE IRPs.
+
+Arguments:
+
+ DeviceObject - The adapter's device object.
+ Irp - The IRP.
+
+Return Value:
+
+ STATUS_SUCCESS if it should be.
+
+--*/
+
+{
+
+ PIO_STACK_LOCATION IrpSp;
+ PFILE_FULL_EA_INFORMATION IrpEaInfo;
+ PNDIS_USER_OPEN_CONTEXT OpenContext;
+ NTSTATUS Status = STATUS_SUCCESS;
+ PNDIS_ADAPTER_BLOCK AdapterBlock;
+ BOOLEAN IsAMiniport;
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisCreateIrpHandler\n");
+ IF_ERROR_CHK {
+ if (DbgIsNull(Irp)) {
+ NdisPrint1(": Null Irp\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(Irp)) {
+ NdisPrint1(": Irp not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ AdapterBlock = (PNDIS_ADAPTER_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1);
+ IsAMiniport = (AdapterBlock->DeviceObject == NULL);
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+ IrpEaInfo = (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
+
+ if (IrpEaInfo == NULL) {
+
+ //
+ // This is a user-mode open, do whatever.
+ //
+
+ OpenContext = (PNDIS_USER_OPEN_CONTEXT)
+ ExAllocatePoolWithTag(NonPagedPool, sizeof(NDIS_USER_OPEN_CONTEXT), ' DN');
+
+ if (OpenContext == NULL) {
+
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+
+ OpenContext->DeviceObject = DeviceObject;
+
+ OpenContext->AdapterBlock = AdapterBlock;
+ OpenContext->OidCount = 0;
+ OpenContext->OidArray = NULL;
+
+ IrpSp->FileObject->FsContext = (PVOID)OpenContext;
+ IrpSp->FileObject->FsContext2 = (PVOID)NDIS_OPEN_QUERY_STATISTICS;
+
+ if (IsAMiniport) {
+ Status = NdisMQueryOidList((PNDIS_M_USER_OPEN_CONTEXT)OpenContext, Irp);
+ } else {
+ Status = NdisQueryOidList(OpenContext, Irp);
+ }
+
+ if (Status != STATUS_SUCCESS) {
+ ExFreePool (OpenContext);
+ }
+
+ }
+
+ } else {
+
+ //
+ // This is an internal open, verify the EA.
+ //
+
+ if ((IrpEaInfo->EaNameLength != sizeof(NdisInternalEaName)) ||
+ (RtlCompareMemory(IrpEaInfo->EaName, NdisInternalEaName, sizeof(NdisInternalEaName)) !=
+ sizeof(NdisInternalEaName)) ||
+ (IrpEaInfo->EaValueLength != sizeof(NdisInternalEaValue)) ||
+ (RtlCompareMemory(&IrpEaInfo->EaName[IrpEaInfo->EaNameLength+1],
+ NdisInternalEaValue, sizeof(NdisInternalEaValue)) !=
+ sizeof(NdisInternalEaValue))) {
+
+ //
+ // Something is wrong, reject it.
+ //
+
+ Status = STATUS_UNSUCCESSFUL;
+
+ } else {
+
+ //
+ // It checks out, just return success and everything
+ // else is done directly using the device object.
+ //
+
+ IrpSp->FileObject->FsContext = NULL;
+ IrpSp->FileObject->FsContext2 = (PVOID)NDIS_OPEN_INTERNAL;
+
+ }
+ }
+
+ Irp->IoStatus.Status = Status;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisCreateIrplHandler\n");
+ return Status;
+}
+
+
+
+NTSTATUS
+NdisQueryOidList(
+ PNDIS_USER_OPEN_CONTEXT OpenContext,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will take care of querying the complete OID
+ list for the MAC and filling in OpenContext->OidArray
+ with the ones that are statistics. It blocks when the
+ MAC pends and so is synchronous.
+
+Arguments:
+
+ OpenContext - The open context.
+ Irp = The IRP that the open was done on (used at completion
+ to distinguish the request).
+
+Return Value:
+
+ STATUS_SUCCESS if it should be.
+
+--*/
+
+{
+
+ NDIS_QUERY_OPEN_REQUEST OpenRequest;
+ NDIS_STATUS NdisStatus;
+ PNDIS_OID TmpBuffer;
+ ULONG TmpBufferLength;
+ UINT i, j;
+
+ //
+ // First query the OID list with no buffer, to find out
+ // how big it should be.
+ //
+
+ KeInitializeEvent(
+ &OpenRequest.Event,
+ NotificationEvent,
+ FALSE
+ );
+
+ OpenRequest.Irp = Irp;
+
+ OpenRequest.Request.RequestType = NdisRequestQueryStatistics;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_SUPPORTED_LIST;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBuffer = NULL;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBufferLength = 0;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded = 0;
+
+ NdisStatus =
+ (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler) (
+ OpenContext->AdapterBlock->MacAdapterContext,
+ &OpenRequest.Request);
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &OpenRequest.Event,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ NdisStatus = OpenRequest.NdisStatus;
+
+ } else if ((NdisStatus != NDIS_STATUS_INVALID_LENGTH) &&
+ (NdisStatus != NDIS_STATUS_BUFFER_TOO_SHORT)) {
+
+ return(NdisStatus);
+
+ }
+
+ //
+ // Now we know how much is needed, allocate temp storage...
+ //
+
+ TmpBufferLength = OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded;
+ TmpBuffer = ExAllocatePoolWithTag(NonPagedPool, TmpBufferLength, ' DN');
+
+ if (TmpBuffer == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // ...and query the real list.
+ //
+
+ KeResetEvent(
+ &OpenRequest.Event
+ );
+
+
+ OpenRequest.Request.RequestType = NdisRequestQueryStatistics;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_SUPPORTED_LIST;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBuffer = TmpBuffer;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBufferLength = TmpBufferLength;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded = 0;
+
+ NdisStatus =
+ (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler) (
+ OpenContext->AdapterBlock->MacAdapterContext,
+ &OpenRequest.Request);
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &OpenRequest.Event,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ NdisStatus = OpenRequest.NdisStatus;
+
+ }
+
+ ASSERT (NdisStatus == NDIS_STATUS_SUCCESS);
+
+
+ //
+ // Now go through the buffer, counting the statistics OIDs.
+ //
+
+ for (i=0; i<TmpBufferLength/sizeof(NDIS_OID); i++) {
+ if ((TmpBuffer[i] & 0x00ff0000) == 0x00020000) {
+ ++OpenContext->OidCount;
+ }
+ }
+
+ //
+ // Now allocate storage for the real OID array.
+ //
+
+ OpenContext->OidArray = ExAllocatePoolWithTag (NonPagedPool, OpenContext->OidCount * sizeof(NDIS_OID), ' DN');
+
+ if (OpenContext->OidArray == NULL) {
+ ExFreePool (TmpBuffer);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now go through the buffer, copying the statistics OIDs.
+ //
+
+ j = 0;
+ for (i=0; i<TmpBufferLength/sizeof(NDIS_OID); i++) {
+
+ if ((TmpBuffer[i] & 0x00ff0000) == 0x00020000) {
+ OpenContext->OidArray[j] = TmpBuffer[i];
+ ++j;
+ }
+ }
+
+ ASSERT (j == OpenContext->OidCount);
+
+ ExFreePool (TmpBuffer);
+ return STATUS_SUCCESS;
+}
+
+#define NDIS_STATISTICS_HEADER_SIZE FIELD_OFFSET(NDIS_STATISTICS_VALUE,Data[0])
+
+
+
+NTSTATUS
+NdisDeviceControlIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ The handle for IRP_MJ_DEVICE_CONTROL IRPs.
+
+Arguments:
+
+ DeviceObject - The adapter's device object.
+ Irp - The IRP.
+
+Return Value:
+
+ STATUS_SUCCESS if it should be.
+
+--*/
+
+{
+
+ PIO_STACK_LOCATION IrpSp;
+ PNDIS_USER_OPEN_CONTEXT OpenContext;
+ PNDIS_QUERY_GLOBAL_REQUEST GlobalRequest;
+ PNDIS_QUERY_ALL_REQUEST AllRequest;
+ NDIS_STATUS NdisStatus;
+ UINT CurrentOid;
+ ULONG BytesWritten, BytesWrittenThisOid;
+ PUCHAR Buffer;
+ ULONG BufferLength;
+ NTSTATUS Status = STATUS_SUCCESS;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ BOOLEAN LocalLock;
+ KIRQL OldIrql;
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisDeviceControlIrpHandler\n");
+ IF_ERROR_CHK {
+ if (DbgIsNull(Irp)) {
+ NdisPrint1(": Null Irp\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(Irp)) {
+ NdisPrint1(": Irp not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ IoMarkIrpPending (Irp);
+ Irp->IoStatus.Status = STATUS_PENDING;
+ Irp->IoStatus.Information = 0;
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ if (IrpSp->FileObject->FsContext2 != (PVOID)NDIS_OPEN_QUERY_STATISTICS) {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
+
+ case IOCTL_NDIS_QUERY_GLOBAL_STATS:
+
+ //
+ // Allocate a request.
+ //
+
+ OpenContext = IrpSp->FileObject->FsContext;
+ GlobalRequest = (PNDIS_QUERY_GLOBAL_REQUEST)
+ ExAllocatePoolWithTag(NonPagedPool, sizeof(NDIS_QUERY_GLOBAL_REQUEST), ' DN');
+
+ if (GlobalRequest == NULL) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ GlobalRequest->Irp = Irp;
+
+ if (OpenContext->AdapterBlock->DeviceObject == NULL) {
+
+ Miniport = (PNDIS_MINIPORT_BLOCK)(OpenContext->AdapterBlock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ } else {
+
+ Miniport = NULL;
+
+ }
+
+ //
+ // Fill in the NDIS request.
+ //
+
+ GlobalRequest->Request.RequestType = NdisRequestQueryStatistics;
+ GlobalRequest->Request.DATA.QUERY_INFORMATION.Oid =
+ *((PULONG)(Irp->AssociatedIrp.SystemBuffer));
+ GlobalRequest->Request.DATA.QUERY_INFORMATION.InformationBuffer =
+ MmGetSystemAddressForMdl (Irp->MdlAddress);
+ GlobalRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength =
+ MmGetMdlByteCount (Irp->MdlAddress);
+ GlobalRequest->Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
+ GlobalRequest->Request.DATA.QUERY_INFORMATION.BytesNeeded = 0;
+
+
+ if (Miniport != NULL) {
+ PNDIS_REQUEST_RESERVED Reserved;
+
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(&(GlobalRequest->Request));
+ Reserved->Next = NULL;
+ Miniport->LastPendingRequest = &(GlobalRequest->Request);
+
+ if (Miniport->FirstPendingRequest == NULL) {
+
+ Miniport->FirstPendingRequest = &(GlobalRequest->Request);
+
+ } else {
+
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Miniport->LastPendingRequest)->Next =
+ &(GlobalRequest->Request);
+
+ }
+
+ if (Miniport->MiniportRequest == NULL) {
+
+ Miniport->RunDoRequests = TRUE;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+
+ }
+
+ //
+ // If we were able to grab the local lock then we can do some
+ // deferred processing now.
+ //
+
+ if ( LocalLock ) {
+ if (!Miniport->ProcessingDeferred) {
+ MiniportProcessDeferred(Miniport);
+ }
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ KeLowerIrql(OldIrql);
+
+ } else {
+
+ //
+ // Pass the request to the MAC.
+ //
+
+ NdisStatus =
+ (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler) (
+ OpenContext->AdapterBlock->MacAdapterContext,
+ &GlobalRequest->Request);
+
+ //
+ // NdisCompleteQueryStatistics handles the completion.
+ //
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+ NdisCompleteQueryStatistics(
+ (NDIS_HANDLE)OpenContext->AdapterBlock,
+ &GlobalRequest->Request,
+ NdisStatus);
+ }
+
+ }
+
+ Status = STATUS_PENDING;
+
+ break;
+
+ case IOCTL_NDIS_QUERY_ALL_STATS:
+
+
+ //
+ // Allocate a request.
+ //
+
+ OpenContext = IrpSp->FileObject->FsContext;
+ AllRequest = (PNDIS_QUERY_ALL_REQUEST)
+ ExAllocatePoolWithTag(NonPagedPool, sizeof(NDIS_QUERY_ALL_REQUEST), ' DN');
+
+ if (AllRequest == NULL) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ if (OpenContext->AdapterBlock->DeviceObject == NULL) {
+
+ Miniport = (PNDIS_MINIPORT_BLOCK)(OpenContext->AdapterBlock);
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ } else {
+
+ Miniport = NULL;
+
+ }
+
+ AllRequest->Irp = Irp;
+
+ Buffer = (PUCHAR)MmGetSystemAddressForMdl (Irp->MdlAddress);
+ BufferLength = MmGetMdlByteCount (Irp->MdlAddress);
+ BytesWritten = 0;
+
+ KeInitializeEvent(
+ &AllRequest->Event,
+ NotificationEvent,
+ FALSE
+ );
+
+ NdisStatus = NDIS_STATUS_SUCCESS;
+
+ for (CurrentOid = 0; CurrentOid<OpenContext->OidCount; CurrentOid++) {
+
+ //
+ // We need room for an NDIS_STATISTICS_VALUE (OID,
+ // Length, Data).
+ //
+
+ if (BufferLength < (ULONG)NDIS_STATISTICS_HEADER_SIZE) {
+ NdisStatus = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ AllRequest->Request.RequestType = NdisRequestQueryStatistics;
+
+ AllRequest->Request.DATA.QUERY_INFORMATION.Oid =
+ OpenContext->OidArray[CurrentOid];
+ AllRequest->Request.DATA.QUERY_INFORMATION.InformationBuffer =
+ Buffer + NDIS_STATISTICS_HEADER_SIZE;
+ AllRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength =
+ BufferLength - NDIS_STATISTICS_HEADER_SIZE;
+
+ AllRequest->Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
+ AllRequest->Request.DATA.QUERY_INFORMATION.BytesNeeded = 0;
+
+ if (Miniport != NULL) {
+
+ PNDIS_REQUEST_RESERVED Reserved;
+
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(&(AllRequest->Request));
+ Reserved->Next = NULL;
+ Miniport->LastPendingRequest = &(AllRequest->Request);
+
+ if (Miniport->FirstPendingRequest == NULL) {
+
+ Miniport->FirstPendingRequest = &(AllRequest->Request);
+
+ } else {
+
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Miniport->LastPendingRequest)->Next =
+ &(AllRequest->Request);
+
+ }
+
+ if (Miniport->MiniportRequest == NULL) {
+
+ Miniport->RunDoRequests = TRUE;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ }
+
+ //
+ // If we were able to grab the local lock then we can do some
+ // deferred processing now.
+ //
+
+ if ( LocalLock ) {
+ if (!Miniport->ProcessingDeferred) {
+ MiniportProcessDeferred(Miniport);
+ }
+ }
+
+ NdisStatus = NDIS_STATUS_PENDING;
+
+ } else {
+
+ NdisStatus =
+ (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler) (
+ OpenContext->AdapterBlock->MacAdapterContext,
+ &AllRequest->Request);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ if (Miniport != NULL) {
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ KeLowerIrql(OldIrql);
+ }
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &AllRequest->Event,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ NdisStatus = AllRequest->NdisStatus;
+
+ if (Miniport != NULL) {
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ LOCK_MINIPORT(Miniport, LocalLock);
+ }
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ PNDIS_STATISTICS_VALUE StatisticsValue =
+ (PNDIS_STATISTICS_VALUE)Buffer;
+
+ //
+ // Create the equivalent of an NDIS_STATISTICS_VALUE
+ // element for this OID value (the data itself was
+ // already written in the right place.
+ //
+
+ StatisticsValue->Oid = OpenContext->OidArray[CurrentOid];
+ StatisticsValue->DataLength = AllRequest->Request.DATA.QUERY_INFORMATION.BytesWritten;
+
+ //
+ // Advance our pointers.
+ //
+
+ BytesWrittenThisOid =
+ AllRequest->Request.DATA.QUERY_INFORMATION.BytesWritten +
+ NDIS_STATISTICS_HEADER_SIZE;
+ Buffer += BytesWrittenThisOid;
+ BufferLength -= BytesWrittenThisOid;
+ BytesWritten += BytesWrittenThisOid;
+
+ } else {
+
+ break;
+
+ }
+
+ KeResetEvent(
+ &AllRequest->Event
+ );
+
+ }
+
+ if (Miniport != NULL) {
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ KeLowerIrql(OldIrql);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_INVALID_LENGTH) {
+ Status = STATUS_BUFFER_OVERFLOW;
+ } else if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ Status = STATUS_UNSUCCESSFUL;
+ }
+
+ Irp->IoStatus.Information = BytesWritten;
+ Irp->IoStatus.Status = Status;
+
+ break;
+
+ default:
+
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ }
+
+ if (Status != STATUS_PENDING) {
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ }
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisCreateIrplHandler\n");
+ return Status;
+}
+
+
+
+VOID
+NdisCompleteQueryStatistics(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS Status
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by MACs when they have completed
+ processing of a MacQueryGlobalStatistics call.
+
+Arguments:
+
+ NdisAdapterHandle - The NDIS adapter context.
+ NdisRequest - The request that has been completed.
+ Status - The status of the request.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_ADAPTER_BLOCK AdapterBlock = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
+ PNDIS_QUERY_GLOBAL_REQUEST GlobalRequest;
+ PNDIS_QUERY_ALL_REQUEST AllRequest;
+ PNDIS_QUERY_OPEN_REQUEST OpenRequest;
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+
+ //
+ // Rely on the fact that all our request structures start with
+ // the same fields: Irp followed by the NdisRequest.
+ //
+
+ GlobalRequest = CONTAINING_RECORD (NdisRequest, NDIS_QUERY_GLOBAL_REQUEST, Request);
+ Irp = GlobalRequest->Irp;
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ switch (IrpSp->MajorFunction) {
+
+ case IRP_MJ_CREATE:
+
+ //
+ // This request is one of the ones made during an open,
+ // while we are trying to determine the OID list. We
+ // set the event we are waiting for, the open code
+ // takes care of the rest.
+ //
+
+ OpenRequest = (PNDIS_QUERY_OPEN_REQUEST)GlobalRequest;
+
+ OpenRequest->NdisStatus = Status;
+ KeSetEvent(
+ &OpenRequest->Event,
+ 0L,
+ FALSE);
+
+ break;
+
+ case IRP_MJ_DEVICE_CONTROL:
+
+ //
+ // This is a real user request, process it as such.
+ //
+
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
+
+ case IOCTL_NDIS_QUERY_GLOBAL_STATS:
+
+ //
+ // A single query, complete the IRP.
+ //
+
+ Irp->IoStatus.Information =
+ NdisRequest->DATA.QUERY_INFORMATION.BytesWritten;
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ } else if (Status == NDIS_STATUS_INVALID_LENGTH) {
+ Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
+ } else {
+ Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; // what else ?
+ }
+
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ ExFreePool (GlobalRequest);
+ break;
+
+ case IOCTL_NDIS_QUERY_ALL_STATS:
+
+ //
+ // An "all" query.
+ //
+
+ AllRequest = (PNDIS_QUERY_ALL_REQUEST)GlobalRequest;
+
+ AllRequest->NdisStatus = Status;
+ KeSetEvent(
+ &AllRequest->Event,
+ 0L,
+ FALSE);
+
+ break;
+
+ }
+
+ break;
+
+ }
+
+}
+
+
+
+NTSTATUS
+NdisCloseIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ The handle for IRP_MJ_CLOSE IRPs.
+
+Arguments:
+
+ DeviceObject - The adapter's device object.
+ Irp - The IRP.
+
+Return Value:
+
+ STATUS_SUCCESS if it should be.
+
+--*/
+
+{
+
+ PIO_STACK_LOCATION IrpSp;
+ PNDIS_USER_OPEN_CONTEXT OpenContext;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisCloseIrpHandler\n");
+ IF_ERROR_CHK {
+ if (DbgIsNull(Irp)) {
+ NdisPrint1(": Null Irp\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(Irp)) {
+ NdisPrint1(": Irp not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ if (IrpSp->FileObject->FsContext2 == (PVOID)NDIS_OPEN_INTERNAL) {
+
+ //
+ // An internal open, nothing needs to be done.
+ //
+
+ } else {
+
+ //
+ // Free the query context.
+ //
+
+ ASSERT (IrpSp->FileObject->FsContext2 == (PVOID)NDIS_OPEN_QUERY_STATISTICS);
+
+ OpenContext = IrpSp->FileObject->FsContext;
+ ExFreePool (OpenContext->OidArray);
+ ExFreePool (OpenContext);
+
+ }
+
+ Irp->IoStatus.Status = Status;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisCloseIrplHandler\n");
+ return Status;
+}
+
+NTSTATUS
+NdisSuccessIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ The "success handler" for any IRPs that we can ignore.
+
+Arguments:
+
+ DeviceObject - The adapter's device object.
+ Irp - The IRP.
+
+Return Value:
+
+ Always STATUS_SUCCESS.
+
+--*/
+
+{
+
+ DeviceObject; // to avoid "unused formal parameter" warning
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisSuccessIrplHandler\n");
+ IF_ERROR_CHK {
+ if (DbgIsNull(Irp)) {
+ NdisPrint1(": Null Irp\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(Irp)) {
+ NdisPrint1(": Irp not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisSuccessIrplHandler\n");
+ return STATUS_SUCCESS;
+}
+
+
+VOID
+NdisKillOpenAndNotifyProtocol(
+ IN PNDIS_OPEN_BLOCK OldOpenP
+ )
+
+/*++
+
+Routine Description:
+
+ Closes an open and notifies the protocol; used when the
+ close is internally generated by the NDIS wrapper (due to
+ a protocol or adapter deregistering with outstanding opens).
+
+Arguments:
+
+ OldOpenP - The open to be closed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Indicate the status to the protocol.
+ //
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisKillOpenAndNotifyProtocol\n");
+ NdisPrint3(" Closing Adapter %wZ and notifying Protocol %wZ\n",
+ &OldOpenP->AdapterHandle->AdapterName,
+ &(OldOpenP->ProtocolHandle)->ProtocolCharacteristics.Name);
+ }
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(OldOpenP)) {
+ NdisPrint1("NdisKillOpenAndNotifyProtocol: Null Open Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(OldOpenP)) {
+ NdisPrint1("NdisKillOpenAndNotifyProtocol: Open Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ (OldOpenP->ProtocolHandle->ProtocolCharacteristics.StatusHandler) (
+ OldOpenP->ProtocolBindingContext,
+ NDIS_STATUS_CLOSING,
+ NULL,
+ 0); // need real reason here
+
+
+ //
+ // Now KillOpen will do the real work.
+ //
+
+ if (OldOpenP->AdapterHandle->DeviceObject == NULL) {
+ //
+ // Miniport
+ //
+ (void)NdisMKillOpen(OldOpenP);
+ } else {
+ //
+ // Mac
+ //
+ (void)NdisKillOpen(OldOpenP);
+ }
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillOpenAndNotifyProtocol\n");
+}
+
+
+BOOLEAN
+NdisKillOpen(
+ PNDIS_OPEN_BLOCK OldOpenP
+ )
+
+/*++
+
+Routine Description:
+
+ Closes an open. Used when NdisCloseAdapter is called, and also
+ for internally generated closes.
+
+Arguments:
+
+ OldOpenP - The open to be closed.
+
+Return Value:
+
+ TRUE if the open finished, FALSE if it pended.
+
+--*/
+
+{
+ PNDIS_OPEN_BLOCK TmpOpen;
+ PFILE_OBJECT FileObject = OldOpenP->FileObject;
+
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisKillOpen\n");
+ NdisPrint3(" Closing Adapter %wZ as requested by %wZ\n",
+ &OldOpenP->AdapterHandle->AdapterName,
+ &(OldOpenP->ProtocolHandle)->ProtocolCharacteristics.Name);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(OldOpenP)) {
+ NdisPrint1("NdisKillOpen: Null Open Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(OldOpenP)) {
+ NdisPrint1("NdisKillOpen: Open Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ ACQUIRE_SPIN_LOCK(&OldOpenP->SpinLock);
+
+ //
+ // See if this open is already closing.
+ //
+
+ if (OldOpenP->Closing) {
+ RELEASE_SPIN_LOCK(&OldOpenP->SpinLock);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillOpen\n");
+ return TRUE;
+ }
+
+
+ //
+ // Indicate to others that this open is closing.
+ //
+
+ OldOpenP->Closing = TRUE;
+ RELEASE_SPIN_LOCK(&OldOpenP->SpinLock);
+
+ //
+ // Inform the MAC.
+ //
+
+ if ((OldOpenP->MacHandle->MacCharacteristics.CloseAdapterHandler) (
+ OldOpenP->MacBindingHandle) == NDIS_STATUS_PENDING) {
+
+ //
+ // MacCloseAdapter pended, will complete later.
+ //
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillOpen\n");
+ return FALSE;
+ }
+
+ //
+ // Remove the reference for this open.
+ //
+ ObDereferenceObject((PVOID)FileObject);
+
+ //
+ // Remove us from the adapter and protocol open queues.
+ //
+
+ NdisDeQueueOpenOnAdapter(OldOpenP, OldOpenP->AdapterHandle);
+ NdisDeQueueOpenOnProtocol(OldOpenP, OldOpenP->ProtocolHandle);
+
+
+ //
+ // MacCloseAdapter did not pend; we ignore the return code.
+ //
+
+ NdisDereferenceProtocol(OldOpenP->ProtocolHandle);
+ NdisDereferenceAdapter(OldOpenP->AdapterHandle);
+
+ NdisFreeSpinLock(&OldOpenP->SpinLock);
+
+ //
+ // Remove from global adpater list
+ //
+ ACQUIRE_SPIN_LOCK(&GlobalOpenListLock);
+
+ if (GlobalOpenList == OldOpenP) {
+
+ GlobalOpenList = OldOpenP->NextGlobalOpen;
+
+ } else {
+
+ TmpOpen = GlobalOpenList;
+
+ while (TmpOpen->NextGlobalOpen != OldOpenP) {
+
+ TmpOpen = TmpOpen->NextGlobalOpen;
+
+ }
+
+ TmpOpen->NextGlobalOpen = OldOpenP->NextGlobalOpen;
+
+ }
+
+ RELEASE_SPIN_LOCK(&GlobalOpenListLock);
+
+ ExFreePool((PVOID)OldOpenP);
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillOpen\n");
+ return TRUE;
+}
+
+
+BOOLEAN
+NdisQueueAdapterOnMac(
+ IN PNDIS_ADAPTER_BLOCK AdaptP,
+ IN PNDIS_MAC_BLOCK MacP
+ )
+
+/*++
+
+Routine Description:
+
+ Adds an adapter to a list of adapters for a MAC.
+
+Arguments:
+
+ AdaptP - The adapter block to queue.
+ MacP - The MAC block to queue it to.
+
+Return Value:
+
+ FALSE if the MAC is closing.
+ TRUE otherwise.
+
+--*/
+
+{
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisQueueAdapterOnMac\n");
+ NdisPrint2(" Adapter %wZ being added to MAC list\n",&AdaptP->MacHandle->MacCharacteristics.Name);
+ }
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(AdaptP)) {
+ NdisPrint1("NdisQueueAdapterOnMac: Null Adapter Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(AdaptP)) {
+ NdisPrint1("NdisQueueAdapterOnMac: Adapter Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(MacP)) {
+ NdisPrint1("NdisQueueAdapterOnMac: Null Mac Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(MacP)) {
+ NdisPrint1("NdisQueueAdapterOnMac: Mac Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ ACQUIRE_SPIN_LOCK(&MacP->Ref.SpinLock);
+
+ //
+ // Make sure the MAC is not closing.
+ //
+
+ if (MacP->Ref.Closing) {
+ RELEASE_SPIN_LOCK(&MacP->Ref.SpinLock);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueAdapterOnMac\n");
+ return FALSE;
+ }
+
+
+ //
+ // Add this adapter at the head of the queue
+ //
+
+ AdaptP->NextAdapter = MacP->AdapterQueue;
+ MacP->AdapterQueue = AdaptP;
+
+ RELEASE_SPIN_LOCK(&MacP->Ref.SpinLock);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueAdapterOnMac\n");
+ return TRUE;
+}
+
+
+VOID
+NdisDeQueueAdapterOnMac(
+ PNDIS_ADAPTER_BLOCK AdaptP,
+ PNDIS_MAC_BLOCK MacP
+ )
+
+/*++
+
+Routine Description:
+
+ Removes an adapter from a list of adapters for a MAC.
+
+Arguments:
+
+ AdaptP - The adapter block to dequeue.
+ MacP - The MAC block to dequeue it from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisDeQueueAdapterOnMac\n");
+ NdisPrint2(" Adapter %wZ being removed from MAC list\n",&AdaptP->MacHandle->MacCharacteristics.Name);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(AdaptP)) {
+ NdisPrint1("NdisDeQueueAdapterOnMac: Null Adapter Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(AdaptP)) {
+ NdisPrint1("NdisDeQueueAdapterOnMac: Adapter Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(MacP)) {
+ NdisPrint1("NdisDeQueueAdapterOnMac: Null Mac Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(MacP)) {
+ NdisPrint1("NdisDeQueueAdapterOnMac: Mac Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ ACQUIRE_SPIN_LOCK(&MacP->Ref.SpinLock);
+
+ //
+ // Find the MAC on the queue, and remove it.
+ //
+
+ if (MacP->AdapterQueue == AdaptP) {
+ MacP->AdapterQueue = AdaptP->NextAdapter;
+ } else {
+ PNDIS_ADAPTER_BLOCK MP = MacP->AdapterQueue;
+
+ while (MP->NextAdapter != AdaptP) {
+ MP = MP->NextAdapter;
+ }
+
+ MP->NextAdapter = MP->NextAdapter->NextAdapter;
+ }
+
+ RELEASE_SPIN_LOCK(&MacP->Ref.SpinLock);
+
+ if (MacP->Unloading && (MacP->AdapterQueue == (PNDIS_ADAPTER_BLOCK)NULL)) {
+
+ KeSetEvent(
+ &MacP->AdaptersRemovedEvent,
+ 0L,
+ FALSE
+ );
+
+ }
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeQueueAdapterOnMac\n");
+}
+
+
+
+VOID
+NdisKillAdapter(
+ PNDIS_ADAPTER_BLOCK OldAdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Removes an adapter. Called by NdisDeregisterAdapter and also
+ for internally generated deregistrations.
+
+Arguments:
+
+ OldAdaptP - The adapter to be removed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // If the adapter is already closing, return.
+ //
+
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisKillAdapter\n");
+ NdisPrint2(" Removing Adapter %s\n",OldAdaptP->AdapterName.Buffer);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(OldAdaptP)) {
+ NdisPrint1("NdisKillAdapter: Null Adapter Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(OldAdaptP)) {
+ NdisPrint1("NdisKillAdapter: Adapter Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ if (!NdisCloseRef(&OldAdaptP->Ref)) {
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillAdapter\n");
+ return;
+ }
+
+
+ //
+ // Kill all the opens for this adapter.
+ //
+
+ while (OldAdaptP->OpenQueue != (PNDIS_OPEN_BLOCK)NULL) {
+
+ //
+ // This removes it from the adapter's OpenQueue etc.
+ //
+
+ NdisKillOpenAndNotifyProtocol(OldAdaptP->OpenQueue);
+ }
+
+
+ //
+ // Remove the adapter from the MAC's list.
+ //
+
+ NdisDeQueueAdapterOnMac(OldAdaptP, OldAdaptP->MacHandle);
+
+ NdisDereferenceAdapter(OldAdaptP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillAdapter\n");
+}
+
+
+
+VOID
+NdisDereferenceAdapter(
+ PNDIS_ADAPTER_BLOCK AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Dereferences an adapter. If the reference count goes to zero,
+ it frees resources associated with the adapter.
+
+Arguments:
+
+ AdaptP - The adapter to be dereferenced.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if (NdisDereferenceRef(&AdaptP->Ref)) {
+
+ //
+ // Free resource memory
+ //
+
+ if (AdaptP->Resources != NULL) {
+
+ ExFreePool(AdaptP->Resources);
+
+ }
+
+ ExFreePool(AdaptP->AdapterName.Buffer);
+
+ if (AdaptP->Master) {
+ UINT i;
+ ULONG MapRegistersPerChannel =
+ ((AdaptP->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2;
+ KIRQL OldIrql;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ for (i=0; i<AdaptP->PhysicalMapRegistersNeeded; i++) {
+ IoFreeMapRegisters(
+ AdaptP->SystemAdapterObject,
+ AdaptP->MapRegisters[i].MapRegister,
+ MapRegistersPerChannel);
+ }
+
+ KeLowerIrql(OldIrql);
+ }
+
+ if ((AdaptP->NumberOfPorts > 0) && AdaptP->InitialPortMapped) {
+ MmUnmapIoSpace (AdaptP->InitialPortMapping, AdaptP->NumberOfPorts);
+ }
+
+ NdisDereferenceMac(AdaptP->MacHandle);
+ IoDeleteDevice(AdaptP->DeviceObject);
+
+ }
+}
+
+
+BOOLEAN
+NdisQueueOpenOnAdapter(
+ IN PNDIS_OPEN_BLOCK OpenP,
+ IN PNDIS_ADAPTER_BLOCK AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Adds an open to a list of opens for an adapter.
+
+Arguments:
+
+ OpenP - The open block to queue.
+ AdaptP - The adapter block to queue it to.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ // attach ourselves to the adapter object linked list of opens
+ ACQUIRE_SPIN_LOCK(&AdaptP->Ref.SpinLock);
+
+ //
+ // Make sure the adapter is not closing.
+ //
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisQueueAdapterOnAdapter\n");
+ NdisPrint2(" Open being added to list for Adapter %s\n",AdaptP->AdapterName.Buffer);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(OpenP)) {
+ NdisPrint1("NdisQueueOpenOnAdapter: Null Open Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(OpenP)) {
+ NdisPrint1("NdisQueueOpenOnAdapter: Open Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(AdaptP)) {
+ NdisPrint1("NdisQueueOpenOnAdapter: Null Adapter Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(AdaptP)) {
+ NdisPrint1("NdisQueueOpenOnAdapter: Adapter Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ if (AdaptP->Ref.Closing) {
+ RELEASE_SPIN_LOCK(&AdaptP->Ref.SpinLock);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueAdapterOnAdapter\n");
+ return FALSE;
+ }
+
+
+ //
+ // Attach this open at the head of the queue.
+ //
+
+ OpenP->AdapterNextOpen = AdaptP->OpenQueue;
+ AdaptP->OpenQueue = OpenP;
+
+
+ RELEASE_SPIN_LOCK(&AdaptP->Ref.SpinLock);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueAdapterOnAdapter\n");
+ return TRUE;
+}
+
+VOID
+NdisDeQueueOpenOnAdapter(
+ PNDIS_OPEN_BLOCK OpenP,
+ PNDIS_ADAPTER_BLOCK AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Removes an open from a list of opens for an adapter.
+
+Arguments:
+
+ OpenP - The open block to dequeue.
+ AdaptP - The adapter block to dequeue it from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisDeQueueAdapterOnAdapter\n");
+ NdisPrint2(" Open being removed from list for Adapter %s\n",AdaptP->AdapterName.Buffer);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(OpenP)) {
+ NdisPrint1("NdisDeQueueOpenOnAdapter: Null Open Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(OpenP)) {
+ NdisPrint1("NdisDeQueueOpenOnAdapter: Open Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(AdaptP)) {
+ NdisPrint1("NdisDeQueueOpenOnAdapter: Null Adapter Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(AdaptP)) {
+ NdisPrint1("NdisDeQueueOpenOnAdapter: Adapter Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ ACQUIRE_SPIN_LOCK(&AdaptP->Ref.SpinLock);
+ //
+ // Find the open on the queue, and remove it.
+ //
+
+ if (AdaptP->OpenQueue == OpenP) {
+ AdaptP->OpenQueue = OpenP->AdapterNextOpen;
+ } else {
+ PNDIS_OPEN_BLOCK AP = AdaptP->OpenQueue;
+
+ while (AP->AdapterNextOpen != OpenP) {
+ AP = AP->AdapterNextOpen;
+ }
+
+ AP->AdapterNextOpen = AP->AdapterNextOpen->AdapterNextOpen;
+ }
+
+ RELEASE_SPIN_LOCK(&AdaptP->Ref.SpinLock);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeQueueAdapterOnAdapter\n");
+}
+
+
+VOID
+NdisDereferenceMac(
+ PNDIS_MAC_BLOCK MacP
+ )
+/*++
+
+Routine Description:
+
+ Removes a reference from the mac, deleting it if the count goes to 0.
+
+Arguments:
+
+ MacP - The Mac block to dereference.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if (NdisDereferenceRef(&(MacP)->Ref)) {
+
+ //
+ // Remove it from the global list.
+ //
+
+ ACQUIRE_SPIN_LOCK(&NdisMacListLock);
+
+ if (NdisMacList == MacP) {
+
+ NdisMacList = MacP->NextMac;
+
+ } else {
+
+ PNDIS_MAC_BLOCK TmpMacP = NdisMacList;
+
+ while(TmpMacP->NextMac != MacP) {
+
+ TmpMacP = TmpMacP->NextMac;
+
+ }
+
+ TmpMacP->NextMac = TmpMacP->NextMac->NextMac;
+
+ }
+
+ RELEASE_SPIN_LOCK(&NdisMacListLock);
+
+ if ( MacP->PciAssignedResources != NULL ) {
+ ExFreePool( MacP->PciAssignedResources );
+ }
+
+ ExFreePool((PVOID)(MacP));
+ }
+
+
+}
+
+
+
+//
+// Stubs to compile with Ndis 3.0 kernel.
+//
+
+NDIS_STATUS
+EthAddFilterAddress() {
+ return(NDIS_STATUS_FAILURE);
+}
+
+NDIS_STATUS
+EthDeleteFilterAddress() {
+ return(NDIS_STATUS_FAILURE);
+}
+
+NDIS_STATUS
+NdisInitializePacketPool() {
+ return(NDIS_STATUS_FAILURE);
+}
+
+
+
+NTSTATUS
+WrapperSaveLinkage(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called with the values for the "Bind" and "Export" multi-strings
+ for a given driver. It allocates memory to hold the data and copies
+ it over.
+
+Arguments:
+
+ ValueName - The name of the value ("Bind" or "Export" -- ignored).
+
+ ValueType - The type of the value (REG_MULTI_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - Unused.
+
+ EntryContext - A pointer to the pointer that holds the copied data.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PWSTR * Data = ((PWSTR *)EntryContext);
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(Context);
+
+
+ *Data = ExAllocatePoolWithTag (NonPagedPool, ValueLength, ' DN');
+
+ if (*Data == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory (*Data, ValueData, ValueLength);
+
+ return STATUS_SUCCESS;
+
+}
+
+
+NTSTATUS
+WrapperCheckRoute(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called with the value for the "Route" multi-string. It
+ counts the number of "'s in the first string and if it is
+ more than two than it knows that this is a layered driver.
+
+Arguments:
+
+ ValueName - The name of the value ("Route" -- ignored).
+
+ ValueType - The type of the value (REG_MULTI_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - Unused.
+
+ EntryContext - A pointer to a BOOLEAN that is set to TRUE
+ if the driver is layered.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+
+ PWSTR CurRouteLoc = (PWSTR)ValueData;
+ UINT QuoteCount = 0;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(ValueLength);
+ UNREFERENCED_PARAMETER(Context);
+
+ while (*CurRouteLoc != 0) {
+
+ if (*CurRouteLoc == (WCHAR)L'"') {
+ ++QuoteCount;
+ }
+ ++CurRouteLoc;
+ }
+
+ if (QuoteCount > 2) {
+ *(PBOOLEAN)EntryContext = TRUE;
+ }
+
+ return STATUS_SUCCESS;
+
+}
+
+NDIS_STATUS
+NdisCallDriverAddAdapter(
+ IN PNDIS_MAC_BLOCK NewMacP
+ )
+
+/*++
+
+Routine Description:
+
+ Reads the driver registry bindings and calls add adapter for each
+ one.
+
+Arguments:
+
+ NewMacP - Pointer to the Mac block allocated for this Mac.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Pointer to a Miniport
+ //
+ PNDIS_M_DRIVER_BLOCK WDriver = (PNDIS_M_DRIVER_BLOCK)NewMacP;
+
+ //
+ // Number of adapters added successfully
+ //
+ UINT AdaptersAdded = 0;
+
+ //
+ // Status of calls to MacAddAdapter
+ //
+ NDIS_STATUS AddAdapterStatus;
+
+ //
+ // Status of calls to MiniportInitialize
+ //
+ NDIS_STATUS MiniportInitializeStatus;
+ NDIS_STATUS OpenErrorStatus;
+
+ UINT SelectedMediumIndex;
+
+ NDIS_MEDIUM MediumArray[] = {NdisMedium802_3,
+ NdisMedium802_5,
+ NdisMediumFddi,
+ NdisMediumArcnet878_2,
+ NdisMediumWan };
+
+ UINT MediumArraySize = 5;
+
+ //
+ // Status of registry requests.
+ //
+ NTSTATUS RegistryStatus;
+ NTSTATUS NtStatus;
+
+ //
+ // subkey containing the card parameters
+ //
+ PWSTR Linkage = L"Linkage";
+
+ //
+ // subkeys below "Linkage"
+ //
+
+ PWSTR Bind = L"Bind";
+ PWSTR Export = L"Export";
+ PWSTR Route = L"Route";
+
+ //
+ // These hold the REG_MULTI_SZ read from "Bind" and "Export".
+ //
+
+ PWSTR BindData;
+ PWSTR ExportData;
+
+ //
+ // These hold our place in the REG_MULTI_SZ read for
+ // "Bind" and "Export".
+ //
+
+ PWSTR CurBindValue;
+ PWSTR CurExportValue;
+
+ //
+ // Will be set to TRUE if the driver is layered (that is,
+ // it binds to another NDIS driver, not to an adapter).
+ //
+
+ BOOLEAN LayeredDriver;
+
+ //
+ // subkey below the driver's service key.
+ //
+
+ PWSTR Parameters = L"Parameters";
+
+ //
+ // The path to our configuration data.
+ //
+ PUNICODE_STRING ConfigurationString;
+
+ //
+ // Holds a null-terminated copy of ConfigurationString
+ //
+ PWSTR ConfigurationPath;
+
+ ULONG i;
+ ULONG BusNumber;
+ NDIS_INTERFACE_TYPE BusType;
+
+ //
+ // Holds the key below services where Parameters are stored.
+ //
+ PWCH BaseFileName;
+
+ //
+ // Used to instruct RtlQueryRegistryValues to read the
+ // Linkage\Bind and Linkage\Export keys
+ //
+ RTL_QUERY_REGISTRY_TABLE LinkageQueryTable[5];
+
+ //
+ // Used to instruct RtlQueryRegistryValues to read the
+ // [Driver]\Parameters keys. This is passed as the
+ // ConfigContext to the MacAddAdapter routine.
+ //
+
+ NDIS_WRAPPER_CONFIGURATION_HANDLE ConfigurationHandle;
+
+ NDIS_WRAPPER_CONFIGURATION_HANDLE WrapperConfigurationHandle;
+
+ //
+ // Used for calls to other Ndis routines
+ //
+ NDIS_STATUS NdisStatus;
+
+ BOOLEAN IsAMiniport;
+
+#define BLOCK_LOCK_MINIPORT(_M, _L) \
+ { \
+ ACQUIRE_SPIN_LOCK(&_M->Lock); \
+ LOCK_MINIPORT(_M, _L); \
+ while (!_L) { \
+ UNLOCK_MINIPORT(_M, _L); \
+ RELEASE_SPIN_LOCK(&_M->Lock); \
+ ACQUIRE_SPIN_LOCK(&_M->Lock); \
+ LOCK_MINIPORT(_M, _L); \
+ } \
+ RELEASE_SPIN_LOCK(&_M->Lock); \
+ }
+
+ IsAMiniport = (WDriver->MiniportIdField == (NDIS_HANDLE)0x01);
+
+ //
+ // Set up LinkageQueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Linkage key below this driver's key
+ //
+
+ LinkageQueryTable[0].QueryRoutine = NULL;
+ LinkageQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ LinkageQueryTable[0].Name = Linkage;
+
+ //
+ // 2) Call WrapperSaveLinkage for "Bind" (as a single multi-string),
+ // which will allocate storage and save the data in BindData.
+ //
+
+ LinkageQueryTable[1].QueryRoutine = WrapperSaveLinkage;
+ LinkageQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ LinkageQueryTable[1].Name = Bind;
+ LinkageQueryTable[1].EntryContext = (PVOID)&BindData;
+ LinkageQueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 3) Call WrapperSaveLinkage for "Export" (as a single multi-string)
+ // which will allocate storage and save the data in ExportData.
+ //
+
+ LinkageQueryTable[2].QueryRoutine = WrapperSaveLinkage;
+ LinkageQueryTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ LinkageQueryTable[2].Name = Export;
+ LinkageQueryTable[2].EntryContext = (PVOID)&ExportData;
+ LinkageQueryTable[2].DefaultType = REG_NONE;
+
+ //
+ // 4) Call WrapperCheckRoute for "Route" (as a single multi-string)
+ // which will set LayeredDriver to TRUE for a layered driver (this
+ // is optional, the default is FALSE).
+ //
+
+ LinkageQueryTable[3].QueryRoutine = WrapperCheckRoute;
+ LinkageQueryTable[3].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
+ LinkageQueryTable[3].Name = Route;
+ LinkageQueryTable[3].EntryContext = (PVOID)&LayeredDriver;
+ LinkageQueryTable[3].DefaultType = REG_NONE;
+
+ LayeredDriver = FALSE;
+
+ //
+ // 5) Stop
+ //
+
+ LinkageQueryTable[4].QueryRoutine = NULL;
+ LinkageQueryTable[4].Flags = 0;
+ LinkageQueryTable[4].Name = NULL;
+
+
+ //
+ // Allocate room for a null-terminated version of the config path
+ //
+
+ if (IsAMiniport) {
+
+ ConfigurationString = (PUNICODE_STRING)(WDriver->NdisDriverInfo->NdisWrapperConfigurationHandle);
+
+ } else {
+
+ ConfigurationString = (PUNICODE_STRING)(NewMacP->NdisMacInfo->NdisWrapperConfigurationHandle);
+
+ }
+
+ ConfigurationPath = (PWSTR)ExAllocatePoolWithTag(
+ NonPagedPool,
+ ConfigurationString->Length + sizeof(WCHAR),
+ ' DN');
+ if (ConfigurationPath == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ RtlCopyMemory (ConfigurationPath, ConfigurationString->Buffer, ConfigurationString->Length);
+ *(PWCHAR)(((PUCHAR)ConfigurationPath)+ConfigurationString->Length) = (WCHAR)L'\0';
+
+ BindData = NULL;
+ ExportData = NULL;
+
+ RegistryStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ ConfigurationPath,
+ LinkageQueryTable,
+ (PVOID)NULL, // no context needed
+ NULL);
+
+ if (!NT_SUCCESS(RegistryStatus)) {
+
+ //
+ // Free memory if needed, exit.
+ //
+
+ ExFreePool (ConfigurationPath);
+
+ if (BindData != NULL) {
+ ExFreePool (BindData);
+ }
+ if (ExportData != NULL) {
+ ExFreePool (ExportData);
+ }
+
+#if DBG
+ if (IsAMiniport) {
+
+ DbgPrint("NDIS: Could not read Bind/Export for %Z: %lx\n",
+ (PUNICODE_STRING)(WDriver->NdisDriverInfo->NdisWrapperConfigurationHandle),
+ RegistryStatus);
+
+ } else {
+
+ DbgPrint("NDIS: Could not read Bind/Export for %Z: %lx\n",
+ (PUNICODE_STRING)(NewMacP->NdisMacInfo->NdisWrapperConfigurationHandle),
+ RegistryStatus);
+
+ }
+#endif
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ //
+ // NdisReadConfiguration assumes that ParametersQueryTable[3].Name is
+ // a key below the services key where the Parameters should be read,
+ // for layered drivers we store the last piece of Configuration
+ // Path there, leading to the desired effect.
+ //
+ // I.e, ConfigurationPath == "...\Services\Driver".
+ //
+ // For a layered driver, ParameterQueryTable[3].Name is "Driver"
+ // for all calls to AddAdapter, and parameters are read from
+ // "...\Services\Driver\Parameters" for all calls.
+ //
+ // For a non-layered driver, ParametersQueryTable[3].Name might be
+ // "Driver01" for the first call to AddAdapter, "Driver02" for the
+ // second, etc., and parameters are read from
+ // "..\Services\Driver01\Parameters" for the first call to
+ // AddAdapter, "...\Services\Driver02\Parameters" for the second
+ // call, etc.
+ //
+
+ if (LayeredDriver) {
+
+ BaseFileName = ConfigurationPath;
+
+ for ( i = 0; i < ConfigurationString->Length / sizeof(WCHAR); i++ ) {
+
+ //
+ // If s points to a directory separator, set BaseFileName to
+ // the character after the separator.
+ //
+
+ if ( ConfigurationPath[i] == OBJ_NAME_PATH_SEPARATOR ) {
+ BaseFileName = &(ConfigurationPath[++i]);
+ }
+
+ }
+
+#if DBG
+ DbgPrint ("NDIS: Loading layered driver %ws\n", BaseFileName);
+#endif
+
+ }
+
+
+ //
+ // Set up ParametersQueryTable. We set most of it up here,
+ // then call the MAC's AddAdapter routine with its address
+ // as a ConfigContext. Inside ReadConfiguration, we get
+ // the ConfigContext back and can then finish initializing
+ // the table and use RtlQueryRegistryValues (with a
+ // callback to WrapperSaveParameter) to read the value
+ // specified.
+ //
+
+
+ //
+ // 1) Switch to the Parameters key below the [DriverName] key
+ // (DriverName is passed as a parameter to RtlQueryRegistryValues).
+ //
+
+ ConfigurationHandle.ParametersQueryTable[0].QueryRoutine = NULL;
+ ConfigurationHandle.ParametersQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ ConfigurationHandle.ParametersQueryTable[0].Name = Parameters;
+
+ //
+ // 2) Call WrapperSaveParameter for a parameter, which
+ // will allocate storage for it.
+ //
+ // ParametersQueryTable[1].Name and ParametersQueryTable[1].EntryContext
+ // are filled in inside ReadConfiguration, in preparation
+ // for the callback.
+ //
+
+ ConfigurationHandle.ParametersQueryTable[1].QueryRoutine = WrapperSaveParameters;
+ ConfigurationHandle.ParametersQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ ConfigurationHandle.ParametersQueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 3) Stop
+ //
+
+ ConfigurationHandle.ParametersQueryTable[2].QueryRoutine = NULL;
+ ConfigurationHandle.ParametersQueryTable[2].Flags = 0;
+ ConfigurationHandle.ParametersQueryTable[2].Name = NULL;
+
+ //
+ // NOTE: Some fields in ParametersQueryTable[3] are used to
+ // store information for later retrieval.
+ //
+
+
+
+ //
+ // OK, Now lock down all the filter packages. If a MAC or
+ // Miniport driver uses any of these, then the filter package
+ // will reference itself, to keep the image in memory.
+ //
+ ArcReferencePackage();
+ EthReferencePackage();
+ FddiReferencePackage();
+ TrReferencePackage();
+ MiniportReferencePackage();
+ NdisMacReferencePackage();
+
+ //
+ // For each binding, get the handle to the card object.
+ // Call the driver's addadapter routine.
+ //
+
+ CurBindValue = BindData;
+ CurExportValue = ExportData;
+
+ while ((*CurBindValue != 0) && (*CurExportValue != 0)) {
+
+ UNICODE_STRING CurBindString;
+ UNICODE_STRING CurExportString;
+ NDIS_CONFIGURATION_HANDLE TmpConfigHandle;
+ NDIS_STRING BusTypeStr = NDIS_STRING_CONST("BusType");
+ NDIS_STRING BusNumberStr = NDIS_STRING_CONST("BusNumber");
+ PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
+ PDEVICE_OBJECT TmpDeviceP;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ LARGE_INTEGER TimeoutValue;
+
+ TimeoutValue.QuadPart = Int32x32To64(100 * 1000, -10000);
+
+ //
+ // Setup the query table to point to the section in
+ // the registry corresponding to what was specified
+ // in "Bind". The "Parameters" key below this is where
+ // config parameters are read from.
+ //
+
+ RtlInitUnicodeString (&CurBindString, CurBindValue);
+
+ //
+ // For layered drivers, BaseFileName is already
+ // initialized.
+ //
+
+ if (!LayeredDriver) {
+
+ //
+ // Parse out the path name, leaving only the driver name.
+ //
+
+ BaseFileName = CurBindString.Buffer;
+
+ for ( i = 0; i < CurBindString.Length / sizeof(WCHAR); i++ ) {
+
+ //
+ // If s points to a directory separator, set fileBaseName to
+ // the character after the separator.
+ //
+
+ if ( CurBindString.Buffer[i] == OBJ_NAME_PATH_SEPARATOR ) {
+ BaseFileName = &(CurBindString.Buffer[++i]);
+ }
+
+ }
+
+ //
+ // Set this to NULL, in case NdisReadBindingInformation
+ // is called.
+ //
+
+ ConfigurationHandle.ParametersQueryTable[3].EntryContext = NULL;
+
+ } else {
+
+ //
+ // This will be returned by NdisReadBindingInformation.
+ //
+
+ ConfigurationHandle.ParametersQueryTable[3].EntryContext = CurBindValue;
+
+ }
+
+
+ //
+ // Save the driver name here; later we will use this as
+ // a parameter to RtlQueryRegistryValues.
+ //
+
+ ConfigurationHandle.ParametersQueryTable[3].Name = BaseFileName;
+
+ //
+ // Also, save the BusType and BusNumber so that we can pull them
+ // out in NdisRegisterAdapter(), NdisReadEisaSlotInformation() and
+ // NdisReadPosInformation().
+ //
+
+ TmpConfigHandle.KeyQueryTable = ConfigurationHandle.ParametersQueryTable;
+ TmpConfigHandle.ParameterList = NULL;
+
+ //
+ // Read Bus Number
+ //
+
+ NdisReadConfiguration(
+ &NdisStatus,
+ &ReturnedValue,
+ &TmpConfigHandle,
+ &BusNumberStr,
+ NdisParameterInteger
+ );
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ BusNumber = ReturnedValue->ParameterData.IntegerData;
+
+ } else {
+
+ BusNumber = (ULONG)(-1);
+ }
+
+ //
+ // Read Bus Type
+ //
+
+ NdisReadConfiguration(
+ &NdisStatus,
+ &ReturnedValue,
+ &TmpConfigHandle,
+ &BusTypeStr,
+ NdisParameterInteger
+ );
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ BusType = (NDIS_INTERFACE_TYPE)(ReturnedValue->ParameterData.IntegerData);
+
+ } else {
+
+ BusType = (NDIS_INTERFACE_TYPE)(-1);
+
+ }
+
+ ConfigurationHandle.ParametersQueryTable[3].DefaultType = (ULONG)(BusType);
+ ConfigurationHandle.ParametersQueryTable[3].DefaultLength = (ULONG)(BusNumber);
+ ConfigurationHandle.ParametersQueryTable[3].DefaultData = NULL;
+
+ //
+ // Call adapter callback. The current value for "Export"
+ // is what we tell him to name this device.
+ //
+
+ RtlInitUnicodeString (&CurExportString, CurExportValue);
+
+ if (IsAMiniport)
+ {
+ ConfigurationHandle.DriverObject = WDriver->NdisDriverInfo->NdisWrapperDriver;
+ }
+ else
+ {
+ ConfigurationHandle.DriverObject = NewMacP->NdisMacInfo->NdisWrapperDriver;
+ }
+
+ if (IsAMiniport)
+ {
+ KIRQL OldIrql;
+ ULONG MaximumLongAddresses;
+ UCHAR CurrentLongAddress[6];
+ ULONG MaximumShortAddresses;
+ UCHAR CurrentShortAddress[2];
+ UINT BytesWritten;
+ UINT BytesNeeded;
+ UINT PacketFilter = 0x1;
+ UCHAR i;
+ BOOLEAN LocalLock;
+ PARC_BUFFER_LIST Buffer;
+ PVOID DataBuffer;
+
+ //
+ // Initialize device.
+ //
+
+ if (!NdisReferenceDriver((PNDIS_M_DRIVER_BLOCK)WDriver)) {
+
+ //
+ // The driver is closing.
+ //
+
+ goto LoopBottom;
+
+ }
+
+ NtStatus = IoCreateDevice(
+ WDriver->NdisDriverInfo->NdisWrapperDriver,
+ sizeof(NDIS_MINIPORT_BLOCK) + sizeof(NDIS_WRAPPER_CONTEXT), // device extension size
+ &CurExportString,
+ FILE_DEVICE_PHYSICAL_NETCARD,
+ 0,
+ FALSE, // exclusive flag
+ &TmpDeviceP
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+
+ //
+ // Initialize the Miniport adapter block in the device object extension
+ //
+ // *** NDIS_WRAPPER_CONTEXT has a higher alignment requirement than
+ // NDIS_MINIPORT_BLOCK, so we put it first in the extension.
+ //
+
+ Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)TmpDeviceP->DeviceExtension + 1);
+
+ Miniport->WrapperContext = TmpDeviceP->DeviceExtension;
+
+ Miniport->BusType = BusType;
+ Miniport->BusNumber = BusNumber;
+ Miniport->DeviceObject = TmpDeviceP;
+ Miniport->DriverHandle = WDriver;
+ Miniport->MiniportName.Buffer = (PWSTR)ExAllocatePoolWithTag(
+ NonPagedPool,
+ CurExportString.MaximumLength,
+ 'naDN'
+ );
+
+ if (Miniport->MiniportName.Buffer == NULL) {
+ NdisDereferenceDriver(WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ goto LoopBottom;
+ }
+
+ Miniport->MiniportName.MaximumLength = CurExportString.MaximumLength;
+ Miniport->MiniportName.Length = CurExportString.Length;
+
+ RtlCopyMemory(Miniport->MiniportName.Buffer,
+ CurExportString.Buffer,
+ CurExportString.MaximumLength
+ );
+
+ Miniport->OpenQueue = (PNDIS_M_OPEN_BLOCK)NULL;
+ Miniport->EthDB = NULL;
+ Miniport->TrDB = NULL;
+ Miniport->FddiDB = NULL;
+ Miniport->ArcDB = NULL;
+ Miniport->BeingRemoved = FALSE;
+ Miniport->SendResourcesAvailable = 0xffffff;
+ Miniport->Flags = 0; // a value that cannot be a pointer.
+ Miniport->InAddDriver = TRUE;
+ NdisAllocateSpinLock(&Miniport->Lock);
+ //KeSetSpecialSpinLock(&Miniport->Lock, "miniport lock" );
+
+ NdisInitializeRef(&Miniport->Ref);
+
+ NdisInitializeTimer(
+ &Miniport->DpcTimer,
+ (PVOID) NdisMDpcTimer,
+ (PVOID) Miniport
+ );
+
+ NdisInitializeTimer(
+ &Miniport->WakeUpDpcTimer,
+ (PVOID) NdisMWakeUpDpc,
+ (PVOID) Miniport
+ );
+
+ if (!NdisQueueMiniportOnDriver(Miniport, WDriver)) {
+
+ //
+ // The Driver is closing, undo what we have done.
+ //
+
+ ExFreePool(Miniport->MiniportName.Buffer);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+
+ //
+ // Now we do something really bogus. We create many
+ // temporary filter databases, just in case any indications
+ // happen.
+ //
+
+ if (!EthCreateFilter(
+ 1,
+ NdisMChangeEthAddresses,
+ NdisMChangeClass,
+ NdisMCloseAction,
+ CurrentLongAddress,
+ &Miniport->Lock,
+ &(Miniport->EthDB)
+ )) {
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ if (!TrCreateFilter(
+ NdisMChangeFunctionalAddress,
+ NdisMChangeGroupAddress,
+ NdisMChangeClass,
+ NdisMCloseAction,
+ CurrentLongAddress,
+ &Miniport->Lock,
+ &(Miniport->TrDB)
+ )) {
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ if (!FddiCreateFilter(
+ 1,
+ 1,
+ NdisMChangeFddiAddresses,
+ NdisMChangeClass,
+ NdisMCloseAction,
+ CurrentLongAddress,
+ CurrentShortAddress,
+ &Miniport->Lock,
+ &(Miniport->FddiDB)
+ )) {
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ if (!ArcCreateFilter(
+ Miniport,
+ NdisMChangeClass,
+ NdisMCloseAction,
+ CurrentLongAddress[0],
+ &Miniport->Lock,
+ &(Miniport->ArcDB)
+ )) {
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ //
+ // Call adapter callback. The current value for "Export"
+ // is what we tell him to name this device.
+ //
+
+ Miniport->InInitialize = TRUE;
+ Miniport->NormalInterrupts = FALSE;
+
+ MiniportInitializeStatus =
+ (WDriver->MiniportCharacteristics.InitializeHandler)(
+ &OpenErrorStatus,
+ &SelectedMediumIndex,
+ MediumArray,
+ MediumArraySize,
+ (NDIS_HANDLE)(Miniport),
+ (NDIS_HANDLE)&ConfigurationHandle
+ );
+
+ Miniport->InInitialize = FALSE;
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ //
+ // Free the slot information buffer
+ //
+
+ if (ConfigurationHandle.ParametersQueryTable[3].DefaultData != NULL ) {
+
+ ExFreePool(ConfigurationHandle.ParametersQueryTable[3].DefaultData);
+
+ }
+
+ if (MiniportInitializeStatus == NDIS_STATUS_SUCCESS) {
+
+ ASSERT(SelectedMediumIndex < MediumArraySize);
+
+ Miniport->MediaType = MediumArray[SelectedMediumIndex];
+
+ KeInitializeEvent(
+ &Miniport->RequestEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ //
+ // Query maximum lookahead
+ //
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ &MaximumLongAddresses,
+ sizeof(MaximumLongAddresses),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x1
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x2
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ //
+ // Now adjust based on media type
+ //
+
+ switch(Miniport->MediaType) {
+
+ case NdisMedium802_3:
+
+ Miniport->MaximumLookahead = (NDIS_M_MAX_LOOKAHEAD - 14 < MaximumLongAddresses) ?
+ NDIS_M_MAX_LOOKAHEAD - 14 :
+ MaximumLongAddresses;
+ break;
+
+ case NdisMedium802_5:
+
+ Miniport->MaximumLookahead = (NDIS_M_MAX_LOOKAHEAD - 32 < MaximumLongAddresses) ?
+ NDIS_M_MAX_LOOKAHEAD - 32 :
+ MaximumLongAddresses;
+ break;
+
+ case NdisMediumFddi:
+ Miniport->MaximumLookahead = (NDIS_M_MAX_LOOKAHEAD - 16 < MaximumLongAddresses) ?
+ NDIS_M_MAX_LOOKAHEAD - 16 :
+ MaximumLongAddresses;
+ break;
+
+ case NdisMediumArcnet878_2:
+ Miniport->MaximumLookahead = (NDIS_M_MAX_LOOKAHEAD - 50 < MaximumLongAddresses) ?
+ NDIS_M_MAX_LOOKAHEAD - 50 :
+ MaximumLongAddresses;
+ break;
+
+ case NdisMediumWan:
+ Miniport->MaximumLookahead = 1514;
+
+ }
+
+ Miniport->CurrentLookahead = Miniport->MaximumLookahead;
+
+ //
+ // Query mac options
+ //
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_GEN_MAC_OPTIONS,
+ &MaximumLongAddresses,
+ sizeof(MaximumLongAddresses),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x3
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ Miniport->MacOptions = (UINT)MaximumLongAddresses;
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x4
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ //
+ // Create filter package
+ //
+ switch(Miniport->MediaType) {
+
+ case NdisMedium802_3:
+
+ //
+ // Query maximum MulticastAddress
+ //
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ &MaximumLongAddresses,
+ sizeof(MaximumLongAddresses),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x5
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (MaximumLongAddresses > NDIS_M_MAX_MULTI_LIST) {
+
+ MaximumLongAddresses = NDIS_M_MAX_MULTI_LIST;
+
+ }
+
+ Miniport->MaximumLongAddresses = MaximumLongAddresses;
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x6
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_802_3_CURRENT_ADDRESS,
+ &(CurrentLongAddress),
+ sizeof(CurrentLongAddress),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x7
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x8
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ //
+ // Now undo the bogus filter package. We lock
+ // the miniport so that no dpcs will get queued.
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ Miniport->InInitialize = TRUE;
+ Miniport->NormalInterrupts = FALSE;
+
+ EthDeleteFilter(Miniport->EthDB);
+ Miniport->EthDB = NULL;
+ TrDeleteFilter(Miniport->TrDB);
+ Miniport->TrDB = NULL;
+ FddiDeleteFilter(Miniport->FddiDB);
+ Miniport->FddiDB = NULL;
+ ArcDeleteFilter(Miniport->ArcDB);
+ Miniport->ArcDB = NULL;
+
+ if (!EthCreateFilter(
+ MaximumLongAddresses,
+ NdisMChangeEthAddresses,
+ NdisMChangeClass,
+ NdisMCloseAction,
+ CurrentLongAddress,
+ &Miniport->Lock,
+ &Miniport->EthDB
+ )) {
+
+ //
+ // Halt the miniport driver
+ //
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ 0xFF00FF00,
+ 0x9
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ Miniport->InInitialize = FALSE;
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ break;
+
+ case NdisMedium802_5:
+
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_802_5_CURRENT_ADDRESS,
+ &(CurrentLongAddress),
+ sizeof(CurrentLongAddress),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0xA
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0xB
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ //
+ // Now undo the bogus filter package. We lock
+ // the miniport so that no dpcs will get queued.
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ Miniport->InInitialize = TRUE;
+ Miniport->NormalInterrupts = FALSE;
+
+ EthDeleteFilter(Miniport->EthDB);
+ Miniport->EthDB = NULL;
+ TrDeleteFilter(Miniport->TrDB);
+ Miniport->TrDB = NULL;
+ FddiDeleteFilter(Miniport->FddiDB);
+ Miniport->FddiDB = NULL;
+ ArcDeleteFilter(Miniport->ArcDB);
+ Miniport->ArcDB = NULL;
+
+ if (!TrCreateFilter(
+ NdisMChangeFunctionalAddress,
+ NdisMChangeGroupAddress,
+ NdisMChangeClass,
+ NdisMCloseAction,
+ CurrentLongAddress,
+ &Miniport->Lock,
+ &Miniport->TrDB
+ )) {
+
+ //
+ // Halt the miniport driver
+ //
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ 0xFF00FF00,
+ 0xC
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ Miniport->InInitialize = FALSE;
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ break;
+
+ case NdisMediumFddi:
+
+ //
+ // Query maximum MulticastAddress
+ //
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_FDDI_LONG_MAX_LIST_SIZE,
+ &MaximumLongAddresses,
+ sizeof(MaximumLongAddresses),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0xD
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (MaximumLongAddresses > NDIS_M_MAX_MULTI_LIST) {
+
+ MaximumLongAddresses = NDIS_M_MAX_MULTI_LIST;
+
+ }
+
+ Miniport->MaximumLongAddresses = MaximumLongAddresses;
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0xE
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ //
+ // Query maximum MulticastAddress
+ //
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_FDDI_SHORT_MAX_LIST_SIZE,
+ &MaximumShortAddresses,
+ sizeof(MaximumShortAddresses),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0xF
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (MaximumShortAddresses > NDIS_M_MAX_MULTI_LIST) {
+
+ MaximumShortAddresses = NDIS_M_MAX_MULTI_LIST;
+
+ }
+
+ Miniport->MaximumShortAddresses = MaximumShortAddresses;
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x10
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_FDDI_LONG_CURRENT_ADDR,
+ &(CurrentLongAddress),
+ sizeof(CurrentLongAddress),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x11
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x12
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_FDDI_SHORT_CURRENT_ADDR,
+ &(CurrentShortAddress),
+ sizeof(CurrentShortAddress),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x13
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x14
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ //
+ // Now undo the bogus filter package. We lock
+ // the miniport so that no dpcs will get queued.
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ Miniport->InInitialize = TRUE;
+ Miniport->NormalInterrupts = FALSE;
+
+ EthDeleteFilter(Miniport->EthDB);
+ Miniport->EthDB = NULL;
+ TrDeleteFilter(Miniport->TrDB);
+ Miniport->TrDB = NULL;
+ FddiDeleteFilter(Miniport->FddiDB);
+ Miniport->FddiDB = NULL;
+ ArcDeleteFilter(Miniport->ArcDB);
+ Miniport->ArcDB = NULL;
+
+ if (!FddiCreateFilter(
+ MaximumLongAddresses,
+ MaximumShortAddresses,
+ NdisMChangeFddiAddresses,
+ NdisMChangeClass,
+ NdisMCloseAction,
+ CurrentLongAddress,
+ CurrentShortAddress,
+ &Miniport->Lock,
+ &Miniport->FddiDB
+ )) {
+
+ //
+ // Halt the miniport driver
+ //
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ 0xFF00FF00,
+ 0x15
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ Miniport->InInitialize = FALSE;
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ //
+ // In case of an encapsulated ethernet binding, we need
+ // to return the maximum number of multicast addresses
+ // possible.
+ //
+
+ Miniport->MaximumLongAddresses = NDIS_M_MAX_MULTI_LIST;
+
+ //
+ // Allocate Buffer pools
+ //
+ NdisAllocateBufferPool(&NdisStatus,
+ &Miniport->ArcnetBufferPool,
+ WRAPPER_ARC_BUFFERS
+ );
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ 0xFF00FF00,
+ 0x16
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ NdisAllocateMemory((PVOID)&Buffer,
+ sizeof(ARC_BUFFER_LIST) *
+ WRAPPER_ARC_BUFFERS,
+ 0,
+ HighestAcceptableMax
+ );
+
+ if (Buffer == NULL) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ 0xFF00FF00,
+ 0x18
+ );
+ NdisFreeBufferPool(Miniport->ArcnetBufferPool);
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ NdisAllocateMemory((PVOID)&DataBuffer,
+ WRAPPER_ARC_HEADER_SIZE *
+ WRAPPER_ARC_BUFFERS,
+ 0,
+ HighestAcceptableMax
+ );
+
+
+ if (DataBuffer == NULL) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ 0xFF00FF00,
+ 0x19
+ );
+ NdisFreeMemory(Buffer,
+ sizeof(ARC_BUFFER_LIST) *
+ WRAPPER_ARC_BUFFERS,
+ 0
+ );
+ NdisFreeBufferPool(Miniport->ArcnetBufferPool);
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ for (i = WRAPPER_ARC_BUFFERS; i != 0 ; i--) {
+
+ Buffer->BytesLeft = Buffer->Size = WRAPPER_ARC_HEADER_SIZE;
+ Buffer->Buffer = DataBuffer;
+ Buffer->Next = Miniport->ArcnetFreeBufferList;
+ Miniport->ArcnetFreeBufferList = Buffer;
+
+ Buffer++;
+ DataBuffer = (PVOID)(((PUCHAR)DataBuffer) +
+ WRAPPER_ARC_HEADER_SIZE);
+
+ }
+
+
+ //
+ // Get current address
+ //
+
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_ARCNET_CURRENT_ADDRESS,
+ &CurrentLongAddress[5], // address = 00-00-00-00-00-XX
+ 1,
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x1A
+ );
+ NdisFreeMemory(Buffer,
+ sizeof(ARC_BUFFER_LIST) *
+ WRAPPER_ARC_BUFFERS,
+ 0
+ );
+ NdisFreeMemory(DataBuffer,
+ WRAPPER_ARC_HEADER_SIZE *
+ WRAPPER_ARC_BUFFERS,
+ 0
+ );
+ NdisFreeBufferPool(Miniport->ArcnetBufferPool);
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x1B
+ );
+ NdisFreeMemory(Buffer,
+ sizeof(ARC_BUFFER_LIST) *
+ WRAPPER_ARC_BUFFERS,
+ 0
+ );
+ NdisFreeMemory(DataBuffer,
+ WRAPPER_ARC_HEADER_SIZE *
+ WRAPPER_ARC_BUFFERS,
+ 0
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ Miniport->ArcnetAddress = CurrentLongAddress[5];
+
+ //
+ // Now undo the bogus filter package. We lock
+ // the miniport so that no dpcs will get queued.
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ Miniport->InInitialize = TRUE;
+ Miniport->NormalInterrupts = FALSE;
+
+ EthDeleteFilter(Miniport->EthDB);
+ Miniport->EthDB = NULL;
+ TrDeleteFilter(Miniport->TrDB);
+ Miniport->TrDB = NULL;
+ FddiDeleteFilter(Miniport->FddiDB);
+ Miniport->FddiDB = NULL;
+ ArcDeleteFilter(Miniport->ArcDB);
+ Miniport->ArcDB = NULL;
+
+ if (!ArcCreateFilter(
+ Miniport,
+ NdisMChangeClass,
+ NdisMCloseAction,
+ CurrentLongAddress[5],
+ &Miniport->Lock,
+ &(Miniport->ArcDB)
+ )) {
+
+ //
+ // Halt the miniport driver
+ //
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ 0xFF00FF00,
+ 0x1C
+ );
+ NdisFreeMemory(Buffer,
+ sizeof(ARC_BUFFER_LIST) *
+ WRAPPER_ARC_BUFFERS,
+ 0
+ );
+ NdisFreeMemory(DataBuffer,
+ WRAPPER_ARC_HEADER_SIZE *
+ WRAPPER_ARC_BUFFERS,
+ 0
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ // Zero all but the last one.
+
+ CurrentLongAddress[0] = 0;
+ CurrentLongAddress[1] = 0;
+ CurrentLongAddress[2] = 0;
+ CurrentLongAddress[3] = 0;
+ CurrentLongAddress[4] = 0;
+
+ if (!EthCreateFilter(
+ 32,
+ NdisMChangeEthAddresses,
+ NdisMChangeClass,
+ NdisMCloseAction,
+ CurrentLongAddress,
+ &Miniport->Lock,
+ &Miniport->EthDB
+ )) {
+
+ //
+ // Halt the miniport driver
+ //
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ 0xFF00FF00,
+ 0x1D
+ );
+ NdisFreeMemory(Buffer,
+ sizeof(ARC_BUFFER_LIST) *
+ WRAPPER_ARC_BUFFERS,
+ 0
+ );
+ NdisFreeMemory(DataBuffer,
+ WRAPPER_ARC_HEADER_SIZE *
+ WRAPPER_ARC_BUFFERS,
+ 0
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ Miniport->InInitialize = FALSE;
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ break;
+
+ case NdisMediumWan:
+
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_WAN_CURRENT_ADDRESS,
+ &(CurrentLongAddress),
+ sizeof(CurrentLongAddress),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x7
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x8
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ //
+ // Now undo the bogus filter package. We lock
+ // the miniport so that no dpcs will get queued.
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ Miniport->InInitialize = TRUE;
+ Miniport->NormalInterrupts = FALSE;
+
+ EthDeleteFilter(Miniport->EthDB);
+ Miniport->EthDB = NULL;
+ TrDeleteFilter(Miniport->TrDB);
+ Miniport->TrDB = NULL;
+ FddiDeleteFilter(Miniport->FddiDB);
+ Miniport->FddiDB = NULL;
+ ArcDeleteFilter(Miniport->ArcDB);
+ Miniport->ArcDB = NULL;
+
+ Miniport->InInitialize = FALSE;
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ break;
+
+ }
+
+ //
+ // Get supported packet filters
+ //
+ Miniport->SupportedPacketFilters = 0;
+
+ //
+ // Set the filter packages bit mask to fake it out.
+ //
+ if (Miniport->EthDB) {
+ Miniport->EthDB->CombinedPacketFilter = 0xFFFFFFFF;
+ }
+ if (Miniport->TrDB) {
+ Miniport->TrDB->CombinedPacketFilter = 0xFFFFFFFF;
+ }
+ if (Miniport->FddiDB) {
+ Miniport->FddiDB->CombinedPacketFilter = 0xFFFFFFFF;
+ }
+
+ //
+ // For WAN there is no packet filter
+ //
+
+ if (Miniport->MediaType==NdisMediumWan) {
+ goto SkipFilter;
+ }
+
+ for (i=0; i<31; i++) {
+
+ //
+ // Set packet filter
+ //
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryStatistics;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ &PacketFilter,
+ sizeof(PacketFilter),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x1E
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+ Miniport->SupportedPacketFilters |= PacketFilter;
+ }
+
+ PacketFilter = PacketFilter << 1;
+
+ }
+
+ //
+ // Set packet filter
+ //
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ PacketFilter = 0;
+
+ Miniport->InternalRequest.RequestType = NdisRequestQueryStatistics;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ &PacketFilter,
+ sizeof(PacketFilter),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ //
+ // Set the filter packages bit mask to fake it out.
+ //
+ if (Miniport->EthDB) {
+ Miniport->EthDB->CombinedPacketFilter = 0;
+ }
+ if (Miniport->TrDB) {
+ Miniport->TrDB->CombinedPacketFilter = 0;
+ }
+ if (Miniport->FddiDB) {
+ Miniport->FddiDB->CombinedPacketFilter = 0;
+ }
+
+SkipFilter:
+
+ //
+ // Start wake up timer
+ //
+ NdisSetTimer(&(Miniport->WakeUpDpcTimer), 2000);
+
+ //
+ // Done with adding this MINIPORT!!!
+ //
+ Miniport->MiniportRequest = NULL;
+ Miniport->InAddDriver = FALSE;
+
+ IoRegisterShutdownNotification(Miniport->DeviceObject);
+
+ ++AdaptersAdded;
+
+ } else{
+
+ //
+ // Undo all the stuff from this mini-port
+ //
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ } else {
+
+ //
+ // NDIS 3.0 MAC
+ //
+ AddAdapterStatus =
+ (NewMacP->MacCharacteristics.AddAdapterHandler)(
+ NewMacP->MacMacContext,
+ &ConfigurationHandle,
+ &CurExportString
+ );
+
+
+ //
+ // Free the slot information buffer
+ //
+
+ if (ConfigurationHandle.ParametersQueryTable[3].DefaultData != NULL ) {
+
+ ExFreePool(ConfigurationHandle.ParametersQueryTable[3].DefaultData);
+
+ }
+
+ if (AddAdapterStatus == NDIS_STATUS_SUCCESS) {
+ ++AdaptersAdded;
+ }
+
+ }
+
+LoopBottom:
+
+
+ //
+ // Now advance the "Bind" and "Export" values.
+ //
+
+ CurBindValue = (PWCHAR)((PUCHAR)CurBindValue + CurBindString.MaximumLength);
+ CurExportValue = (PWCHAR)((PUCHAR)CurExportValue + CurExportString.MaximumLength);
+
+ }
+
+
+ //
+ // OK, Now dereference all the filter packages. If a MAC or
+ // Miniport driver uses any of these, then the filter package
+ // will reference itself, to keep the image in memory.
+ //
+ ArcDereferencePackage();
+ EthDereferencePackage();
+ FddiDereferencePackage();
+ TrDereferencePackage();
+ MiniportDereferencePackage();
+ NdisMacDereferencePackage();
+
+ //
+ // Now close the handles we opened at the beginning.
+ //
+
+
+ ExFreePool (ConfigurationPath);
+ ExFreePool (BindData);
+ ExFreePool (ExportData);
+
+ //
+ // Succeed if any adapters were added.
+ //
+
+ if (AdaptersAdded > 0) {
+ return NDIS_STATUS_SUCCESS;
+ } else {
+ return NDIS_STATUS_FAILURE;
+ }
+
+#undef BLOCK_LOCK_MINIPORT
+
+}
+
+
+VOID
+NdisReadEisaSlotInformation(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PUINT SlotNumber,
+ OUT PNDIS_EISA_FUNCTION_INFORMATION EisaData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads the EISA data from the slot given.
+
+Arguments:
+
+ Status - Status of request to be returned to the user.
+ WrapperConfigurationContext - Context passed to MacAddAdapter.
+ SlotNumber - the EISA Slot where the card is at.
+ EisaData - pointer to a buffer where the EISA configuration is to be
+ returned.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_EISA_FUNCTION_INFORMATION EisaBlockPointer;
+ PNDIS_EISA_SLOT_INFORMATION SlotInformation;
+ NTSTATUS NtStatus;
+ ULONG BusNumber;
+ ULONG DataLength;
+ ULONG SearchSlotNumber;
+ ULONG FoundSlotNumber;
+ BOOLEAN Found;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG CompressedId = 0;
+ PWSTR CompressedIDString = L"EisaCompressedId";
+ PWSTR SlotNumberString = L"SlotNumber";
+ PWSTR Parameters = L"\\Parameters";
+ PNDIS_CONFIGURATION_PARAMETER ParameterValue;
+ NDIS_CONFIGURATION_HANDLE NdisConfiguration;
+ ULONG Length;
+ PWSTR PathName;
+
+ //
+ // Get the BusNumber and the BusType from the Context here!!
+ //
+
+ NdisConfiguration.KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+
+ BusType = (NDIS_INTERFACE_TYPE)(NdisConfiguration.KeyQueryTable[3].DefaultType);
+
+ BusNumber = NdisConfiguration.KeyQueryTable[3].DefaultLength;
+
+ //
+ // First check if any bus access is allowed
+ //
+
+ if ((BusType == (NDIS_INTERFACE_TYPE)-1) ||
+ (BusNumber == (ULONG)-1)) {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ SlotInformation = NdisConfiguration.KeyQueryTable[3].DefaultData;
+
+ *SlotNumber = 0;
+
+ if (BusType != Eisa) {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+
+ //
+ // Find the CompressedId for this board.
+ //
+
+ NdisConfiguration.KeyQueryTable[1].Name = CompressedIDString;
+ NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ //
+ // Get the value from the registry; this chains it on to the
+ // parameter list at NdisConfiguration.
+ //
+
+ NtStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ NdisConfiguration.KeyQueryTable,
+ &NdisConfiguration, // context
+ NULL);
+
+ if (NtStatus != NDIS_STATUS_SUCCESS) {
+ CompressedId = 0xffffffff;
+ } else if (ParameterValue->ParameterType != NdisParameterInteger) {
+ CompressedId = 0xffffffff;
+ } else {
+ CompressedId = ParameterValue->ParameterData.IntegerData;
+ }
+
+ //
+ // Was there already a buffer allocated?
+ //
+
+ if (SlotInformation == NULL) {
+
+ //
+ // No, allocate a buffer
+ //
+
+ SlotInformation = (PNDIS_EISA_SLOT_INFORMATION)ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ sizeof(NDIS_EISA_FUNCTION_INFORMATION),
+ 'isDN'
+ );
+
+ if (SlotInformation == NULL) {
+
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+
+ }
+
+ //
+ // Free any old buffer
+ //
+
+ if (NdisConfiguration.KeyQueryTable[3].DefaultData != NULL) {
+
+ ExFreePool(NdisConfiguration.KeyQueryTable[3].DefaultData);
+
+ }
+
+ NdisConfiguration.KeyQueryTable[3].DefaultData = SlotInformation;
+
+ }
+
+ //
+ // Now read the slot number
+ //
+
+ NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString;
+ NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ //
+ // Get the value from the registry; this chains it on to the
+ // parameter list at NdisConfiguration.
+ //
+
+ NtStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ NdisConfiguration.KeyQueryTable,
+ &NdisConfiguration, // context
+ NULL);
+
+ if ((NtStatus == NDIS_STATUS_SUCCESS) &&
+ (ParameterValue->ParameterType == NdisParameterInteger)) {
+
+ *SlotNumber = ParameterValue->ParameterData.IntegerData;
+
+ } else {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ DataLength = HalGetBusData(
+ EisaConfiguration,
+ BusNumber,
+ *SlotNumber,
+ (PVOID)SlotInformation,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ sizeof(NDIS_EISA_FUNCTION_INFORMATION)
+ );
+
+ if ((CompressedId != 0xFFFFFFFF) &&
+ ((SlotInformation->CompressedId & 0xFFFFFF) != CompressedId)) {
+
+ //
+ // The card seems to have been moved on us. Now we search for it.
+ //
+
+ SearchSlotNumber = 1;
+ Found = FALSE;
+
+ while (TRUE) {
+
+ //
+ // Search this slot
+ //
+ DataLength = HalGetBusData(
+ EisaConfiguration,
+ BusNumber,
+ SearchSlotNumber,
+ (PVOID)SlotInformation,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ sizeof(NDIS_EISA_FUNCTION_INFORMATION)
+ );
+
+ if ((DataLength == 0) ||
+ (SearchSlotNumber == 0xFF)) {
+ //
+ // End of slots.
+ //
+ break;
+
+ }
+
+ if ((SlotInformation->CompressedId & 0xFFFFFF) == CompressedId) {
+
+ //
+ // Found one!
+ //
+
+ if (Found) {
+
+ //
+ // Uh-oh, found two of them! Fail
+ //
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ Found = TRUE;
+ FoundSlotNumber = SearchSlotNumber;
+
+ }
+
+ SearchSlotNumber++;
+
+ }
+
+ if (!Found) {
+ //
+ // No card found
+ //
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ //
+ // Find the SlotNumber parameter in the registry.
+ //
+
+ *SlotNumber = FoundSlotNumber;
+
+ NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString;
+ NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ Length = wcslen(NdisConfiguration.KeyQueryTable[3].Name);
+
+ PathName = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(L"\\Parameters") +
+ (Length * sizeof(WCHAR)) +
+ sizeof(WCHAR),
+ ' DN'
+ );
+
+ if (PathName != NULL) {
+
+ NdisZeroMemory(PathName, sizeof(L"\\Parameters") +
+ (Length * sizeof(WCHAR)) +
+ sizeof(WCHAR)
+ );
+
+ NdisMoveMemory(PathName,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ Length * sizeof(WCHAR)
+ );
+
+ NdisMoveMemory(PathName + Length, Parameters, sizeof(L"\\Parameters"));
+
+ //
+ // Update the value
+ //
+
+ NtStatus = RtlWriteRegistryValue(
+ RTL_REGISTRY_SERVICES,
+ PathName,
+ SlotNumberString,
+ REG_DWORD,
+ &FoundSlotNumber,
+ sizeof(FoundSlotNumber)
+ );
+
+ ExFreePool(PathName);
+
+ }
+
+ //
+ // Get the new information
+ //
+
+ DataLength = HalGetBusData(
+ EisaConfiguration,
+ BusNumber,
+ FoundSlotNumber,
+ (PVOID)SlotInformation,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ sizeof(NDIS_EISA_FUNCTION_INFORMATION)
+ );
+
+ }
+
+ EisaBlockPointer = (PNDIS_EISA_FUNCTION_INFORMATION)
+ ((PUCHAR)SlotInformation + sizeof(CM_EISA_SLOT_INFORMATION));
+
+ *EisaData = *EisaBlockPointer;
+ *Status = NDIS_STATUS_SUCCESS;
+
+}
+
+
+VOID
+NdisReadEisaSlotInformationEx(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PUINT SlotNumber,
+ OUT PNDIS_EISA_FUNCTION_INFORMATION *EisaData,
+ OUT PUINT NumberOfFunctions
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads the EISA data from the slot given.
+
+Arguments:
+
+ Status - Status of request to be returned to the user.
+ WrapperConfigurationContext - Context passed to MacAddAdapter.
+ SlotNumber - the EISA Slot where the card is at.
+ EisaData - pointer to a buffer where the EISA configuration is to be
+ returned.
+ NumberOfFunctions - Returns the number of function structures in the EisaData.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_EISA_FUNCTION_INFORMATION EisaBlockPointer;
+ PNDIS_EISA_SLOT_INFORMATION SlotInformation;
+ NTSTATUS NtStatus;
+ ULONG BusNumber;
+ ULONG DataLength;
+ ULONG SearchSlotNumber;
+ ULONG FoundSlotNumber;
+ BOOLEAN Found;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG CompressedId = 0;
+ PWSTR CompressedIDString = L"EisaCompressedId";
+ PWSTR SlotNumberString = L"SlotNumber";
+ PWSTR Parameters = L"\\Parameters";
+ PNDIS_CONFIGURATION_PARAMETER ParameterValue;
+ NDIS_CONFIGURATION_HANDLE NdisConfiguration;
+ ULONG Length;
+ PWSTR PathName;
+
+ //
+ // Get the BusNumber and the BusType from the Context here!!
+ //
+
+ NdisConfiguration.KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+
+ BusType = (NDIS_INTERFACE_TYPE)(NdisConfiguration.KeyQueryTable[3].DefaultType);
+
+ BusNumber = NdisConfiguration.KeyQueryTable[3].DefaultLength;
+
+ //
+ // First check if any bus access is allowed
+ //
+
+ if ((BusType == (NDIS_INTERFACE_TYPE)-1) ||
+ (BusNumber == (ULONG)-1)) {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ SlotInformation = NdisConfiguration.KeyQueryTable[3].DefaultData;
+
+ *SlotNumber = 0;
+ *NumberOfFunctions = 2;
+
+ if (BusType != Eisa) {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+
+ //
+ // Find the CompressedId for this board.
+ //
+
+ NdisConfiguration.KeyQueryTable[1].Name = CompressedIDString;
+ NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ //
+ // Get the value from the registry; this chains it on to the
+ // parameter list at NdisConfiguration.
+ //
+
+ NtStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ NdisConfiguration.KeyQueryTable,
+ &NdisConfiguration, // context
+ NULL);
+
+ if (NtStatus != NDIS_STATUS_SUCCESS) {
+ CompressedId = 0xffffffff;
+ } else if (ParameterValue->ParameterType != NdisParameterInteger) {
+ CompressedId = 0xffffffff;
+ } else {
+ CompressedId = ParameterValue->ParameterData.IntegerData;
+ }
+
+ //
+ // Was there already a buffer allocated?
+ //
+
+ if (SlotInformation == NULL) {
+
+ //
+ // No, allocate a buffer
+ //
+
+ SlotInformation = (PNDIS_EISA_SLOT_INFORMATION)ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ (*NumberOfFunctions *
+ sizeof(NDIS_EISA_FUNCTION_INFORMATION)),
+ 'isDN'
+ );
+
+ if (SlotInformation == NULL) {
+
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+
+ }
+
+ //
+ // Free any old buffer
+ //
+
+ if (NdisConfiguration.KeyQueryTable[3].DefaultData != NULL) {
+
+ ExFreePool(NdisConfiguration.KeyQueryTable[3].DefaultData);
+
+ }
+
+ NdisConfiguration.KeyQueryTable[3].DefaultData = SlotInformation;
+
+ }
+
+ //
+ // Now read the slot number
+ //
+
+ NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString;
+ NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ //
+ // Get the value from the registry; this chains it on to the
+ // parameter list at NdisConfiguration.
+ //
+
+ NtStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ NdisConfiguration.KeyQueryTable,
+ &NdisConfiguration, // context
+ NULL);
+
+ if ((NtStatus == NDIS_STATUS_SUCCESS) &&
+ (ParameterValue->ParameterType == NdisParameterInteger)) {
+
+ *SlotNumber = ParameterValue->ParameterData.IntegerData;
+
+ } else {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ DataLength = HalGetBusData(
+ EisaConfiguration,
+ BusNumber,
+ *SlotNumber,
+ (PVOID)SlotInformation,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION))
+ );
+
+ if ((CompressedId != 0xFFFFFFFF) &&
+ ((SlotInformation->CompressedId & 0xFFFFFF) != CompressedId)) {
+
+ //
+ // The card seems to have been moved on us. Now we search for it.
+ //
+
+ SearchSlotNumber = 1;
+ Found = FALSE;
+
+ while (TRUE) {
+
+ //
+ // Search this slot
+ //
+ DataLength = HalGetBusData(
+ EisaConfiguration,
+ BusNumber,
+ SearchSlotNumber,
+ (PVOID)SlotInformation,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION))
+ );
+
+ if ((DataLength == 0) ||
+ (SearchSlotNumber == 0xFF)) {
+ //
+ // End of slots.
+ //
+ break;
+
+ }
+
+ if ((SlotInformation->CompressedId & 0xFFFFFF) == CompressedId) {
+
+ //
+ // Found one!
+ //
+
+ if (Found) {
+
+ //
+ // Uh-oh, found two of them! Fail
+ //
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ Found = TRUE;
+ FoundSlotNumber = SearchSlotNumber;
+
+ }
+
+ SearchSlotNumber++;
+
+ }
+
+ if (!Found) {
+ //
+ // No card found
+ //
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ //
+ // Find the SlotNumber parameter in the registry.
+ //
+
+ *SlotNumber = FoundSlotNumber;
+
+ NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString;
+ NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ Length = wcslen(NdisConfiguration.KeyQueryTable[3].Name);
+
+ PathName = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(L"\\Parameters") +
+ (Length * sizeof(WCHAR)) +
+ sizeof(WCHAR),
+ ' DN'
+ );
+
+ if (PathName != NULL) {
+
+ NdisZeroMemory(PathName, sizeof(L"\\Parameters") +
+ (Length * sizeof(WCHAR)) +
+ sizeof(WCHAR)
+ );
+
+ NdisMoveMemory(PathName,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ Length * sizeof(WCHAR)
+ );
+
+ NdisMoveMemory(PathName + Length, Parameters, sizeof(L"\\Parameters"));
+
+ //
+ // Update the value
+ //
+
+ NtStatus = RtlWriteRegistryValue(
+ RTL_REGISTRY_SERVICES,
+ PathName,
+ SlotNumberString,
+ REG_DWORD,
+ &FoundSlotNumber,
+ sizeof(FoundSlotNumber)
+ );
+
+ ExFreePool(PathName);
+
+ }
+
+ //
+ // Get the new information
+ //
+
+ DataLength = HalGetBusData(
+ EisaConfiguration,
+ BusNumber,
+ FoundSlotNumber,
+ (PVOID)SlotInformation,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION))
+ );
+
+ }
+
+
+ //
+ // Now check for multiple functions in the Eisa data.
+ //
+
+ while (DataLength == (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION))) {
+
+ *NumberOfFunctions++;
+
+ //
+ // Now allocate a new buffer
+ //
+
+ SlotInformation = (PNDIS_EISA_SLOT_INFORMATION)ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ (*NumberOfFunctions *
+ sizeof(NDIS_EISA_FUNCTION_INFORMATION)),
+ 'isDN'
+ );
+
+ if (SlotInformation == NULL) {
+
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+
+ }
+
+ //
+ // Free any old buffer
+ //
+
+ if (NdisConfiguration.KeyQueryTable[3].DefaultData != NULL) {
+
+ ExFreePool(NdisConfiguration.KeyQueryTable[3].DefaultData);
+
+ }
+
+ NdisConfiguration.KeyQueryTable[3].DefaultData = SlotInformation;
+
+ //
+ // Get new information
+ //
+
+ DataLength = HalGetBusData(
+ EisaConfiguration,
+ BusNumber,
+ FoundSlotNumber,
+ (PVOID)SlotInformation,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION))
+ );
+
+ }
+
+ EisaBlockPointer = (PNDIS_EISA_FUNCTION_INFORMATION)
+ ((PUCHAR)SlotInformation + sizeof(CM_EISA_SLOT_INFORMATION));
+
+ *EisaData = EisaBlockPointer;
+ *NumberOfFunctions--; // We overshoot by 1 to verify last one found.
+ *Status = NDIS_STATUS_SUCCESS;
+
+}
+
+
+VOID
+NdisReadMcaPosInformation(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PUINT ChannelNumber,
+ OUT PNDIS_MCA_POS_DATA McaData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads the MCA data from the POS corresponding to
+ the channel specified.
+
+Arguments:
+
+ WrapperConfigurationContext - Context passed to MacAddAdapter.
+ ChannelNumber - the MCA channel number.
+ McaData - pointer to a buffer where the channel information is to be
+ returned.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ OBJECT_ATTRIBUTES BusObjectAttributes;
+ PWSTR McaPath = L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter";
+ PWSTR ConfigData = L"Configuration Data";
+ PWSTR PosIdString = L"McaPosId";
+ PWSTR SlotNumberString = L"SlotNumber";
+ UNICODE_STRING RootName;
+ UNICODE_STRING BusName;
+ UNICODE_STRING ConfigDataName;
+ NTSTATUS NtStatus;
+ PKEY_BASIC_INFORMATION BasicInformation;
+ PKEY_VALUE_FULL_INFORMATION ValueInformation;
+ PUCHAR BufferPointer;
+ PCM_FULL_RESOURCE_DESCRIPTOR FullResource;
+ PCM_PARTIAL_RESOURCE_LIST ResourceList;
+ PNDIS_MCA_POS_DATA McaBlockPointer;
+ HANDLE McaHandle, BusHandle;
+ ULONG BytesWritten, BytesNeeded;
+ ULONG Index;
+ ULONG i;
+ ULONG BusNumber;
+ ULONG MaxSlotNumber;
+ ULONG SearchSlotNumber;
+ ULONG FoundSlotNumber;
+ BOOLEAN Found;
+ USHORT PosId;
+ NDIS_INTERFACE_TYPE BusType;
+ NDIS_CONFIGURATION_HANDLE NdisConfiguration;
+ PNDIS_CONFIGURATION_PARAMETER ParameterValue;
+ PWSTR Parameters = L"\\Parameters";
+ ULONG Length;
+ PWSTR PathName;
+
+ *Status = NDIS_STATUS_FAILURE;
+
+ NdisConfiguration.KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+
+ //
+ // Get the BusNumber and the BusType from the Context here!!
+ //
+
+ BusType = (NDIS_INTERFACE_TYPE)(NdisConfiguration.KeyQueryTable[3].DefaultType);
+ BusNumber = NdisConfiguration.KeyQueryTable[3].DefaultLength;
+
+ //
+ // First check if any bus access is allowed
+ //
+
+ if ((BusType == (NDIS_INTERFACE_TYPE)-1) ||
+ (BusNumber == (ULONG)-1)) {
+
+ return;
+
+ }
+
+
+ if (BusType != MicroChannel) {
+
+ return;
+
+ }
+
+ *ChannelNumber = 0;
+
+ //
+ // Find the PosId for this board.
+ //
+
+ NdisConfiguration.KeyQueryTable[1].Name = PosIdString;
+ NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ //
+ // Get the value from the registry; this chains it on to the
+ // parameter list at NdisConfiguration.
+ //
+
+ NtStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ NdisConfiguration.KeyQueryTable,
+ &NdisConfiguration, // context
+ NULL);
+
+ if (NtStatus != NDIS_STATUS_SUCCESS) {
+ PosId = 0xffff;
+ } else if (ParameterValue->ParameterType != NdisParameterInteger) {
+ PosId = 0xffff;
+ } else {
+ PosId = (USHORT)(ParameterValue->ParameterData.IntegerData);
+ }
+
+ RtlInitUnicodeString(
+ &RootName,
+ McaPath
+ );
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &RootName,
+ OBJ_CASE_INSENSITIVE,
+ (HANDLE)NULL,
+ NULL
+ );
+
+ //
+ // Open the root.
+ //
+
+ NtStatus = ZwOpenKey(
+ &McaHandle,
+ KEY_READ,
+ &ObjectAttributes
+ );
+
+ if (!NT_SUCCESS(NtStatus)) {
+
+ return;
+
+ }
+
+ Index = 0;
+
+ while (TRUE) {
+
+ //
+ // Enumerate through keys, searching for the proper bus number
+ //
+
+ NtStatus = ZwEnumerateKey(
+ McaHandle,
+ Index,
+ KeyBasicInformation,
+ NULL,
+ 0,
+ &BytesNeeded
+ );
+
+ //
+ // That should fail!
+ //
+
+ if (BytesNeeded == 0) {
+
+ Index++;
+ continue;
+
+ }
+
+ BasicInformation = (PKEY_BASIC_INFORMATION)ExAllocatePoolWithTag(
+ NonPagedPool,
+ BytesNeeded,
+ ' DN'
+ );
+
+ if (BasicInformation == NULL) {
+
+ ZwClose(McaHandle);
+
+ return;
+ }
+
+ NtStatus = ZwEnumerateKey(
+ McaHandle,
+ Index,
+ KeyBasicInformation,
+ BasicInformation,
+ BytesNeeded,
+ &BytesWritten
+ );
+
+ if (!NT_SUCCESS(NtStatus)) {
+
+ ExFreePool(BasicInformation);
+
+ ZwClose(McaHandle);
+
+ return;
+ }
+
+
+ //
+ // Init the BusName String
+ //
+
+ BusName.MaximumLength = (USHORT)BasicInformation->NameLength;
+ BusName.Length = (USHORT)BasicInformation->NameLength;
+ BusName.Buffer = BasicInformation->Name;
+
+ //
+ // Now try to find Configuration Data within this Key
+ //
+
+ InitializeObjectAttributes(
+ &BusObjectAttributes,
+ &BusName,
+ OBJ_CASE_INSENSITIVE,
+ (HANDLE)McaHandle,
+ NULL
+ );
+
+ //
+ // Open the MCA root + Bus Number
+ //
+
+ NtStatus = ZwOpenKey(
+ &BusHandle,
+ KEY_READ,
+ &BusObjectAttributes
+ );
+
+ ExFreePool(BasicInformation);
+
+ if (!NT_SUCCESS(NtStatus)) {
+
+ Index++;
+
+ continue;
+
+ }
+
+ //
+ // opening the configuration data. This first call tells us how
+ // much memory we need to allocate
+ //
+
+ RtlInitUnicodeString(
+ &ConfigDataName,
+ ConfigData
+ );
+
+ //
+ // This should fail
+ //
+
+ NtStatus = ZwQueryValueKey(
+ BusHandle,
+ &ConfigDataName,
+ KeyValueFullInformation,
+ NULL,
+ 0,
+ &BytesNeeded
+ );
+
+
+ ValueInformation = (PKEY_VALUE_FULL_INFORMATION)ExAllocatePoolWithTag(
+ NonPagedPool,
+ BytesNeeded,
+ ' DN'
+ );
+
+
+ if (ValueInformation == NULL) {
+
+ Index++;
+
+ ZwClose(BusHandle);
+
+ continue;
+
+ }
+
+ NtStatus = ZwQueryValueKey(
+ BusHandle,
+ &ConfigDataName,
+ KeyValueFullInformation,
+ ValueInformation,
+ BytesNeeded,
+ &BytesWritten
+ );
+
+ if (!NT_SUCCESS(NtStatus)) {
+
+ Index++;
+
+ ExFreePool(ValueInformation);
+
+ ZwClose(BusHandle);
+
+ continue;
+
+ }
+
+ //
+ // Search for our bus number and type
+ //
+
+
+ //
+ // What we got back from the registry is actually a blob of data that
+ // looks like this
+ //
+ // ------------------------------------------
+ // |FULL |PAR |PAR |MCA |MCA |MCA |
+ // |RES. |RES |RES |POS |POS |POS | . . .
+ // |DESC |LIST|DESC|DATA|DATA|DATA|
+ // ------------------------------------------
+ // slot 0 1 2 . . .
+ //
+ // Out of this mess we need to grovel a pointer to the first block
+ // of MCA_POS_DATA, then we can just index by slot number.
+ //
+
+ BufferPointer = ((PUCHAR)ValueInformation) + ValueInformation->DataOffset;
+ FullResource = (PCM_FULL_RESOURCE_DESCRIPTOR) BufferPointer;
+
+ if (FullResource->InterfaceType != MicroChannel) {
+
+ //
+ // Get next key
+ //
+
+ ExFreePool(ValueInformation);
+
+ Index++;
+
+ ZwClose(BusHandle);
+
+ continue;
+
+ }
+
+ if (FullResource->BusNumber != BusNumber) {
+
+ //
+ // Get next key
+ //
+
+ ExFreePool(ValueInformation);
+
+ Index++;
+
+ ZwClose(BusHandle);
+
+ continue;
+
+ }
+
+
+ //
+ // Found it!!
+ //
+
+ ResourceList = &FullResource->PartialResourceList;
+
+ //
+ // Find the device-specific information, which is where the POS data is.
+ //
+
+ for (i=0; i<ResourceList->Count; i++) {
+ if (ResourceList->PartialDescriptors[i].Type == CmResourceTypeDeviceSpecific) {
+ break;
+ }
+ }
+
+ if (i == ResourceList->Count) {
+ //
+ // Couldn't find device-specific information.
+ //
+
+#if DBG
+ DbgPrint("NDIS: couldn't find POS data in registry\n");
+#endif
+
+ ExFreePool(ValueInformation);
+ *Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+ return;
+
+ }
+
+ //
+ // Was there a buffer already there?
+ //
+
+ if (NdisConfiguration.KeyQueryTable[3].DefaultData != NULL) {
+
+ //
+ // Free it
+ //
+
+ ExFreePool(NdisConfiguration.KeyQueryTable[3].DefaultData);
+
+ }
+
+ //
+ // Now read the slot number
+ //
+
+ NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString;
+ NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ //
+ // Get the value from the registry; this chains it on to the
+ // parameter list at NdisConfiguration.
+ //
+
+ NtStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ NdisConfiguration.KeyQueryTable,
+ &NdisConfiguration, // context
+ NULL);
+
+ if ((NtStatus == NDIS_STATUS_SUCCESS) &&
+ (ParameterValue->ParameterType == NdisParameterInteger)) {
+
+ *ChannelNumber = ParameterValue->ParameterData.IntegerData;
+
+ } else {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ //
+ // Store buffer
+ //
+
+ NdisConfiguration.KeyQueryTable[3].DefaultData = ValueInformation;
+
+ McaBlockPointer = (PNDIS_MCA_POS_DATA)(&ResourceList->PartialDescriptors[i+1]);
+ MaxSlotNumber = ResourceList->PartialDescriptors[i].u.DeviceSpecificData.DataSize /
+ sizeof(NDIS_MCA_POS_DATA);
+
+ *McaData = *(McaBlockPointer + (*ChannelNumber) - 1);
+
+ if ((PosId != 0xFFFF) &&
+ (McaData->AdapterId != PosId)) {
+
+ //
+ // The card seems to have been moved on us. Now we search for it.
+ //
+
+ SearchSlotNumber = 1;
+ Found = FALSE;
+
+ while (SearchSlotNumber <= MaxSlotNumber) {
+
+ *McaData = *(McaBlockPointer + (SearchSlotNumber - 1));
+
+ if (McaData->AdapterId == PosId) {
+
+ //
+ // Found one!
+ //
+
+ if (Found) {
+
+ //
+ // Uh-oh, found two of them! Fail
+ //
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ Found = TRUE;
+ FoundSlotNumber = SearchSlotNumber;
+
+ }
+
+ SearchSlotNumber++;
+
+ }
+
+ if (!Found) {
+ //
+ // No card found
+ //
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ //
+ // Find the SlotNumber parameter in the registry.
+ //
+
+ *ChannelNumber = FoundSlotNumber;
+
+ NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString;
+ NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ Length = wcslen(NdisConfiguration.KeyQueryTable[3].Name);
+
+ PathName = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(L"\\Parameters") +
+ (Length * sizeof(WCHAR)) +
+ sizeof(WCHAR),
+ ' DN'
+ );
+
+ if (PathName != NULL) {
+
+ NdisZeroMemory(PathName, sizeof(L"\\Parameters") +
+ (Length * sizeof(WCHAR)) +
+ sizeof(WCHAR)
+ );
+
+ NdisMoveMemory(PathName,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ Length * sizeof(WCHAR)
+ );
+
+ NdisMoveMemory(PathName + Length, Parameters, sizeof(L"\\Parameters"));
+
+ //
+ // Update the value
+ //
+
+ NtStatus = RtlWriteRegistryValue(
+ RTL_REGISTRY_SERVICES,
+ PathName,
+ SlotNumberString,
+ REG_DWORD,
+ &FoundSlotNumber,
+ sizeof(FoundSlotNumber)
+ );
+
+ ExFreePool(PathName);
+
+ }
+
+ //
+ // Update the value
+ //
+ NtStatus = RtlWriteRegistryValue(
+ RTL_REGISTRY_SERVICES,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ SlotNumberString,
+ REG_DWORD,
+ &FoundSlotNumber,
+ sizeof(FoundSlotNumber)
+ );
+
+ //
+ // Get the new information
+ //
+
+ *McaData = *(McaBlockPointer + (FoundSlotNumber - 1));
+
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ ZwClose(McaHandle);
+
+ return;
+
+ }
+
+}
+
+#if !defined(BUILD_FOR_3_1)
+
+NDIS_STATUS
+NdisPciAssignResources(
+ IN NDIS_HANDLE NdisMacHandle,
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SlotNumber,
+ OUT PNDIS_RESOURCE_LIST *AssignedResources
+ )
+/*++
+
+Routine Description:
+
+ This routine uses the Hal to assign a set of resources to a PCI
+ device.
+
+Arguments:
+
+ NdisMacHandle - Handle returned from NdisRegisterMac.
+
+ NdisWrapperHandle - Handle returned from NdisInitializeWrapper.
+
+ WrapperConfigurationContext - Handle passed to MacAddAdapter.
+
+ SlotNumber - Slot number of the device.
+
+ AssignedResources - The returned resources.
+
+Return Value:
+
+ Status of the operation
+
+--*/
+{
+ NTSTATUS NtStatus;
+ ULONG BusNumber;
+ NDIS_INTERFACE_TYPE BusType;
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable;
+ PCM_RESOURCE_LIST AllocatedResources = NULL;
+ PNDIS_WRAPPER_HANDLE NdisMacInfo = (PNDIS_WRAPPER_HANDLE)NdisWrapperHandle;
+
+ //
+ // Get the BusNumber and the BusType from the Context here!!
+ //
+
+ KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+
+ BusType = (NDIS_INTERFACE_TYPE)KeyQueryTable[3].DefaultType;
+
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ NtStatus = HalAssignSlotResources (
+ (PUNICODE_STRING)(NdisMacInfo->NdisWrapperConfigurationHandle),
+ NULL,
+ NdisMacInfo->NdisWrapperDriver,
+ NULL,
+ BusType,
+ BusNumber,
+ SlotNumber,
+ &AllocatedResources
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+ *AssignedResources = NULL;
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Store resources into the driver wide block
+ //
+ ((PNDIS_MAC_BLOCK)NdisMacHandle)->PciAssignedResources = AllocatedResources;
+
+ *AssignedResources = &(AllocatedResources->List[0].PartialResourceList);
+
+ return(NDIS_STATUS_SUCCESS);
+
+}
+
+
+
+ULONG
+NdisReadPciSlotInformation(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This routine reads from the PCI configuration space a specified
+ length of bytes at a certain offset.
+
+Arguments:
+
+ NdisAdapterHandle - Adapter we are talking about.
+
+ SlotNumber - The slot number of the device.
+
+ Offset - Offset to read from
+
+ Buffer - Place to store the bytes
+
+ Length - Number of bytes to read
+
+Return Value:
+
+ Returns the number of bytes read.
+
+--*/
+{
+ PNDIS_ADAPTER_BLOCK Adapter = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle;
+ ULONG DataLength;
+
+ if (Adapter->DeviceObject == NULL) {
+
+ //
+ // This is a mini-port
+ //
+
+#if DBG
+ ASSERT(Miniport->BusType == NdisInterfacePci);
+#endif
+
+ DataLength = HalGetBusDataByOffset(
+ PCIConfiguration,
+ Miniport->BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length
+ );
+
+ return(DataLength);
+
+ } else {
+
+#if DBG
+ ASSERT(Adapter->BusType == NdisInterfacePci);
+#endif
+
+ DataLength = HalGetBusDataByOffset(
+ PCIConfiguration,
+ Adapter->BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length
+ );
+
+ return(DataLength);
+
+ }
+
+}
+
+ULONG
+NdisWritePciSlotInformation(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This routine writes to the PCI configuration space a specified
+ length of bytes at a certain offset.
+
+Arguments:
+
+ NdisAdapterHandle - Adapter we are talking about.
+
+ SlotNumber - The slot number of the device.
+
+ Offset - Offset to read from
+
+ Buffer - Place to store the bytes
+
+ Length - Number of bytes to read
+
+Return Value:
+
+ Returns the number of bytes written.
+
+--*/
+{
+ PNDIS_ADAPTER_BLOCK Adapter = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle;
+ ULONG DataLength;
+
+ if (Adapter->DeviceObject == NULL) {
+
+ //
+ // This is a mini-port
+ //
+
+#if DBG
+ ASSERT(Miniport->BusType == NdisInterfacePci);
+#endif
+
+ DataLength = HalSetBusDataByOffset(
+ PCIConfiguration,
+ Miniport->BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length
+ );
+
+ return(DataLength);
+
+ } else {
+
+#if DBG
+ ASSERT(Adapter->BusType == NdisInterfacePci);
+#endif
+
+ DataLength = HalSetBusDataByOffset(
+ PCIConfiguration,
+ Adapter->BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length
+ );
+
+ return(DataLength);
+
+ }
+
+}
+
+#else // !defined(BUILD_FOR_3_1)
+
+NDIS_STATUS
+NdisPciAssignResources(
+ IN NDIS_HANDLE NdisMacHandle,
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SlotNumber,
+ OUT PNDIS_RESOURCE_LIST *AssignedResources
+ )
+{
+ return NDIS_STATUS_FAILURE;
+}
+
+ULONG
+NdisReadPciSlotInformation(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+{
+ return 0;
+}
+
+ULONG
+NdisWritePciSlotInformation(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+{
+ return 0;
+}
+
+#endif // else !defined(BUILD_FOR_3_1)
+
+
+VOID
+NdisOpenFile(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE FileHandle,
+ OUT PUINT FileLength,
+ IN PNDIS_STRING FileName,
+ IN NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine opens a file for future mapping and reads its contents
+ into allocated memory.
+
+Arguments:
+
+ Status - The status of the operation
+
+ FileHandle - A handle to be associated with this open
+
+ FileLength - Returns the length of the file
+
+ FileName - The name of the file
+
+ HighestAcceptableAddress - The highest physical address at which
+ the memory for the file can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ NTSTATUS NtStatus;
+ IO_STATUS_BLOCK IoStatus;
+ HANDLE NtFileHandle;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ ULONG LengthOfFile;
+ WCHAR PathPrefix[] = L"\\SystemRoot\\system32\\drivers\\";
+ NDIS_STRING FullFileName;
+ ULONG FullFileNameLength;
+ PNDIS_FILE_DESCRIPTOR FileDescriptor;
+ PVOID FileImage;
+
+ //
+ // This structure represents the data from the
+ // NtQueryInformationFile API with an information
+ // class of FileStandardInformation.
+ //
+
+ FILE_STANDARD_INFORMATION StandardInfo;
+
+
+ //
+ // Insert the correct path prefix.
+ //
+
+ FullFileNameLength = sizeof(PathPrefix) + FileName->MaximumLength;
+ FullFileName.Buffer = ExAllocatePoolWithTag (NonPagedPool, FullFileNameLength, ' DN');
+
+ if (FullFileName.Buffer == NULL) {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+ FullFileName.Length = sizeof (PathPrefix) - sizeof(WCHAR);
+ FullFileName.MaximumLength = (USHORT)FullFileNameLength;
+ RtlCopyMemory (FullFileName.Buffer, PathPrefix, sizeof(PathPrefix));
+
+ RtlAppendUnicodeStringToString (&FullFileName, FileName);
+
+#if DBG
+ DbgPrint ("NDIS: Attempting to open %Z\n", &FullFileName);
+#endif
+
+ InitializeObjectAttributes (
+ &ObjectAttributes,
+ &FullFileName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ NtStatus = ZwCreateFile(
+ &NtFileHandle,
+ SYNCHRONIZE | FILE_READ_DATA,
+ &ObjectAttributes,
+ &IoStatus,
+ NULL,
+ 0,
+ FILE_SHARE_READ,
+ FILE_OPEN,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0
+ );
+
+ if (!NT_SUCCESS(NtStatus)) {
+#if DBG
+ DbgPrint ("Error opening file %x\n", NtStatus);
+#endif
+ ExFreePool (FullFileName.Buffer);
+ *Status = NDIS_STATUS_FILE_NOT_FOUND;
+ return;
+ }
+
+ ExFreePool (FullFileName.Buffer);
+
+ //
+ // Query the object to determine its length.
+ //
+
+ NtStatus = ZwQueryInformationFile(
+ NtFileHandle,
+ &IoStatus,
+ &StandardInfo,
+ sizeof(FILE_STANDARD_INFORMATION),
+ FileStandardInformation
+ );
+
+ if (!NT_SUCCESS(NtStatus)) {
+#if DBG
+ DbgPrint ("Error querying info on file %x\n", NtStatus);
+#endif
+ ZwClose(NtFileHandle);
+ *Status = NDIS_STATUS_ERROR_READING_FILE;
+ return;
+ }
+
+ LengthOfFile = StandardInfo.EndOfFile.LowPart;
+
+#if DBG
+ DbgPrint ("File length is %d\n", LengthOfFile);
+#endif
+
+ //
+ // Might be corrupted.
+ //
+
+ if (LengthOfFile < 1) {
+#if DBG
+ DbgPrint ("Bad file length %d\n", LengthOfFile);
+#endif
+ ZwClose(NtFileHandle);
+ *Status = NDIS_STATUS_ERROR_READING_FILE;
+ return;
+ }
+
+ //
+ // Allocate buffer for this file
+ //
+
+ FileImage = ExAllocatePoolWithTag(NonPagedPool, LengthOfFile, ' DN');
+
+ if (FileImage == NULL) {
+
+#if DBG
+ DbgPrint ("Could not allocate buffer\n");
+#endif
+ ZwClose(NtFileHandle);
+ *Status = NDIS_STATUS_ERROR_READING_FILE;
+ return;
+
+ }
+
+ //
+ // Read the file into our buffer.
+ //
+
+ NtStatus = ZwReadFile(
+ NtFileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ FileImage,
+ LengthOfFile,
+ NULL,
+ NULL
+ );
+
+ ZwClose(NtFileHandle);
+
+ if ((!NT_SUCCESS(NtStatus)) || (IoStatus.Information != LengthOfFile)) {
+#if DBG
+ DbgPrint ("error reading file %x\n", NtStatus);
+#endif
+ *Status = NDIS_STATUS_ERROR_READING_FILE;
+ ExFreePool(FileImage);
+ return;
+ }
+
+ //
+ // Allocate a structure to describe the file.
+ //
+
+ FileDescriptor = ExAllocatePoolWithTag (NonPagedPool, sizeof(NDIS_FILE_DESCRIPTOR), ' DN');
+
+ if (FileDescriptor == NULL) {
+ *Status = NDIS_STATUS_RESOURCES;
+ ExFreePool(FileImage);
+ return;
+ }
+
+
+ FileDescriptor->Data = FileImage;
+ NdisAllocateSpinLock (&FileDescriptor->Lock);
+ FileDescriptor->Mapped = FALSE;
+
+ *FileHandle = (NDIS_HANDLE)FileDescriptor;
+ *FileLength = LengthOfFile;
+ *Status = STATUS_SUCCESS;
+
+}
+
+
+VOID
+NdisCloseFile(
+ IN NDIS_HANDLE FileHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine closes a file previously opened with NdisOpenFile.
+ The file is unmapped if needed and the memory is freed.
+
+Arguments:
+
+ FileHandle - The handle returned by NdisOpenFile
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_FILE_DESCRIPTOR FileDescriptor = (PNDIS_FILE_DESCRIPTOR)FileHandle;
+
+ ExFreePool (FileDescriptor->Data);
+ ExFreePool (FileDescriptor);
+
+}
+
+
+VOID
+NdisMapFile(
+ OUT PNDIS_STATUS Status,
+ OUT PVOID * MappedBuffer,
+ IN NDIS_HANDLE FileHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine maps an open file, so that the contents can be accessed.
+ Files can only have one active mapping at any time.
+
+Arguments:
+
+ Status - The status of the operation
+
+ MappedBuffer - Returns the virtual address of the mapping.
+
+ FileHandle - The handle returned by NdisOpenFile.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_FILE_DESCRIPTOR FileDescriptor = (PNDIS_FILE_DESCRIPTOR)FileHandle;
+
+ ACQUIRE_SPIN_LOCK(&FileDescriptor->Lock);
+
+ if (FileDescriptor->Mapped == TRUE) {
+ *Status = NDIS_STATUS_ALREADY_MAPPED;
+ RELEASE_SPIN_LOCK (&FileDescriptor->Lock);
+ return;
+ }
+
+ FileDescriptor->Mapped = TRUE;
+ RELEASE_SPIN_LOCK (&FileDescriptor->Lock);
+
+ *MappedBuffer = FileDescriptor->Data;
+ *Status = STATUS_SUCCESS;
+
+}
+
+
+VOID
+NdisUnmapFile(
+ IN NDIS_HANDLE FileHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unmaps a file previously mapped with NdisOpenFile.
+ The file is unmapped if needed and the memory is freed.
+
+Arguments:
+
+ FileHandle - The handle returned by NdisOpenFile
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_FILE_DESCRIPTOR FileDescriptor = (PNDIS_FILE_DESCRIPTOR)FileHandle;
+
+ FileDescriptor->Mapped = FALSE;
+
+}
+
+
+#if defined(_ALPHA_)
+VOID
+NdisCreateLookaheadBufferFromSharedMemory(
+ IN PVOID pSharedMemory,
+ IN UINT LookaheadLength,
+ OUT PVOID *pLookaheadBuffer
+ )
+/*++
+
+Routine Description:
+
+ This routine creates a lookahead buffer from a pointer to shared
+ RAM because some architectures (like ALPHA) do not allow access
+ through a pointer to shared ram.
+
+Arguments:
+
+ pSharedMemory - Pointer to shared ram space.
+
+ LookaheadLength - Amount of Lookahead to copy.
+
+ pLookaheadBuffer - Pointer to host memory space with a copy of the
+ stuff in pSharedMemory.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_LOOKAHEAD_ELEMENT TmpElement;
+
+ ACQUIRE_SPIN_LOCK(&NdisLookaheadBufferLock);
+
+ if (NdisLookaheadBufferLength < (LookaheadLength +
+ sizeof(NDIS_LOOKAHEAD_ELEMENT))) {
+
+ //
+ // Free current list
+ //
+ while (NdisLookaheadBufferList != NULL) {
+
+ TmpElement = NdisLookaheadBufferList;
+ NdisLookaheadBufferList = NdisLookaheadBufferList->Next;
+
+ ExFreePool ( TmpElement ) ;
+
+ }
+
+ NdisLookaheadBufferLength = LookaheadLength +
+ sizeof(NDIS_LOOKAHEAD_ELEMENT);
+
+ }
+
+ if (NdisLookaheadBufferList == NULL) {
+
+ NdisLookaheadBufferList = (PNDIS_LOOKAHEAD_ELEMENT)ExAllocatePoolWithTag(
+ NonPagedPool,
+ NdisLookaheadBufferLength,
+ 'blDN'
+ );
+
+ if (NdisLookaheadBufferList == NULL) {
+
+ *pLookaheadBuffer = NULL;
+ RELEASE_SPIN_LOCK(&NdisLookaheadBufferLock);
+ return;
+
+ }
+
+ NdisLookaheadBufferList->Next = NULL;
+ NdisLookaheadBufferList->Length = NdisLookaheadBufferLength;
+
+ }
+
+
+ //
+ // Get the buffer
+ //
+
+ *pLookaheadBuffer = (PVOID)(NdisLookaheadBufferList + 1);
+ NdisLookaheadBufferList = NdisLookaheadBufferList->Next;
+
+ RELEASE_SPIN_LOCK(&NdisLookaheadBufferLock);
+
+ //
+ // Copy the stuff across
+ //
+
+ READ_REGISTER_BUFFER_UCHAR(pSharedMemory, *pLookaheadBuffer, LookaheadLength);
+
+}
+
+
+VOID
+NdisDestroyLookaheadBufferFromSharedMemory(
+ IN PVOID pLookaheadBuffer
+ )
+/*++
+
+Routine Description:
+
+ This routine returns resources associated with a lookahead buffer.
+
+Arguments:
+
+ pLookaheadBuffer - Lookahead buffer created by
+ CreateLookaheadBufferFromSharedMemory.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_LOOKAHEAD_ELEMENT Element = (PNDIS_LOOKAHEAD_ELEMENT)pLookaheadBuffer;
+
+ Element--;
+
+ if (Element->Length != NdisLookaheadBufferLength) {
+
+ ExFreePool(Element);
+
+ } else {
+
+ ACQUIRE_SPIN_LOCK(&NdisLookaheadBufferLock);
+
+ Element->Next = NdisLookaheadBufferList;
+ NdisLookaheadBufferList = Element;
+
+ RELEASE_SPIN_LOCK(&NdisLookaheadBufferLock);
+
+ }
+
+}
+
+#endif // _ALPHA_
+
+
+BOOLEAN CheckPortUsage(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG PortNumber,
+ IN ULONG Length,
+ IN PDRIVER_OBJECT DriverObject
+)
+/*++
+
+Routine Description:
+
+ This routine checks if a port is currently in use somewhere in the
+ system via IoReportUsage -- which fails if there is a conflict.
+
+Arguments:
+
+ InterfaceType - The bus type (ISA, EISA)
+ BusNumber - Bus number in the system
+ PortNumber - Address of the port to access.
+ Length - Number of ports from the base address to access.
+
+Return Value:
+
+ FALSE if there is a conflict, else TRUE
+
+--*/
+
+{
+ NTSTATUS NtStatus;
+ BOOLEAN Conflict;
+ NTSTATUS FirstNtStatus;
+ BOOLEAN FirstConflict;
+ PCM_RESOURCE_LIST Resources;
+
+ //
+ // Allocate space for resources
+ //
+
+ Resources = (PCM_RESOURCE_LIST)ExAllocatePool(
+ NonPagedPool,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
+ );
+
+ if (Resources == NULL) {
+
+ //
+ // Error out
+ //
+
+ return(FALSE);
+
+ }
+
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = InterfaceType;
+ Resources->List[0].BusNumber = BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+ Resources->List[0].PartialResourceList.Count = 1;
+
+ //
+ // Setup port
+ //
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].Type = CmResourceTypePort;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition = CmResourceShareDriverExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].Flags =
+ (InterfaceType == Internal)?
+ CM_RESOURCE_PORT_MEMORY :
+ CM_RESOURCE_PORT_IO;
+#if !defined(BUILD_FOR_3_1)
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start.QuadPart = PortNumber;
+#else
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start =
+ RtlConvertUlongToLargeInteger((ULONG)(PortNumber));
+#endif
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Length =
+ Length;
+
+ //
+ // Submit Resources
+ //
+
+ FirstNtStatus = IoReportResourceUsage(
+ NULL,
+ DriverObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NULL,
+ NULL,
+ 0,
+ TRUE,
+ &FirstConflict
+ );
+
+ //
+ // Now clear it out
+ //
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ DriverObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NULL,
+ NULL,
+ 0,
+ TRUE,
+ &Conflict
+ );
+
+ ExFreePool(Resources);
+
+ //
+ // Check for conflict.
+ //
+
+ if (FirstConflict || (FirstNtStatus != STATUS_SUCCESS)) {
+
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+NTSTATUS
+StartMapping(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG InitialAddress,
+ IN ULONG Length,
+ OUT PVOID *InitialMapping,
+ OUT PBOOLEAN Mapped
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initialize the mapping of a address into virtual
+ space dependent on the bus number, etc.
+
+Arguments:
+
+ InterfaceType - The bus type (ISA, EISA)
+ BusNumber - Bus number in the system
+ InitialAddress - Address to access.
+ Length - Number of bytes from the base address to access.
+ InitialMapping - The virtual address space to use when accessing the
+ address.
+ Mapped - Did an MmMapIoSpace() take place.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ PHYSICAL_ADDRESS Address;
+ PHYSICAL_ADDRESS InitialPhysAddress;
+ ULONG addressSpace;
+
+ //
+ // Get the system physical address for this card. The card uses
+ // I/O space, except for "internal" Jazz devices which use
+ // memory space.
+ //
+
+ *Mapped = FALSE;
+
+ addressSpace = (InterfaceType == Internal) ? 0 : 1;
+
+ InitialPhysAddress.LowPart = InitialAddress;
+
+ InitialPhysAddress.HighPart = 0;
+
+ if ( !HalTranslateBusAddress(
+ InterfaceType, // InterfaceType
+ BusNumber, // BusNumber
+ InitialPhysAddress, // Bus Address
+ &addressSpace, // AddressSpace
+ &Address // Translated address
+ ) ) {
+
+ //
+ // It would be nice to return a better status here, but we only get
+ // TRUE/FALSE back from HalTranslateBusAddress.
+ //
+
+ return NDIS_STATUS_FAILURE;
+ }
+
+ if (addressSpace == 0) {
+
+ //
+ // memory space
+ //
+
+ *InitialMapping = MmMapIoSpace(
+ Address,
+ Length,
+ FALSE
+ );
+
+ if (*InitialMapping == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ *Mapped = TRUE;
+
+ } else {
+
+ //
+ // I/O space
+ //
+
+ *InitialMapping = (PVOID)Address.LowPart;
+
+ }
+
+ return(STATUS_SUCCESS);
+
+}
+
+
+NTSTATUS
+EndMapping(
+ IN PVOID InitialMapping,
+ IN ULONG Length,
+ IN BOOLEAN Mapped
+ )
+
+/*++
+
+Routine Description:
+
+ This routine undoes the mapping of an address into virtual
+ space dependent on the bus number, etc.
+
+Arguments:
+
+ InitialMapping - The virtual address space to use when accessing the
+ address.
+ Length - Number of bytes from the base address to access.
+ Mapped - Do we need to call MmUnmapIoSpace.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+
+ if (Mapped) {
+
+ //
+ // memory space
+ //
+
+ MmUnmapIoSpace(InitialMapping, Length);
+
+ }
+
+ return(STATUS_SUCCESS);
+
+}
+
+
+VOID
+NdisImmediateReadPortUchar(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ OUT PUCHAR Data
+ )
+/*++
+
+Routine Description:
+
+ This routine reads from a port a UCHAR. It does all the mapping,
+ etc, to do the read here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ Port - Port number to read from.
+
+ Data - Pointer to place to store the result.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID PortMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the port is available.
+ //
+ if (CheckPortUsage(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(UCHAR),
+ DriverObject
+ ) == FALSE) {
+
+ *Data = (UCHAR)0xFF;
+ return;
+
+ }
+
+ //
+ // Map the space
+ //
+
+ Status = StartMapping(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(UCHAR),
+ &PortMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ *Data = (UCHAR)0xFF;
+ return;
+
+ }
+
+ //
+ // Read from the port
+ //
+
+ *Data = READ_PORT_UCHAR((PUCHAR)PortMapping);
+
+ //
+ // End port mapping
+ //
+
+ EndMapping(
+ PortMapping,
+ sizeof(UCHAR),
+ Mapped
+ );
+
+}
+
+VOID
+NdisImmediateReadPortUshort(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ OUT PUSHORT Data
+ )
+/*++
+
+Routine Description:
+
+ This routine reads from a port a USHORT. It does all the mapping,
+ etc, to do the read here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ Port - Port number to read from.
+
+ Data - Pointer to place to store the result.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID PortMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the port is available.
+ //
+ if (CheckPortUsage(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(USHORT),
+ DriverObject
+ ) == FALSE) {
+
+ *Data = (USHORT)0xFFFF;
+ return;
+
+ }
+
+ //
+ // Map the space
+ //
+
+ Status = StartMapping(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(USHORT),
+ &PortMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ *Data = (USHORT)0xFFFF;
+ return;
+
+ }
+
+ //
+ // Read from the port
+ //
+
+ *Data = READ_PORT_USHORT((PUSHORT)PortMapping);
+
+ //
+ // End port mapping
+ //
+
+ EndMapping(
+ PortMapping,
+ sizeof(USHORT),
+ Mapped
+ );
+
+}
+
+VOID
+NdisImmediateReadPortUlong(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ OUT PULONG Data
+ )
+/*++
+
+Routine Description:
+
+ This routine reads from a port a ULONG. It does all the mapping,
+ etc, to do the read here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ Port - Port number to read from.
+
+ Data - Pointer to place to store the result.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID PortMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the port is available.
+ //
+ if (CheckPortUsage(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(ULONG),
+ DriverObject
+ ) == FALSE) {
+
+ *Data = (ULONG)0xFFFFFFFF;
+ return;
+
+ }
+
+ //
+ // Map the space
+ //
+
+ Status = StartMapping(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(ULONG),
+ &PortMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ *Data = (ULONG)0xFFFFFFFF;
+ return;
+
+ }
+
+ //
+ // Read from the port
+ //
+
+ *Data = READ_PORT_ULONG((PULONG)PortMapping);
+
+ //
+ // End port mapping
+ //
+
+ EndMapping(
+ PortMapping,
+ sizeof(ULONG),
+ Mapped
+ );
+
+}
+
+VOID
+NdisImmediateWritePortUchar(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ IN UCHAR Data
+ )
+/*++
+
+Routine Description:
+
+ This routine writes to a port a UCHAR. It does all the mapping,
+ etc, to do the write here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ Port - Port number to read from.
+
+ Data - Pointer to place to store the result.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID PortMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the port is available.
+ //
+ if (CheckPortUsage(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(UCHAR),
+ DriverObject
+ ) == FALSE) {
+
+ return;
+
+ }
+
+ //
+ // Map the space
+ //
+
+ Status = StartMapping(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(UCHAR),
+ &PortMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ return;
+
+ }
+
+ //
+ // Read from the port
+ //
+
+ WRITE_PORT_UCHAR((PUCHAR)PortMapping, Data);
+
+ //
+ // End port mapping
+ //
+
+ EndMapping(
+ PortMapping,
+ sizeof(UCHAR),
+ Mapped
+ );
+
+}
+
+VOID
+NdisImmediateWritePortUshort(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ IN USHORT Data
+ )
+/*++
+
+Routine Description:
+
+ This routine writes to a port a USHORT. It does all the mapping,
+ etc, to do the write here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ Port - Port number to read from.
+
+ Data - Pointer to place to store the result.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID PortMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the port is available.
+ //
+ if (CheckPortUsage(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(USHORT),
+ DriverObject
+ ) == FALSE) {
+
+ return;
+
+ }
+
+ //
+ // Map the space
+ //
+
+ Status = StartMapping(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(USHORT),
+ &PortMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ return;
+
+ }
+
+ //
+ // Read from the port
+ //
+
+ WRITE_PORT_USHORT((PUSHORT)PortMapping, Data);
+
+ //
+ // End port mapping
+ //
+
+ EndMapping(
+ PortMapping,
+ sizeof(USHORT),
+ Mapped
+ );
+
+}
+
+VOID
+NdisImmediateWritePortUlong(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ IN ULONG Data
+ )
+/*++
+
+Routine Description:
+
+ This routine writes to a port a ULONG. It does all the mapping,
+ etc, to do the write here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ Port - Port number to read from.
+
+ Data - Pointer to place to store the result.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID PortMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the port is available.
+ //
+ if (CheckPortUsage(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(ULONG),
+ DriverObject
+ ) == FALSE) {
+
+ return;
+
+ }
+
+ //
+ // Map the space
+ //
+
+ Status = StartMapping(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(ULONG),
+ &PortMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ return;
+
+ }
+
+ //
+ // Read from the port
+ //
+
+ WRITE_PORT_ULONG((PULONG)PortMapping, Data);
+
+ //
+ // End port mapping
+ //
+
+ EndMapping(
+ PortMapping,
+ sizeof(ULONG),
+ Mapped
+ );
+
+}
+
+BOOLEAN CheckMemoryUsage(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG Address,
+ IN ULONG Length,
+ IN PDRIVER_OBJECT DriverObject
+)
+/*++
+Routine Description:
+
+ This routine checks if a range of memory is currently in use somewhere
+ in the system via IoReportUsage -- which fails if there is a conflict.
+
+Arguments:
+
+ InterfaceType - The bus type (ISA, EISA)
+ BusNumber - Bus number in the system
+ Address - Starting Address of the memory to access.
+ Length - Length of memory from the base address to access.
+
+Return Value:
+
+ FALSE if there is a conflict, else TRUE
+
+--*/
+{
+ NTSTATUS NtStatus;
+ BOOLEAN Conflict;
+ NTSTATUS FirstNtStatus;
+ BOOLEAN FirstConflict;
+ PCM_RESOURCE_LIST Resources;
+
+ //
+ // Allocate space for resources
+ //
+
+ Resources = (PCM_RESOURCE_LIST)ExAllocatePool(
+ NonPagedPool,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
+ );
+
+ if (Resources == NULL) {
+
+ //
+ // Error out
+ //
+
+ return(FALSE);
+
+ }
+
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = InterfaceType;
+ Resources->List[0].BusNumber = BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+ Resources->List[0].PartialResourceList.Count = 1;
+
+ //
+ // Setup memory
+ //
+
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].Type =
+ CmResourceTypeMemory;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition =
+ CmResourceShareDriverExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].Flags =
+ CM_RESOURCE_MEMORY_READ_WRITE;
+#if !defined(BUILD_FOR_3_1)
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Memory.Start.QuadPart = Address;
+#else
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Memory.Start =
+ RtlConvertUlongToLargeInteger((ULONG)(Address));
+#endif
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Memory.Length =
+ Length;
+
+
+ //
+ // Submit Resources
+ //
+
+ FirstNtStatus = IoReportResourceUsage(
+ NULL,
+ DriverObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NULL,
+ NULL,
+ 0,
+ TRUE,
+ &FirstConflict
+ );
+
+ //
+ // Now clear it out
+ //
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ DriverObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NULL,
+ NULL,
+ 0,
+ TRUE,
+ &Conflict
+ );
+
+ ExFreePool(Resources);
+
+ //
+ // Check for conflict.
+ //
+
+ if (FirstConflict || (FirstNtStatus != STATUS_SUCCESS)) {
+
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+VOID
+NdisImmediateReadSharedMemory(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SharedMemoryAddress,
+ OUT PUCHAR Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This routine read into a buffer from shared ram. It does all the mapping,
+ etc, to do the read here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ SharedMemoryAddress - The physical address to read from.
+
+ Buffer - The buffer to read into.
+
+ Length - Length of the buffer in bytes.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID MemoryMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the memory is available.
+ //
+ if (CheckMemoryUsage(
+ BusType,
+ BusNumber,
+ SharedMemoryAddress,
+ Length,
+ DriverObject
+ ) == FALSE) {
+
+ return;
+
+ }
+
+ //
+ // Map the space
+ //
+
+ Status = StartMapping(
+ BusType,
+ BusNumber,
+ SharedMemoryAddress,
+ Length,
+ &MemoryMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ return;
+
+ }
+
+ //
+ // Read from memory
+ //
+
+#ifdef _M_IX86
+
+ memcpy(Buffer, MemoryMapping, Length);
+
+#else
+
+ READ_REGISTER_BUFFER_UCHAR(MemoryMapping,Buffer,Length);
+
+#endif
+
+ //
+ // End mapping
+ //
+
+ EndMapping(
+ MemoryMapping,
+ Length,
+ Mapped
+ );
+
+}
+
+VOID
+NdisImmediateWriteSharedMemory(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SharedMemoryAddress,
+ IN PUCHAR Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This routine writes a buffer to shared ram. It does all the mapping,
+ etc, to do the write here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ SharedMemoryAddress - The physical address to write to.
+
+ Buffer - The buffer to write.
+
+ Length - Length of the buffer in bytes.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID MemoryMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the memory is available.
+ //
+ if (CheckMemoryUsage(
+ BusType,
+ BusNumber,
+ SharedMemoryAddress,
+ Length,
+ DriverObject
+ ) == FALSE) {
+
+ return;
+
+ }
+
+ //
+ // Map the space
+ //
+
+ Status = StartMapping(
+ BusType,
+ BusNumber,
+ SharedMemoryAddress,
+ Length,
+ &MemoryMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ return;
+
+ }
+
+ //
+ // Write to memory
+ //
+
+#ifdef _M_IX86
+
+ memcpy(MemoryMapping, Buffer, Length);
+
+#else
+
+ WRITE_REGISTER_BUFFER_UCHAR(MemoryMapping,Buffer,Length);
+
+#endif
+
+ //
+ // End mapping
+ //
+
+ EndMapping(
+ MemoryMapping,
+ Length,
+ Mapped
+ );
+
+}
+
+#if !defined(BUILD_FOR_3_1)
+
+ULONG
+NdisImmediateReadPciSlotInformation(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This routine reads from the PCI configuration space a specified
+ length of bytes at a certain offset.
+
+Arguments:
+
+ WrapperConfigurationContext - Context passed to MacAddAdapter.
+
+ SlotNumber - The slot number of the device.
+
+ Offset - Offset to read from
+
+ Buffer - Place to store the bytes
+
+ Length - Number of bytes to read
+
+Return Value:
+
+ Returns the number of bytes read.
+
+--*/
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ ULONG BusNumber;
+ ULONG DataLength;
+
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+#if DBG
+ {
+ NDIS_INTERFACE_TYPE BusType;
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ ASSERT(BusType == NdisInterfacePci);
+ }
+#endif
+
+ DataLength = HalGetBusDataByOffset(
+ PCIConfiguration,
+ BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length
+ );
+
+ return(DataLength);
+}
+
+ULONG
+NdisImmediateWritePciSlotInformation(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This routine writes to the PCI configuration space a specified
+ length of bytes at a certain offset.
+
+Arguments:
+
+ WrapperConfigurationContext - Context passed to MacAddAdapter.
+
+ SlotNumber - The slot number of the device.
+
+ Offset - Offset to read from
+
+ Buffer - Place to store the bytes
+
+ Length - Number of bytes to read
+
+Return Value:
+
+ Returns the number of bytes written.
+
+--*/
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ ULONG BusNumber;
+ ULONG DataLength;
+
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+#if DBG
+ {
+ NDIS_INTERFACE_TYPE BusType;
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ ASSERT(BusType == NdisInterfacePci);
+ }
+#endif
+
+ DataLength = HalSetBusDataByOffset(
+ PCIConfiguration,
+ BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length
+ );
+
+ return(DataLength);
+}
+
+#else // !defined(BUILD_FOR_3_1)
+
+ULONG
+NdisImmediateReadPciSlotInformation(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+{
+ return 0;
+}
+
+ULONG
+NdisImmediateWritePciSlotInformation(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+{
+ return 0;
+}
+
+#endif // !defined(BUILD_FOR_3_1)
+
+
+CCHAR
+NdisSystemProcessorCount(
+ VOID
+ )
+{
+ return *KeNumberProcessors;
+}
+
+
+VOID
+NdisOverrideBusNumber(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN NDIS_HANDLE MiniportAdapterHandle OPTIONAL,
+ IN ULONG BusNumber
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to override the BusNumber value retrieved
+ from the registry. It is expected to be used by PCI drivers
+ that discover that their adapter's bus number has changed.
+
+Arguments:
+
+ WrapperConfigurationContext - a handle pointing to an RTL_QUERY_REGISTRY_TABLE
+ that is set up for this driver's parameters.
+
+ MiniportAdapterHandle - points to the adapter block, if the calling
+ driver is a miniport. If the calling driver is a full MAC, this
+ parameter must be NULL.
+
+ BusNumber - the new bus number.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+
+ ((PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext)[3].DefaultLength = BusNumber;
+
+ if (Miniport != NULL) {
+ Miniport->BusNumber = BusNumber;
+ }
+
+ return;
+}
+
diff --git a/private/ntos/ndis/ndis30/wrapper.h b/private/ntos/ndis/ndis30/wrapper.h
new file mode 100644
index 000000000..8885bd800
--- /dev/null
+++ b/private/ntos/ndis/ndis30/wrapper.h
@@ -0,0 +1,473 @@
+#include <ntddk.h>
+#include <ndismain.h>
+#include <ndismac.h>
+#include <ndismini.h>
+
+
+#if defined(BUILD_FOR_3_5) || defined(BUILD_FOR_3_1)
+
+#define Increment(a,b) ExInterlockedIncrementLong(a,b)
+#define Decrement(a,b) ExInterlockedDecrementLong(a,b)
+
+#else
+
+#define Increment(a,b) InterlockedIncrement(a)
+#define Decrement(a,b) InterlockedDecrement(a)
+
+#endif
+
+#if defined(BUILD_FOR_3_1)
+
+#define FASTCALL
+
+#define MmLockPagableImageSection(a) NULL
+#define MmUnlockPagableImageSection(a)
+
+#define COMPUTE_PAGES_SPANNED(Va, Size) \
+ ((((ULONG)Va & (PAGE_SIZE -1)) + (Size) + (PAGE_SIZE - 1)) >> PAGE_SHIFT)
+
+#define Int32x32To64(a,b) RtlEnlargedIntegerMultiply((a),(b)).QuadPart
+
+#define ExAllocatePoolWithTag(a,b,c) ExAllocatePool((a),(b))
+
+NTSTATUS
+NTAPI
+RtlCharToInteger (
+ PCSZ String,
+ ULONG Base,
+ PULONG Value
+ );
+
+#endif
+
+#if defined(BUILD_FOR_3_5)
+#define MmLockPagableCodeSection(x) MmLockPagableImageSection(x)
+#endif
+
+#define ACQUIRE_SPIN_LOCK(_SpinLock) KeAcquireSpinLock(&(_SpinLock)->SpinLock, &(_SpinLock)->OldIrql)
+#define RELEASE_SPIN_LOCK(_SpinLock) KeReleaseSpinLock(&(_SpinLock)->SpinLock, (_SpinLock)->OldIrql)
+#define ACQUIRE_SPIN_LOCK_DPC(_SpinLock) KeAcquireSpinLockAtDpcLevel(&(_SpinLock)->SpinLock)
+#define RELEASE_SPIN_LOCK_DPC(_SpinLock) KeReleaseSpinLockFromDpcLevel(&(_SpinLock)->SpinLock)
+
+
+#if DBG
+#define NDISDBG 0
+#endif
+#if !defined(NDISDBG)
+#define NDISDBG 0
+#endif
+
+#if NDISDBG
+
+#if defined(MEMPRINT)
+#include "memprint.h" //DavidTr's memprint program at ntos\srv
+#endif // MEMPRINT
+
+extern int NdisMsgLevel;
+extern BOOLEAN NdisChkErrorFlag;
+
+#define TRACE_NONE 0x0000
+#define TRACE_IMPT 0x0001
+#define TRACE_ALL 0x0002
+
+#define IF_TRACE(level) if ( NdisMsgLevel >= (level) ) //for tracing
+
+#define IF_ERROR_CHK if (NdisChkErrorFlag) // for parameter checking
+
+#define DbgIsNonPaged(_Address) \
+ ( MmIsNonPagedSystemAddressValid((PVOID)(_Address)) )
+
+#define DbgIsPacket(_Packet) \
+ ( ((_Packet)->Private.Pool->PacketLength) > sizeof(_Packet) )
+
+#define DbgIsNull(_Ptr) ( ((PVOID)(_Ptr)) == NULL )
+
+#define NdisPrint1(fmt) DbgPrint(fmt)
+#define NdisPrint2(fmt,v1) DbgPrint(fmt,v1)
+#define NdisPrint3(fmt,v1,v2) DbgPrint(fmt,v1,v2)
+#define NdisPrint4(fmt,v1,v2,v3) DbgPrint(fmt,v1,v2,v3)
+#define NdisPrint5(fmt,v1,v2,v3,v4) DbgPrint(fmt,v1,v2,v3,v4)
+
+#else // NDISDBG
+
+#define IF_TRACE(level) if (FALSE)
+#define IF_ERROR_CHK if (FALSE)
+
+#define DbgIsNonPaged(_Address) TRUE
+#define DbgIsPacket(_Packet) TRUE
+#define DbgIsNull(_Ptr) FALSE
+
+#define NdisPrint1(fmt)
+#define NdisPrint2(fmt,v1)
+#define NdisPrint3(fmt,v1,v2)
+#define NdisPrint4(fmt,v1,v2,v3)
+#define NdisPrint5(fmt,v1,v2,v3,v4)
+
+#endif // NDISDBG
+
+
+#if DBG
+#define MINIPORT_AT_DPC_LEVEL (KeGetCurrentIrql() == DISPATCH_LEVEL)
+#else
+#define MINIPORT_AT_DPC_LEVEL 1
+#endif
+
+
+//
+// This is the number of extra OIDs that ARCnet with Ethernet encapsulation
+// supports.
+//
+#define ARC_NUMBER_OF_EXTRA_OIDS 2
+
+
+
+//
+// Internal wrapper data structures.
+//
+
+//
+// NDIS_WRAPPER_CONTEXT
+//
+// This data structure contains internal data items for use by the wrapper.
+//
+
+typedef struct _NDIS_WRAPPER_CONTEXT {
+
+ //
+ // Mac/miniport defined shutdown context.
+ //
+
+ PVOID ShutdownContext;
+
+ //
+ // Mac/miniport registered shutdown handler.
+ //
+
+ ADAPTER_SHUTDOWN_HANDLER ShutdownHandler;
+
+#if !defined(BUILD_FOR_3_1)
+ //
+ // Kernel bugcheck record for bugcheck handling.
+ //
+
+ KBUGCHECK_CALLBACK_RECORD BugcheckCallbackRecord;
+#endif
+
+ //
+ // Miniport assigned resources for PCI, PCMCIA, EISA, etc.
+ //
+
+ PCM_RESOURCE_LIST AssignedSlotResources;
+
+ //
+ // HAL common buffer cache.
+ //
+
+ PVOID SharedMemoryPage[2];
+ ULONG SharedMemoryLeft[2];
+ NDIS_PHYSICAL_ADDRESS SharedMemoryAddress[2];
+
+} NDIS_WRAPPER_CONTEXT, *PNDIS_WRAPPER_CONTEXT;
+
+//
+// Lock/unlock miniport macros.
+//
+
+#define LOCK_MINIPORT(_M_, _L) \
+{ \
+ if (_M_->LockAcquired) { \
+ _L = FALSE; \
+ } else { \
+ _L = TRUE; \
+ _M_->LockAcquired = TRUE; \
+ } \
+}
+
+#define UNLOCK_MINIPORT(_M_, _L) \
+{ \
+ if (_L) { \
+ _M_->LockAcquired = FALSE; \
+ } \
+}
+
+
+NDIS_STATUS
+NdisInitialInit(
+ PDRIVER_OBJECT Driver OPTIONAL
+ );
+
+VOID
+FASTCALL
+MiniportProcessDeferred(
+ PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+NDIS_STATUS
+NdisMTransferDataSync(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+#define MINIPORT_DISABLE_INTERRUPT(_M_) \
+{ \
+ ASSERT(_M_->DriverHandle->MiniportCharacteristics.DisableInterruptHandler != NULL); \
+ (_M_->DriverHandle->MiniportCharacteristics.DisableInterruptHandler)( \
+ _M_->MiniportAdapterContext \
+ ); \
+}
+
+#define MINIPORT_SYNC_DISABLE_INTERRUPT(_M_) \
+{ \
+ if (_M_->DriverHandle->MiniportCharacteristics.DisableInterruptHandler != NULL) { \
+ KeSynchronizeExecution( \
+ (_M_)->Interrupt->InterruptObject, \
+ (PKSYNCHRONIZE_ROUTINE)(_M_->DriverHandle->MiniportCharacteristics.DisableInterruptHandler),\
+ _M_->MiniportAdapterContext \
+ ); \
+ } \
+}
+
+#define CHECK_FOR_NORMAL_INTERRUPTS(_Miniport) \
+ _Miniport->NormalInterrupts = (BOOLEAN)(!_Miniport->HaltingMiniport && \
+ !_Miniport->InInitialize && \
+ (_Miniport->Interrupt != NULL) && \
+ !_Miniport->Interrupt->IsrRequested && \
+ !_Miniport->Interrupt->SharedInterrupt)
+
+//
+// general reference/dereference functions
+//
+
+BOOLEAN
+NdisReferenceRef(
+ IN PREFERENCE RefP
+ );
+
+
+BOOLEAN
+NdisDereferenceRef(
+ PREFERENCE RefP
+ );
+
+
+VOID
+NdisInitializeRef(
+ PREFERENCE RefP
+ );
+
+
+BOOLEAN
+NdisCloseRef(
+ PREFERENCE RefP
+ );
+
+
+/*++
+BOOLEAN
+NdisReferenceProtocol(
+ IN PNDIS_PROTOCOL_BLOCK ProtP
+ );
+--*/
+
+#define NdisReferenceProtocol(ProtP) \
+ NdisReferenceRef(&(ProtP)->Ref)
+
+
+
+BOOLEAN
+QueueOpenOnProtocol(
+ IN PNDIS_OPEN_BLOCK OpenP,
+ IN PNDIS_PROTOCOL_BLOCK ProtP
+ );
+
+
+/*++
+VOID
+NdisDereferenceProtocol(
+ PNDIS_PROTOCOL_BLOCK ProtP
+ );
+--*/
+#define NdisDereferenceProtocol(ProtP) { \
+ if (NdisDereferenceRef(&(ProtP)->Ref)) { \
+ ExFreePool((PVOID)(ProtP)); \
+ } \
+}
+
+
+
+VOID
+NdisDeQueueOpenOnProtocol(
+ PNDIS_OPEN_BLOCK OpenP,
+ PNDIS_PROTOCOL_BLOCK ProtP
+ );
+
+
+BOOLEAN
+NdisFinishOpen(
+ PNDIS_OPEN_BLOCK OpenP
+ );
+
+
+VOID
+NdisKillOpenAndNotifyProtocol(
+ PNDIS_OPEN_BLOCK OldOpenP
+ );
+
+
+BOOLEAN
+NdisKillOpen(
+ PNDIS_OPEN_BLOCK OldOpenP
+ );
+
+/*++
+BOOLEAN
+NdisReferenceMac(
+ IN PNDIS_MAC_BLOCK MacP
+ );
+--*/
+#define NdisReferenceMac(MacP) \
+ NdisReferenceRef(&(MacP)->Ref)
+
+static
+VOID
+NdisDereferenceMac(
+ PNDIS_MAC_BLOCK MacP
+ );
+
+BOOLEAN
+NdisQueueAdapterOnMac(
+ PNDIS_ADAPTER_BLOCK AdaptP,
+ PNDIS_MAC_BLOCK MacP
+ );
+
+VOID
+NdisDeQueueAdapterOnMac(
+ PNDIS_ADAPTER_BLOCK AdaptP,
+ PNDIS_MAC_BLOCK MacP
+ );
+
+/*++
+BOOLEAN
+NdisReferenceAdapter(
+ IN PNDIS_ADAPTER_BLOCK AdaptP
+ );
+--*/
+#define NdisReferenceAdapter(AdaptP) \
+ NdisReferenceRef(&(AdaptP)->Ref)
+
+
+BOOLEAN
+NdisQueueOpenOnAdapter(
+ PNDIS_OPEN_BLOCK OpenP,
+ PNDIS_ADAPTER_BLOCK AdaptP
+ );
+
+VOID
+NdisKillAdapter(
+ PNDIS_ADAPTER_BLOCK OldAdaptP
+ );
+
+VOID
+NdisDereferenceAdapter(
+ PNDIS_ADAPTER_BLOCK AdaptP
+ );
+
+VOID
+NdisDeQueueOpenOnAdapter(
+ PNDIS_OPEN_BLOCK OpenP,
+ PNDIS_ADAPTER_BLOCK AdaptP
+ );
+
+NDIS_STATUS
+NdisCallDriverAddAdapter(
+ IN PNDIS_MAC_BLOCK NewMacP
+ );
+
+/*++
+BOOLEAN
+NdisReferenceDriver(
+ IN PNDIS_M_DRIVER_BLOCK DriverP
+ );
+--*/
+#define NdisReferenceDriver(DriverP) \
+ NdisReferenceRef(&(DriverP)->Ref)
+
+
+VOID
+NdisDereferenceDriver(
+ PNDIS_M_DRIVER_BLOCK DriverP
+ );
+
+BOOLEAN
+NdisQueueMiniportOnDriver(
+ PNDIS_MINIPORT_BLOCK MiniportP,
+ PNDIS_M_DRIVER_BLOCK DriverP
+ );
+
+VOID
+NdisDequeueMiniportOnDriver(
+ PNDIS_MINIPORT_BLOCK MiniportP,
+ PNDIS_M_DRIVER_BLOCK DriverP
+ );
+
+BOOLEAN
+NdisQueueOpenOnMiniport(
+ PNDIS_M_OPEN_BLOCK OpenP,
+ PNDIS_MINIPORT_BLOCK MiniportP
+ );
+
+VOID
+NdisKillMiniport(
+ PNDIS_MINIPORT_BLOCK OldMiniportP
+ );
+
+/*++
+BOOLEAN
+NdisReferenceMiniport(
+ IN PNDIS_MINIPORT_BLOCK MiniportP
+ );
+--*/
+#define NdisReferenceMiniport(MiniportP) \
+ NdisReferenceRef(&(MiniportP)->Ref)
+
+VOID
+NdisDereferenceMiniport(
+ PNDIS_MINIPORT_BLOCK MiniportP
+ );
+
+VOID
+NdisDeQueueOpenOnMiniport(
+ PNDIS_M_OPEN_BLOCK OpenP,
+ PNDIS_MINIPORT_BLOCK MiniportP
+ );
+
+VOID
+MiniportInitializePackage(
+ VOID
+ );
+
+VOID
+MiniportReferencePackage(
+ VOID
+ );
+
+VOID
+MiniportDereferencePackage(
+ VOID
+ );
+
+NDIS_STATUS ArcConvertOidListToEthernet(
+ IN PNDIS_OID pOidList,
+ IN PULONG pcbOidList,
+ IN PNDIS_OID pTmpBuffer
+);
+
+VOID
+NdisBugcheckHandler(
+ IN PNDIS_WRAPPER_CONTEXT WrapperContext,
+ IN ULONG Size
+ );
diff --git a/private/ntos/ndis/ndis30/wrapper.txt b/private/ntos/ndis/ndis30/wrapper.txt
new file mode 100644
index 000000000..2e52189f0
--- /dev/null
+++ b/private/ntos/ndis/ndis30/wrapper.txt
@@ -0,0 +1,120 @@
+Debug Wrapper
+
+Johnson Apacible (johnsona)
+3-11-91
+
+
+
+The debug version of the wrapper allows developers to
+1. turn on/off error checking
+2. control level of tracing. There are currently 2 levels of tracing:
+Level 2 tracing turns on tracing on all wrapper functions; while level
+1 tracing turns on tracing only on the more interesting functions.
+Level 1 and 2 functions are enumerated below:
+
+
+Level 1 Tracing enables tracing on the following functions:
+
+ NdisInitializePacketPool
+ NdisTerminatePacketPool
+
+ NdisRegisterProtocol
+ NdisDeregisterProtocol
+
+ NdisOpenAdapter
+ NdisCloseAdapter
+ FinishOpen
+
+ KillOpenAndNotifyProtocol
+ KillOpen
+
+ NdisInitializeWrapper
+ NdisTerminateWrapper
+
+ NdisRegisterMac
+ NdisDeregisterMac
+ DeQueueAdapterOnMac
+ QueueAdapterOnMac
+
+ QueueOpenOnProtocol
+ DeQueueOpenOnProtocol
+ NdisRegisterAdapter
+ NdisDeregisterAdapter
+ KillAdapter
+ QueueAdapterOnAdapter
+ DeQueueAdapterOnAdapter
+ NdisSetPacketFilter
+ NdisAddMulticastAddress
+ NdisDeleteMulticastAddress
+ NdisSend
+ NdisTransferData
+ NdisQueryInformation
+ NdisSetInformation
+ NdisReset
+ NdisTest
+ NdisCompleteRequest
+ NdisCompleteSend
+ NdisCompleteTransferData
+ NdisIndicateStatus
+ NdisIndicateStatusComplete
+
+
+Level 2 tracing enables tracing the functions listedbelow in addition
+to all Level 1 functions:
+
+ NdisQueryBuffer
+ NdisAllocatePacket
+ NdisDeallocatePacket
+ NdisReinitializePacket
+ NdisChainBufferAtFront
+ NdisChainBufferAtBack
+ NdisUnchainBufferAtFront
+ NdisUnchainBufferAtBack
+ NdisQueryPacket
+ NdisGetNextBuffer
+ ReferenceRef
+ DereferenceRef
+ InitializeRef
+ CloseRef
+ ReferenceProtocol
+ DereferenceProtocol
+ NdisSuccessIrplHandler
+ ReferencMac
+ ReferenceAdapter
+ DereferenceAdapter
+
+ NdisIndicateReceive
+ NdisIndicateReceiveComplete
+
+
+
+Turning on/off error checking
+
+Error checking may be turned on/off during run-time by changing the
+value of the flag NdisChkErrorFlag. A zero value turns off error
+checking and a non-zero value turn it on. This flag is turned on
+by default.
+
+
+Controlling level of messages
+
+Message level may by specified by changing the NdisMsgLevel variable.
+
+ Value of NdisMsgLevel Meaning
+ 0x000 Turn off all messages
+ 0x001 Turn on tracing on Level 1 functions
+ 0x002 Turn on all tracing
+
+NdisMsgLevel is set to 0 by default
+
+
+
+The debug code will be included only if the NDISDBG flag is turned on (== 1).
+
+If you do change this flag, be sure to delete (1) all nbf .obj files,
+(2) ntos\dd\init\obj\i386\ddinit.obj, (3) ntos\init\obj\i386\init.obj, and
+(4) recompile everything under ndis, since this flag will change a lot
+of goings on inside ndis.h
+
+
+ \ No newline at end of file