summaryrefslogtreecommitdiffstats
path: root/private/ntos/ndis/ndis40
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/ndis/ndis40')
-rw-r--r--private/ntos/ndis/ndis40/afilter.c2617
-rw-r--r--private/ntos/ndis/ndis40/bus.c1009
-rw-r--r--private/ntos/ndis/ndis40/common.c3452
-rw-r--r--private/ntos/ndis/ndis40/config.c2788
-rw-r--r--private/ntos/ndis/ndis40/configm.c2077
-rw-r--r--private/ntos/ndis/ndis40/data.c190
-rw-r--r--private/ntos/ndis/ndis40/debug.c422
-rw-r--r--private/ntos/ndis/ndis40/dirs23
-rw-r--r--private/ntos/ndis/ndis40/dummy.c56
-rw-r--r--private/ntos/ndis/ndis40/efilter.c2845
-rw-r--r--private/ntos/ndis/ndis40/ffilter.c3869
-rw-r--r--private/ntos/ndis/ndis40/filter.h181
-rw-r--r--private/ntos/ndis/ndis40/init.c1415
-rw-r--r--private/ntos/ndis/ndis40/initpnp.c2463
-rw-r--r--private/ntos/ndis/ndis40/mac.c3591
-rw-r--r--private/ntos/ndis/ndis40/mac.h48
-rw-r--r--private/ntos/ndis/ndis40/makefile6
-rw-r--r--private/ntos/ndis/ndis40/makefile.inc11
-rw-r--r--private/ntos/ndis/ndis40/mini.h251
-rw-r--r--private/ntos/ndis/ndis40/minint.c1293
-rw-r--r--private/ntos/ndis/ndis40/miniport.c3180
-rw-r--r--private/ntos/ndis/ndis40/minisub.c569
-rw-r--r--private/ntos/ndis/ndis40/mp/makefile6
-rw-r--r--private/ntos/ndis/ndis40/mp/ndis.prf136
-rw-r--r--private/ntos/ndis/ndis40/mp/sources29
-rw-r--r--private/ntos/ndis/ndis40/ndis.c1349
-rw-r--r--private/ntos/ndis/ndis40/ndis.rc39
-rw-r--r--private/ntos/ndis/ndis40/ndis.src328
-rw-r--r--private/ntos/ndis/ndis40/ndis_co.c3873
-rw-r--r--private/ntos/ndis/ndis40/ndisdbg.h270
-rw-r--r--private/ntos/ndis/ndis40/ndisnt.h325
-rw-r--r--private/ntos/ndis/ndis40/ndistags.h53
-rw-r--r--private/ntos/ndis/ndis40/pragma.h733
-rw-r--r--private/ntos/ndis/ndis40/precomp.h17
-rw-r--r--private/ntos/ndis/ndis40/protocol.c1757
-rw-r--r--private/ntos/ndis/ndis40/protos.h1991
-rw-r--r--private/ntos/ndis/ndis40/requestm.c3994
-rw-r--r--private/ntos/ndis/ndis40/sendm.c3212
-rw-r--r--private/ntos/ndis/ndis40/sendm.h334
-rw-r--r--private/ntos/ndis/ndis40/sources.inc77
-rw-r--r--private/ntos/ndis/ndis40/tfilter.c2813
-rw-r--r--private/ntos/ndis/ndis40/timer.c794
-rw-r--r--private/ntos/ndis/ndis40/timerm.c1080
-rw-r--r--private/ntos/ndis/ndis40/up/makefile6
-rw-r--r--private/ntos/ndis/ndis40/up/ndis.prf136
-rw-r--r--private/ntos/ndis/ndis40/up/sources29
-rw-r--r--private/ntos/ndis/ndis40/wrapper.h681
-rw-r--r--private/ntos/ndis/ndis40/wrapper.txt120
48 files changed, 56538 insertions, 0 deletions
diff --git a/private/ntos/ndis/ndis40/afilter.c b/private/ntos/ndis/ndis40/afilter.c
new file mode 100644
index 000000000..f0b8c972a
--- /dev/null
+++ b/private/ntos/ndis/ndis40/afilter.c
@@ -0,0 +1,2617 @@
+/*++
+
+Copyright (c) 1990-1995 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:
+
+ Jameel Hyder (JameelH) Re-organization 01-Jun-95
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+#include "sendm.h"
+
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_AFILTER
+
+//
+// Given an NDIS_PACKET this macro will tell us if it is
+// encapsulated ethernet.
+//
+#define ARC_PACKET_IS_ENCAPSULATED(Packet) \
+ (PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Open->Flags & fMINIPORT_OPEN_USING_ETH_ENCAPSULATION)
+
+//
+// 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:
+//
+// None
+//
+//--*/
+#define ARC_FILTER_FREE_OPEN(Filter, LocalOpen)\
+{\
+ SET_BIT_IN_MASK(((LocalOpen)->FilterIndex), &((Filter)->FreeBindingMask)); \
+ NdisFreeMemory((LocalOpen), sizeof(ARC_BINDING_INFO), 0);\
+}
+
+
+//
+// Defines for resource growth
+//
+#define ARC_BUFFER_SIZE 1024
+#define ARC_BUFFER_ALLOCATION_UNIT 8
+#define ARC_PACKET_ALLOCATION_UNIT 2
+
+
+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);
+ }
+
+ ZeroMemory(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
+ //
+ TmpUchar = ((ARC_PROTOCOL_HEADER *)pRawHeader)->ProtId;
+
+ if ( TmpUchar == 0xE8 )
+ {
+ if ((Length < (ARC_MAX_FRAME_SIZE + 4)) && (Length > 0))
+ {
+ //
+ // 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, // ethernet header.
+ Length); // length of ethernet frame.
+ //
+ // Ethernet header should be pData now
+ // Length should be data now
+ // We're done.
+ //
+ }
+
+ return;
+
+ }
+
+ // If the data portion is greater than 507 its a bad deal
+ if ((Length > ARC_MAX_FRAME_SIZE + 3) || (Length == 0))
+ {
+ return;
+ }
+
+ //
+ // Get information from packet
+ //
+ NewFrameInfo.ProtHeader.SourceId[0] = *((PUCHAR)pRawHeader);
+ NewFrameInfo.ProtHeader.DestId[0] = *((PUCHAR)pRawHeader + 1);
+
+ 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.
+ //
+ TmpUchar = *((PUCHAR)pData);
+
+ if (TmpUchar == 0xFF)
+ {
+ pData += 4;
+ Length -= 4;
+
+ //
+ // Re-read the split flag.
+ //
+ TmpUchar = *((PUCHAR)pData);
+ }
+
+ //
+ // Save off the split flag.
+ //
+ NewFrameInfo.SplitFlag = TmpUchar;
+
+ //
+ // Read the sequence number, which follows the split flag.
+ //
+ TmpUshort = 0;
+ TmpUshort = *((PUCHAR)pData + 1);
+ TmpUchar = *((PUCHAR)pData + 2);
+
+ TmpUshort = TmpUshort | (TmpUchar << 8);
+ NewFrameInfo.FrameSequence = TmpUshort;
+ //
+ // Point pData at protocol data.
+ //
+ Length -= 3; //... Length of protocol data.
+ pData += 3; //... Beginning of protocol data.
+ // Length is decreased by SF + SEQ0 + SEQ 1 = 3
+
+ //
+ // NOTE: Length is now the Length of the data portion of this packet
+ //
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_INFO,
+ ("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(DBG_COMP_FILTER, DBG_LEVEL_INFO,
+ ("ArcFilter: Data at address: %lx, Length = %ld\n", pData, Length));
+
+ 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;
+ }
+
+ ZeroMemory(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;
+
+ NdisFreeMemory(Packet, sizeof(ARC_PACKET), 0);
+ }
+
+ while (Filter->FreeBufferList)
+ {
+ Buffer = Filter->FreeBufferList;
+ Filter->FreeBufferList = Buffer->Next;
+
+ NdisFreeMemory(Buffer->Buffer, ARC_BUFFER_SIZE, 0);
+ NdisFreeMemory(Buffer, sizeof(ARC_BUFFER_LIST), 0);
+ }
+
+ 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;
+ 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)
+ {
+ PARC_BINDING_INFO *ppBI;
+
+ //
+ // Remove it from the list.
+ //
+
+ for (ppBI = &Filter->OpenList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextOpen)
+ {
+ if (*ppBI == LocalOpen)
+ {
+ *ppBI = LocalOpen->NextOpen;
+ break;
+ }
+ }
+ ASSERT(*ppBI == LocalOpen->NextOpen);
+
+ //
+ // First we finish any NdisIndicateReceiveComplete that
+ // may be needed for this binding.
+ //
+
+ if (LocalOpen->ReceivedAPacket)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+ }
+
+ 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;
+}
+
+
+VOID
+arcUndoFilterAdjust(
+ IN PARC_FILTER Filter,
+ IN PARC_BINDING_INFO Binding
+ )
+{
+ Binding->PacketFilters = Binding->OldPacketFilters;
+ Filter->CombinedPacketFilter = Filter->OldCombinedPacketFilter;
+}
+
+
+
+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->OldPacketFilters = LocalOpen->PacketFilters;
+ 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.
+ //
+ Filter->OldCombinedPacketFilter = Filter->CombinedPacketFilter;
+
+
+ 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, NextOpen;
+
+ 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.
+ //
+
+ if (!ArcConvertToNdisPacket(Filter, Packet, TRUE))
+ {
+ //
+ // Out of resources, abort.
+ //
+ return;
+ }
+
+ for (LocalOpen = Filter->OpenList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ NextOpen = LocalOpen->NextOpen;
+
+ //
+ // Reference the open during indication.
+ //
+
+ BindingFilters = LocalOpen->PacketFilters;
+
+ if (BindingFilters & AddressType)
+ {
+ LocalOpen->References++;
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ //
+ // 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);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ if ((--(LocalOpen->References)) == 0)
+ {
+ PARC_BINDING_INFO *ppBI;
+
+ //
+ // This binding is shutting down. We have to kill it.
+ //
+
+ //
+ // Remove it from the list.
+ //
+
+ for (ppBI = &Filter->OpenList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextOpen)
+ {
+ if (*ppBI == LocalOpen)
+ {
+ *ppBI = LocalOpen->NextOpen;
+ break;
+ }
+ }
+ ASSERT(*ppBI == LocalOpen->NextOpen);
+
+ //
+ // Call the IndicateComplete routine.
+ //
+
+
+ if (LocalOpen->ReceivedAPacket)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+ }
+
+ //
+ // 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);
+ } // end of if binding is shutting down
+
+ } // end of if any binding wants the packet
+ } // 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, NextOpen;
+
+ //
+ // We need to acquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+
+
+
+ for (LocalOpen = Filter->OpenList; LocalOpen != NULL; LocalOpen = NextOpen)
+ {
+ NextOpen = LocalOpen->NextOpen;
+
+ if (LocalOpen->ReceivedAPacket)
+ {
+ //
+ // Indicate the binding.
+ //
+
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ LocalOpen->References++;
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ if ((--(LocalOpen->References)) == 0)
+ {
+ PARC_BINDING_INFO *ppBI;
+
+ //
+ // This binding is shutting down. We have to kill it.
+ //
+
+ //
+ // Remove it from the list.
+ //
+
+ for (ppBI = &Filter->OpenList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextOpen)
+ {
+ if (*ppBI == LocalOpen)
+ {
+ *ppBI = LocalOpen->NextOpen;
+ break;
+ }
+ }
+ ASSERT(*ppBI == 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);
+ }
+ }
+ }
+}
+
+
+NDIS_STATUS
+ArcConvertOidListToEthernet(
+ IN PNDIS_OID OidList,
+ IN PULONG NumberOfOids
+)
+
+/*++
+
+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 < *NumberOfOids; c++)
+ {
+ switch (OidList[c])
+ {
+ case OID_ARCNET_PERMANENT_ADDRESS:
+ OidList[cArcOids++] = OID_802_3_PERMANENT_ADDRESS;
+ break;
+
+ case OID_ARCNET_CURRENT_ADDRESS:
+ OidList[cArcOids++] = OID_802_3_CURRENT_ADDRESS;
+ break;
+
+ case OID_ARCNET_RECONFIGURATIONS:
+ break;
+
+ default:
+ if ((OidList[c] & 0xFFF00000) != 0x06000000)
+ OidList[cArcOids++] = OidList[c];
+ break;
+ }
+ }
+
+ //
+ // Add the ethernet OIDs.
+ //
+ CopyMemory((PUCHAR)OidList + (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.
+ //
+ *NumberOfOids = cArcOids + ARC_NUMBER_OF_EXTRA_OIDS;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+VOID
+ndisMArcCopyFromBufferToPacket(
+ 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
+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)
+ {
+ ULONG PacketLength = 0;
+ PUCHAR Header = DataBuffer;
+
+ PacketLength = (ULONG)(((USHORT)Header[12] << 8) | (USHORT)Header[13]);
+
+ NdisMEthIndicateReceive(
+ (NDIS_HANDLE)Miniport, // miniport handle.
+ (NDIS_HANDLE)MacReceiveContext, // receive context.
+ DataBuffer, // ethernet header.
+ 14, // ethernet header length.
+ (PUCHAR)DataBuffer + 14, // ethernet data.
+ PacketLength, // ethernet data length.
+ PacketLength); // 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;
+ PNDIS_PACKET SrcPacket;
+ PNDIS_BUFFER NdisBuffer;
+ NDIS_STATUS Status;
+ NDIS_PACKET TempPacket;
+ KIRQL OldIrql;
+
+ MiniportOpen = (PNDIS_M_OPEN_BLOCK) NdisBindingHandle;
+ Miniport = MiniportOpen->MiniportHandle;
+ NdisBuffer = NULL;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ 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 (MINIPORT_TEST_FLAG(MiniportOpen, fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
+ {
+ //
+ // 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.
+
+ ZeroMemory(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);
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+NDIS_STATUS
+ndisMArcnetSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ PNDIS_PACKET_RESERVED Reserved;
+ KIRQL OldIrql;
+ BOOLEAN LocalLock;
+ PSINGLE_LIST_ENTRY Link;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, '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;
+
+ //
+ // Place the packet on the packet queue.
+ //
+ if (Miniport->FirstPacket == NULL)
+ {
+ //
+ // Place the packet at the head of the queue.
+ //
+ Miniport->FirstPacket = Packet;
+ }
+ else
+ {
+ CHECK_FOR_DUPLICATE_PACKET(Miniport, Packet);
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = Packet;
+ }
+
+ Miniport->LastPacket = Packet;
+
+ MINIPORT_CLEAR_PACKET_FLAG(Packet, fPACKET_HAS_BEEN_LOOPED_BACK);
+
+ if (Miniport->FirstPendingPacket == NULL)
+ {
+ Miniport->FirstPendingPacket = Packet;
+ }
+
+ //
+ // Queue a workitem to process the send.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+
+ //
+ // Can we get the lock?
+ //
+ 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.
+ //
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'W');
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ return(NDIS_STATUS_PENDING);
+}
+
+NDIS_STATUS
+ndisMBuildArcnetHeader(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_M_OPEN_BLOCK Open,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_BUFFER TmpBuffer;
+ UINT Flags;
+ PUCHAR Address;
+ PARC_BUFFER_LIST Buffer;
+ PNDIS_BUFFER NdisBuffer;
+ NDIS_STATUS Status;
+
+ //
+ // Only ethernet encapsulation needs this.
+ //
+ if (!MINIPORT_TEST_FLAG(Open, fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
+ {
+ return(NDIS_STATUS_SUCCESS);
+ }
+
+ if (NULL == Miniport->ArcnetFreeBufferList)
+ {
+ //
+ // 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;
+
+}
+
+VOID
+ndisMFreeArcnetHeader(
+ 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.
+
+
+ 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 (MINIPORT_TEST_FLAG(Open, fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
+ {
+ 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;
+ }
+}
+
+BOOLEAN
+FASTCALL
+ndisMArcnetSendLoopback(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN 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;
+ 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);
+ ASSERT(NdisMediumArcnet878_2 == Miniport->MediaType);
+
+ FirstBuffer = Packet->Private.Head;
+ BufferAddress = MDL_ADDRESS(FirstBuffer);
+
+ //
+ // Is this an ethernet encapsulated packet?
+ //
+ 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 = MDL_ADDRESS(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);
+ }
+ 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;
+ }
+ }
+
+ //
+ // If it's not a loopback packet then get out of here!
+ //
+ if (!Loopback)
+ {
+ ASSERT(!SelfDirected);
+ return(SelfDirected);
+ }
+
+ //
+ // Get the buffer length
+ //
+ NdisQueryPacket(Packet, NULL, NULL, NULL, &Length);
+
+ //
+ // If the packet is encapsulated ethernet then don't count the
+ // arcnet header in with the length.
+ //
+ if (ARC_PACKET_IS_ENCAPSULATED(Packet))
+ {
+ Length -= ARC_PROTOCOL_HEADER_SIZE;
+ }
+
+ //
+ // 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 = MDL_SIZE(FirstBuffer);
+// BufferLength = (UINT)((PUSHORT)BufferAddress)[6]; // Hack around.
+
+ if ((BufferLength < NDIS_M_MAX_LOOKAHEAD) && (BufferLength != Length))
+ {
+ UINT BytesToCopy;
+ UINT Offset;
+
+ if (ARC_PACKET_IS_ENCAPSULATED(Packet))
+ {
+ //
+ // Copy the encapsulated ethernet header.
+ //
+ BytesToCopy = 14;
+
+ //
+ // Skip the fake arcnet header.
+ //
+ Offset = 3;
+ }
+ else
+ {
+ //
+ // Copy the arcnet header.
+ //
+ BytesToCopy = ARC_PROTOCOL_HEADER_SIZE;
+
+ //
+ // Don't skip anything.
+ //
+ Offset = 0;
+ }
+
+ BufferAddress = Miniport->ArcnetLookaheadBuffer;
+ BytesToCopy += Miniport->CurrentLookahead;
+
+ ndisMCopyFromPacketToBuffer(
+ 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;
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'L');
+
+ //
+ // Indicate the packet to every open binding
+ // that could want it.
+ //
+ if (ARC_PACKET_IS_ENCAPSULATED(Packet))
+ {
+ EthFilterDprIndicateReceive(
+ Miniport->EthDB,
+ Packet,
+ BufferAddress,
+ BufferAddress,
+ 14,
+ BufferAddress + 14,
+ BufferLength - 14,
+ Length - 14);
+
+ EthFilterDprIndicateReceiveComplete(Miniport->EthDB);
+ }
+ else
+ {
+ PUCHAR PlaceInBuffer;
+ PUCHAR ArcDataBuffer;
+ UINT ArcDataLength;
+ UINT PacketDataOffset;
+ UCHAR FrameCount;
+ UCHAR i;
+ UINT IndicateDataLength;
+
+ //
+ // Calculate how many frames we will need.
+ //
+ ArcDataLength = Length - ARC_PROTOCOL_HEADER_SIZE;
+ PacketDataOffset = ARC_PROTOCOL_HEADER_SIZE;
+
+ FrameCount = (UCHAR)(ArcDataLength / ARC_MAX_FRAME_SIZE);
+
+ if ((ArcDataLength % ARC_MAX_FRAME_SIZE) != 0)
+ {
+ FrameCount++;
+ }
+
+ for (i = 0; i < FrameCount; ++i)
+ {
+ PlaceInBuffer = Miniport->ArcnetLookaheadBuffer;
+
+ //
+ // Point data buffer to start of 'data'
+ // Don't include system code as part of data
+ //
+ ArcDataBuffer = Miniport->ArcnetLookaheadBuffer +
+ ARC_PROTOCOL_HEADER_SIZE;
+
+ //
+ // Copy Header (SrcId/DestId/ProtId)
+ //
+ ndisMCopyFromPacketToBuffer(
+ Packet,
+ 0,
+ ARC_PROTOCOL_HEADER_SIZE,
+ PlaceInBuffer,
+ &BufferLength);
+
+ PlaceInBuffer += ARC_PROTOCOL_HEADER_SIZE;
+
+ //
+ // 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;
+ }
+
+ ndisMCopyFromPacketToBuffer(
+ Packet,
+ PacketDataOffset,
+ IndicateDataLength,
+ PlaceInBuffer,
+ &BufferLength);
+
+ //
+ // Indicate the actual data length which should not
+ // include the system code.
+ //
+ ArcFilterDprIndicateReceive(
+ Miniport->ArcDB,
+ Miniport->ArcnetLookaheadBuffer,
+ ArcDataBuffer,
+ IndicateDataLength + ARC_PROTOCOL_HEADER_SIZE);
+
+ ArcDataLength -= ARC_MAX_FRAME_SIZE;
+ PacketDataOffset += ARC_MAX_FRAME_SIZE;
+ }
+
+ ArcFilterDprIndicateReceiveComplete(Miniport->ArcDB);
+ }
+
+ Miniport->LoopbackPacket = NULL;
+
+ return(SelfDirected);
+}
+
+
diff --git a/private/ntos/ndis/ndis40/bus.c b/private/ntos/ndis/ndis40/bus.c
new file mode 100644
index 000000000..4cc6b0d29
--- /dev/null
+++ b/private/ntos/ndis/ndis40/bus.c
@@ -0,0 +1,1009 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ bus.c
+
+Abstract:
+
+ NDIS wrapper functions to handle specific buses
+
+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
+ 01-Jun-1995 JameelH Re-organization/optimization
+ 06-Dec-1996 KyleB Placed a sanity check for MCA SlotNumber in
+ ndisFixBusInformation.
+
+--*/
+
+
+#include <precomp.h>
+#pragma hdrstop
+
+#include <stdarg.h>
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_BUS
+
+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 pData;
+ UINT NumberOfFunctions;
+
+ NdisReadEisaSlotInformationEx(Status,
+ WrapperConfigurationContext,
+ SlotNumber,
+ &pData,
+ &NumberOfFunctions);
+ if (*Status == NDIS_STATUS_SUCCESS)
+ {
+ ASSERT(NumberOfFunctions > 0);
+ *EisaData = *pData;
+ }
+}
+
+
+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;
+ NDIS_INTERFACE_TYPE BusType;
+ NDIS_CONFIGURATION_HANDLE NdisConfiguration;
+
+ //
+ // 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;
+
+ *Status = NDIS_STATUS_FAILURE; // Assume failure
+
+ do
+ {
+ //
+ // First check if any bus access is allowed
+ //
+ if (BusType != Eisa)
+ {
+ break;
+ }
+
+ SlotInformation = NdisConfiguration.KeyQueryTable[3].DefaultData;
+ *NumberOfFunctions = 2;
+
+ //
+ // Was there already a buffer allocated?
+ //
+
+ if (SlotInformation == NULL)
+ {
+ //
+ // No, allocate a buffer
+ //
+
+ SlotInformation = (PNDIS_EISA_SLOT_INFORMATION)
+ ALLOC_FROM_POOL(sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION)),
+ NDIS_TAG_SLOT_INFO);
+
+ if (SlotInformation == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ //
+ // Free any old buffer
+ //
+
+ if (NdisConfiguration.KeyQueryTable[3].DefaultData != NULL)
+ {
+ FREE_POOL(NdisConfiguration.KeyQueryTable[3].DefaultData);
+ }
+
+ NdisConfiguration.KeyQueryTable[3].DefaultData = SlotInformation;
+ }
+
+ //
+ // Now get the slot number that we read in earlier
+ //
+ *SlotNumber = NdisConfiguration.KeyQueryTable[4].DefaultLength;
+ DataLength = HalGetBusDataByOffset(EisaConfiguration,
+ BusNumber,
+ *SlotNumber,
+ (PVOID)SlotInformation,
+ 0,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION)));
+
+ //
+ // 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)
+ ALLOC_FROM_POOL(sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ (*NumberOfFunctions *sizeof(NDIS_EISA_FUNCTION_INFORMATION)),
+ NDIS_TAG_SLOT_INFO);
+
+ if (SlotInformation == NULL)
+ {
+ break;
+ }
+
+ //
+ // Free any old buffer
+ //
+
+ if (NdisConfiguration.KeyQueryTable[3].DefaultData != NULL)
+ {
+ FREE_POOL(NdisConfiguration.KeyQueryTable[3].DefaultData);
+ }
+
+ NdisConfiguration.KeyQueryTable[3].DefaultData = SlotInformation;
+
+ //
+ // Get new information
+ //
+
+ DataLength = HalGetBusDataByOffset(EisaConfiguration,
+ BusNumber,
+ *SlotNumber,
+ (PVOID)SlotInformation,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ 0,
+ (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION)));
+ }
+
+ if (SlotInformation == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+
+ 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;
+ } while (FALSE);
+}
+
+
+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.
+
+--*/
+{
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NDIS_CONFIGURATION_HANDLE NdisConfiguration;
+ ULONG DataLength;
+
+ //
+ // 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;
+
+ *Status = NDIS_STATUS_FAILURE;
+ *ChannelNumber = 0;
+
+ do
+ {
+ //
+ // First check if any bus access is allowed
+ //
+ if (BusType != MicroChannel)
+ {
+ break;
+ }
+
+ //
+ // Get the channel number that we read in earlier. Note that the HAL
+ // apis expect the channel to be zero based.
+ //
+ *ChannelNumber = NdisConfiguration.KeyQueryTable[4].DefaultLength;
+
+ DataLength = HalGetBusDataByOffset(Pos,
+ BusNumber,
+ *ChannelNumber - 1,
+ (PVOID)McaData,
+ 0,
+ sizeof(NDIS_MCA_POS_DATA));
+ *Status = NDIS_STATUS_SUCCESS;
+ } while (FALSE);
+}
+
+
+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.
+
+--*/
+{
+ ULONG DataLength = 0;
+ ULONG BusNumber;
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable;
+ KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ ASSERT((NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType) == NdisInterfacePci);
+ 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.
+
+--*/
+{
+ ULONG DataLength = 0;
+ ULONG BusNumber;
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable;
+ KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ ASSERT((NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType) == NdisInterfacePci);
+ DataLength = HalSetBusDataByOffset(PCIConfiguration,
+ BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length);
+ return DataLength;
+}
+
+
+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.
+
+--*/
+{
+ ULONG DataLength = 0;
+ PNDIS_ADAPTER_BLOCK Adapter = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle;
+
+ if (Adapter->DeviceObject == NULL)
+ {
+ //
+ // This is a mini-port
+ //
+ ASSERT(Miniport->BusType == NdisInterfacePci);
+
+ DataLength = HalGetBusDataByOffset(PCIConfiguration,
+ Miniport->BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length);
+ }
+ else
+ {
+ ASSERT(Adapter->BusType == NdisInterfacePci);
+ 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.
+
+--*/
+{
+ ULONG DataLength = 0;
+ PNDIS_ADAPTER_BLOCK Adapter = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle;
+
+ if (Adapter->DeviceObject == NULL)
+ {
+ //
+ // This is a mini-port
+ //
+ ASSERT(Miniport->BusType == NdisInterfacePci);
+ DataLength = HalSetBusDataByOffset(PCIConfiguration,
+ Miniport->BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length);
+ }
+ else
+ {
+ ASSERT(Adapter->BusType == NdisInterfacePci);
+ DataLength = HalSetBusDataByOffset(PCIConfiguration,
+ Adapter->BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length);
+ }
+ return DataLength;
+}
+
+
+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;
+ }
+}
+
+
+
+NDIS_STATUS
+ndisFixBusInformation(
+ IN PNDIS_CONFIGURATION_HANDLE ConfigHandle,
+ IN PBUS_SLOT_DB pDb
+ )
+/*++
+
+ Make sure that the card is in the slot that the registry says it is. If it is not,
+ scan the bus to see if we find the card. If we do, then fix up the registry so that
+ next time we do not have to do this. Also keep track of the cards so that we handle
+ multiple instances.
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_FAILURE;
+ ULONGLONG Buffer[(sizeof(NDIS_EISA_SLOT_INFORMATION)+sizeof(NDIS_EISA_FUNCTION_INFORMATION))/sizeof(ULONGLONG) + 1];
+ PNDIS_EISA_SLOT_INFORMATION SlotInformation;
+ PNDIS_MCA_POS_DATA McaData;
+ NDIS_CONFIGURATION_PARAMETER ParmValue;
+ ULONG BusId, Mask = 0xFFFFFFFF;
+ ULONG DataLength;
+ ULONG Bus, Slot, MaxSlot = 0xFF;
+
+ SlotInformation = (PNDIS_EISA_SLOT_INFORMATION)Buffer;
+ McaData = (PNDIS_MCA_POS_DATA)Buffer;
+
+ //
+ // Read the slot information for the slot specified in the registry
+ //
+ switch (pDb->BusType)
+ {
+ case NdisInterfaceEisa:
+ Mask = 0xFFFFFF;
+ DataLength = HalGetBusDataByOffset(EisaConfiguration,
+ pDb->BusNumber,
+ pDb->SlotNumber,
+ SlotInformation,
+ 0,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ sizeof(NDIS_EISA_FUNCTION_INFORMATION));
+ BusId = SlotInformation->CompressedId;
+ break;
+
+ case NdisInterfaceMca:
+ MaxSlot = 7;
+ DataLength = 0;
+ if ((pDb->SlotNumber <= MaxSlot) && (pDb->SlotNumber > 0))
+ {
+ DataLength = HalGetBusDataByOffset(Pos,
+ pDb->BusNumber,
+ pDb->SlotNumber - 1,
+ McaData,
+ 0,
+ sizeof(NDIS_MCA_POS_DATA));
+ BusId = McaData->AdapterId;
+ }
+
+ break;
+
+ case NdisInterfacePci:
+ DataLength = HalGetBusDataByOffset(PCIConfiguration,
+ pDb->BusNumber,
+ pDb->SlotNumber,
+ &BusId,
+ 0,
+ sizeof(ULONG));
+ }
+
+ if ((DataLength != 0) &&
+ ((BusId & Mask) == (pDb->BusId & Mask)))
+ {
+ //
+ // The card seems to be where it is supposed to be. Make sure that is the
+ // case by searching our db to see if this is already installed. Use BusId
+ // and not the masked busid for search and in our database.
+ //
+ // If we found an EISA card where the registry says it should be but found another
+ // loaded instance, allow it - for multifunction EISA cards, we can have two cards
+ // with the same bus#/slot#.
+ //
+ if (!ndisSearchGlobalDb(pDb->BusType,
+ BusId,
+ pDb->BusNumber,
+ pDb->SlotNumber) ||
+ (pDb->BusType == NdisInterfaceEisa))
+ {
+ if (ndisAddGlobalDb(pDb->BusType,
+ BusId,
+ pDb->BusNumber,
+ pDb->SlotNumber))
+ {
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ //
+ // We could not add to global list. Unlikely we can proceed anyway.
+ //
+ return NDIS_STATUS_RESOURCES;
+ }
+ }
+
+ //
+ // The card is not where it ought to be. Scan the bus and find out where it is.
+ //
+ for (Bus = 0; NOTHING; Bus ++)
+ {
+ for (Slot = 0; Slot < MaxSlot; Slot ++)
+ {
+ switch (pDb->BusType)
+ {
+ case NdisInterfaceEisa:
+ DataLength = HalGetBusDataByOffset(EisaConfiguration,
+ Bus,
+ Slot,
+ SlotInformation,
+ 0,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ sizeof(NDIS_EISA_FUNCTION_INFORMATION));
+ BusId = SlotInformation->CompressedId;
+ break;
+
+ case NdisInterfaceMca:
+ DataLength = HalGetBusDataByOffset(Pos,
+ Bus,
+ Slot,
+ McaData,
+ 0,
+ sizeof(NDIS_MCA_POS_DATA));
+ BusId = McaData->AdapterId;
+ break;
+
+ case NdisInterfacePci:
+ DataLength = HalGetBusDataByOffset(PCIConfiguration,
+ Bus,
+ Slot,
+ &BusId,
+ 0,
+ sizeof(ULONG));
+ break;
+ }
+
+ if (DataLength == 0)
+ {
+ //
+ // No more buses, we failed
+ //
+ return NDIS_STATUS_FAILURE;
+ }
+
+ if ((BusId & Mask) == (pDb->BusId & Mask))
+ {
+ if (pDb->BusType == NdisInterfaceMca)
+ {
+ //
+ // MCA Slot #s are 0 based for HAL and 1 based for registry
+ //
+ Slot ++;
+ }
+
+ //
+ // Found one, make sure we do not already know about it
+ //
+ if (!ndisSearchGlobalDb(pDb->BusType,
+ pDb->BusId,
+ Bus,
+ Slot))
+ {
+ NDIS_STRING BusNumStr = NDIS_STRING_CONST("BusNumber");
+ NDIS_STRING SlotNumStr = NDIS_STRING_CONST("SlotNumber");
+ //
+ // This is it. First write it back to the registry. Then
+ // to the global db.
+ //
+ ParmValue.ParameterType = NdisParameterInteger;
+ ParmValue.ParameterData.IntegerData = Bus;
+ NdisWriteConfiguration(&Status,
+ ConfigHandle,
+ &BusNumStr,
+ &ParmValue);
+
+ ParmValue.ParameterData.IntegerData = Slot;
+ NdisWriteConfiguration(&Status,
+ ConfigHandle,
+ &SlotNumStr,
+ &ParmValue);
+
+ if (ndisAddGlobalDb(pDb->BusType,
+ pDb->BusId,
+ Bus,
+ Slot))
+ {
+ pDb->BusNumber = Bus;
+ pDb->SlotNumber = Slot;
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ //
+ // We could not add to global list. Unlikely we can proceed anyway.
+ //
+ return NDIS_STATUS_RESOURCES;
+ }
+ }
+
+ }
+ }
+
+ return Status;
+}
+
+
+VOID
+ndisAddBusInformation(
+ IN PNDIS_CONFIGURATION_HANDLE ConfigHandle,
+ IN PBUS_SLOT_DB pDb
+ )
+/*++
+
+ For OEM adapters that do not have their bus-id in the registry, do them a favor and add it.
+
+--*/
+{
+ ULONGLONG Buffer[(sizeof(NDIS_EISA_SLOT_INFORMATION)+sizeof(NDIS_EISA_FUNCTION_INFORMATION))/sizeof(ULONGLONG) + 1];
+ PNDIS_STRING BusIdStr;
+ NDIS_STRING PciIdStr = NDIS_STRING_CONST("AdapterCFID");
+ NDIS_STRING EisaIdStr = NDIS_STRING_CONST("EisaCompressedId");
+ NDIS_STRING McaIdStr = NDIS_STRING_CONST("McaPosId");
+ PNDIS_EISA_SLOT_INFORMATION SlotInformation;
+ NDIS_CONFIGURATION_PARAMETER ParmValue;
+ PNDIS_MCA_POS_DATA McaData;
+ NDIS_STATUS Status;
+ ULONG BusId, DataLength = 0;
+
+ //
+ // Read the bus-id by politely asking the HAL
+ //
+ switch (pDb->BusType)
+ {
+ case NdisInterfaceEisa:
+ SlotInformation = (PNDIS_EISA_SLOT_INFORMATION)Buffer;
+ DataLength = HalGetBusDataByOffset(EisaConfiguration,
+ pDb->BusNumber,
+ pDb->SlotNumber,
+ SlotInformation,
+ 0,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ sizeof(NDIS_EISA_FUNCTION_INFORMATION));
+ BusId = SlotInformation->CompressedId;
+ break;
+
+ case NdisInterfaceMca:
+ McaData = (PNDIS_MCA_POS_DATA)Buffer;
+ DataLength = HalGetBusDataByOffset(Pos,
+ pDb->BusNumber,
+ pDb->SlotNumber - 1,
+ McaData,
+ 0,
+ sizeof(NDIS_MCA_POS_DATA));
+ BusId = McaData->AdapterId;
+ break;
+
+ case NdisInterfacePci:
+ DataLength = HalGetBusDataByOffset(PCIConfiguration,
+ pDb->BusNumber,
+ pDb->SlotNumber,
+ &BusId,
+ 0,
+ sizeof(ULONG));
+ }
+ if (DataLength != 0)
+ {
+ ParmValue.ParameterType = NdisParameterInteger;
+ ParmValue.ParameterData.IntegerData = BusId;
+
+ switch (pDb->BusType)
+ {
+ case NdisInterfaceEisa:
+ BusIdStr = &EisaIdStr;
+ break;
+
+ case NdisInterfaceMca:
+ BusIdStr = &McaIdStr;
+ break;
+
+ case NdisInterfacePci:
+ BusIdStr = &PciIdStr;
+ break;
+ }
+
+ if (pDb->BusType != NdisInterfacePci)
+ {
+ //
+ // Do not do it for Pci buses just yet. Some OEM cards do bogus things.
+ //
+ NdisWriteConfiguration(&Status,
+ ConfigHandle,
+ BusIdStr,
+ &ParmValue);
+
+ //
+ // Finally create a data-base entry for this
+ //
+ ndisAddGlobalDb(pDb->BusType,
+ pDb->BusId,
+ pDb->BusNumber,
+ pDb->SlotNumber);
+ }
+ }
+}
+
+
+BOOLEAN
+ndisSearchGlobalDb(
+ IN NDIS_INTERFACE_TYPE BusType,
+ IN ULONG BusId,
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber
+ )
+{
+ PBUS_SLOT_DB pScan;
+ KIRQL OldIrql;
+ BOOLEAN rc = FALSE;
+
+ ACQUIRE_SPIN_LOCK(&ndisGlobalDbLock, &OldIrql);
+
+ for (pScan = ndisGlobalDb;
+ pScan != NULL;
+ pScan = pScan->Next)
+ {
+ if ((pScan->BusType == BusType) &&
+ (pScan->BusId == BusId) &&
+ (pScan->BusNumber == BusNumber) &&
+ (pScan->SlotNumber == SlotNumber))
+ {
+ rc = TRUE;
+ break;
+ }
+ }
+
+ RELEASE_SPIN_LOCK(&ndisGlobalDbLock, OldIrql);
+
+ return rc;
+}
+
+
+BOOLEAN
+ndisAddGlobalDb(
+ IN NDIS_INTERFACE_TYPE BusType,
+ IN ULONG BusId,
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber
+ )
+{
+ PBUS_SLOT_DB pDb;
+ KIRQL OldIrql;
+ BOOLEAN rc = FALSE;
+
+ pDb = ALLOC_FROM_POOL(sizeof(BUS_SLOT_DB), NDIS_TAG_DEFAULT);
+ if (pDb != NULL)
+ {
+ pDb->BusType = BusType;
+ pDb->BusId = BusId;
+ pDb->BusNumber = BusNumber;
+ pDb->SlotNumber = SlotNumber;
+ ACQUIRE_SPIN_LOCK(&ndisGlobalDbLock, &OldIrql);
+
+ pDb->Next = ndisGlobalDb;
+ ndisGlobalDb = pDb;
+
+ RELEASE_SPIN_LOCK(&ndisGlobalDbLock, OldIrql);
+
+ rc = TRUE;
+ }
+
+ return rc;
+}
+
+BOOLEAN
+ndisDeleteGlobalDb(
+ IN NDIS_INTERFACE_TYPE BusType,
+ IN ULONG BusId,
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber
+ )
+{
+ PBUS_SLOT_DB pScan, *ppScan;
+ KIRQL OldIrql;
+
+ ACQUIRE_SPIN_LOCK(&ndisGlobalDbLock, &OldIrql);
+
+ for (ppScan = &ndisGlobalDb;
+ (pScan = *ppScan) != NULL;
+ ppScan = &pScan->Next)
+ {
+ if ((pScan->BusType == BusType) &&
+ (pScan->BusId == BusId) &&
+ (pScan->BusNumber == BusNumber) &&
+ (pScan->SlotNumber == SlotNumber))
+ {
+ *ppScan = pScan->Next;
+ break;
+ }
+ }
+
+ RELEASE_SPIN_LOCK(&ndisGlobalDbLock, OldIrql);
+
+ if (pScan != NULL)
+ {
+ FREE_POOL(pScan);
+ }
+
+ return (pScan != NULL);
+}
+
+
diff --git a/private/ntos/ndis/ndis40/common.c b/private/ntos/ndis/ndis40/common.c
new file mode 100644
index 000000000..d9ef88449
--- /dev/null
+++ b/private/ntos/ndis/ndis40/common.c
@@ -0,0 +1,3452 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ common.c
+
+Abstract:
+
+ NDIS wrapper functions common to miniports and full mac drivers
+
+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
+ 01-Jun-1995 JameelH Re-organization/optimization
+ 09-Apr-1996 KyleB Added resource remove and acquisition routines.
+
+--*/
+
+
+#include <precomp.h>
+#pragma hdrstop
+
+#include <stdarg.h>
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_COMMON
+
+//
+// Routines for dealing with making the PKG specific routines pagable
+//
+
+VOID
+ndisInitializePackage(
+ IN PPKG_REF pPkg,
+ IN PVOID RoutineName
+ )
+{
+ //
+ // Allocate the spin lock
+ //
+ INITIALIZE_SPIN_LOCK(&pPkg->ReferenceLock);
+
+ //
+ // Initialize the "in page" event.
+ //
+ INITIALIZE_EVENT(&pPkg->PagedInEvent);
+
+ // Lock and unlock the section to obtain the handle. Subsequent locks will be faster
+ pPkg->ImageHandle = MmLockPagableCodeSection(RoutineName);
+ MmUnlockPagableImageSection(pPkg->ImageHandle);
+}
+
+
+VOID
+ndisReferencePackage(
+ IN PPKG_REF pPkg
+)
+{
+ KIRQL OldIrql;
+
+ //
+ // Grab the spin lock
+ //
+ ACQUIRE_SPIN_LOCK(&pPkg->ReferenceLock, &OldIrql);
+
+ //
+ // Increment the reference count
+ //
+ pPkg->ReferenceCount++;
+
+ if (pPkg->ReferenceCount == 1)
+ {
+ //
+ // We are the first reference. Page everything in.
+ //
+
+ //
+ // Clear the event
+ //
+ RESET_EVENT(&pPkg->PagedInEvent);
+
+ //
+ // Set the spin lock free
+ //
+ RELEASE_SPIN_LOCK(&pPkg->ReferenceLock, OldIrql);
+
+ //
+ // Page in all the functions
+ //
+ MmLockPagableSectionByHandle(pPkg->ImageHandle);
+
+ //
+ // Signal to everyone to go
+ //
+ SET_EVENT(&pPkg->PagedInEvent);
+ }
+ else
+ {
+ //
+ // Set the spin lock free
+ //
+ RELEASE_SPIN_LOCK(&pPkg->ReferenceLock, OldIrql);
+
+ //
+ // Wait for everything to be paged in
+ //
+ WAIT_FOR_OBJECT(&pPkg->PagedInEvent, NULL);
+ }
+}
+
+
+VOID
+ndisDereferencePackage(
+ IN PPKG_REF pPkg
+ )
+{
+ KIRQL OldIrql;
+
+ //
+ // Get the spin lock
+ //
+ ACQUIRE_SPIN_LOCK(&pPkg->ReferenceLock, &OldIrql);
+
+ pPkg->ReferenceCount--;
+
+ if (pPkg->ReferenceCount == 0)
+ {
+ //
+ // Let next one in
+ //
+ RELEASE_SPIN_LOCK(&pPkg->ReferenceLock, OldIrql);
+
+ //
+ // Page out all the functions
+ //
+ MmUnlockPagableImageSection(pPkg->ImageHandle);
+ }
+ else
+ {
+ //
+ // Let next one in
+ //
+ RELEASE_SPIN_LOCK(&pPkg->ReferenceLock, OldIrql);
+ }
+}
+
+
+
+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 = ALLOC_FROM_POOL(Length, NDIS_TAG_ALLOC_MEM);
+ }
+ else if (MemoryFlags & NDIS_MEMORY_NONCACHED)
+ {
+ *VirtualAddress = MmAllocateNonCachedMemory(Length);
+ }
+ else if (MemoryFlags & NDIS_MEMORY_CONTIGUOUS)
+ {
+ *VirtualAddress = MmAllocateContiguousMemory(Length, HighestAcceptableAddress);
+ }
+
+ return (*VirtualAddress == NULL) ? NDIS_STATUS_FAILURE : NDIS_STATUS_SUCCESS;
+}
+
+
+NDIS_STATUS
+NdisAllocateMemoryWithTag(
+ OUT PVOID * VirtualAddress,
+ IN UINT Length,
+ IN ULONG Tag
+ )
+/*++
+
+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.
+ Tag - tag to associate with this memory.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if successful.
+ NDIS_STATUS_FAILURE if not successful. *VirtualAddress will be NULL.
+
+
+--*/
+{
+
+ *VirtualAddress = ALLOC_FROM_POOL(Length, Tag);
+ return (*VirtualAddress == NULL) ? NDIS_STATUS_FAILURE : 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)
+ {
+ FREE_POOL(VirtualAddress);
+ }
+ else if (MemoryFlags & NDIS_MEMORY_NONCACHED)
+ {
+ MmFreeNonCachedMemory(VirtualAddress, Length);
+ }
+ else if (MemoryFlags & NDIS_MEMORY_CONTIGUOUS)
+ {
+ MmFreeContiguousMemory(VirtualAddress);
+ }
+}
+
+//
+// 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).
+ //
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisAllocatePacketPool\n"));
+
+ PacketLength = FIELD_OFFSET(NDIS_PACKET, ProtocolReserved) +
+ sizeof(NDIS_PACKET_OOB_DATA) +
+ sizeof(NDIS_PACKET_PRIVATE_EXTENSION) +
+ ((ProtocolReservedLength + sizeof(ULONGLONG) - 1) & ~(sizeof(ULONGLONG) -1));
+
+ //
+ // Allocate space needed
+ //
+ TmpPool = (PNDIS_PACKET_POOL)ALLOC_FROM_POOL(sizeof(NDIS_PACKET_POOL) +
+ (PacketLength * NumberOfDescriptors),
+ NDIS_TAG_PKT_POOL);
+ if (TmpPool == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ ZeroMemory(TmpPool, PacketLength * NumberOfDescriptors);
+ 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;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisAllocatePacketPool\n"));
+}
+
+
+#undef NdisFreePacketPool
+
+VOID
+NdisFreePacketPool(
+ IN NDIS_HANDLE PoolHandle
+ )
+{
+ NdisFreeSpinLock(&((PNDIS_PACKET_POOL)PoolHandle)->SpinLock);
+ FREE_POOL(PoolHandle);
+}
+
+
+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);
+
+ *Status = NDIS_STATUS_FAILURE;
+ if ((*Buffer = IoAllocateMdl(VirtualAddress,
+ Length,
+ FALSE,
+ FALSE,
+ NULL)) != NULL)
+ {
+ MmBuildMdlForNonPagedPool(*Buffer);
+ (*Buffer)->Next = NULL;
+ *Status = NDIS_STATUS_SUCCESS;
+ }
+}
+
+
+#undef NdisAdjustBufferLength
+VOID
+NdisAdjustBufferLength(
+ IN PNDIS_BUFFER Buffer,
+ IN UINT Length
+ )
+{
+ Buffer->ByteCount = Length;
+}
+
+
+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)MDL_VA(SourceDescriptor)) + Offset);
+
+ UNREFERENCED_PARAMETER(PoolHandle);
+
+ *Status = NDIS_STATUS_FAILURE;
+ if ((*Buffer = IoAllocateMdl(BaseVa,
+ Length,
+ FALSE,
+ FALSE,
+ NULL)) != NULL)
+ {
+ IoBuildPartialMdl(SourceDescriptor,
+ *Buffer,
+ BaseVa,
+ Length);
+
+ (*Buffer)->Next = NULL;
+ *Status = NDIS_STATUS_SUCCESS;
+ }
+}
+
+
+#define ndisAllocatePacketFromPool(_Pool, _ppPacket) \
+ { \
+ \
+ /* \
+ * See if any packets are on pool free list. \
+ */ \
+ \
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO, \
+ ("==>NdisAllocatePacket\n")); \
+ \
+ IF_DBG(DBG_COMP_CONFIG, DBG_LEVEL_ERR) \
+ { \
+ if (DbgIsNull(PoolHandle)) \
+ { \
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR, \
+ ("AllocatePacket: NULL Pool address\n")); \
+ DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR); \
+ } \
+ if (!DbgIsNonPaged(PoolHandle)) \
+ { \
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR, \
+ ("AllocatePacket: Pool not in NonPaged Memory\n")); \
+ DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR); \
+ } \
+ } \
+ \
+ *(_ppPacket) = Pool->FreeList; \
+ if (Pool->FreeList != (PNDIS_PACKET)NULL) \
+ { \
+ /* \
+ * Take free packet off head of list and return it. \
+ */ \
+ \
+ Pool->FreeList = (PNDIS_PACKET)(*(_ppPacket))->Private.Head; \
+ } \
+ }
+
+#define ndisInitializePacket(_Pool, _Packet) \
+ { \
+ PNDIS_PACKET_PRIVATE_EXTENSION PacketExt; \
+ \
+ ZeroMemory((_Packet), (_Pool)->PacketLength); \
+ (_Packet)->Private.Pool = (PNDIS_PACKET_POOL)(_Pool); \
+ (_Packet)->Private.ValidCounts = TRUE; \
+ (_Packet)->Private.NdisPacketFlags = fPACKET_ALLOCATED_BY_NDIS; \
+ \
+ /* \
+ * Set the offset to the out of band data. \
+ */ \
+ (_Packet)->Private.NdisPacketOobOffset = (USHORT)( \
+ (_Pool)->PacketLength - \
+ sizeof(NDIS_PACKET_OOB_DATA) - \
+ sizeof(NDIS_PACKET_PRIVATE_EXTENSION));\
+ \
+ /* \
+ * Set the pointer to the packet linkage information for ndis. \
+ */ \
+ PacketExt = (PNDIS_PACKET_PRIVATE_EXTENSION)((PUCHAR)(_Packet) + \
+ (_Packet)->Private.NdisPacketOobOffset + \
+ sizeof(NDIS_PACKET_OOB_DATA)); \
+ PacketExt->Packet = (_Packet); \
+ }
+
+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 Pool = (PNDIS_PACKET_POOL)PoolHandle;
+ KIRQL OldIrql;
+
+ NDIS_ACQUIRE_SPIN_LOCK(&Pool->SpinLock, &OldIrql);
+
+ ndisAllocatePacketFromPool(PoolHandle, Packet);
+
+ NDIS_RELEASE_SPIN_LOCK(&Pool->SpinLock, OldIrql);
+
+ if (*Packet != (PNDIS_PACKET)NULL)
+ {
+ //
+ // Clear packet elements.
+ //
+ ndisInitializePacket(Pool, *Packet);
+
+ *Status = NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ //
+ // No, cannot satisfy request.
+ //
+
+ *Status = NDIS_STATUS_RESOURCES;
+ }
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisAllocatePacket\n"));
+}
+
+
+VOID
+NdisDprAllocatePacket(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_PACKET * Packet,
+ IN NDIS_HANDLE PoolHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates a packet out of a packet pool. Similar to NdisAllocatePacket
+ but can only be called at raised irql.
+
+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 Pool = (PNDIS_PACKET_POOL)PoolHandle;
+
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(&Pool->SpinLock);
+
+ ndisAllocatePacketFromPool(PoolHandle, Packet);
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(&Pool->SpinLock);
+
+ if (*Packet != (PNDIS_PACKET)NULL)
+ {
+ //
+ // Clear packet elements.
+ //
+ ndisInitializePacket(Pool, *Packet);
+
+ *Status = NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ //
+ // No, cannot satisfy request.
+ //
+
+ *Status = NDIS_STATUS_RESOURCES;
+ }
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisDprAllocatePacket\n"));
+}
+
+
+VOID
+NdisDprAllocatePacketNonInterlocked(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_PACKET * Packet,
+ IN NDIS_HANDLE PoolHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates a packet out of a packet pool. Similar to NdisAllocatePacket
+ but is not interlocked. Caller guarantees synchronization.
+
+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 Pool = (PNDIS_PACKET_POOL)PoolHandle;
+
+ ndisAllocatePacketFromPool(PoolHandle, Packet);
+
+ if (*Packet != (PNDIS_PACKET)NULL)
+ {
+ //
+ // Clear packet elements.
+ //
+ ndisInitializePacket(Pool, *Packet);
+
+ *Status = NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ //
+ // No, cannot satisfy request.
+ //
+
+ *Status = NDIS_STATUS_RESOURCES;
+ }
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisDprAllocatePacketNonInterlocked\n"));
+}
+
+
+#undef NdisFreePacket
+
+VOID
+NdisFreePacket(
+ IN PNDIS_PACKET Packet
+ )
+{
+ Packet->Private.Head = (PNDIS_BUFFER)(Packet->Private.Pool->FreeList);
+ Packet->Private.Pool->FreeList = Packet;
+}
+
+#undef NdisDprFreePacket
+
+VOID
+NdisDprFreePacket(
+ IN PNDIS_PACKET Packet
+ )
+{
+ NdisDprAcquireSpinLock(&Packet->Private.Pool->SpinLock);
+
+ Packet->Private.Head = (PNDIS_BUFFER)(Packet->Private.Pool->FreeList);
+ Packet->Private.Pool->FreeList = Packet;
+
+ NdisDprReleaseSpinLock(&Packet->Private.Pool->SpinLock);
+}
+
+#undef NdisDprFreePacketNonInterlocked
+
+VOID
+NdisDprFreePacketNonInterlocked(
+ IN PNDIS_PACKET Packet
+ )
+{
+ Packet->Private.Head = (PNDIS_BUFFER)(Packet->Private.Pool->FreeList);
+ Packet->Private.Pool->FreeList = Packet;
+}
+
+
+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.
+ //
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisUnchainBufferAtFront\n"));
+
+ IF_DBG(DBG_COMP_CONFIG, DBG_LEVEL_ERR)
+ {
+ BOOLEAN f = FALSE;
+ if (DbgIsNull(Packet))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("UnchainBufferAtFront: Null Packet Pointer\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(Packet))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("UnchainBufferAtFront: Packet not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (!DbgIsPacket(Packet))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("UnchainBufferAtFront: Illegal Packet Size\n"));
+ f = TRUE;
+ }
+ if (f)
+ DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
+ }
+
+ if (*Buffer != (PNDIS_BUFFER)NULL)
+ {
+ Packet->Private.Head = (*Buffer)->Next; // may be NULL
+ (*Buffer)->Next = (PNDIS_BUFFER)NULL;
+ Packet->Private.ValidCounts = FALSE;
+ }
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==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 BufP = Packet->Private.Head;
+ PNDIS_BUFFER Result;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisUnchainBufferAtBack\n"));
+
+ IF_DBG(DBG_COMP_CONFIG, DBG_LEVEL_ERR)
+ {
+ BOOLEAN f = FALSE;
+ if (DbgIsNull(Packet))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("UnchainBufferAtBack: Null Packet Pointer\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(Packet))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("UnchainBufferAtBack: Packet not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (!DbgIsPacket(Packet))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("UnchainBufferAtBack: Illegal Packet Size\n"));
+ f = TRUE;
+ }
+ if (f)
+ DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
+ }
+ if (BufP != (PNDIS_BUFFER)NULL)
+ {
+ //
+ // The packet is not empty, return the tail buffer.
+ //
+
+ Result = Packet->Private.Tail;
+ if (BufP == Result)
+ {
+ //
+ // There was only one buffer on the queue.
+ //
+
+ Packet->Private.Head = (PNDIS_BUFFER)NULL;
+ }
+ else
+ {
+ //
+ // Determine the new tail buffer.
+ //
+
+ while (BufP->Next != Result)
+ {
+ BufP = BufP->Next;
+ }
+ Packet->Private.Tail = BufP;
+ BufP->Next = NULL;
+ }
+
+ Result->Next = (PNDIS_BUFFER)NULL;
+ Packet->Private.ValidCounts = FALSE;
+ }
+ else
+ {
+ //
+ // Packet is empty.
+ //
+
+ Result = (PNDIS_BUFFER)NULL;
+ }
+
+ *Buffer = Result;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==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));
+
+ CopyMemory(DestinationVirtualAddress, SourceVirtualAddress, AmountToMove);
+
+ DestinationVirtualAddress =
+ (PCHAR)DestinationVirtualAddress + AmountToMove;
+ SourceVirtualAddress =
+ (PCHAR)SourceVirtualAddress + AmountToMove;
+
+ LocalBytesCopied += AmountToMove;
+ SourceCurrentLength -= AmountToMove;
+ DestinationCurrentLength -= AmountToMove;
+ }
+ }
+
+ *BytesCopied = LocalBytesCopied;
+}
+
+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.
+
+--*/
+
+{
+ 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(("You are not a busmaster\n"));
+ return;
+ }
+
+ //
+ // Compute allocation size by aligning to the proper boundary.
+ //
+
+ ASSERT(Length != 0);
+
+ Length = (Length + ndisDmaAlignment - 1) & ~(ndisDmaAlignment - 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);
+
+ do
+ {
+ if (WrapperContext->SharedMemoryLeft[Type] < Length)
+ {
+ if ((Length + sizeof(ULONG)) >= PAGE_SIZE)
+ {
+ //
+ // The allocation is greater than a page.
+ //
+
+ *VirtualAddress = HalAllocateCommonBuffer(SystemAdapterObject,
+ Length,
+ PhysicalAddress,
+ Cached);
+ break;
+ }
+
+ //
+ // 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;
+ break;
+ }
+
+ //
+ // 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]));
+
+ PhysicalAddress->QuadPart = WrapperContext->SharedMemoryAddress[Type].QuadPart +
+ ((ULONG)*VirtualAddress & (PAGE_SIZE - 1));
+
+ WrapperContext->SharedMemoryLeft[Type] -= Length;
+ } while (FALSE);
+
+ ExReleaseResource(&SharedMemoryResource);
+}
+
+
+#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.
+ //
+
+ 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:
+
+ Frees shared memory allocated via NdisAllocateSharedMemory.
+
+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.
+
+--*/
+
+{
+ 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);
+
+ Length = (Length + ndisDmaAlignment - 1) & ~(ndisDmaAlignment - 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);
+}
+
+
+BOOLEAN
+ndisCheckPortUsage(
+ 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)ALLOC_FROM_POOL(sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NDIS_TAG_DEFAULT);
+
+ 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;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start.QuadPart = PortNumber;
+ 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);
+
+ FREE_POOL(Resources);
+
+ //
+ // Check for conflict.
+ //
+
+ if (FirstConflict || (FirstNtStatus != STATUS_SUCCESS))
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+NTSTATUS
+ndisStartMapping(
+ 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
+ndisEndMapping(
+ 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 so map the space.
+ //
+ if ((ndisCheckPortUsage(BusType,
+ BusNumber,
+ Port,
+ sizeof(UCHAR),
+ DriverObject) == FALSE) ||
+ !NT_SUCCESS(Status = ndisStartMapping(BusType,
+ BusNumber,
+ Port,
+ sizeof(UCHAR),
+ &PortMapping,
+ &Mapped)))
+ {
+ *Data = (UCHAR)0xFF;
+ return;
+ }
+ //
+ // Read from the port
+ //
+
+ *Data = READ_PORT_UCHAR((PUCHAR)PortMapping);
+
+ //
+ // End port mapping
+ //
+
+ ndisEndMapping(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 so map the space.
+ //
+ if ((ndisCheckPortUsage(BusType,
+ BusNumber,
+ Port,
+ sizeof(USHORT),
+ DriverObject) == FALSE) ||
+ !NT_SUCCESS(Status = ndisStartMapping(BusType,
+ BusNumber,
+ Port,
+ sizeof(USHORT),
+ &PortMapping,
+ &Mapped)))
+ {
+ *Data = (USHORT)0xFFFF;
+ return;
+ }
+
+ //
+ // Read from the port
+ //
+
+ *Data = READ_PORT_USHORT((PUSHORT)PortMapping);
+
+ //
+ // End port mapping
+ //
+
+ ndisEndMapping(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 so map the space.
+ //
+ if ((ndisCheckPortUsage(BusType,
+ BusNumber,
+ Port,
+ sizeof(ULONG),
+ DriverObject) == FALSE) ||
+ !NT_SUCCESS(Status = ndisStartMapping(BusType,
+ BusNumber,
+ Port,
+ sizeof(ULONG),
+ &PortMapping,
+ &Mapped)))
+ {
+ *Data = (ULONG)0xFFFFFFFF;
+ return;
+ }
+
+ //
+ // Read from the port
+ //
+
+ *Data = READ_PORT_ULONG((PULONG)PortMapping);
+
+ //
+ // End port mapping
+ //
+
+ ndisEndMapping(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 so map the space.
+ //
+ if ((ndisCheckPortUsage(BusType,
+ BusNumber,
+ Port,
+ sizeof(UCHAR),
+ DriverObject) == FALSE) ||
+ !NT_SUCCESS(Status = ndisStartMapping(BusType,
+ BusNumber,
+ Port,
+ sizeof(UCHAR),
+ &PortMapping,
+ &Mapped)))
+ {
+ return;
+ }
+
+ //
+ // Read from the port
+ //
+
+ WRITE_PORT_UCHAR((PUCHAR)PortMapping, Data);
+
+ //
+ // End port mapping
+ //
+
+ ndisEndMapping(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 so map the space.
+ //
+ if ((ndisCheckPortUsage(BusType,
+ BusNumber,
+ Port,
+ sizeof(USHORT),
+ DriverObject) == FALSE) ||
+ !NT_SUCCESS(Status = ndisStartMapping(BusType,
+ BusNumber,
+ Port,
+ sizeof(USHORT),
+ &PortMapping,
+ &Mapped)))
+ {
+ return;
+ }
+
+ //
+ // Read from the port
+ //
+
+ WRITE_PORT_USHORT((PUSHORT)PortMapping, Data);
+
+ //
+ // End port mapping
+ //
+
+ ndisEndMapping(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 so map the space.
+ //
+ if ((ndisCheckPortUsage(BusType,
+ BusNumber,
+ Port,
+ sizeof(ULONG),
+ DriverObject) == FALSE) ||
+ !NT_SUCCESS(Status = ndisStartMapping(BusType,
+ BusNumber,
+ Port,
+ sizeof(ULONG),
+ &PortMapping,
+ &Mapped)))
+ //
+ // Read from the port
+ //
+
+ WRITE_PORT_ULONG((PULONG)PortMapping, Data);
+
+ //
+ // End port mapping
+ //
+
+ ndisEndMapping(PortMapping, sizeof(ULONG), Mapped);
+}
+
+
+BOOLEAN
+ndisCheckMemoryUsage(
+ 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)ALLOC_FROM_POOL(sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NDIS_TAG_DEFAULT);
+
+ 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;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Memory.Start.QuadPart = Address;
+ 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);
+
+ FREE_POOL(Resources);
+
+ //
+ // Check for conflict.
+ //
+
+ return (FirstConflict || (FirstNtStatus != STATUS_SUCCESS)) ? FALSE : 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;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the memory is available. Map the space
+ //
+
+ if ((ndisCheckMemoryUsage(BusType,
+ BusNumber,
+ SharedMemoryAddress,
+ Length,
+ DriverObject) == FALSE) ||
+ !NT_SUCCESS(ndisStartMapping(BusType,
+ BusNumber,
+ SharedMemoryAddress,
+ Length,
+ &MemoryMapping,
+ &Mapped)))
+ {
+ return;
+ }
+
+ //
+ // Read from memory
+ //
+
+#ifdef _M_IX86
+
+ memcpy(Buffer, MemoryMapping, Length);
+
+#else
+
+ READ_REGISTER_BUFFER_UCHAR(MemoryMapping,Buffer,Length);
+
+#endif
+
+ //
+ // End mapping
+ //
+
+ ndisEndMapping(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;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the memory is available. Map the space
+ //
+ if ((ndisCheckMemoryUsage(BusType,
+ BusNumber,
+ SharedMemoryAddress,
+ Length,
+ DriverObject) == FALSE) ||
+ !NT_SUCCESS(ndisStartMapping(BusType,
+ BusNumber,
+ SharedMemoryAddress,
+ Length,
+ &MemoryMapping,
+ &Mapped)))
+ {
+ return;
+ }
+
+ //
+ // Write to memory
+ //
+
+#ifdef _M_IX86
+
+ memcpy(MemoryMapping, Buffer, Length);
+
+#else
+
+ WRITE_REGISTER_BUFFER_UCHAR(MemoryMapping,Buffer,Length);
+
+#endif
+
+ //
+ // End mapping
+ //
+
+ ndisEndMapping(MemoryMapping, Length, Mapped);
+}
+
+
+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 = ALLOC_FROM_POOL(FullFileNameLength, NDIS_TAG_DEFAULT);
+
+ do
+ {
+ if (FullFileName.Buffer == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+ FullFileName.Length = sizeof (PathPrefix) - sizeof(WCHAR);
+ FullFileName.MaximumLength = (USHORT)FullFileNameLength;
+ CopyMemory (FullFileName.Buffer, PathPrefix, sizeof(PathPrefix));
+
+ RtlAppendUnicodeStringToString (&FullFileName, FileName);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("Attempting to open %Z\n", &FullFileName));
+
+ 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);
+
+ FREE_POOL(FullFileName.Buffer);
+
+ if (!NT_SUCCESS(NtStatus))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("Error opening file %x\n", NtStatus));
+ *Status = NDIS_STATUS_FILE_NOT_FOUND;
+ break;
+ }
+
+ //
+ // Query the object to determine its length.
+ //
+
+ NtStatus = ZwQueryInformationFile(NtFileHandle,
+ &IoStatus,
+ &StandardInfo,
+ sizeof(FILE_STANDARD_INFORMATION),
+ FileStandardInformation);
+
+ if (!NT_SUCCESS(NtStatus))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("Error querying info on file %x\n", NtStatus));
+ ZwClose(NtFileHandle);
+ *Status = NDIS_STATUS_ERROR_READING_FILE;
+ break;
+ }
+
+ LengthOfFile = StandardInfo.EndOfFile.LowPart;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("File length is %d\n", LengthOfFile));
+
+ //
+ // Might be corrupted.
+ //
+
+ if (LengthOfFile < 1)
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("Bad file length %d\n", LengthOfFile));
+ ZwClose(NtFileHandle);
+ *Status = NDIS_STATUS_ERROR_READING_FILE;
+ break;
+ }
+
+ //
+ // Allocate buffer for this file
+ //
+
+ FileImage = ALLOC_FROM_POOL(LengthOfFile, NDIS_TAG_DEFAULT);
+
+ if (FileImage == NULL)
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("Could not allocate buffer\n"));
+ ZwClose(NtFileHandle);
+ *Status = NDIS_STATUS_ERROR_READING_FILE;
+ break;
+ }
+
+ //
+ // 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))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("error reading file %x\n", NtStatus));
+ *Status = NDIS_STATUS_ERROR_READING_FILE;
+ FREE_POOL(FileImage);
+ break;
+ }
+
+ //
+ // Allocate a structure to describe the file.
+ //
+
+ FileDescriptor = ALLOC_FROM_POOL(sizeof(NDIS_FILE_DESCRIPTOR), NDIS_TAG_DEFAULT);
+
+ if (FileDescriptor == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ FREE_POOL(FileImage);
+ break;
+ }
+
+ FileDescriptor->Data = FileImage;
+ INITIALIZE_SPIN_LOCK (&FileDescriptor->Lock);
+ FileDescriptor->Mapped = FALSE;
+
+ *FileHandle = (NDIS_HANDLE)FileDescriptor;
+ *FileLength = LengthOfFile;
+ *Status = STATUS_SUCCESS;
+ } while (FALSE);
+}
+
+
+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;
+
+ FREE_POOL(FileDescriptor->Data);
+ FREE_POOL(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.
+
+--*/
+{
+ KIRQL OldIrql;
+
+ PNDIS_FILE_DESCRIPTOR FileDescriptor = (PNDIS_FILE_DESCRIPTOR)FileHandle;
+
+ ACQUIRE_SPIN_LOCK(&FileDescriptor->Lock, &OldIrql);
+
+ if (FileDescriptor->Mapped == TRUE)
+ {
+ *Status = NDIS_STATUS_ALREADY_MAPPED;
+ RELEASE_SPIN_LOCK (&FileDescriptor->Lock, OldIrql);
+ return;
+ }
+
+ FileDescriptor->Mapped = TRUE;
+ RELEASE_SPIN_LOCK (&FileDescriptor->Lock, OldIrql);
+
+ *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;
+ KIRQL OldIrql;
+
+ ACQUIRE_SPIN_LOCK(&FileDescriptor->Lock, &OldIrql);
+ FileDescriptor->Mapped = FALSE;
+ RELEASE_SPIN_LOCK (&FileDescriptor->Lock, OldIrql);
+}
+
+
+CCHAR
+NdisSystemProcessorCount(
+ VOID
+ )
+{
+ return **((PCHAR *)&KeNumberProcessors);
+}
+
+
+VOID
+NdisGetSystemUpTime(
+ OUT PULONG pSystemUpTime
+ )
+{
+ LARGE_INTEGER TickCount;
+
+ //
+ // Get tick count and convert to hundreds of nanoseconds.
+ //
+ KeQueryTickCount(&TickCount);
+ TickCount = RtlExtendedIntegerMultiply(TickCount,
+ KeQueryTimeIncrement());
+ TickCount = RtlExtendedIntegerMultiply(TickCount, 10000);
+
+ ASSERT(TickCount.HighPart == 0);
+ *pSystemUpTime = TickCount.LowPart;
+}
+
+VOID
+NdisGetCurrentProcessorCpuUsage(
+ IN PULONG pCpuUsage
+)
+{
+ PKPRCB Prcb;
+
+ Prcb = KeGetCurrentPrcb();
+ *pCpuUsage = 100 - (ULONG)(UInt32x32To64(Prcb->IdleThread->KernelTime, 100) /
+ (ULONGLONG)(Prcb->KernelTime + Prcb->UserTime));
+}
+
+
+VOID
+NdisGetCurrentProcessorCounts(
+ OUT PULONG pIdleCount,
+ OUT PULONG pKernelAndUser,
+ OUT PULONG pIndex
+ )
+{
+ PKPRCB Prcb;
+
+ Prcb = KeGetCurrentPrcb();
+ *pIdleCount = Prcb->IdleThread->KernelTime;
+ *pKernelAndUser = Prcb->KernelTime + Prcb->UserTime;
+ *pIndex = (ULONG)Prcb->Number;
+}
+
+#undef NdisGetCurrentSystemTime
+VOID
+NdisGetCurrentSystemTime(
+ IN PLARGE_INTEGER pCurrentTime
+)
+{
+ KeQuerySystemTime(pCurrentTime);
+}
+
+
+
+NDIS_STATUS
+NdisQueryMapRegisterCount(
+ IN NDIS_INTERFACE_TYPE BusType,
+ OUT PUINT MapRegisterCount
+)
+{
+ NTSTATUS Status;
+ UINT Count, Tmp;
+
+ Count = (UINT)BusType;
+ Status = HalQuerySystemInformation(HalMapRegisterInformation,
+ sizeof(UINT),
+ &Count,
+ &Tmp);
+ if (NT_SUCCESS(Status))
+ {
+ *MapRegisterCount = Count;
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ return NDIS_STATUS_NOT_SUPPORTED;
+}
+
+
+//
+// NDIS Event support
+//
+
+VOID
+NdisInitializeEvent(
+ IN PNDIS_EVENT Event
+ )
+{
+ INITIALIZE_EVENT(&Event->Event);
+}
+
+VOID
+NdisSetEvent(
+ IN PNDIS_EVENT Event
+ )
+{
+ SET_EVENT(&Event->Event);
+}
+
+VOID
+NdisResetEvent(
+ IN PNDIS_EVENT Event
+ )
+{
+ RESET_EVENT(&Event->Event);
+}
+
+BOOLEAN
+NdisWaitEvent(
+ IN PNDIS_EVENT Event,
+ IN UINT MsToWait
+ )
+{
+ NTSTATUS Status;
+ TIME Time, *pTime;
+
+ pTime = NULL;
+ if (MsToWait != 0)
+ {
+ ASSERT(CURRENT_IRQL < DISPATCH_LEVEL);
+ Time.QuadPart = Int32x32To64(MsToWait, -10000);
+ pTime = &Time;
+ }
+
+ Status = WAIT_FOR_OBJECT(&Event->Event, pTime);
+
+ return(Status == NDIS_STATUS_SUCCESS);
+}
+
+VOID
+NdisInitializeString(
+ OUT PNDIS_STRING Destination,
+ IN PUCHAR Source
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ WCHAR *strptr;
+
+ Destination->Length = strlen(Source) * sizeof(WCHAR);
+ Destination->MaximumLength = Destination->Length + sizeof(WCHAR);
+ Destination->Buffer = ALLOC_FROM_POOL(Destination->MaximumLength, NDIS_TAG_STRING);
+
+ strptr = Destination->Buffer;
+ while (*Source != '\0')
+ {
+ *strptr = (WCHAR)*Source;
+ Source++;
+ strptr++;
+ }
+ *strptr = UNICODE_NULL;
+}
+
+
+NDIS_STATUS
+ndisReportResources(
+ PCM_RESOURCE_LIST Resources,
+ PDRIVER_OBJECT DriverObject,
+ PDEVICE_OBJECT DeviceObject,
+ PNDIS_STRING AdapterName,
+ ULONG NewResourceType
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ BOOLEAN Conflict;
+
+ //
+ // When we report the resources we need to subtract 1 from the
+ // count. this is because the sizeof(CM_RESOURCE_LIST) already includes
+ // one CM_PARTIAL_RESOURCE_DESCRIPTOR and if we multiply by the current
+ // Count the size passed to IoReportResourceUsage will be one descriptor
+ // too many.
+ //
+ Status = IoReportResourceUsage(NULL,
+ DriverObject,
+ NULL,
+ 0,
+ DeviceObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ (Resources->List->PartialResourceList.Count - 1)),
+ TRUE,
+ &Conflict);
+
+ //
+ // 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;
+ USHORT logsize;
+
+ baseFileName = AdapterName->Buffer;
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+ for (i = 0; i < AdapterName->Length / sizeof(WCHAR); i++)
+ {
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+ if (AdapterName->Buffer[i] == OBJ_NAME_PATH_SEPARATOR)
+ {
+ baseFileName = &(AdapterName->Buffer[++i]);
+ }
+ }
+
+ StringSize = AdapterName->MaximumLength -
+ ((ULONG)baseFileName - (ULONG)AdapterName->Buffer);
+ logsize = sizeof(IO_ERROR_LOG_PACKET) + StringSize + 6;
+ if (logsize > 255)
+ {
+ logsize = 255;
+ }
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ DeviceObject,
+ (UCHAR)logsize);
+ if (errorLogEntry != NULL)
+ {
+ switch (NewResourceType)
+ {
+ case CmResourceTypePort:
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_IO_PORT_CONFLICT;
+
+ break;
+
+ case CmResourceTypeDma:
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_DMA_CONFLICT;
+
+ break;
+
+ case CmResourceTypeMemory:
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_MEMORY_CONFLICT;
+
+ break;
+
+ case CmResourceTypeInterrupt:
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_INTERRUPT_CONFLICT;
+
+ break;
+ }
+
+ //
+ // 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);
+
+ MoveMemory(((PUCHAR)errorLogEntry) + sizeof(IO_ERROR_LOG_PACKET),
+ baseFileName,
+ logsize - (sizeof(IO_ERROR_LOG_PACKET) + 6));
+
+ 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);
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+ndisRemoveResource(
+ OUT PCM_RESOURCE_LIST *pResources,
+ IN PCM_PARTIAL_RESOURCE_DESCRIPTOR DeadResource,
+ IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PNDIS_STRING AdapterName
+ )
+/*++
+
+Routine Description:
+
+ this routine will walk the current resource list looking for the
+ dead resource. it will construct a new resource list without the
+ dead resource and report this new list to the system.
+
+Arguments:
+
+ pResource - On entry this is the current resource list.
+ On exit this is the newly constructed resource list.
+ DriverObject - Driver object to report the resources for.
+ DeviceObject - Device object to report the resources for.
+ DeadResource - This is the resource to remove.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if the routine succeeded.
+
+--*/
+{
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR Dst;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR Partial;
+ PCM_RESOURCE_LIST CurrentList = *pResources;
+ PCM_RESOURCE_LIST Resources;
+ UINT c;
+ UINT Remaining;
+ BOOLEAN Conflict;
+ NDIS_STATUS Status;
+ BOOLEAN fFoundResource;
+
+ //
+ // Sanity check!
+ //
+ if ((NULL == pResources) || (NULL == *pResources))
+ {
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Allocate a new resource map.
+ //
+ Resources = (PCM_RESOURCE_LIST)ALLOC_FROM_POOL(
+ sizeof(CM_RESOURCE_LIST) +
+ (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ (CurrentList->List->PartialResourceList.Count - 1)),
+ NDIS_TAG_RSRC_LIST);
+ if (NULL == Resources)
+ {
+ //
+ // Leave it there...
+ //
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ //
+ // Copy the head information.
+ //
+ MoveMemory(Resources, CurrentList, sizeof(CM_RESOURCE_LIST));
+
+ Resources->List->PartialResourceList.Count--;
+
+ //
+ // Get our destination pointer.
+ //
+ Dst = Resources->List->PartialResourceList.PartialDescriptors;
+
+ //
+ // Find the resource in our resource list.
+ //
+ Partial = CurrentList->List->PartialResourceList.PartialDescriptors;
+ for (c = 0, fFoundResource = FALSE;
+ (c < CurrentList->List->PartialResourceList.Count) && !fFoundResource;
+ c++, Partial++)
+ {
+ //
+ // Is this the resource we are supposed to remove?
+ //
+ if (RtlEqualMemory(
+ Partial,
+ DeadResource,
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)))
+ {
+ //
+ // copy the remaining portion of the list.
+ //
+ fFoundResource = TRUE;
+
+ //
+ // Copy any remaining resources into the list.
+ //
+ Remaining = CurrentList->List->PartialResourceList.Count - (c+1);
+ if (Remaining > 0)
+ {
+ MoveMemory(Dst, Partial+1, Remaining * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
+ }
+ }
+ else
+ {
+ //
+ // Copy this resource to our new list!
+ //
+ MoveMemory(Dst, Partial, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
+ Dst++;
+ }
+
+ }
+
+ //
+ // Did we find the resource?
+ //
+ if (!fFoundResource)
+ {
+ FREE_POOL(Resources);
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Free the old resource list and save the new one.
+ //
+ FREE_POOL(*pResources);
+
+ *pResources = Resources;
+
+ //
+ // Report the resources to the system.
+ //
+ Status = ndisReportResources(
+ Resources,
+ DriverObject,
+ DeviceObject,
+ AdapterName,
+ DeadResource->Type);
+
+ return(Status);
+}
+
+
+NDIS_STATUS
+ndisAddResource(
+ OUT PCM_RESOURCE_LIST *pResources,
+ IN PCM_PARTIAL_RESOURCE_DESCRIPTOR NewResource,
+ IN NDIS_INTERFACE_TYPE AdapterType,
+ IN ULONG BusNumber,
+ IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PNDIS_STRING AdapterName
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PCM_RESOURCE_LIST Resources;
+ UINT NumberOfElements;
+ BOOLEAN Conflict;
+ NDIS_STATUS Status;
+
+ if (*pResources != NULL)
+ {
+ NumberOfElements = (*pResources)->List->PartialResourceList.Count;
+ }
+ else
+ {
+ NumberOfElements = 0;
+ }
+
+ //
+ // Allocate room for the new list. Note that we don't have to add one
+ // to the NumberOfElements since a CM_RESOURCE_LIST already contains a
+ // single CM_PARTIAL_RESOURCE_DESCRIPTOR.
+ //
+ Resources = (PCM_RESOURCE_LIST)ALLOC_FROM_POOL(
+ sizeof(CM_RESOURCE_LIST) +
+ (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * NumberOfElements),
+ NDIS_TAG_RSRC_LIST);
+ if (NULL == Resources)
+ {
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ if (*pResources != NULL)
+ {
+ //
+ // We need to subtract the size of a CM_PARTIAL_RESOURCE_DESCRIPTOR
+ // from the size of the CM_RESOURCE_LIST.
+ //
+ MoveMemory(Resources,
+ *pResources,
+ (sizeof(CM_RESOURCE_LIST) -
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)) +
+ (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ (*pResources)->List->PartialResourceList.Count));
+ }
+ else
+ {
+ //
+ // Setup initial resource information.
+ //
+ Resources->Count = 1;
+ Resources->List->InterfaceType = AdapterType;
+ Resources->List->BusNumber = BusNumber;
+ Resources->List->PartialResourceList.Version = 0;
+ Resources->List->PartialResourceList.Revision = 0;
+ Resources->List->PartialResourceList.Count = 0;
+ }
+
+ //
+ // Add the new resource.
+ //
+ Resources->List->PartialResourceList.PartialDescriptors[Resources->List->PartialResourceList.Count] = *NewResource;
+ Resources->List->PartialResourceList.Count++;
+
+ if (*pResources != NULL)
+ {
+ FREE_POOL(*pResources);
+ }
+
+ *pResources = Resources;
+
+ //
+ // Report the resources to the system.
+ //
+ Status = ndisReportResources(
+ Resources,
+ DriverObject,
+ DeviceObject,
+ AdapterName,
+ NewResource->Type);
+
+ return(Status);
+}
+
+
+
diff --git a/private/ntos/ndis/ndis40/config.c b/private/ntos/ndis/ndis40/config.c
new file mode 100644
index 000000000..12840f032
--- /dev/null
+++ b/private/ntos/ndis/ndis40/config.c
@@ -0,0 +1,2788 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ config.c
+
+Abstract:
+
+ NDIS wrapper functions for full mac drivers configuration/initialization
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 05-Oct-93
+ Jameel Hyder (JameelH) 01-Jun-95 Re-organization/optimization
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+#include <stdarg.h>
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_CONFIG
+
+//
+// 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;
+ PUNICODE_STRING RegPath;
+
+ PNDIS_WRAPPER_HANDLE WrapperHandle;
+
+ UNREFERENCED_PARAMETER (SystemSpecific3);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisInitializeWrapper\n"));
+
+ *NdisWrapperHandle = NULL;
+ Status = NdisAllocateMemory((PVOID*)NdisWrapperHandle,
+ sizeof(NDIS_WRAPPER_HANDLE) +
+ sizeof(UNICODE_STRING) +
+ ((PUNICODE_STRING)SystemSpecific2)->Length +
+ sizeof(WCHAR),
+ 0,
+ HighestAcceptableMax);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ WrapperHandle = (PNDIS_WRAPPER_HANDLE)(*NdisWrapperHandle);
+ WrapperHandle->NdisWrapperDriver = (PDRIVER_OBJECT)SystemSpecific1;
+ RegPath = (PUNICODE_STRING)((PUCHAR)WrapperHandle + sizeof(NDIS_WRAPPER_HANDLE));
+ RegPath->Buffer = (PWSTR)((PUCHAR)RegPath + sizeof(UNICODE_STRING));
+ RegPath->MaximumLength =
+ RegPath->Length = ((PUNICODE_STRING)SystemSpecific2)->Length;
+ NdisMoveMemory(RegPath->Buffer,
+ ((PUNICODE_STRING)SystemSpecific2)->Buffer,
+ RegPath->Length);
+ WrapperHandle->NdisWrapperConfigurationHandle = RegPath;
+ }
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==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;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisTerminateWrapper\n"));
+
+ UNREFERENCED_PARAMETER(SystemSpecific);
+
+
+ if (NdisMacInfo != NULL)
+ {
+ NdisFreeMemory(NdisMacInfo, sizeof(NDIS_WRAPPER_HANDLE), 0);
+ }
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisTerminateWrapper\n"));
+}
+
+
+
+//
+// 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;
+ ULONG BusNumber;
+ NDIS_INTERFACE_TYPE BusType;
+ PHYSICAL_ADDRESS PhysicalTemp;
+ PCM_RESOURCE_LIST Resources, Resc;
+ 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
+ //
+
+ BusType = (AdptrP->DeviceObject != NULL) ? AdptrP->BusType : Miniport->BusType;
+ BusNumber = (AdptrP->DeviceObject != NULL) ? AdptrP->BusNumber : Miniport->BusNumber;
+
+ do
+ {
+ if ((BusType == (NDIS_INTERFACE_TYPE)-1) || (BusNumber == (ULONG)-1))
+ {
+ *Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // First check for resource conflict by expanding current resource list,
+ // adding in the mapped space, and then re-submitting the resource list.
+ //
+
+ Resc = (AdptrP->DeviceObject != NULL) ? AdptrP->Resources : Miniport->Resources;
+ if (Resc != NULL)
+ {
+ NumberOfElements = Resc->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)ALLOC_FROM_POOL(sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ NumberOfElements,
+ NDIS_TAG_RSRC_LIST);
+
+ if (Resources == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ if (Resc != NULL)
+ {
+ CopyMemory(Resources,
+ Resc,
+ 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 = 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 (Resc != NULL)
+ {
+ FREE_POOL(Resc);
+ }
+
+ 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);
+
+ CopyMemory (((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++)
+ {
+ WCHAR c;
+
+ c = (WCHAR)((Value >> (((sizeof(ULONG) * 2) - i) * 4)) & 0x0F);
+ if (c <= 9)
+ {
+ Character = L'0' + c;
+ }
+ else
+ {
+ Character = L'A' + c - 10;
+ }
+
+ 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;
+ break;
+ }
+
+ *Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ if (!HalTranslateBusAddress(BusType,
+ 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;
+ break;
+ }
+
+ if (addressSpace == 0)
+ {
+ //
+ // memory space
+ //
+
+ *VirtualAddress = MmMapIoSpace(PhysicalTemp, (Length), FALSE);
+ }
+ else
+ {
+ //
+ // I/O space
+ //
+
+ *VirtualAddress = (PVOID)(PhysicalTemp.LowPart);
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+ if (*VirtualAddress == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ }
+ } while (FALSE);
+}
+
+
+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)ALLOC_FROM_POOL(sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ NumberOfElements,
+ NDIS_TAG_RSRC_LIST);
+
+ if (Resources == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+
+ }
+
+ if ((IsAMiniport ? Miniport->Resources : AdapterBlock->Resources) != NULL)
+ {
+ CopyMemory(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)
+ {
+ FREE_POOL((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);
+
+ CopyMemory(((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)
+ {
+ Character = L'0' + (WCHAR)(Value / 10);
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ Place += sizeof(WCHAR);
+
+ Value -= 10;
+ }
+
+ Character = L'0' + (WCHAR)Value;
+
+ 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.
+ //
+
+ ZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
+
+ DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
+
+ DeviceDescription.Master =
+ (BOOLEAN)(IsAMiniport ?
+ MINIPORT_TEST_FLAG(Miniport, fMINIPORT_BUS_MASTER) : FALSE);
+
+ DeviceDescription.ScatterGather =
+ (BOOLEAN)(IsAMiniport ?
+ MINIPORT_TEST_FLAG(Miniport, fMINIPORT_BUS_MASTER) : FALSE);
+
+ DeviceDescription.DemandMode = DmaDescription->DemandMode;
+ DeviceDescription.AutoInitialize = DmaDescription->AutoInitialize;
+
+ DeviceDescription.Dma32BitAddresses =
+ (BOOLEAN)(IsAMiniport ?
+ MINIPORT_TEST_FLAG(Miniport, fMINIPORT_DMA_32_BIT_ADDRESSES) : 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)ALLOC_FROM_POOL(sizeof(NDIS_DMA_BLOCK), NDIS_TAG_DMA);
+
+ if (DmaBlock == (PNDIS_DMA_BLOCK)NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ //
+ // Use this event to tell us when ndisAllocationExecutionRoutine
+ // has been called.
+ //
+ INITIALIZE_EVENT(&DmaBlock->AllocationEvent);
+
+ //
+ // We save this to call IoFreeAdapterChannel later.
+ //
+ DmaBlock->SystemAdapterObject = AdapterObject;
+
+ //
+ // Now allocate the adapter channel.
+ //
+ RAISE_IRQL_TO_DISPATCH(&OldIrql);
+
+ NtStatus = IoAllocateAdapterChannel(
+ AdapterObject,
+ (IsAMiniport ? Miniport->DeviceObject : AdapterBlock->DeviceObject),
+ MapRegistersNeeded,
+ ndisDmaExecutionRoutine,
+ (PVOID)DmaBlock);
+
+ LOWER_IRQL(OldIrql);
+
+ if (!NT_SUCCESS(NtStatus))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus));
+ FREE_POOL(DmaBlock);
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ TimeoutValue.QuadPart = Int32x32To64(100 * 1000, -10000);
+
+ //
+ // ndisDmaExecutionRoutine will set this event
+ // when it has been called.
+ //
+ NtStatus = WAIT_FOR_OBJECT(&DmaBlock->AllocationEvent, &TimeoutValue);
+
+ if (NtStatus != STATUS_SUCCESS)
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus));
+ FREE_POOL(DmaBlock);
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ RESET_EVENT(&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 NDIS_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;
+
+ RAISE_IRQL_TO_DISPATCH(&OldIrql);
+ IoFreeAdapterChannel (DmaBlock->SystemAdapterObject);
+ LOWER_IRQL(OldIrql);
+
+ FREE_POOL(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)(MDL_VA(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)(MDL_VA(Buffer)) + Offset,
+ LengthMapped,
+ WriteToDevice);
+
+ DmaBlock->InProgress = FALSE;
+ *Status = NDIS_STATUS_RESOURCES;
+ }
+
+ else *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)(MDL_VA(Buffer)) + Offset,
+ Length,
+ WriteToDevice);
+
+ *Status = (Successful ? NDIS_STATUS_SUCCESS : NDIS_STATUS_RESOURCES);
+ DmaBlock->InProgress = FALSE;
+}
+
+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_WRAPPER_HANDLE NdisMacInfo = (PNDIS_WRAPPER_HANDLE)(NdisWrapperHandle);
+ PNDIS_MAC_BLOCK MacBlock;
+ UNICODE_STRING Us;
+ PWSTR pWch;
+ USHORT i;
+ UINT MemNeeded;
+ KIRQL OldIrql;
+
+ //
+ // check that this is an NDIS 3.0 MAC.
+ //
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisRegisterMac\n"));
+
+ do
+ {
+ *NdisMacHandle = (NDIS_HANDLE)NULL;
+
+ if (NdisMacInfo == NULL)
+ {
+ *Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ IF_DBG(DBG_COMP_CONFIG, DBG_LEVEL_ERR)
+ {
+ BOOLEAN f = FALSE;
+
+ if (DbgIsNull(MacCharacteristics->OpenAdapterHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterMac: Null OpenAdapterHandler \n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(MacCharacteristics->CloseAdapterHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterMac: Null CloseAdapterHandler \n"));
+ f = TRUE;
+ }
+
+ if (DbgIsNull(MacCharacteristics->SendHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterMac: Null SendHandler \n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(MacCharacteristics->TransferDataHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterMac: Null TransferDataHandler \n"));
+ f = TRUE;
+ }
+
+ if (DbgIsNull(MacCharacteristics->ResetHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterMac: Null ResetHandler \n"));
+ f = TRUE;
+ }
+
+ if (DbgIsNull(MacCharacteristics->RequestHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterMac: Null RequestHandler \n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(MacCharacteristics->QueryGlobalStatisticsHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterMac: Null QueryGlobalStatisticsHandler \n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(MacCharacteristics->UnloadMacHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterMac: Null UnloadMacHandler \n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(MacCharacteristics->AddAdapterHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterMac: Null AddAdapterHandler \n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(MacCharacteristics->RemoveAdapterHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterMac: Null RemoveAdapterHandler \n"));
+ f = TRUE;
+ }
+
+ if (f)
+ DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
+ }
+
+ if ((MacCharacteristics->MajorNdisVersion != 3) ||
+ (MacCharacteristics->MinorNdisVersion != 0))
+ {
+ *Status = NDIS_STATUS_BAD_VERSION;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisRegisterMac\n"));
+ break;
+ }
+
+ //
+ // Check that CharacteristicsLength is enough.
+ //
+
+ if (CharacteristicsLength < sizeof(NDIS_MAC_CHARACTERISTICS))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("char len = %d < %d\n",
+ CharacteristicsLength,
+ sizeof(NDIS_MAC_CHARACTERISTICS)));
+
+ *Status = NDIS_STATUS_BAD_CHARACTERISTICS;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisRegisterMac\n"));
+ break;
+ }
+
+ //
+ // Allocate memory for the NDIS MAC block.
+ //
+ MemNeeded = sizeof(NDIS_MAC_BLOCK) + MacCharacteristics->Name.Length;
+
+ //
+ // Extract the base-name, determine its length and allocate that much more
+ //
+ Us = *(PUNICODE_STRING)(NdisMacInfo->NdisWrapperConfigurationHandle);
+
+ for (i = Us.Length/sizeof(WCHAR), pWch = Us.Buffer + i - 1;
+ i > 0;
+ pWch --, i--)
+ {
+ if (*pWch == L'\\')
+ {
+ Us.Buffer = pWch + 1;
+ Us.Length -= i*sizeof(WCHAR);
+ Us.MaximumLength = Us.Length + sizeof(WCHAR);
+ break;
+ }
+ }
+ MemNeeded += Us.MaximumLength;
+ MacBlock = (PNDIS_MAC_BLOCK)ALLOC_FROM_POOL(MemNeeded, NDIS_TAG_MAC_BLOCK);
+ if (MacBlock == (PNDIS_MAC_BLOCK)NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisRegisterMac\n"));
+ break;
+ }
+ ZeroMemory(MacBlock, MemNeeded);
+ MacBlock->Length = MemNeeded;
+
+ //
+ // Copy over the characteristics table.
+ //
+
+ CopyMemory((PVOID)&MacBlock->MacCharacteristics,
+ (PVOID)MacCharacteristics,
+ sizeof(NDIS_MAC_CHARACTERISTICS));
+
+ //
+ // Move buffer pointer to correct location (extra space at the end of
+ // the characteristics table)
+ //
+ MacBlock->MacCharacteristics.Name.Buffer = (PWSTR)((PUCHAR)MacBlock + sizeof(NDIS_MAC_BLOCK));
+
+ //
+ // Copy String over.
+ //
+ MacBlock->MacCharacteristics.Name.Length =
+ MacBlock->MacCharacteristics.Name.MaximumLength = MacCharacteristics->Name.Length;
+ CopyMemory(MacBlock->MacCharacteristics.Name.Buffer,
+ MacCharacteristics->Name.Buffer,
+ MacCharacteristics->Name.Length);
+
+ //
+ // Upcase the base-name and save it in the MiniBlock
+ //
+ MacBlock->BaseName.Buffer = (PWSTR)((PUCHAR)MacBlock->MacCharacteristics.Name.Buffer +
+ MacCharacteristics->Name.Length);
+ MacBlock->BaseName.Length = Us.Length;
+ MacBlock->BaseName.MaximumLength = Us.MaximumLength;
+ RtlUpcaseUnicodeString(&MacBlock->BaseName,
+ &Us,
+ FALSE);
+ //
+ // No adapters yet registered for this MAC.
+ //
+ MacBlock->AdapterQueue = (PNDIS_ADAPTER_BLOCK)NULL;
+
+ MacBlock->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;
+
+ MacBlock->NdisMacInfo = NdisMacInfo;
+
+ //
+ // Use this event to tell us when all adapters are removed from the mac
+ // during an unload
+ //
+ INITIALIZE_EVENT(&MacBlock->AdaptersRemovedEvent);
+
+ MacBlock->Unloading = FALSE;
+
+ NdisInitializeRef(&MacBlock->Ref);
+
+ // Lock the init code down now - before we take the lock below
+ InitReferencePackage();
+
+ //
+ // Put MAC on global list.
+ //
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+
+ MacBlock->NextMac = ndisMacDriverList;
+ ndisMacDriverList = MacBlock;
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ *NdisMacHandle = (NDIS_HANDLE)MacBlock;
+
+ if (NdisMacInfo->NdisWrapperConfigurationHandle)
+ {
+ *Status = ndisInitializeAllAdapterInstances(MacBlock, NULL);
+
+ if (*Status != NDIS_STATUS_SUCCESS)
+ {
+ *Status = NDIS_STATUS_FAILURE;
+ ndisDereferenceMac(MacBlock);
+ }
+ }
+ else
+ {
+ *Status = NDIS_STATUS_FAILURE;
+ }
+
+ InitDereferencePackage();
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisRegisterMac\n"));
+ } while (FALSE);
+
+ ASSERT(CURRENT_IRQL < DISPATCH_LEVEL);
+}
+
+
+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;
+ }
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisDeregisterMac\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ (" Mac %wZ being deregistered\n",&OldMacP->MacCharacteristics.Name));
+
+ IF_DBG(DBG_COMP_CONFIG, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(NdisMacHandle))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("DeregisterMac: Null Handle\n"));
+ DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(NdisMacHandle))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("DeregisterMac: Handle not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
+ }
+ }
+ if (!NdisCloseRef(&OldMacP->Ref))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisDeregisterMac\n"));
+ return;
+ }
+
+ ASSERT(OldMacP->AdapterQueue == (PNDIS_ADAPTER_BLOCK)NULL);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisDeregisterMac\n"));
+}
+
+
+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 = NULL;
+ PDEVICE_OBJECT TmpDeviceP = NULL;
+ PNDIS_WRAPPER_CONFIGURATION_HANDLE ConfigurationHandle;
+ PNDIS_MAC_BLOCK TmpMacP;
+ NTSTATUS NtStatus;
+ NDIS_STRING NdisAdapterName = { 0 };
+ PHYSICAL_ADDRESS PortAddress;
+ PHYSICAL_ADDRESS InitialPortAddress;
+ ULONG addressSpace;
+ PNDIS_ADAPTER_INFORMATION AdapterInfo = (PNDIS_ADAPTER_INFORMATION)AdapterInformation;
+ BOOLEAN Conflict, ValidBus;
+ PCM_RESOURCE_LIST Resources = NULL;
+ LARGE_INTEGER TimeoutValue;
+ BOOLEAN AllocateIndividualPorts = TRUE, DerefMacOnError = FALSE;
+ ULONG i, Size;
+ ULONG BusNumber;
+ NDIS_INTERFACE_TYPE BusType;
+ NDIS_STATUS Status;
+ UNICODE_STRING DeviceName, UpcaseDeviceName;
+ UNICODE_STRING SymbolicLink;
+ WCHAR SymLnkBuf[40];
+ KIRQL OldIrql;
+
+ ConfigurationHandle = (PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisRegisterAdapter\n"));
+
+ IF_DBG(DBG_COMP_CONFIG, DBG_LEVEL_ERR)
+ {
+ BOOLEAN f = FALSE;
+ if (DbgIsNull(NdisMacHandle))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterAdapter: Null Handle\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(NdisMacHandle))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterAdapter: Handle not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(MacAdapterContext))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterAdapter: Null Context\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(MacAdapterContext))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterAdapter: Context not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (f)
+ DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
+ }
+
+ do
+ {
+ //
+ // Increment the MAC's refernce count.
+ //
+ if (!ndisReferenceMac((PNDIS_MAC_BLOCK)NdisMacHandle))
+ {
+ //
+ // The MAC is closing.
+ //
+
+ Status = NDIS_STATUS_CLOSING;
+ break;
+ }
+ DerefMacOnError = TRUE;
+
+ //
+ // 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)ALLOC_FROM_POOL(AdapterName->MaximumLength,
+ NDIS_TAG_NAME_BUF);
+ if (NdisAdapterName.Buffer == NULL)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ NdisAdapterName.MaximumLength = AdapterName->MaximumLength;
+ NdisAdapterName.Length = AdapterName->Length;
+
+ CopyMemory(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) +
+ ConfigurationHandle->DriverBaseName->Length +
+ sizeof(NDIS_WRAPPER_CONTEXT),
+ AdapterName,
+ FILE_DEVICE_PHYSICAL_NETCARD,
+ 0,
+ FALSE, // exclusive flag
+ &TmpDeviceP);
+
+ if (NtStatus != STATUS_SUCCESS)
+ {
+ Status = NDIS_STATUS_DEVICE_FAILED;
+ break;
+ }
+
+ //
+ // Create symbolic link for the device
+ //
+ SymbolicLink.Buffer = SymLnkBuf;
+ SymbolicLink.Length = sizeof(L"\\DosDevices\\") - sizeof(WCHAR);
+ SymbolicLink.MaximumLength = sizeof(SymLnkBuf);
+ RtlCopyMemory(SymLnkBuf, L"\\DosDevices\\", sizeof(L"\\DosDevices\\"));
+ RtlAppendUnicodeStringToString(&SymbolicLink, ConfigurationHandle->DriverBaseName);
+ IoCreateSymbolicLink(&SymbolicLink, AdapterName);
+
+ //
+ // 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);
+ ZeroMemory(NewAdaptP, sizeof(NDIS_ADAPTER_BLOCK));
+
+ NewAdaptP->BaseName.Buffer = (PWSTR)((PUCHAR)NewAdaptP + sizeof(NDIS_ADAPTER_BLOCK));
+ NewAdaptP->BaseName.MaximumLength =
+ NewAdaptP->BaseName.Length = ConfigurationHandle->DriverBaseName->Length;
+ RtlUpcaseUnicodeString(&NewAdaptP->BaseName,
+ ConfigurationHandle->DriverBaseName,
+ FALSE);
+
+ 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;
+
+ //
+ // Save the bus information in the adapter block
+ //
+ NewAdaptP->BusType = ConfigurationHandle->Db.BusType;
+ NewAdaptP->BusId = ConfigurationHandle->Db.BusId;
+ NewAdaptP->BusNumber = ConfigurationHandle->Db.BusNumber;
+ NewAdaptP->SlotNumber = ConfigurationHandle->Db.SlotNumber;
+
+ //
+ // Get the BusNumber and BusType from the context
+ //
+ BusNumber = ConfigurationHandle->ParametersQueryTable[3].DefaultLength;
+ if (ConfigurationHandle->ParametersQueryTable[3].DefaultType == (NDIS_INTERFACE_TYPE)-1)
+ {
+ BusType = (NDIS_INTERFACE_TYPE)-1;
+ }
+ else
+ {
+ BusType = AdapterInfo->AdapterType;
+ }
+
+ //
+ // 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
+ //
+ ValidBus = ((BusType != (NDIS_INTERFACE_TYPE)-1) && (BusNumber != (ULONG)-1));
+
+ if ((BusType == (NDIS_INTERFACE_TYPE)-1) || (BusNumber == (ULONG)-1))
+ {
+ if ((AdapterInfo != NULL) && ((AdapterInfo->NumberOfPortDescriptors != 0) || (AdapterInfo->Master)))
+ {
+ //
+ // Error out
+ //
+ Status = NDIS_STATUS_BAD_CHARACTERISTICS;
+ break;
+ }
+ }
+
+ //
+ // Free up previously assigned Resource memory
+ //
+ if ((BusType == NdisInterfacePci) &&
+ (BusNumber != -1) &&
+ (AdapterInfo != NULL) &&
+ (TmpMacP->PciAssignedResources != NULL))
+ {
+ TmpMacP->PciAssignedResources->Count = 0;
+ NtStatus = IoReportResourceUsage(NULL,
+ ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver,
+ TmpMacP->PciAssignedResources,
+ sizeof(CM_RESOURCE_LIST),
+ NULL,
+ NULL,
+ 0,
+ TRUE,
+ &Conflict);
+ FREE_POOL(TmpMacP->PciAssignedResources);
+ TmpMacP->PciAssignedResources = NULL;
+ }
+
+ //
+ // Calculate size of new buffer
+ //
+ Size = sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ (AdapterInfo->NumberOfPortDescriptors +
+ (((AdapterInfo->Master == TRUE) && (AdapterInfo->AdapterType == NdisInterfaceIsa)) ? 1 : 0));
+ Resources = (PCM_RESOURCE_LIST)ALLOC_FROM_POOL(Size, NDIS_TAG_RSRC_LIST);
+
+ if (Resources == NULL)
+ {
+ //
+ // Error out
+ //
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ //
+ // Fix up counts
+ //
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ //
+ // Setup resources for the ports
+ //
+ if (ValidBus)
+ {
+ 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;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].u.Port.Start.QuadPart =
+ (ULONG)AdapterInfo->PortDescriptors[i].InitialPort;
+ 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
+ //
+
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+ }
+
+ NewAdaptP->BeingRemoved = FALSE;
+
+ if (ValidBus)
+ {
+ //
+ // 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);
+
+ CopyMemory (((PUCHAR)errorLogEntry) + sizeof(IO_ERROR_LOG_PACKET),
+ (PVOID)baseFileName,
+ StringSize);
+ }
+ else
+ {
+ errorLogEntry->NumberOfStrings = 0;
+ }
+
+ //
+ // write it out
+ //
+ IoWriteErrorLogEntry(errorLogEntry);
+ }
+
+ Status = NDIS_STATUS_RESOURCE_CONFLICT;
+ break;
+ }
+
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // 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)
+ {
+ Status = NDIS_STATUS_SUCCESS;
+
+ //
+ // 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
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ if (addressSpace == 0)
+ {
+ //
+ // memory space
+ //
+ *(AdapterInfo->PortDescriptors[i].PortOffset) =
+ MmMapIoSpace(PortAddress,
+ AdapterInfo->PortDescriptors[i].NumberOfPorts,
+ FALSE);
+
+ if (*(AdapterInfo->PortDescriptors[i].PortOffset) == NULL)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+ }
+ else
+ {
+ //
+ // I/O space
+ //
+ *(AdapterInfo->PortDescriptors[i].PortOffset) = (PUCHAR)PortAddress.LowPart;
+ }
+ }
+ if (!NT_SUCCESS(Status))
+ break;
+ }
+ 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
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ if (addressSpace == 0)
+ {
+ //
+ // memory space
+ //
+ NewAdaptP->InitialPortMapping = MmMapIoSpace(PortAddress,
+ NewAdaptP->NumberOfPorts,
+ FALSE);
+
+ if (NewAdaptP->InitialPortMapping == NULL)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ 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)
+ {
+ break;
+ }
+ }
+
+ //
+ // 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 && ValidBus && (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);
+
+ CopyMemory (((PUCHAR)errorLogEntry) + sizeof(IO_ERROR_LOG_PACKET),
+ (PVOID)baseFileName,
+ StringSize);
+ }
+ else
+ {
+ errorLogEntry->NumberOfStrings = 0;
+ }
+
+ //
+ // write it out
+ //
+ IoWriteErrorLogEntry(errorLogEntry);
+ }
+
+ Status = NDIS_STATUS_RESOURCE_CONFLICT;
+ break;
+ }
+
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+ }
+
+ //
+ // 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) && ValidBus)
+ {
+ //
+ // 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)ALLOC_FROM_POOL(sizeof(MAP_REGISTER_ENTRY) *
+ NewAdaptP->PhysicalMapRegistersNeeded,
+ NDIS_TAG_MAP_REG);
+
+ if (NewAdaptP->MapRegisters == (PMAP_REGISTER_ENTRY)NULL)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ //
+ // Use this event to tell us when ndisAllocationExecutionRoutine
+ // has been called.
+ //
+ INITIALIZE_EVENT(&NewAdaptP->AllocationEvent);
+
+ //
+ // Set up the device description; zero it out in case its
+ // size changes.
+ //
+ ZeroMemory(&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)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ 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;
+
+ RAISE_IRQL_TO_DISPATCH(&OldIrql);
+
+ Status = IoAllocateAdapterChannel(AdapterObject,
+ NewAdaptP->DeviceObject,
+ MapRegistersPerChannel,
+ ndisAllocationExecutionRoutine,
+ (PVOID)NewAdaptP);
+ if (!NT_SUCCESS(Status))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("Failed to load driver because of\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("insufficient map registers.\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("AllocateAdapterChannel: %lx\n", Status));
+
+ FREE_POOL(Resources);
+
+ for (; i != 0; i--)
+ {
+ IoFreeMapRegisters(NewAdaptP->SystemAdapterObject,
+ NewAdaptP->MapRegisters[i-1].MapRegister,
+ MapRegistersPerChannel);
+ }
+
+ LOWER_IRQL(OldIrql);
+
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ LOWER_IRQL(OldIrql);
+
+ TimeoutValue.QuadPart = Int32x32To64(10 * 1000, -10000);
+
+ //
+ // ndisAllocationExecutionRoutine will set this event
+ // when it has gotten FirstTranslationEntry.
+ //
+ NtStatus = WAIT_FOR_OBJECT(&NewAdaptP->AllocationEvent, &TimeoutValue);
+
+ if (NtStatus != STATUS_SUCCESS)
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus));
+ FREE_POOL(Resources);
+
+ RAISE_IRQL_TO_DISPATCH(&OldIrql);
+
+ for (; i != 0; i--)
+ {
+ IoFreeMapRegisters(NewAdaptP->SystemAdapterObject,
+ NewAdaptP->MapRegisters[i-1].MapRegister,
+ MapRegistersPerChannel);
+ }
+
+ LOWER_IRQL(OldIrql);
+
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ RESET_EVENT(&NewAdaptP->AllocationEvent);
+ }
+
+ if (!NT_SUCCESS(Status))
+ break;
+ }
+
+ NdisInitializeRef(&NewAdaptP->Ref);
+
+ if (!ndisQueueAdapterOnMac(NewAdaptP, TmpMacP))
+ {
+ //
+ // The MAC is closing, undo what we have done.
+ //
+ if (NewAdaptP->Master)
+ {
+ ULONG MapRegistersPerChannel =
+ ((NewAdaptP->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2;
+
+ for (i=0; i<NewAdaptP->PhysicalMapRegistersNeeded; i++)
+ {
+ RAISE_IRQL_TO_DISPATCH(&OldIrql);
+
+ IoFreeMapRegisters(NewAdaptP->SystemAdapterObject,
+ NewAdaptP->MapRegisters[i].MapRegister,
+ MapRegistersPerChannel);
+
+ LOWER_IRQL(OldIrql);
+ }
+ }
+ Status = NDIS_STATUS_CLOSING;
+ break;
+ }
+
+ //
+ // Add an extra reference because the wrapper is using the MAC
+ //
+ ndisReferenceAdapter(NewAdaptP);
+ MacReferencePackage();
+
+ *NdisAdapterHandle = (NDIS_HANDLE)NewAdaptP;
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisRegisterAdapter\n"));
+ } while (FALSE);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisRegisterAdapter\n"));
+
+ if (NewAdaptP != NULL)
+ {
+ NdisWriteErrorLogEntry(NewAdaptP,
+ Status,
+ 0);
+ }
+ if (DerefMacOnError)
+ {
+ ndisDereferenceMac(TmpMacP);
+ }
+ if (NdisAdapterName.Buffer != NULL)
+ {
+ FREE_POOL(NdisAdapterName.Buffer);
+ }
+ if (TmpDeviceP != NULL)
+ {
+ IoDeleteDevice(TmpDeviceP);
+ if (NewAdaptP->MapRegisters != NULL)
+ {
+ FREE_POOL(NewAdaptP->MapRegisters);
+ }
+ if (Resources != NULL)
+ {
+ FREE_POOL(Resources);
+ }
+ }
+ }
+
+ return Status;
+}
+
+
+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.
+ //
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisDeregisterAdapter\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ (" Deregistering Adapter %s\n",
+ ((PNDIS_ADAPTER_BLOCK)NdisAdapterHandle)->AdapterName.Buffer));
+
+ IF_DBG(DBG_COMP_CONFIG, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(NdisAdapterHandle))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("DeregisterAdapter: Null Handle\n"));
+ DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(NdisAdapterHandle))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("DeregisterAdapter: Handle not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
+ }
+ }
+ ndisKillAdapter((PNDIS_ADAPTER_BLOCK)NdisAdapterHandle);
+
+ //
+ // Remove reference from wrapper
+ //
+ ndisDereferenceAdapter((PNDIS_ADAPTER_BLOCK)NdisAdapterHandle);
+
+ MacDereferencePackage();
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisDeregisterAdapter\n"));
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+VOID
+NdisRegisterAdapterShutdownHandler(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PVOID ShutdownContext,
+ IN ADAPTER_SHUTDOWN_HANDLER ShutdownHandler
+ )
+/*++
+
+Routine Description:
+
+ Registers 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);
+
+ 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.
+ }
+}
+
+
+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);
+
+ KeDeregisterBugCheckCallback(&WrapperContext->BugcheckCallbackRecord);
+ }
+}
+
+
+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 NdisStatus = NDIS_STATUS_FAILURE;
+ 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 = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->ParametersQueryTable;
+
+ 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);
+
+ *AssignedResources = NULL; // Assume failure
+ if (NtStatus == STATUS_SUCCESS)
+ {
+ //
+ // Store resources into the driver wide block
+ //
+ ((PNDIS_MAC_BLOCK)NdisMacHandle)->PciAssignedResources = AllocatedResources;
+
+ *AssignedResources = &(AllocatedResources->List[0].PartialResourceList);
+
+ //
+ // Update slot number since the driver can also scan and so the one
+ // in the registry is probably invalid
+ //
+ KeyQueryTable[4].DefaultLength = SlotNumber;
+
+ NdisStatus = NDIS_STATUS_SUCCESS;
+ }
+
+ return NdisStatus;
+}
+
diff --git a/private/ntos/ndis/ndis40/configm.c b/private/ntos/ndis/ndis40/configm.c
new file mode 100644
index 000000000..b155d1a90
--- /dev/null
+++ b/private/ntos/ndis/ndis40/configm.c
@@ -0,0 +1,2077 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ configm.c
+
+Abstract:
+
+ NDIS wrapper functions for miniport configuration/initialization
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 05-Oct-93
+ Jameel Hyder (JameelH) 01-Jun-95
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_CONFIGM
+
+
+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.
+
+--*/
+
+{
+ NDIS_STATUS Status;
+ PNDIS_M_DRIVER_BLOCK MiniBlock;
+ PNDIS_WRAPPER_HANDLE DriverInfo = (PNDIS_WRAPPER_HANDLE)(NdisWrapperHandle);
+
+ Status = NdisIMRegisterLayeredMiniport(NdisWrapperHandle,
+ MiniportCharacteristics,
+ CharacteristicsLength,
+ &MiniBlock);
+
+ DBGPRINT(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
+ ("Exit mini-port register\n"));
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ InitReferencePackage();
+ if (DriverInfo->NdisWrapperConfigurationHandle)
+ {
+ Status = ndisInitializeAllAdapterInstances((PNDIS_MAC_BLOCK)MiniBlock, NULL);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ ndisDereferenceDriver(MiniBlock);
+ Status = NDIS_STATUS_FAILURE;
+ }
+ }
+ else
+ {
+ Status = NDIS_STATUS_FAILURE;
+ }
+ InitDereferencePackage();
+ }
+
+ ASSERT (CURRENT_IRQL < DISPATCH_LEVEL);
+
+ return Status;
+}
+
+NDIS_STATUS
+NdisIMRegisterLayeredMiniport(
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN PNDIS_MINIPORT_CHARACTERISTICS MiniportCharacteristics,
+ IN UINT CharacteristicsLength,
+ OUT PNDIS_HANDLE DriverHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Used to register a layered 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.
+
+ DriverHandle - Returns a handle which can be used to call NdisMInitializeDeviceInstance.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_M_DRIVER_BLOCK MiniBlock;
+ PNDIS_WRAPPER_HANDLE DriverInfo = (PNDIS_WRAPPER_HANDLE)(NdisWrapperHandle);
+ UNICODE_STRING Us;
+ PWSTR pWch;
+ USHORT i, size;
+ UINT MemNeeded;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+
+ DBGPRINT(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
+ ("Enter mini-port register\n"));
+
+ do
+ {
+ if (DriverInfo == NULL)
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // Check version numbers and CharacteristicsLength.
+ //
+
+ size = 0; // Used to indicate bad version below
+ if (MiniportCharacteristics->MajorNdisVersion == 3)
+ {
+ if (MiniportCharacteristics->MinorNdisVersion == 0)
+ size = sizeof(NDIS30_MINIPORT_CHARACTERISTICS);
+ }
+
+ else if (MiniportCharacteristics->MajorNdisVersion == 4)
+ {
+ if (MiniportCharacteristics->MinorNdisVersion == 0)
+ {
+ size = sizeof(NDIS40_MINIPORT_CHARACTERISTICS);
+ }
+ else if (MiniportCharacteristics->MinorNdisVersion == 1)
+ {
+ size = sizeof(NDIS41_MINIPORT_CHARACTERISTICS);
+ }
+ }
+
+ //
+ // Check that this is an NDIS 3.0/4.0/4.1 miniport.
+ //
+ if (size == 0)
+ {
+ Status = NDIS_STATUS_BAD_VERSION;
+ break;
+ }
+
+ //
+ // Check that CharacteristicsLength is enough.
+ //
+ if (CharacteristicsLength < size)
+ {
+ Status = NDIS_STATUS_BAD_CHARACTERISTICS;
+ break;
+ }
+
+ //
+ // Allocate memory for the NDIS MINIPORT block.
+ //
+ MemNeeded = sizeof(NDIS_M_DRIVER_BLOCK);
+
+ //
+ // Extract the base-name, determine its length and allocate that much more
+ //
+ Us = *(PUNICODE_STRING)(DriverInfo->NdisWrapperConfigurationHandle);
+
+ for (i = Us.Length/sizeof(WCHAR), pWch = Us.Buffer + i - 1;
+ i > 0;
+ pWch --, i--)
+ {
+ if (*pWch == L'\\')
+ {
+ Us.Buffer = pWch + 1;
+ Us.Length -= i*sizeof(WCHAR);
+ Us.MaximumLength = Us.Length + sizeof(WCHAR);
+ break;
+ }
+ }
+ MemNeeded += Us.MaximumLength;
+
+ MiniBlock = (PNDIS_M_DRIVER_BLOCK)ALLOC_FROM_POOL(MemNeeded, NDIS_TAG_MINI_BLOCK);
+
+ if (MiniBlock == (PNDIS_M_DRIVER_BLOCK)NULL)
+ {
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ ZeroMemory(MiniBlock, MemNeeded);
+
+ MiniBlock->Length = MemNeeded;
+
+ //
+ // Copy over the characteristics table.
+ //
+
+ CopyMemory(&MiniBlock->MiniportCharacteristics,
+ MiniportCharacteristics,
+ size);
+
+ //
+ // Upcase the base-name and save it in the MiniBlock
+ //
+ MiniBlock->BaseName.Buffer = (PWSTR)((PUCHAR)MiniBlock + sizeof(NDIS_M_DRIVER_BLOCK));
+ MiniBlock->BaseName.Length =
+ MiniBlock->BaseName.MaximumLength = Us.Length;
+ RtlUpcaseUnicodeString(&MiniBlock->BaseName,
+ &Us,
+ FALSE);
+ //
+ // No adapters yet registered for this Miniport.
+ //
+
+ MiniBlock->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;
+
+ //
+ // Use this event to tell us when all adapters are removed from the mac
+ // during an unload
+ //
+ INITIALIZE_EVENT(&MiniBlock->MiniportsRemovedEvent);
+
+ MiniBlock->Unloading = FALSE;
+ MiniBlock->NdisDriverInfo = DriverInfo;
+ MiniBlock->MiniportIdField = (NDIS_HANDLE)0x1;
+
+ NdisInitializeRef(&MiniBlock->Ref);
+
+ // Lock the init code down now - before we take the lock below
+ MiniportReferencePackage();
+
+ //
+ // Put Driver on global list.
+ //
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+
+ MiniBlock->NextDriver = ndisMiniDriverList;
+ ndisMiniDriverList = MiniBlock;
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ MiniportDereferencePackage();
+
+ *DriverHandle = MiniBlock;
+
+ Status = NDIS_STATUS_SUCCESS;
+ } while (FALSE);
+
+ return Status;
+}
+
+
+NDIS_STATUS
+NdisIMDeInitializeDeviceInstance(
+ IN NDIS_HANDLE NdisMiniportHandle
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport;
+ NDIS_STATUS Status = NDIS_STATUS_FAILURE;
+
+ Miniport = (PNDIS_MINIPORT_BLOCK)NdisMiniportHandle;
+
+ if (ndisReferenceMiniport(Miniport))
+ {
+ Status = ndisUnloadMiniport(Miniport);
+ ndisDereferenceMiniport(Miniport);
+ }
+
+ return Status;
+}
+
+VOID
+ndisMOpenAdapter(
+ 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;
+ BOOLEAN DerefMini = FALSE, FreeOpen = FALSE,
+ DerefProt = FALSE;
+
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ do
+ {
+ if (!ndisReferenceMiniport(Miniport))
+ {
+ //
+ // The adapter is closing.
+ //
+ *Status = NDIS_STATUS_CLOSING;
+ break;
+ }
+ DerefMini = TRUE;
+
+ //
+ // Increment the protocol's reference count.
+ //
+ TmpProtP = (PNDIS_PROTOCOL_BLOCK)NdisProtocolHandle;
+
+ if (!ndisReferenceProtocol(TmpProtP))
+ {
+ //
+ // The protocol is closing.
+ //
+ *Status = NDIS_STATUS_CLOSING;
+ break;
+ }
+ DerefProt = TRUE;
+
+ //
+ // Now allocate a complete set of MAC structures for the protocol
+ // and set them up to transfer to the Miniport handler routines.
+ //
+ if (Miniport->FakeMac == NULL)
+ {
+ //
+ // Allocate a fake MAC block for the characteristics.
+ //
+ FakeMac = (PNDIS_MAC_BLOCK)ALLOC_FROM_POOL(sizeof(NDIS_MAC_BLOCK), NDIS_TAG_DEFAULT);
+ if (FakeMac == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ //
+ // Initialize the fake mac block.
+ //
+ ZeroMemory(FakeMac, sizeof(NDIS_MAC_BLOCK));
+
+ //
+ // Save the fake mac block with the miniport.
+ //
+ Miniport->FakeMac = FakeMac;
+
+ //
+ // 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;
+ }
+
+ //
+ // Initialize the reset handler.
+ //
+ FakeMac->MacCharacteristics.ResetHandler = ndisMReset;
+
+ //
+ // Initialize the request handler.
+ //
+ FakeMac->MacCharacteristics.RequestHandler = ndisMRequest;
+
+ //
+ // Initialize the send handler.
+ //
+ switch (Miniport->MediaType)
+ {
+ case NdisMediumArcnet878_2:
+
+ FakeMac->MacCharacteristics.SendHandler = ndisMArcnetSend;
+ break;
+
+ case NdisMediumWan:
+
+ FakeMac->MacCharacteristics.SendHandler = (PVOID)ndisMWanSend;
+ break;
+
+ default:
+ //
+ // If this is a fullduplex miniport then change the reset handler.
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ FakeMac->MacCharacteristics.ResetHandler = ndisMResetFullDuplex;
+ }
+
+ //
+ // Set up the send packet handlers miniports that support
+ // the new NDIS 4.0 SendPackets handler.
+ //
+ if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY))
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Using ndisMSendFullDuplexToSendPackets\n"));
+ FakeMac->MacCharacteristics.SendHandler = ndisMSendFullDuplexToSendPackets;
+ }
+ else
+ {
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Using ndisMSendToSendPackets\n"));
+ FakeMac->MacCharacteristics.SendHandler = ndisMSendToSendPackets;
+ }
+ }
+ else
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Using ndisMSendFullDuplex\n"));
+ FakeMac->MacCharacteristics.SendHandler = ndisMSendFullDuplex;
+ }
+ else
+ {
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Using ndisMSend\n"));
+ FakeMac->MacCharacteristics.SendHandler = ndisMSend;
+ }
+ }
+ break;
+ }
+
+ //
+ // If the miniport indicates packets the we have a dummy
+ // transfer data.
+ //
+ if (Miniport->DriverHandle->MiniportCharacteristics.ReturnPacketHandler != NULL)
+ {
+ // This driver supports the receive packet paradigm
+ // Fake the transferdata handler so if any xport calls
+ // this, we're still ok
+ FakeMac->MacCharacteristics.TransferDataHandler = ndisMDummyTransferData;
+ }
+ }
+ else
+ {
+ FakeMac = Miniport->FakeMac;
+ }
+
+ //
+ // Allocate an open within the Miniport context
+ //
+ MiniportOpen = (PNDIS_M_OPEN_BLOCK)ALLOC_FROM_POOL(sizeof(NDIS_M_OPEN_BLOCK), NDIS_TAG_DEFAULT);
+ if (MiniportOpen == (PNDIS_M_OPEN_BLOCK)NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ FreeOpen = TRUE;
+
+ //
+ // Initialize the open block.
+ //
+ ZeroMemory(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->CurrentLookahead = Miniport->CurrentLookahead;
+
+ NdisAllocateSpinLock(&(MiniportOpen->SpinLock));
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO, ("=1 0x%x\n", MiniportOpen));
+
+ MiniportOpen->References = 1;
+
+ if (UsingEncapsulation)
+ {
+ MINIPORT_SET_FLAG(MiniportOpen, fMINIPORT_OPEN_USING_ETH_ENCAPSULATION);
+ }
+
+ //
+ // Save the handlers with the open block.
+ //
+ 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;
+
+ //
+ // NDIS 4.0 miniport extensions
+ //
+ MiniportOpen->SendPacketsHandler = Miniport->DriverHandle->MiniportCharacteristics.SendPacketsHandler;
+
+ //
+ // NDIS 4.0 protocol extensions
+ //
+ MiniportOpen->ReceivePacketHandler =
+ (Miniport->DriverHandle->MiniportCharacteristics.ReturnPacketHandler == NULL) ?
+ NULL :
+ TmpProtP->ProtocolCharacteristics.ReceivePacketHandler;
+
+ //
+ // NDIS 4.1 miniport extensions
+ //
+ MiniportOpen->MiniportCoRequestHandler = Miniport->DriverHandle->MiniportCharacteristics.CoRequestHandler;
+ MiniportOpen->MiniportCoCreateVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoCreateVcHandler;
+
+ //
+ // NDIS 4.1 protocol extensions
+ //
+ MiniportOpen->CoRequestCompleteHandler =
+ TmpProtP->ProtocolCharacteristics.CoRequestCompleteHandler;
+
+ //
+ // initialize Lists
+ //
+ InitializeListHead(&MiniportOpen->ActiveVcHead);
+ InitializeListHead(&MiniportOpen->InactiveVcHead);
+
+ //
+ // Set up the elements of the open structure.
+ //
+ INITIALIZE_SPIN_LOCK(&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 (NdisMediumArcnet878_2 == Miniport->MediaType)
+ {
+ NewOpenP->TransferDataHandler = ndisMArcTransferData;
+ }
+ else
+ {
+ NewOpenP->TransferDataHandler = FakeMac->MacCharacteristics.TransferDataHandler;
+ }
+
+ //
+ // Set the send handler in the open block.
+ //
+ NewOpenP->SendHandler = FakeMac->MacCharacteristics.SendHandler;
+ NewOpenP->RequestHandler = ndisMRequest;
+
+ //
+ // Set up the send packets handler.
+ //
+ if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY))
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Using ndisMSendPacketsFullDuplex\n"));
+ NewOpenP->SendPacketsHandler = ndisMSendPacketsFullDuplex;
+ }
+ else
+ {
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Using ndisMSendPackets\n"));
+ NewOpenP->SendPacketsHandler = ndisMSendPackets;
+ }
+ }
+ else
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Using ndisMSendPacketsFullDuplexToSend\n"));
+ NewOpenP->SendPacketsHandler = ndisMSendPacketsFullDuplexToSend;
+ }
+ else
+ {
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Using ndisMSendPacketsToSend\n"));
+ NewOpenP->SendPacketsHandler = ndisMSendPacketsToSend;
+ }
+ }
+
+ //
+ // For WAN miniports, the send handler is different.
+ //
+ if (NdisMediumWan == Miniport->MediaType)
+ {
+ NewOpenP->SendHandler = (PVOID)ndisMWanSend;
+ }
+ else if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
+ {
+ //
+ // the convential send function is not available for CO miniports
+ // since this send function does not specify the Vc to send upon
+ // However for components which want to use this let them.
+ //
+ if ((NewOpenP->SendHandler == NULL) && (NewOpenP->SendPacketsHandler == NULL))
+ {
+ NewOpenP->SendHandler = ndisMRejectSend;
+ FakeMac->MacCharacteristics.SendHandler = ndisMRejectSend;
+ }
+
+ //
+ // Trap the conventional request handlers if they are not specified.
+ //
+ if ((Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler == NULL) ||
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler == NULL))
+ {
+ FakeMac->MacCharacteristics.RequestHandler = ndisMWrappedRequest;
+ NewOpenP->RequestHandler = ndisMWrappedRequest;
+ }
+ }
+
+ 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;
+ NewOpenP->ResetHandler = ndisMReset;
+ NewOpenP->ReceivePacketHandler =
+ (Miniport->DriverHandle->MiniportCharacteristics.ReturnPacketHandler == NULL) ?
+ NULL :
+ TmpProtP->ProtocolCharacteristics.ReceivePacketHandler;
+
+ //
+ // 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 = 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;
+
+
+ default:
+ //
+ // Bogus non-NULL value
+ //
+ FilterOpen = 1;
+ break;
+ }
+
+ //
+ // Check for an open filter failure.
+ //
+ if (!FilterOpen)
+ {
+ //
+ // Something went wrong, clean up and exit.
+ //
+ *Status = NDIS_STATUS_OPEN_FAILED;
+ break;
+ }
+
+ 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;
+
+ //
+ // If this is the first open on the adapter then fire the
+ // wake-up-dpc timer.
+ //
+ if (NULL == MiniportOpen->MiniportNextOpen)
+ {
+ //
+ // Start wake up timer
+ //
+ NdisMSetPeriodicTimer((PNDIS_MINIPORT_TIMER)(&Miniport->WakeUpDpcTimer),
+ Miniport->CheckForHangTimeout);
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+ } while (FALSE);
+
+ //
+ // Cleanup failure case
+ //
+ if (*Status != NDIS_STATUS_SUCCESS)
+ {
+ if (DerefMini)
+ {
+ ndisDereferenceMiniport(Miniport);
+ }
+ if (DerefProt)
+ {
+ ndisDereferenceProtocol(TmpProtP);
+ }
+ if (FreeOpen)
+ {
+ FREE_POOL(MiniportOpen);
+ }
+ ObDereferenceObject(FileObject);
+ FREE_POOL(NewOpenP);
+ }
+}
+
+NDIS_STATUS
+ndisMFinishPendingOpen(
+ IN PMINIPORT_PENDING_OPEN MiniportPendingOpen
+ )
+/*++
+
+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:
+
+ Returns the status code of the open.
+
+--*/
+
+{
+ //
+ // Do the open again.
+ //
+ ndisMOpenAdapter(&MiniportPendingOpen->Status,
+ &MiniportPendingOpen->OpenErrorStatus,
+ MiniportPendingOpen->NdisBindingHandle,
+ MiniportPendingOpen->NdisProtocolHandle,
+ MiniportPendingOpen->ProtocolBindingContext,
+ MiniportPendingOpen->AdapterName,
+ MiniportPendingOpen->OpenOptions,
+ MiniportPendingOpen->AddressingInformation,
+ MiniportPendingOpen->Miniport,
+ MiniportPendingOpen->NewOpenP,
+ MiniportPendingOpen->FileObject,
+ (BOOLEAN)(MINIPORT_TEST_FLAG(MiniportPendingOpen,
+ fPENDING_OPEN_USING_ENCAPSULATION) ? TRUE : FALSE));
+
+ //
+ // If the open didn't pend then call the NdisCompleteOpenAdapter(),
+ //
+ if (MiniportPendingOpen->Status != NDIS_STATUS_PENDING)
+ {
+ //
+ // Complete the open to the protocol in a worker thread since we want this
+ // to happen at passive irql.
+ //
+ INITIALIZE_WORK_ITEM(&MiniportPendingOpen->WorkItem,
+ ndisMFinishQueuedPendingOpen,
+ MiniportPendingOpen);
+ QUEUE_WORK_ITEM(&MiniportPendingOpen->WorkItem, HyperCriticalWorkQueue);
+ }
+
+ return(MiniportPendingOpen->Status);
+}
+
+VOID
+ndisMFinishQueuedPendingOpen(
+ IN PMINIPORT_PENDING_OPEN MiniportPendingOpen
+ )
+/*++
+
+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:
+
+ Returns the status code of the open.
+
+--*/
+
+{
+ PNDIS_OPEN_BLOCK OpenP = MiniportPendingOpen->NewOpenP;
+
+ (OpenP->ProtocolHandle->ProtocolCharacteristics.OpenAdapterCompleteHandler) (
+ OpenP->ProtocolBindingContext,
+ MiniportPendingOpen->Status,
+ MiniportPendingOpen->OpenErrorStatus);
+
+ //
+ // We're done with this pending open context.
+ //
+ NdisFreeMemory(MiniportPendingOpen, sizeof(MINIPORT_PENDING_OPEN), 0);
+}
+
+//
+// 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;
+ NDIS_STATUS Status;
+
+ CM_PARTIAL_RESOURCE_DESCRIPTOR Resource;
+
+ //
+ // First check if any bus access is allowed
+ //
+ if ((Miniport->BusType == (NDIS_INTERFACE_TYPE)-1) ||
+ (Miniport->BusNumber == (ULONG)-1))
+ {
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Setup port
+ //
+ Resource.Type = CmResourceTypePort;
+ Resource.ShareDisposition = CmResourceShareDeviceExclusive;
+ Resource.Flags = (Miniport->AdapterType == NdisInterfaceInternal) ?
+ CM_RESOURCE_PORT_MEMORY : CM_RESOURCE_PORT_IO;
+ Resource.u.Port.Start.QuadPart = InitialPort;
+ Resource.u.Port.Length = NumberOfPorts;
+
+ //
+ // Add the new resource.
+ //
+ Status = ndisAddResource(
+ &Miniport->Resources,
+ &Resource,
+ Miniport->AdapterType,
+ Miniport->BusNumber,
+ Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver,
+ Miniport->DeviceObject,
+ &Miniport->MiniportName);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return(Status);
+ }
+
+ //
+ // 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;
+ CM_PARTIAL_RESOURCE_DESCRIPTOR Resource;
+ NDIS_STATUS Status;
+
+ //
+ // 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;
+
+ HalTranslateBusAddress(Miniport->BusType, // InterfaceType
+ Miniport->BusNumber, // BusNumber
+ InitialPortAddress, // Bus Address
+ &addressSpace, // AddressSpace
+ &PortAddress); // Translated address
+ if (addressSpace == 0)
+ {
+ //
+ // memory space
+ //
+ MmUnmapIoSpace(PortOffset, NumberOfPorts);
+ }
+
+ //
+ // Build the resource to remove.
+ //
+ Resource.Type = CmResourceTypePort;
+ Resource.ShareDisposition = CmResourceShareDeviceExclusive;
+ Resource.Flags = (Miniport->AdapterType == NdisInterfaceInternal) ?
+ CM_RESOURCE_PORT_MEMORY : CM_RESOURCE_PORT_IO;
+ Resource.u.Port.Start.QuadPart = InitialPort;
+ Resource.u.Port.Length = NumberOfPorts;
+
+ //
+ // Remove the resource.
+ //
+ Status = ndisRemoveResource(
+ &Miniport->Resources,
+ &Resource,
+ Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver,
+ Miniport->DeviceObject,
+ &Miniport->MiniportName);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO,
+ ("NdisMDeregisterIoPortRange failed to remove the resource\n"));
+ }
+}
+
+
+//
+// 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;
+
+ if (BusMaster)
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_BUS_MASTER);
+
+ Miniport->AdapterType = AdapterType;
+
+ MiniportReferencePackage();
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
+ {
+ CoReferencePackage();
+ }
+}
+
+VOID
+NdisMSetAttributesEx(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN UINT CheckForHangTimeInSeconds OPTIONAL,
+ IN ULONG AttributeFlags,
+ IN NDIS_INTERFACE_TYPE AdapterType OPTIONAL
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+
+ Miniport->MiniportAdapterContext = MiniportAdapterContext;
+
+ Miniport->AdapterType = AdapterType;
+
+ //
+ // Set the new timeout value.
+ //
+ if (!ARGUMENT_PRESENT(CheckForHangTimeInSeconds))
+ {
+ CheckForHangTimeInSeconds = 2;
+ }
+
+ Miniport->CheckForHangTimeout = CheckForHangTimeInSeconds * 1000;
+
+ //
+ // Is this a bus master.
+ //
+ if (AttributeFlags & NDIS_ATTRIBUTE_BUS_MASTER)
+ {
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_BUS_MASTER);
+ }
+
+ //
+ // Should we ignore the packet queues?
+ //
+ if (AttributeFlags & NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT)
+ {
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_IGNORE_PACKET_QUEUE);
+ }
+
+ //
+ // Should we ignore the request queues?
+ //
+ if (AttributeFlags & NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT)
+ {
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_IGNORE_REQUEST_QUEUE);
+ }
+
+ //
+ // Should we ignore token ring errors?
+ //
+ if (AttributeFlags & NDIS_ATTRIBUTE_IGNORE_TOKEN_RING_ERRORS)
+ {
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_IGNORE_TOKEN_RING_ERRORS);
+ }
+
+ //
+ // Is this an intermediate miniport?
+ //
+ if (AttributeFlags & NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER)
+ {
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_INTERMEDIATE_DRIVER);
+ }
+
+ MiniportReferencePackage();
+}
+
+
+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
+ )
+{
+#ifndef _ALPHA_
+ MmUnmapIoSpace(VirtualAddress, Length);
+#endif
+}
+
+
+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);
+}
+
+NDIS_STATUS
+NdisMAllocateSharedMemoryAsync(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN ULONG Length,
+ IN BOOLEAN Cached,
+ IN PVOID Context
+ )
+{
+ //
+ // Convert the handle to our internal structure.
+ //
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportAdapterHandle;
+ PASYNC_WORKITEM pWorkItem = NULL;
+
+ // Allocate a workitem
+ if ((Miniport->SystemAdapterObject != NULL) &&
+ (Miniport->DriverHandle->MiniportCharacteristics.AllocateCompleteHandler != NULL))
+ {
+ NdisAllocateMemory(&pWorkItem,
+ sizeof(ASYNC_WORKITEM),
+ 0,
+ HighestAcceptableMax);
+ }
+
+ if ((pWorkItem == NULL) ||
+ !ndisReferenceMiniport(Miniport))
+ {
+ if (pWorkItem != NULL)
+ NdisFreeMemory(pWorkItem, sizeof(ASYNC_WORKITEM), 0);
+ return NDIS_STATUS_FAILURE;
+ }
+
+ // Initialize the workitem and queue it up to a worker thread
+ pWorkItem->Miniport = Miniport;
+ pWorkItem->Length = Length;
+ pWorkItem->Cached = Cached;
+ pWorkItem->Context = Context;
+ INITIALIZE_WORK_ITEM(&pWorkItem->ExWorkItem, ndisMQueuedAllocateSharedHandler, pWorkItem);
+ QUEUE_WORK_ITEM(&pWorkItem->ExWorkItem, CriticalWorkQueue);
+
+ return NDIS_STATUS_PENDING;
+}
+
+
+VOID
+ndisMQueuedAllocateSharedHandler(
+ IN PASYNC_WORKITEM pWorkItem
+ )
+{
+ KIRQL OldIrql;
+
+ // Allocate the memory
+ NdisMAllocateSharedMemory(pWorkItem->Miniport,
+ pWorkItem->Length,
+ pWorkItem->Cached,
+ &pWorkItem->VAddr,
+ &pWorkItem->PhyAddr);
+
+ if (pWorkItem->Miniport->Flags & fMINIPORT_IS_CO)
+ {
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(pWorkItem->Miniport, &OldIrql);
+ }
+ else
+ {
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ }
+
+ // Call the miniport back
+ (*pWorkItem->Miniport->DriverHandle->MiniportCharacteristics.AllocateCompleteHandler)(
+ pWorkItem->Miniport->MiniportAdapterContext,
+ pWorkItem->VAddr,
+ &pWorkItem->PhyAddr,
+ pWorkItem->Length,
+ pWorkItem->Context);
+
+ if (pWorkItem->Miniport->Flags & fMINIPORT_IS_CO)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(pWorkItem->Miniport, OldIrql);
+ }
+ else
+ {
+ KeLowerIrql(OldIrql);
+ }
+
+ // Dereference the miniport
+ ndisDereferenceMiniport(pWorkItem->Miniport);
+
+ // And finally free the work-item
+ NdisFreeMemory(pWorkItem, sizeof(ASYNC_WORKITEM), 0);
+}
+
+VOID
+NdisMFreeSharedMemory(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN ULONG Length,
+ IN BOOLEAN Cached,
+ IN PVOID VirtualAddress,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+
+ if (CURRENT_IRQL < DISPATCH_LEVEL)
+ {
+ NdisFreeSharedMemory(MiniportAdapterHandle,
+ Length,
+ Cached,
+ VirtualAddress,
+ PhysicalAddress);
+ }
+ else if (ndisReferenceMiniport(Miniport))
+ {
+ PASYNC_WORKITEM pWorkItem = NULL;
+
+ // Allocate a work-item and queue it up to a worker thread
+ NdisAllocateMemory(&pWorkItem,
+ sizeof(ASYNC_WORKITEM),
+ 0,
+ HighestAcceptableMax);
+
+ if (pWorkItem != NULL)
+ {
+ // Initialize the workitem and queue it up to a worker thread
+ pWorkItem->Miniport = Miniport;
+ pWorkItem->Length = Length;
+ pWorkItem->Cached = Cached;
+ pWorkItem->VAddr = VirtualAddress;
+ pWorkItem->PhyAddr = PhysicalAddress;
+ INITIALIZE_WORK_ITEM(&pWorkItem->ExWorkItem, ndisMQueuedFreeSharedHandler, pWorkItem);
+ QUEUE_WORK_ITEM(&pWorkItem->ExWorkItem, CriticalWorkQueue);
+ }
+
+ // What do we do now ?
+ }
+}
+
+VOID
+ndisMQueuedFreeSharedHandler(
+ IN PASYNC_WORKITEM pWorkItem
+ )
+{
+ // Free the memory
+ NdisFreeSharedMemory(pWorkItem->Miniport,
+ pWorkItem->Length,
+ pWorkItem->Cached,
+ pWorkItem->VAddr,
+ pWorkItem->PhyAddr);
+
+ // Dereference the miniport
+ ndisDereferenceMiniport(pWorkItem->Miniport);
+
+ // And finally free the work-item
+ NdisFreeMemory(pWorkItem, sizeof(ASYNC_WORKITEM), 0);
+}
+
+
+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);
+
+ if (Dma32BitAddresses)
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_DMA_32_BIT_ADDRESSES);
+
+ NdisAllocateDmaChannel(&Status,
+ MiniportDmaHandle,
+ (NDIS_HANDLE)Miniport,
+ DmaDescription,
+ MaximumLength);
+
+ return Status;
+}
+
+
+
+VOID
+NdisMDeregisterDmaChannel(
+ IN NDIS_HANDLE MiniportDmaHandle
+ )
+{
+ NdisFreeDmaChannel(MiniportDmaHandle);
+}
+
+
+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_TEST_FLAG(Miniport, fMINIPORT_BUS_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)
+ ALLOC_FROM_POOL(sizeof(MAP_REGISTER_ENTRY) * PhysicalMapRegistersNeeded,
+ NDIS_TAG_DEFAULT);
+
+ 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.
+ //
+
+ INITIALIZE_EVENT(&Miniport->AllocationEvent);
+
+ //
+ // Set up the device description; zero it out in case its
+ // size changes.
+ //
+
+ ZeroMemory(&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);
+
+ FREE_POOL(Miniport->MapRegisters);
+ Miniport->MapRegisters = NULL;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==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;
+
+ RAISE_IRQL_TO_DISPATCH(&OldIrql);
+
+ NtStatus = IoAllocateAdapterChannel(AdapterObject,
+ Miniport->DeviceObject,
+ MapRegistersPerChannel,
+ ndisAllocationExecutionRoutine,
+ Miniport);
+
+ if (!NT_SUCCESS(NtStatus))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("AllocateAdapterChannel: %lx\n", NtStatus));
+
+ for (; i != 0; i--)
+ {
+ IoFreeMapRegisters(Miniport->SystemAdapterObject,
+ Miniport->MapRegisters[i-1].MapRegister,
+ MapRegistersPerChannel);
+ }
+
+ LOWER_IRQL(OldIrql);
+
+ NdisWriteErrorLogEntry((NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 1,
+ 0xFFFFFFFF);
+
+ FREE_POOL(Miniport->MapRegisters);
+ Miniport->MapRegisters = NULL;
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ LOWER_IRQL(OldIrql);
+
+ TimeoutValue.QuadPart = Int32x32To64(2 * 1000, -10000);
+
+ //
+ // ndisAllocationExecutionRoutine will set this event
+ // when it has gotten FirstTranslationEntry.
+ //
+
+ NtStatus = WAIT_FOR_OBJECT(&Miniport->AllocationEvent, &TimeoutValue);
+
+ if (NtStatus != STATUS_SUCCESS)
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus));
+
+ RAISE_IRQL_TO_DISPATCH(&OldIrql);
+
+ for (; i != 0; i--)
+ {
+ IoFreeMapRegisters(Miniport->SystemAdapterObject,
+ Miniport->MapRegisters[i-1].MapRegister,
+ MapRegistersPerChannel);
+ }
+
+ LOWER_IRQL(OldIrql);
+
+ NdisWriteErrorLogEntry((NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 1,
+ 0xFFFFFFFF);
+
+ FREE_POOL(Miniport->MapRegisters);
+ Miniport->MapRegisters = NULL;
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ RESET_EVENT(&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_TEST_FLAG(Miniport, fMINIPORT_BUS_MASTER) &&
+ (Miniport->MapRegisters != NULL)
+ )
+ {
+ ULONG MapRegistersPerChannel =
+ ((Miniport->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2;
+
+ for (i=0; i<Miniport->PhysicalMapRegistersNeeded; i++)
+ {
+ RAISE_IRQL_TO_DISPATCH(&OldIrql);
+
+ IoFreeMapRegisters(Miniport->SystemAdapterObject,
+ Miniport->MapRegisters[i].MapRegister,
+ MapRegistersPerChannel);
+
+ LOWER_IRQL(OldIrql);
+ }
+
+ FREE_POOL(Miniport->MapRegisters);
+
+ Miniport->MapRegisters = NULL;
+ }
+}
+
+
+
+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);
+}
+
+
+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);
+ }
+ }
+}
+
+
+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;
+
+ //
+ // Register our shutdown handler for a bugcheck. (Note that we are
+ // already registered for shutdown notification.)
+ //
+
+ KeInitializeCallbackRecord(&WrapperContext->BugcheckCallbackRecord);
+
+ KeRegisterBugCheckCallback(&WrapperContext->BugcheckCallbackRecord, // callback record.
+ ndisBugcheckHandler, // callback routine.
+ WrapperContext, // free form buffer.
+ sizeof(NDIS_WRAPPER_CONTEXT), // buffer size.
+ "Ndis miniport"); // component id.
+ }
+}
+
+
+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)
+ {
+ KeDeregisterBugCheckCallback(&WrapperContext->BugcheckCallbackRecord);
+ WrapperContext->ShutdownHandler = NULL;
+ }
+}
+
+
+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);
+
+ //
+ // Update slot number since the driver can also scan and so the one
+ // in the registry is probably invalid
+ //
+ Miniport->SlotNumber = SlotNumber;
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+VOID
+NdisMQueryAdapterResources(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PNDIS_RESOURCE_LIST ResourceList,
+ IN IN PUINT BufferSize
+ )
+{
+ *Status = NDIS_STATUS_NOT_SUPPORTED;
+}
+
+
+
diff --git a/private/ntos/ndis/ndis40/data.c b/private/ntos/ndis/ndis40/data.c
new file mode 100644
index 000000000..e65838217
--- /dev/null
+++ b/private/ntos/ndis/ndis40/data.c
@@ -0,0 +1,190 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ data.c
+
+Abstract:
+
+ NDIS wrapper Data
+
+Author:
+
+ 01-Jun-1995 JameelH Re-organization
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ 10-July-1995 KyleB Added spinlock logging debug code.
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_DATA
+
+#if DBG
+ULONG ndisDebugSystems = 0;
+LONG ndisDebugLevel = DBG_LEVEL_FATAL;
+ULONG ndisDebugInformationOffset;
+#endif
+
+UCHAR ndisValidProcessors[32] = { 0 };
+ULONG ndisMaximumProcessor = 0;
+ULONG ndisCurrentProcessor = 0;
+UCHAR ndisInternalEaName[4] = "NDIS";
+UCHAR ndisInternalEaValue[8] = "INTERNAL";
+const NDIS_PHYSICAL_ADDRESS HighestAcceptableMax = NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
+PKG_REF ProtocolPkg = {0};
+PKG_REF MacPkg = {0};
+PKG_REF CoPkg = {0};
+PKG_REF InitPkg = {0};
+PKG_REF PnPPkg = {0};
+PKG_REF MiniportPkg = {0};
+PKG_REF ArcPkg = {0};
+PKG_REF EthPkg = {0};
+PKG_REF TrPkg = {0};
+PKG_REF FddiPkg = {0};
+KSPIN_LOCK ndisDriverListLock = {0};
+PNDIS_MAC_BLOCK ndisMacDriverList = (PNDIS_MAC_BLOCK)NULL;
+PNDIS_M_DRIVER_BLOCK ndisMiniDriverList = NULL;
+PNDIS_PROTOCOL_BLOCK ndisProtocolList = NULL;
+PNDIS_OPEN_BLOCK ndisGlobalOpenList = NULL;
+PNDIS_AF_LIST ndisAfList = NULL;
+KSPIN_LOCK ndisGlobalOpenListLock = {0};
+TDI_REGISTER_CALLBACK ndisTdiRegisterCallback = NULL;
+ULONG ndisDmaAlignment = 0;
+ERESOURCE SharedMemoryResource = {0};
+KSPIN_LOCK ndisLookaheadBufferLock = {0};
+ULONG ndisLookaheadBufferLength = 0;
+#if defined(_ALPHA_)
+PNDIS_LOOKAHEAD_ELEMENT ndisLookaheadBufferList = NULL;
+#endif
+ULONG MiniportDebug = 0; // MINIPORT_DEBUG_LOUD;
+
+UCHAR ndisMSendRescBuffer[512] = {0};
+ULONG ndisMSendRescIndex = 0;
+UCHAR ndisMSendLog[256] = {0};
+UCHAR ndisMSendLogIndex = 0;
+BOOLEAN ndisSkipProcessorAffinity = FALSE;
+BOOLEAN ndisMediaTypeCl[NdisMediumMax] =
+ {
+ TRUE,
+ TRUE,
+ TRUE,
+ FALSE,
+ TRUE,
+ TRUE,
+ TRUE,
+ TRUE,
+ FALSE,
+ TRUE,
+ TRUE
+ };
+NDIS_MEDIUM ndisMediumBuffer[NdisMediumMax + EXPERIMENTAL_SIZE] = // Keep some space for experimental media
+ {
+ NdisMedium802_3,
+ NdisMedium802_5,
+ NdisMediumFddi,
+ NdisMediumWan,
+ NdisMediumLocalTalk,
+ NdisMediumDix,
+ NdisMediumArcnetRaw,
+ NdisMediumArcnet878_2,
+ NdisMediumAtm,
+ NdisMediumWirelessWan,
+ NdisMediumIrda
+ };
+NDIS_MEDIUM * ndisMediumArray = ndisMediumBuffer;
+UINT ndisMediumArraySize = NdisMediumMax * sizeof(NDIS_MEDIUM);
+UINT ndisMediumArrayMaxSize = sizeof(ndisMediumBuffer);
+PBUS_SLOT_DB ndisGlobalDb = NULL;
+KSPIN_LOCK ndisGlobalDbLock = {0};
+
+
+#if TRACK_MEMORY
+
+KSPIN_LOCK ALock = 0;
+#define MAX_PTR_COUNT 2048
+
+struct _MemPtr
+{
+ PVOID Ptr;
+ ULONG Size;
+ ULONG ModLine;
+ ULONG Tag;
+} ndisMemPtrs[MAX_PTR_COUNT] = { 0 };
+
+PVOID
+AllocateM(
+ IN UINT Size,
+ IN ULONG ModLine,
+ IN ULONG Tag
+ )
+{
+ PVOID p;
+
+ p = ExAllocatePoolWithTag(NonPagedPool, Size, Tag);
+
+ if (p != NULL)
+ {
+ KIRQL OldIrql;
+ UINT i;
+
+ ACQUIRE_SPIN_LOCK(&ALock, &OldIrql);
+
+ for (i = 0; i < MAX_PTR_COUNT; i++)
+ {
+ if (ndisMemPtrs[i].Ptr == NULL)
+ {
+ ndisMemPtrs[i].Ptr = p;
+ ndisMemPtrs[i].Size = Size;
+ ndisMemPtrs[i].ModLine = ModLine;
+ ndisMemPtrs[i].Tag = Tag;
+ break;
+ }
+ }
+
+ RELEASE_SPIN_LOCK(&ALock, OldIrql);
+ }
+
+ return(p);
+}
+
+VOID
+FreeM(
+ IN PVOID MemPtr
+ )
+{
+ KIRQL OldIrql;
+ UINT i;
+
+ ACQUIRE_SPIN_LOCK(&ALock, &OldIrql);
+
+ for (i = 0; i < MAX_PTR_COUNT; i++)
+ {
+ if (ndisMemPtrs[i].Ptr == MemPtr)
+ {
+ ndisMemPtrs[i].Ptr = NULL;
+ ndisMemPtrs[i].Size = 0;
+ ndisMemPtrs[i].ModLine = 0;
+ ndisMemPtrs[i].Tag = 0;
+ }
+ }
+
+ RELEASE_SPIN_LOCK(&ALock, OldIrql);
+
+ ExFreePool(MemPtr);
+}
+
+#endif
+
diff --git a/private/ntos/ndis/ndis40/debug.c b/private/ntos/ndis/ndis40/debug.c
new file mode 100644
index 000000000..c3e6feb05
--- /dev/null
+++ b/private/ntos/ndis/ndis40/debug.c
@@ -0,0 +1,422 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ debug.c
+
+Abstract:
+
+ NDIS wrapper definitions
+
+Author:
+
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ 10/22/95 Kyle Brandon Created.
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+//
+// Define module number for debug code
+//
+#define MODULE_NUMBER MODULE_DEBUG
+
+#if DBG && _DBG
+
+
+VOID
+ndisMInitializeDebugInformation(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_MOJO NdisMojo;
+
+ //
+ // Allocate the initial debug structure.
+ //
+ NdisMojo = ALLOC_FROM_POOL(sizeof(NDIS_MOJO), NDIS_TAG_DBG);
+
+ ASSERT(NdisMojo != NULL);
+
+ //
+ // Clear out the log memory.
+ //
+ ZeroMemory(NdisMojo, sizeof(NDIS_MOJO));
+
+ //
+ // Allocate memory for the spin lock log.
+ //
+ NdisMojo->SpinLockLog = ALLOC_FROM_POOL(sizeof(SPIN_LOCK_LOG) +
+ (sizeof(SPIN_LOCK_LOG_ENTRY) * LOG_SIZE),
+ NDIS_TAG_DBG_S);
+
+ ASSERT(NdisMojo->SpinLockLog != NULL);
+
+ //
+ // Initialize the spin lock log.
+ //
+ NdisZeroMemory(
+ NdisMojo->SpinLockLog,
+ sizeof(SPIN_LOCK_LOG) + (sizeof(SPIN_LOCK_LOG_ENTRY) * LOG_SIZE));
+
+ NdisMojo->SpinLockLog->Buffer = (PSPIN_LOCK_LOG_ENTRY)((PUCHAR)NdisMojo->SpinLockLog + sizeof(SPIN_LOCK_LOG));
+ NdisMojo->SpinLockLog->CurrentEntry = (LOG_SIZE - 1);
+
+
+ //
+ // Allocate memory for the local lock log.
+ //
+ NdisMojo->LocalLockLog = ALLOC_FROM_POOL(sizeof(LOCAL_LOCK_LOG) +
+ (sizeof(LOCAL_LOCK_LOG_ENTRY) * LOG_SIZE),
+ NDIS_TAG_DBG_L);
+ ASSERT(NdisMojo->LocalLockLog != NULL);
+
+ //
+ // Initialize the local lock log.
+ //
+ NdisZeroMemory(
+ NdisMojo->LocalLockLog,
+ sizeof(LOCAL_LOCK_LOG) + (sizeof(LOCAL_LOCK_LOG_ENTRY) * LOG_SIZE));
+
+ NdisMojo->LocalLockLog->Buffer = (PLOCAL_LOCK_LOG_ENTRY)((PUCHAR)NdisMojo->LocalLockLog + sizeof(LOCAL_LOCK_LOG));
+ NdisMojo->LocalLockLog->CurrentEntry = (LOG_SIZE - 1);
+
+ //
+ // Allocate memory for the send packet log.
+ //
+ NdisMojo->SendPacketLog = ALLOC_FROM_POOL(
+ sizeof(PACKET_LOG) +
+ (sizeof(PACKET_LOG_ENTRY) * LOG_SIZE),
+ NDIS_TAG_DBG_P);
+ ASSERT(NdisMojo->SendPacketLog != NULL);
+
+ //
+ // Initialize the packet log.
+ //
+ NdisZeroMemory(
+ NdisMojo->SendPacketLog,
+ sizeof(PACKET_LOG) + (sizeof(PACKET_LOG_ENTRY) * LOG_SIZE));
+
+ NdisMojo->SendPacketLog->Buffer = (PPACKET_LOG_ENTRY)((PUCHAR)NdisMojo->SendPacketLog + sizeof(PACKET_LOG));
+ NdisMojo->SendPacketLog->CurrentEntry = (LOG_SIZE - 1);
+
+ //
+ // Allocate memory for the receive packet log.
+ //
+ NdisMojo->RecvPacketLog = ALLOC_FROM_POOL(
+ sizeof(PACKET_LOG) +
+ (sizeof(PACKET_LOG_ENTRY) * LOG_SIZE),
+ NDIS_TAG_DBG_P);
+ ASSERT(NdisMojo->RecvPacketLog != NULL);
+
+ //
+ // Initialize the packet log.
+ //
+ NdisZeroMemory(
+ NdisMojo->RecvPacketLog,
+ sizeof(PACKET_LOG) + (sizeof(PACKET_LOG_ENTRY) * LOG_SIZE));
+
+ NdisMojo->RecvPacketLog->Buffer = (PPACKET_LOG_ENTRY)((PUCHAR)NdisMojo->RecvPacketLog + sizeof(PACKET_LOG));
+ NdisMojo->RecvPacketLog->CurrentEntry = (LOG_SIZE - 1);
+
+
+ //
+ // Initialize the spin locks.
+ //
+ INITIALIZE_SPIN_LOCK(&NdisMojo->SpinLockLog->Lock);
+ INITIALIZE_SPIN_LOCK(&NdisMojo->LocalLockLog->Lock);
+ INITIALIZE_SPIN_LOCK(&NdisMojo->SendPacketLog->Lock);
+ INITIALIZE_SPIN_LOCK(&NdisMojo->RecvPacketLog->Lock);
+
+ //
+ // Save the debug information with the miniport.
+ //
+ Miniport->Reserved = NdisMojo;
+
+}
+
+VOID
+NDISM_LOG_RECV_PACKET(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PVOID Context1,
+ IN PVOID Context2,
+ IN ULONG Ident
+ )
+{
+ KIRQL OldIrql;
+
+ IF_DBG(DBG_COMP_RECV, DBG_LEVEL_LOG)
+ {
+ ACQUIRE_SPIN_LOCK(&RPL_LOCK(Miniport), &OldIrql);
+
+ RPL_HEAD(Miniport) = &RPL_LOG(Miniport)[RPL_CURRENT_ENTRY(Miniport)];
+ RPL_HEAD(Miniport)->Miniport = Miniport;
+ RPL_HEAD(Miniport)->Context1 = Context1;
+ RPL_HEAD(Miniport)->Context2 = Context2;
+ RPL_HEAD(Miniport)->Ident = Ident;
+
+ if (RPL_CURRENT_ENTRY(Miniport)-- == 0)
+ {
+ RPL_CURRENT_ENTRY(Miniport) = (LOG_SIZE - 1);
+ }
+
+ RELEASE_SPIN_LOCK(&RPL_LOCK(Miniport), OldIrql);
+ }
+}
+
+VOID
+NDISM_LOG_PACKET(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_PACKET Context1,
+ IN PVOID Context2,
+ IN ULONG Ident
+ )
+{
+ KIRQL OldIrql;
+
+ IF_DBG(DBG_COMP_SEND, DBG_LEVEL_LOG)
+ {
+ ACQUIRE_SPIN_LOCK(&SPL_LOCK(Miniport), &OldIrql);
+
+ SPL_HEAD(Miniport) = &SPL_LOG(Miniport)[SPL_CURRENT_ENTRY(Miniport)];
+ SPL_HEAD(Miniport)->Miniport = Miniport;
+ SPL_HEAD(Miniport)->Context1 = Context1;
+ SPL_HEAD(Miniport)->Context2 = Context2;
+ SPL_HEAD(Miniport)->Ident = Ident;
+
+ if (SPL_CURRENT_ENTRY(Miniport)-- == 0)
+ {
+ SPL_CURRENT_ENTRY(Miniport) = (LOG_SIZE - 1);
+ }
+
+ RELEASE_SPIN_LOCK(&SPL_LOCK(Miniport), OldIrql);
+ }
+}
+
+#if defined(_M_IX86) && defined(_NDIS_INTERNAL_DEBUG)
+
+//
+// gWatchMask[x][y]
+// x is the break point to set 0-3.
+// y is the following:
+// 0 - Mask to OR with dr7 to enable breakpoint x.
+// 1 - Mask to AND ~ with dr7 to disable breakpoint x.
+// 2 - The linear address that is currently in drX.
+// This is 0 if drX is clear.
+//
+ULONG gWatch[4][3] =
+{
+ {
+ 0xD0303,
+ 0xD0003,
+ 0
+ },
+ {
+ 0xD0030C,
+ 0xD0000C,
+ 0
+ },
+ {
+ 0xD000330,
+ 0xD000030,
+ 0
+ },
+ {
+ 0xD00003C0,
+ 0xD00000C0,
+ 0
+ }
+};
+
+#define SET_WATCH 0
+#define CLEAR_WATCH 1
+#define CURRENT_WATCH 2
+
+#define NO_ADDRESS_SET 0
+#define NO_DEBUG_REGISTERS_AVAILABLE 4
+
+VOID
+NdisMSetWriteBreakPoint(
+ IN PVOID LinearAddress
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ UINT c;
+ ULONG Mask;
+
+ //
+ // Find the first free debug register that we can use.
+ //
+ for (c = 0; c < NO_DEBUG_REGISTERS_AVAILABLE; c++)
+ {
+ if (NO_ADDRESS_SET == gWatch[c][CURRENT_WATCH])
+ {
+ break;
+ }
+ }
+
+ //
+ // Did we get a debug register?
+ //
+ if (NO_DEBUG_REGISTERS_AVAILABLE == c)
+ {
+ DbgPrint("Attempted to set a write breakpoint with no registers available\n");
+ DbgBreakPoint();
+ return;
+ }
+
+ //
+ // Separate code for each debug register.
+ //
+ switch (c)
+ {
+ case 0:
+
+ _asm {
+
+ mov eax, LinearAddress
+ mov dr0, eax
+ }
+
+ break;
+
+ case 1:
+
+ _asm {
+
+ mov eax, LinearAddress
+ mov dr1, eax
+ }
+
+ break;
+
+ case 2:
+
+ _asm {
+
+ mov eax, LinearAddress
+ mov dr2, eax
+ }
+
+ break;
+
+ case 3:
+
+ _asm {
+
+ mov eax, LinearAddress
+ mov dr3, eax
+ }
+
+ break;
+
+
+ default:
+
+ DbgPrint("Invalid debug register selected!!\n");
+ DbgBreakPoint();
+ }
+
+ //
+ // Enable the break point.
+ //
+ Mask = gWatch[c][SET_WATCH];
+
+ _asm {
+ mov eax, dr7
+ or eax, Mask
+ mov dr7, eax
+ }
+
+}
+
+
+VOID
+NdisMClearWriteBreakPoint(
+ IN PVOID LinearAddress
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ UINT c;
+ ULONG Mask;
+
+ //
+ // Find the register that this address is in.
+ //
+ for (c = 0; c < NO_DEBUG_REGISTERS_AVAILABLE; c++)
+ {
+ if (gWatch[c][CURRENT_WATCH] == (ULONG)LinearAddress)
+ {
+ break;
+ }
+ }
+
+ //
+ // Did we get a debug register?
+ //
+ if (NO_DEBUG_REGISTERS_AVAILABLE == c)
+ {
+ DbgPrint("Attempted to set a write breakpoint with no registers available\n");
+ DbgBreakPoint();
+ return;
+ }
+
+ //
+ // Clear the address from our state array.
+ //
+ gWatch[c][CURRENT_WATCH] = 0;
+
+ //
+ // Enable the break point.
+ //
+ Mask = gWatch[c][CLEAR_WATCH];
+
+ _asm {
+ mov eax, dr7
+ mov ebx, Mask
+ not ebx
+ and eax, ebx
+ mov dr7, eax
+ }
+}
+
+#endif
+
+#else
+
+#endif
+
diff --git a/private/ntos/ndis/ndis40/dirs b/private/ntos/ndis/ndis40/dirs
new file mode 100644
index 000000000..b3d6b7888
--- /dev/null
+++ b/private/ntos/ndis/ndis40/dirs
@@ -0,0 +1,23 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=up \
+ mp
diff --git a/private/ntos/ndis/ndis40/dummy.c b/private/ntos/ndis/ndis40/dummy.c
new file mode 100644
index 000000000..350258c2e
--- /dev/null
+++ b/private/ntos/ndis/ndis40/dummy.c
@@ -0,0 +1,56 @@
+/*++
+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
+
+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
+
+--*/
+
+{
+
+ return STATUS_SUCCESS;
+
+} // DriverEntry
diff --git a/private/ntos/ndis/ndis40/efilter.c b/private/ntos/ndis/ndis40/efilter.c
new file mode 100644
index 000000000..1e3b985df
--- /dev/null
+++ b/private/ntos/ndis/ndis40/efilter.c
@@ -0,0 +1,2845 @@
+/*++
+
+Copyright (c) 1990-1995 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
+
+ 10-July-1995 KyleB Added separate queues for bindings
+ that receive directed and broadcast
+ packets. Also fixed the request code
+ that requires the filter database.
+
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_EFILTER
+
+#define ETH_CHECK_FOR_INVALID_BROADCAST_INDICATION(_F) \
+IF_DBG(DBG_COMP_FILTER, DBG_LEVEL_WARN) \
+{ \
+ if (!((_F)->CombinedPacketFilter & NDIS_PACKET_TYPE_BROADCAST)) \
+ { \
+ /* \
+ We should never receive directed packets \
+ to someone else unless in p-mode. \
+ */ \
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_ERR, \
+ ("Bad driver, indicating broadcast when not set to.\n"));\
+ DBGBREAK(DBG_COMP_FILTER, DBG_LEVEL_ERR); \
+ } \
+}
+
+#define ETH_CHECK_FOR_INVALID_DIRECTED_INDICATION(_F, _A) \
+IF_DBG(DBG_COMP_FILTER, DBG_LEVEL_WARN) \
+{ \
+ /* \
+ 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((_F)->AdapterAddress, (_A), &Result);\
+ if (Result != 0) \
+ { \
+ /* \
+ We should never receive directed packets \
+ to someone else unless in p-mode. \
+ */ \
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_ERR, \
+ ("Bad driver, indicating packets to another station when not in promiscuous mode.\n"));\
+ DBGBREAK(DBG_COMP_FILTER, DBG_LEVEL_ERR); \
+ } \
+}
+
+
+//
+// VOID
+// ETH_FILTER_ALLOC_OPEN(
+// IN PETH_FILTER Filter,
+// OUT PUINT FilterIndex
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Allocates an open block. This only allocates 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:
+//
+// None
+//
+//--*/
+#define ETH_FILTER_FREE_OPEN(Filter, LocalOpen) \
+{ \
+ SET_BIT_IN_MASK(((LocalOpen)->FilterIndex), &((Filter)->FreeBindingMask));\
+ FreePhys((LocalOpen), sizeof(ETH_BINDING_INFO));\
+}
+
+
+VOID
+ethRemoveBindingFromLists(
+ IN PETH_FILTER Filter,
+ IN PETH_BINDING_INFO Binding
+ )
+/*++
+
+ This routine will remove a binding from all of the list in a
+ filter database. These lists include the list of bindings,
+ the directed filter list and the broadcast filter list.
+
+Arguments:
+
+ Filter - Pointer to the filter database to remove the binding from.
+ Binding - Pointer to the binding to remove.
+
+--*/
+{
+ PETH_BINDING_INFO *ppBI;
+
+ //
+ // Remove the binding from the filters list
+ // of all bindings.
+ //
+ for (ppBI = &Filter->OpenList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextOpen)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextOpen;
+ break;
+ }
+ }
+ ASSERT(*ppBI == Binding->NextOpen);
+
+ //
+ // Remove it from the directed binding list - conditionally
+ //
+ for (ppBI = &Filter->DirectedList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextDirected)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextDirected;
+ break;
+ }
+ }
+
+ //
+ // Remove it from the broadcast/multicast binding list - conditionally
+ //
+ for (ppBI = &Filter->BMList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextBM)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextBM;
+ break;
+ }
+ }
+
+ Binding->NextDirected = NULL;
+ Binding->NextBM = NULL;
+ Binding->NextOpen = NULL;
+}
+
+VOID
+ethRemoveAndFreeBinding(
+ IN PETH_FILTER Filter,
+ IN PETH_BINDING_INFO Binding,
+ IN BOOLEAN fCallCloseAction
+ )
+/*++
+
+Routine Description:
+
+ This routine will remove a binding from the filter database and
+ indicate a receive complete if necessary. This was made a function
+ to remove code redundancey in following routines. Its not time
+ critical so it's cool.
+
+Arguments:
+
+ Filter - Pointer to the filter database to remove the binding from.
+ Binding - Pointer to the binding to remove.
+ fCallCloseAction - TRUE if we should call the filter's close
+ action routine. FALSE if not.
+--*/
+{
+ //
+ // Remove the binding.
+ //
+ ethRemoveBindingFromLists(Filter, Binding);
+
+ //
+ // If we have received and packet indications then
+ // notify the binding of the indication completion.
+ //
+ if (Binding->ReceivedAPacket)
+ {
+ if (NULL != Filter->Miniport)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+ }
+ else
+ {
+ NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ }
+
+ FilterIndicateReceiveComplete(Binding->NdisBindingContext);
+
+ if (NULL != Filter->Miniport)
+ {
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+ }
+ else
+ {
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ }
+ }
+
+ //
+ // Do we need to call the driver's close action routine?
+ //
+ if (fCallCloseAction)
+ {
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+ Filter->CloseAction(Binding->MacBindingHandle);
+ }
+
+ //
+ // Free the open.
+ //
+ ETH_FILTER_FREE_OPEN(Filter, Binding);
+}
+
+
+
+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));
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ return(FALSE);
+ }
+
+ //
+ // Clear the memory.
+ //
+ ZeroMemory(LocalFilter, sizeof(ETH_FILTER));
+
+ //
+ // Allocate memory for the multicast array list.
+ //
+ 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;
+ }
+
+ //
+ // Allocate memory for the multicast array.
+ //
+ AllocStatus = AllocPhys(
+ &LocalFilter->MulticastAddresses,
+ ETH_LENGTH_OF_ADDRESS * MaximumMulticastAddresses);
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ EthDeleteFilter(LocalFilter);
+ return(FALSE);
+ }
+
+ //
+ // Allocate memory for the OldMulticastAddresses list,
+ // this is incase we have to restore the original list.
+ //
+ AllocStatus = AllocPhys(
+ &LocalFilter->OldMulticastAddresses,
+ ETH_LENGTH_OF_ADDRESS * MaximumMulticastAddresses);
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ EthDeleteFilter(LocalFilter);
+ return(FALSE);
+ }
+
+ //
+ // Allocate memory for the bindings using the addresses.
+ //
+ AllocStatus = AllocPhys(
+ &LocalFilter->BindingsUsingAddress,
+ sizeof(ETH_MASK) * MaximumMulticastAddresses);
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ EthDeleteFilter(LocalFilter);
+ return(FALSE);
+ }
+
+ //
+ // Allocate memory for the old bindings using the addresses.
+ //
+ AllocStatus = AllocPhys(
+ &LocalFilter->OldBindingsUsingAddress,
+ sizeof(ETH_MASK) * MaximumMulticastAddresses);
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ EthDeleteFilter(LocalFilter);
+ return(FALSE);
+ }
+
+ EthReferencePackage();
+
+ LocalFilter->FreeBindingMask = (ULONG)(-1);
+
+ ETH_COPY_NETWORK_ADDRESS(LocalFilter->AdapterAddress, AdapterAddress);
+ LocalFilter->Lock = Lock;
+ LocalFilter->AddressChangeAction = AddressChangeAction;
+ LocalFilter->FilterChangeAction = FilterChangeAction;
+ LocalFilter->CloseAction = CloseAction;
+ LocalFilter->MaximumMulticastAddresses = MaximumMulticastAddresses;
+
+ *Filter = LocalFilter;
+ 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);
+
+ //
+ // Free the memory that was allocated for the current multicast
+ // address list.
+ //
+ if (Filter->MulticastAddresses)
+ {
+ FreePhys(Filter->MulticastAddresses,
+ ETH_LENGTH_OF_ADDRESS * Filter->MaximumMulticastAddresses);
+ }
+
+ //
+ // Free the memory that was allocated for the old multicast
+ // address list.
+ //
+ if (Filter->OldMulticastAddresses)
+ {
+ FreePhys(Filter->OldMulticastAddresses,
+ ETH_LENGTH_OF_ADDRESS * Filter->MaximumMulticastAddresses);
+ }
+
+ //
+ // Free the memory that we allocted for the current bindings
+ // using address mask.
+ //
+ if (Filter->BindingsUsingAddress)
+ {
+ FreePhys(Filter->BindingsUsingAddress,
+ sizeof(ETH_MASK) * Filter->MaximumMulticastAddresses);
+ }
+
+ //
+ // Free the memory that we allocted for the old bindings
+ // using address mask.
+ //
+ if (Filter->OldBindingsUsingAddress)
+ {
+ FreePhys(Filter->OldBindingsUsingAddress,
+ 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);
+
+ //
+ // Allocate memory for the binding.
+ //
+ AllocStatus = AllocPhys(&LocalOpen, sizeof(ETH_BINDING_INFO));
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ return(FALSE);
+
+ //
+ // Zero the memory
+ //
+ ZeroMemory(LocalOpen, sizeof(ETH_BINDING_INFO));
+
+ //
+ // Get place for the open and insert it.
+ //
+ ETH_FILTER_ALLOC_OPEN(Filter, &LocalIndex);
+
+ LocalOpen->NextOpen = Filter->OpenList;
+ Filter->OpenList = LocalOpen;
+
+ LocalOpen->References = 1;
+ LocalOpen->FilterIndex = (UCHAR)LocalIndex;
+ LocalOpen->MacBindingHandle = MacBindingHandle;
+ LocalOpen->NdisBindingContext = NdisBindingContext;
+
+ *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;
+
+ //
+ // Set the packet filter to NONE.
+ //
+ StatusToReturn = EthFilterAdjust(Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ (UINT)0,
+ FALSE);
+ if ((StatusToReturn == NDIS_STATUS_SUCCESS) ||
+ (StatusToReturn == NDIS_STATUS_PENDING))
+ {
+ NDIS_STATUS StatusToReturn2;
+
+ //
+ // Clear the multicast addresses.
+ //
+ 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 the binding from the necessary lists.
+ //
+ ethRemoveAndFreeBinding(Filter, LocalOpen, FALSE);
+ }
+ 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);
+}
+
+
+VOID
+ethUndoChangeFilterAddresses(
+ IN PETH_FILTER Filter
+ )
+/*++
+
+Routine Description:
+
+ Undo changes to the ethernet filter addresses. This routine is incase
+ of a failure that went down to the driver and pended.
+
+Arguments:
+
+ Filter - Pointer to the ethernet filter database.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Restore the original number of addresses.
+ //
+ Filter->NumberOfAddresses = Filter->OldNumberOfAddresses;
+
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+ MoveMemory((PVOID)Filter->MulticastAddresses,
+ (PVOID)Filter->OldMulticastAddresses,
+ Filter->NumberOfAddresses * ETH_LENGTH_OF_ADDRESS);
+
+ MoveMemory((PVOID)Filter->BindingsUsingAddress,
+ (PVOID)Filter->OldBindingsUsingAddress,
+ Filter->NumberOfAddresses * ETH_LENGTH_OF_ADDRESS);
+}
+
+
+
+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;
+
+ //
+ // Set true when the address array changes
+ //
+ UINT AddressesChanged = 0;
+
+ //
+ // Simple iteration variables.
+ //
+ UINT ArrayIndex;
+ UINT i;
+
+ //
+ // Simple Temp variable
+ //
+ PCHAR CurrentAddress;
+
+ PETH_BINDING_INFO LocalOpen = (PETH_BINDING_INFO)NdisFilterHandle;
+
+ //
+ // 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((PVOID)Filter->OldBindingsUsingAddress,
+ (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((PVOID)Filter->OldMulticastAddresses,
+ (PVOID)Filter->MulticastAddresses,
+ Filter->NumberOfAddresses * ETH_LENGTH_OF_ADDRESS);
+
+ //
+ // Save the number of addresses.
+ //
+ Filter->OldNumberOfAddresses = 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.
+ //
+#ifdef NDIS_NT
+ MoveMemory(Filter->MulticastAddresses[ArrayIndex],
+ Filter->MulticastAddresses[ArrayIndex+1],
+ (Filter->NumberOfAddresses - (ArrayIndex+1)) * ETH_LENGTH_OF_ADDRESS);
+#else // NDIS_WIN
+ MoveOverlappedMemory(Filter->MulticastAddresses[ArrayIndex],
+ Filter->MulticastAddresses[ArrayIndex+1],
+ (Filter->NumberOfAddresses - (ArrayIndex+1)) * ETH_LENGTH_OF_ADDRESS);
+#endif
+
+#ifdef NDIS_NT
+ MoveMemory(&Filter->BindingsUsingAddress[ArrayIndex],
+ &Filter->BindingsUsingAddress[ArrayIndex+1],
+ (Filter->NumberOfAddresses - (ArrayIndex + 1)) * (sizeof(ETH_MASK)));
+#else
+ MoveOverlappedMemory(&Filter->BindingsUsingAddress[ArrayIndex],
+ &Filter->BindingsUsingAddress[ArrayIndex+1],
+ (Filter->NumberOfAddresses - (ArrayIndex + 1)) * (sizeof(ETH_MASK)));
+#endif
+
+ 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 (EthFindMulticast(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.
+ //
+#ifdef NDIS_NT
+ MoveMemory(Filter->MulticastAddresses[ArrayIndex + 1],
+ Filter->MulticastAddresses[ArrayIndex],
+ (Filter->NumberOfAddresses - ArrayIndex) * ETH_LENGTH_OF_ADDRESS);
+#else // NDIS_WIN
+ MoveOverlappedMemory(Filter->MulticastAddresses[ArrayIndex + 1],
+ Filter->MulticastAddresses[ArrayIndex],
+ (Filter->NumberOfAddresses - ArrayIndex) * ETH_LENGTH_OF_ADDRESS);
+#endif
+
+ ETH_COPY_NETWORK_ADDRESS(Filter->MulticastAddresses[ArrayIndex], CurrentAddress);
+
+#ifdef NDIS_NT
+ MoveMemory(&(Filter->BindingsUsingAddress[ArrayIndex+1]),
+ &(Filter->BindingsUsingAddress[ArrayIndex]),
+ (Filter->NumberOfAddresses - ArrayIndex) * sizeof(ETH_MASK));
+#else // NDIS_WIN
+ MoveOverlappedMemory(&(Filter->BindingsUsingAddress[ArrayIndex+1]),
+ &(Filter->BindingsUsingAddress[ArrayIndex]),
+ (Filter->NumberOfAddresses - ArrayIndex) * sizeof(ETH_MASK));
+#endif
+
+ CLEAR_MASK(&Filter->BindingsUsingAddress[ArrayIndex]);
+
+ SET_BIT_IN_MASK(LocalOpen->FilterIndex, &Filter->BindingsUsingAddress[ArrayIndex]);
+
+ Filter->NumberOfAddresses++;
+ }
+ else
+ {
+ //
+ // No room in the array, oh well.
+ //
+ ethUndoChangeFilterAddresses(Filter);
+
+ return(NDIS_STATUS_MULTICAST_FULL);
+ }
+ }
+ }
+
+ //
+ // Check to see if address array has chnaged
+ //
+ AddressesChanged = Filter->NumberOfAddresses -
+ Filter->OldNumberOfAddresses;
+ for (i = 0;
+ (i < Filter->OldNumberOfAddresses) && (AddressesChanged == 0);
+ i++
+ )
+ {
+ ETH_COMPARE_NETWORK_ADDRESSES_EQ(Filter->MulticastAddresses[i],
+ Filter->OldMulticastAddresses[i],
+ &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(
+ Filter->OldNumberOfAddresses,
+ Filter->OldMulticastAddresses,
+ 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.
+ //
+ ethUndoChangeFilterAddresses(Filter);
+ }
+ }
+ else
+ {
+ StatusOfChange = NDIS_STATUS_SUCCESS;
+ }
+
+ return(StatusOfChange);
+}
+
+
+VOID
+ethUpdateDirectedBindingList(
+ IN OUT PETH_FILTER Filter,
+ IN PETH_BINDING_INFO Binding,
+ IN BOOLEAN fAddBindingToList
+ )
+{
+ PETH_BINDING_INFO CurrentBinding;
+ BOOLEAN AlreadyOnList;
+
+ //
+ // Do we need to add it to the directed list?
+ //
+ if (fAddBindingToList)
+ {
+ //
+ // First we need to see if it is already on the
+ // directed list.
+ //
+ for (CurrentBinding = Filter->DirectedList, AlreadyOnList = FALSE;
+ CurrentBinding != NULL;
+ CurrentBinding = CurrentBinding->NextDirected
+ )
+ {
+ if (CurrentBinding == Binding)
+ {
+ AlreadyOnList = TRUE;
+ }
+ }
+
+ if (!AlreadyOnList)
+ {
+ Binding->NextDirected = Filter->DirectedList;
+ Filter->DirectedList = Binding;
+ }
+ }
+ else
+ {
+ PETH_BINDING_INFO *ppBI;
+
+ for (ppBI = &Filter->DirectedList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextDirected)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextDirected;
+ break;
+ }
+ }
+ Binding->NextDirected = NULL;
+ }
+}
+
+
+VOID
+ethUpdateBroadcastBindingList(
+ IN OUT PETH_FILTER Filter,
+ IN PETH_BINDING_INFO Binding,
+ IN BOOLEAN fAddToList
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PETH_BINDING_INFO CurrentBinding;
+ BOOLEAN AlreadyOnList;
+
+ //
+ // Do we need to add it to the directed list?
+ //
+ if (fAddToList)
+ {
+ //
+ // First we need to see if it is already on the
+ // broadcast/multicast list.
+ //
+ for (CurrentBinding = Filter->BMList, AlreadyOnList = FALSE;
+ CurrentBinding != NULL;
+ CurrentBinding = CurrentBinding->NextBM
+ )
+ {
+ if (CurrentBinding == Binding)
+ {
+ AlreadyOnList = TRUE;
+ }
+ }
+
+ if (!AlreadyOnList)
+ {
+ Binding->NextBM = Filter->BMList;
+ Filter->BMList = Binding;
+ }
+ }
+ else
+ {
+ PETH_BINDING_INFO *ppBI;
+
+ for (ppBI = &Filter->BMList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextBM)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextBM;
+ break;
+ }
+ }
+
+ Binding->NextBM = NULL;
+ }
+}
+
+
+VOID
+ethUpdateSpecificBindingLists(
+ IN OUT PETH_FILTER Filter,
+ IN PETH_BINDING_INFO Binding
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ BOOLEAN fOnDirectedList = FALSE;
+ BOOLEAN fOnBMList = FALSE;
+ BOOLEAN fAddToDirectedList = FALSE;
+ BOOLEAN fAddToBMList = FALSE;
+
+ //
+ // If the old filter is promsicuous then it is currently on
+ // both lists.
+ //
+ if (Binding->OldPacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL))
+ {
+ fOnDirectedList = TRUE;
+ fOnBMList = TRUE;
+ }
+ else
+ {
+ //
+ // If the binding had the directed bit set then it is on
+ // the directed list.
+ //
+ if (Binding->OldPacketFilters & NDIS_PACKET_TYPE_DIRECTED)
+ {
+ fOnDirectedList = TRUE;
+ }
+
+ //
+ // If the binding had the broadcast bit set then it is on
+ // the broadcast list.
+ //
+ if (Binding->OldPacketFilters & (NDIS_PACKET_TYPE_BROADCAST |
+ NDIS_PACKET_TYPE_MULTICAST |
+ NDIS_PACKET_TYPE_ALL_MULTICAST))
+ {
+ fOnBMList = TRUE;
+ }
+ }
+
+ //
+ // If the current filter has the promsicuous bit set then we
+ // need to add it to both lists.
+ //
+ if (Binding->PacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL))
+ {
+ fAddToDirectedList = TRUE;
+ fAddToBMList = TRUE;
+ }
+ else
+ {
+ //
+ // Was the directed bit set?
+ //
+ if (Binding->PacketFilters & NDIS_PACKET_TYPE_DIRECTED)
+ {
+ fAddToDirectedList = TRUE;
+ }
+
+ //
+ // Was the broadcast bit set?
+ //
+ if (Binding->PacketFilters & (NDIS_PACKET_TYPE_BROADCAST |
+ NDIS_PACKET_TYPE_MULTICAST |
+ NDIS_PACKET_TYPE_ALL_MULTICAST))
+ {
+ fAddToBMList = TRUE;
+ }
+ }
+
+ //
+ // Determine if the binding should be added or removed from
+ // the directed list.
+ //
+ if (!fOnDirectedList && fAddToDirectedList)
+ {
+ //
+ // Add the binding to the directed list.
+ //
+ ethUpdateDirectedBindingList(Filter, Binding, TRUE);
+ }
+ else if (fOnDirectedList && !fAddToDirectedList)
+ {
+ //
+ // Remove it from the directed list.
+ //
+ ethUpdateDirectedBindingList(Filter, Binding, FALSE);
+ }
+
+ //
+ // Determine if the binding should be added or removed from
+ // the broadcast list.
+ //
+ if (!fOnBMList && fAddToBMList)
+ {
+ //
+ // Add the binding to the broadcast list.
+ //
+ ethUpdateBroadcastBindingList(Filter, Binding, TRUE);
+ }
+ else if (fOnBMList && !fAddToBMList)
+ {
+ //
+ // Remove the binding from the broadcast list.
+ //
+ ethUpdateBroadcastBindingList(Filter, Binding, FALSE);
+ }
+}
+
+
+VOID
+ethUndoFilterAdjust(
+ IN PETH_FILTER Filter,
+ IN PETH_BINDING_INFO Binding
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ Binding->PacketFilters = Binding->OldPacketFilters;
+ Filter->CombinedPacketFilter = Filter->OldCombinedPacketFilter;
+
+ //
+ // Update the filter lists.
+ //
+ ethUpdateSpecificBindingLists(Filter, Binding);
+}
+
+
+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 changed 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.
+
+--*/
+
+{
+ PETH_BINDING_INFO LocalOpen = (PETH_BINDING_INFO)NdisFilterHandle;
+ PETH_BINDING_INFO OpenList;
+
+ //
+ // 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->OldPacketFilters = LocalOpen->PacketFilters;
+ LocalOpen->PacketFilters = FilterClasses;
+
+ Filter->OldCombinedPacketFilter = Filter->CombinedPacketFilter;
+
+ //
+ // We always have to reform the combined 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;
+ }
+
+ //
+ // Update the filter lists.
+ //
+ ethUpdateSpecificBindingLists(Filter, LocalOpen);
+
+ if ((Filter->OldCombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL) !=
+ (Filter->CombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL))
+ {
+ StatusOfAdjust = Filter->FilterChangeAction(
+ Filter->OldCombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL,
+ Filter->CombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL,
+ 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.
+ //
+ ethUndoFilterAdjust(Filter, LocalOpen);
+ }
+ }
+ 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;
+
+ UINT FilterIndex = ((PETH_BINDING_INFO)NdisFilterHandle)->FilterIndex;
+
+ for (IndexOfAddress = 0, CountOfAddresses = 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;
+ UINT FilterIndex = ((PETH_BINDING_INFO)NdisFilterHandle)->FilterIndex;
+
+ for (IndexOfAddress = 0, CountOfAddresses = 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;
+}
+
+
+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
+EthFilterDprIndicateReceiveFullMac(
+ 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. This is the
+ code path for ndis 3.0 miniport drivers.
+
+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;
+
+ //
+ // Current Open to indicate to.
+ //
+ PETH_BINDING_INFO LocalOpen;
+ PETH_BINDING_INFO NextOpen;
+
+ //
+ // If the packet is a runt packet, then only indicate to PROMISCUOUS, ALL_LOCAL
+ //
+ if ((HeaderBufferSize >= 14) && (PacketSize != 0))
+ {
+ //
+ // Handle the directed packet case first
+ //
+ if (!ETH_IS_MULTICAST(Address))
+ {
+ UINT IsNotOurs;
+
+ //
+ // If it is a directed packet, then check if the combined packet
+ // filter is PROMISCUOUS, if it is check if it is directed towards
+ // us
+ //
+ IsNotOurs = FALSE; // Assume it is
+ if (Filter->CombinedPacketFilter & (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_MULTICAST |
+ NDIS_PACKET_TYPE_ALL_LOCAL))
+ {
+ ETH_COMPARE_NETWORK_ADDRESSES_EQ(Filter->AdapterAddress,
+ Address,
+ &IsNotOurs);
+ }
+
+ //
+ // We definitely have a directed packet so lets indicate it now.
+ //
+ // Walk the directed list and indicate up the packets.
+ //
+ for (LocalOpen = Filter->DirectedList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextDirected;
+
+ //
+ // Ignore if not directed to us and if the binding is not promiscuous
+ //
+ if (((LocalOpen->PacketFilters & NDIS_PACKET_TYPE_PROMISCUOUS) == 0) &&
+ IsNotOurs)
+ {
+ continue;
+ }
+
+ LocalOpen->References++;
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ //
+ // Indicate the packet to the binding.
+ //
+ ProtocolFilterIndicateReceive(&StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize,
+ NdisMedium802_3);
+
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ --LocalOpen->References;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ ethRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+
+ return;
+ }
+
+ //
+ // It is at least a multicast address. Check to see if
+ // it is a broadcast address.
+ //
+ if (ETH_IS_BROADCAST(Address))
+ {
+ ETH_CHECK_FOR_INVALID_BROADCAST_INDICATION(Filter);
+
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+ }
+ else
+ {
+ AddressType = NDIS_PACKET_TYPE_MULTICAST;
+ }
+ }
+ else
+ {
+ // Runt packet
+ AddressType = NDIS_PACKET_TYPE_PROMISCUOUS;
+ }
+
+ //
+ // At this point we know that the packet is either:
+ // - Runt packet - indicated by AddressType = NDIS_PACKET_TYPE_PROMISCUOUS (OR)
+ // - Broadcast packet - indicated by AddressType = NDIS_PACKET_TYPE_BROADCAST (OR)
+ // - Multicast packet - indicated by AddressType = NDIS_PACKET_TYPE_MULTICAST
+ //
+ // Walk the broadcast/multicast list and indicate up the packets.
+ //
+ // The packet is indicated if it meets the following criteria:
+ //
+ // if ((Binding is promiscuous) OR
+ // ((Packet is broadcast) AND (Binding is Broadcast)) OR
+ // ((Packet is multicast) AND
+ // ((Binding is all-multicast) OR
+ // ((Binding is multicast) AND (address in multicast list)))))
+ //
+ for (LocalOpen = Filter->BMList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ UINT LocalFilter = LocalOpen->PacketFilters;
+ UINT IndexOfAddress;
+
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextBM;
+
+ if ((LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_BROADCAST) &&
+ (LocalFilter & NDIS_PACKET_TYPE_BROADCAST)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_MULTICAST) &&
+ ((LocalFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) ||
+ ((LocalFilter & NDIS_PACKET_TYPE_MULTICAST) &&
+ EthFindMulticast(Filter->NumberOfAddresses,
+ Filter->MulticastAddresses,
+ Address,
+ &IndexOfAddress) &&
+ IS_BIT_SET_IN_MASK(
+ LocalOpen->FilterIndex,
+ Filter->BindingsUsingAddress[IndexOfAddress])
+ )
+ )
+ )
+ )
+ {
+ LocalOpen->References++;
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ //
+ // Indicate the packet to the binding.
+ //
+
+ ProtocolFilterIndicateReceive(&StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize,
+ NdisMedium802_3);
+
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ --LocalOpen->References;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ ethRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+ }
+}
+
+
+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;
+
+ NDIS_ACQUIRE_SPIN_LOCK(Filter->Lock, &OldIrql);
+
+ EthFilterDprIndicateReceiveFullMac(Filter,
+ MacReceiveContext,
+ Address,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize);
+
+ NDIS_RELEASE_SPIN_LOCK(Filter->Lock, OldIrql);
+}
+
+
+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. This is the
+ code path for ndis 3.0 miniport drivers.
+
+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;
+
+ //
+ // Current Open to indicate to.
+ //
+ PETH_BINDING_INFO LocalOpen;
+ PETH_BINDING_INFO NextOpen;
+
+ //
+ // If the packet is a runt packet, then only indicate to PROMISCUOUS, ALL_LOCAL
+ //
+ if ((HeaderBufferSize >= 14) && (PacketSize != 0))
+ {
+ //
+ // Handle the directed packet case first
+ //
+ if (!ETH_IS_MULTICAST(Address))
+ {
+ UINT IsNotOurs;
+
+ //
+ // If it is a directed packet, then check if the combined packet
+ // filter is PROMISCUOUS, if it is check if it is directed towards
+ // us
+ //
+ IsNotOurs = FALSE; // Assume it is
+ if (Filter->CombinedPacketFilter & (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_MULTICAST |
+ NDIS_PACKET_TYPE_ALL_LOCAL))
+ {
+ ETH_COMPARE_NETWORK_ADDRESSES_EQ(Filter->AdapterAddress,
+ Address,
+ &IsNotOurs);
+ }
+
+ //
+ // We definitely have a directed packet so lets indicate it now.
+ //
+ // Walk the directed list and indicate up the packets.
+ //
+ for (LocalOpen = Filter->DirectedList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextDirected;
+
+ //
+ // Ignore if not directed to us and if the binding is not promiscuous
+ //
+ if (((LocalOpen->PacketFilters & NDIS_PACKET_TYPE_PROMISCUOUS) == 0) &&
+ IsNotOurs)
+ {
+ continue;
+ }
+
+ LocalOpen->References++;
+
+// NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ //
+ // Indicate the packet to the binding.
+ //
+ ProtocolFilterIndicateReceive(&StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize,
+ NdisMedium802_3);
+
+// NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ --LocalOpen->References;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ ethRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+
+ return;
+ }
+
+ //
+ // It is at least a multicast address. Check to see if
+ // it is a broadcast address.
+ //
+ if (ETH_IS_BROADCAST(Address))
+ {
+ ETH_CHECK_FOR_INVALID_BROADCAST_INDICATION(Filter);
+
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+ }
+ else
+ {
+ AddressType = NDIS_PACKET_TYPE_MULTICAST;
+ }
+ }
+ else
+ {
+ // Runt packet
+ AddressType = NDIS_PACKET_TYPE_PROMISCUOUS;
+ }
+
+ //
+ // At this point we know that the packet is either:
+ // - Runt packet - indicated by AddressType = NDIS_PACKET_TYPE_PROMISCUOUS (OR)
+ // - Broadcast packet - indicated by AddressType = NDIS_PACKET_TYPE_BROADCAST (OR)
+ // - Multicast packet - indicated by AddressType = NDIS_PACKET_TYPE_MULTICAST
+ //
+ // Walk the broadcast/multicast list and indicate up the packets.
+ //
+ // The packet is indicated if it meets the following criteria:
+ //
+ // if ((Binding is promiscuous) OR
+ // ((Packet is broadcast) AND (Binding is Broadcast)) OR
+ // ((Packet is multicast) AND
+ // ((Binding is all-multicast) OR
+ // ((Binding is multicast) AND (address in multicast list)))))
+ //
+ for (LocalOpen = Filter->BMList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ UINT LocalFilter = LocalOpen->PacketFilters;
+ UINT IndexOfAddress;
+
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextBM;
+
+ if ((LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_BROADCAST) &&
+ (LocalFilter & NDIS_PACKET_TYPE_BROADCAST)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_MULTICAST) &&
+ ((LocalFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) ||
+ ((LocalFilter & NDIS_PACKET_TYPE_MULTICAST) &&
+ EthFindMulticast(Filter->NumberOfAddresses,
+ Filter->MulticastAddresses,
+ Address,
+ &IndexOfAddress) &&
+ IS_BIT_SET_IN_MASK(
+ LocalOpen->FilterIndex,
+ Filter->BindingsUsingAddress[IndexOfAddress])
+ )
+ )
+ )
+ )
+ {
+ LocalOpen->References++;
+
+// NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ //
+ // Indicate the packet to the binding.
+ //
+
+ ProtocolFilterIndicateReceive(&StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize,
+ NdisMedium802_3);
+
+// NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ --LocalOpen->References;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ ethRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+ }
+}
+
+
+
+VOID
+EthFilterDprIndicateReceivePacket(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+)
+
+/*++
+
+Routine Description:
+
+ This routine is called by the Miniport to indicate packets to
+ all bindings. The packets will be filtered so that only the
+ appropriate bindings will receive the individual packets.
+ This is the code path for ndis 4.0 miniport drivers.
+
+Arguments:
+
+ Miniport - The Miniport block.
+
+ PacketArray - An array of Packets indicated by the miniport.
+
+ NumberOfPackets - Self-explanatory.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // The Filter of interest
+ //
+ PETH_FILTER Filter = Miniport->EthDB;
+
+ //
+ // Current packet being processed
+ //
+ PPNDIS_PACKET pPktArray = PacketArray;
+
+ //
+ // Pointer to the buffer in the ndispacket
+ //
+ PNDIS_BUFFER Buffer;
+
+ //
+ // Pointer to the 1st segment of the buffer, points to dest address
+ //
+ PUCHAR Address;
+
+ //
+ // Total packet length
+ //
+ UINT i, LASize, PacketSize, NumIndicates = 0;
+
+ //
+ // 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;
+
+ //
+ // Decides whether we use the protocol's revpkt handler or fall
+ // back to old rcvindicate handler
+ //
+ BOOLEAN fFallBack, fPmode, FixRef;
+
+ //
+ // Current Open to indicate to.
+ //
+ PETH_BINDING_INFO LocalOpen, NextOpen;
+ PNDIS_OPEN_BLOCK pOpenBlock; \
+
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
+
+ // Walk all the packets
+ for (i = 0; i < NumberOfPackets; i++, pPktArray++)
+ {
+ PNDIS_PACKET Packet = *pPktArray;
+ PNDIS_PACKET_OOB_DATA pOob;
+
+ ASSERT(Packet != NULL);
+
+ pOob = NDIS_OOB_DATA_FROM_PACKET(Packet);
+
+ NdisGetFirstBufferFromPacket(Packet,
+ &Buffer,
+ &Address,
+ &LASize,
+ &PacketSize);
+ ASSERT(Buffer != NULL);
+
+ ASSERT (pOob->HeaderSize == 14);
+ ASSERT (PacketSize <= 1514);
+
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount = 0;
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->Miniport = Miniport;
+
+ //
+ // Set the status here that nobody is holding the packet. This will get
+ // overwritten by the real status from the protocol. Pay heed to what
+ // the miniport is saying.
+ //
+ if (pOob->Status != NDIS_STATUS_RESOURCES)
+ {
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount --;
+ pOob->Status = NDIS_STATUS_SUCCESS;
+ fFallBack = FALSE;
+ FixRef = TRUE;
+ }
+ else
+ {
+ fFallBack = TRUE;
+ FixRef = FALSE;
+ }
+
+ //
+ // Ensure that we force re-calculation.
+ //
+ Packet->Private.ValidCounts = FALSE;
+
+ //
+ // A quick check for Runt packets. These are only indicated to Promiscuous bindings
+ //
+ if (PacketSize >= 14)
+ {
+ //
+ // Handle the directed packet case first
+ //
+ if (!ETH_IS_MULTICAST(Address))
+ {
+ UINT IsNotOurs;
+
+ //
+ // If it is a directed packet, then check if the combined packet
+ // filter is PROMISCUOUS, if it is check if it is directed towards us
+ //
+ IsNotOurs = FALSE; // Assume it is
+ if (Filter->CombinedPacketFilter & (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_LOCAL |
+ NDIS_PACKET_TYPE_ALL_MULTICAST))
+ {
+ ETH_COMPARE_NETWORK_ADDRESSES_EQ(Filter->AdapterAddress,
+ Address,
+ &IsNotOurs);
+ }
+
+ //
+ // We definitely have a directed packet so lets indicate it now.
+ //
+ // Walk the directed list and indicate up the packets.
+ //
+ for (LocalOpen = Filter->DirectedList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextDirected;
+
+ //
+ // Ignore if not directed to us and if the binding is not promiscuous
+ //
+ if (((LocalOpen->PacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) == 0) &&
+ IsNotOurs)
+ {
+ continue;
+ }
+
+ pOpenBlock = (PNDIS_OPEN_BLOCK)(LocalOpen->NdisBindingContext);
+ LocalOpen->ReceivedAPacket = TRUE;
+ LocalOpen->References ++;
+ NumIndicates ++;
+
+ fPmode = (LocalOpen->PacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ?
+ TRUE : FALSE;
+ IndicateToProtocol(Miniport,
+ Filter,
+ pOpenBlock,
+ Packet,
+ Address,
+ PacketSize,
+ 14,
+ &fFallBack,
+ fPmode,
+ NdisMedium802_3);
+
+ LocalOpen->References --;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ ethRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+
+ if (FixRef)
+ {
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount++;
+ if (PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount != 0)
+ {
+ NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_PENDING);
+ }
+ }
+ continue; // Done with this packet
+ }
+
+ //
+ // It is at least a multicast address. Check to see if
+ // it is a broadcast address.
+ //
+ if (ETH_IS_BROADCAST(Address))
+ {
+ ETH_CHECK_FOR_INVALID_BROADCAST_INDICATION(Filter);
+
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+ }
+ else
+ {
+ AddressType = NDIS_PACKET_TYPE_MULTICAST;
+ }
+ }
+ else
+ {
+ // Runt packet
+ AddressType = NDIS_PACKET_TYPE_PROMISCUOUS;
+ }
+
+ //
+ // At this point we know that the packet is either:
+ // - Runt packet - indicated by AddressType = NDIS_PACKET_TYPE_PROMISCUOUS (OR)
+ // - Broadcast packet - indicated by AddressType = NDIS_PACKET_TYPE_BROADCAST (OR)
+ // - Multicast packet - indicated by AddressType = NDIS_PACKET_TYPE_MULTICAST
+ //
+ // Walk the broadcast/multicast list and indicate up the packets.
+ //
+ // The packet is indicated if it meets the following criteria:
+ //
+ // if ((Binding is promiscuous) OR
+ // ((Packet is broadcast) AND (Binding is Broadcast)) OR
+ // ((Packet is multicast) AND
+ // ((Binding is all-multicast) OR
+ // ((Binding is multicast) AND (address in multicast list)))))
+ //
+ for (LocalOpen = Filter->BMList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ UINT LocalFilter = LocalOpen->PacketFilters;
+ UINT IndexOfAddress;
+
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextBM;
+
+ if ((LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_BROADCAST) &&
+ (LocalFilter & NDIS_PACKET_TYPE_BROADCAST)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_MULTICAST) &&
+ ((LocalFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) ||
+ ((LocalFilter & NDIS_PACKET_TYPE_MULTICAST) &&
+ EthFindMulticast(Filter->NumberOfAddresses,
+ Filter->MulticastAddresses,
+ Address,
+ &IndexOfAddress) &&
+ IS_BIT_SET_IN_MASK(
+ LocalOpen->FilterIndex,
+ Filter->BindingsUsingAddress[IndexOfAddress])
+ )
+ )
+ )
+ )
+ {
+ pOpenBlock = (PNDIS_OPEN_BLOCK)(LocalOpen->NdisBindingContext);
+ LocalOpen->ReceivedAPacket = TRUE;
+ LocalOpen->References ++;
+ NumIndicates ++;
+
+ fPmode = (LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ?
+ TRUE : FALSE;
+ IndicateToProtocol(Miniport,
+ Filter,
+ pOpenBlock,
+ Packet,
+ Address,
+ PacketSize,
+ 14,
+ &fFallBack,
+ fPmode,
+ NdisMedium802_3);
+
+ LocalOpen->References --;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ ethRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+ }
+
+ if (FixRef)
+ {
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount++;
+ if (PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount != 0)
+ {
+ NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_PENDING);
+ }
+ }
+ }
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
+
+ if (NumIndicates > 0)
+ {
+ EthFilterDprIndicateReceiveComplete(Filter);
+ }
+}
+
+
+
+VOID
+EthFilterDprIndicateReceiveCompleteFullMac(
+ 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, NextOpen;
+
+ //
+ // We need to aquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+
+ for (LocalOpen = Filter->OpenList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ NextOpen = LocalOpen->NextOpen;
+
+ if (LocalOpen->ReceivedAPacket)
+ {
+ //
+ // Indicate the binding.
+ //
+
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ LocalOpen->References++;
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ if ((--(LocalOpen->References)) == 0)
+ {
+ //
+ // This binding is shutting down. We have to kill it.
+ //
+ ethRemoveBindingFromLists(Filter, LocalOpen);
+
+ //
+ // 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);
+ }
+ }
+ }
+}
+
+
+VOID
+EthFilterIndicateReceiveComplete(
+ IN PETH_FILTER Filter
+ )
+{
+ KIRQL OldIrql;
+
+ NDIS_ACQUIRE_SPIN_LOCK(Filter->Lock, &OldIrql);
+
+ EthFilterDprIndicateReceiveCompleteFullMac(Filter);
+
+ NDIS_RELEASE_SPIN_LOCK(Filter->Lock, OldIrql);
+}
+
+
+
+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, NextOpen;
+
+ //
+ // We need to aquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+
+ for (LocalOpen = Filter->OpenList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ NextOpen = LocalOpen->NextOpen;
+
+ if (LocalOpen->ReceivedAPacket)
+ {
+ //
+ // Indicate the binding.
+ //
+
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ LocalOpen->References++;
+
+// NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+// NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ if ((--(LocalOpen->References)) == 0)
+ {
+ //
+ // This binding is shutting down. We have to kill it.
+ //
+ ethRemoveBindingFromLists(Filter, LocalOpen);
+
+ //
+ // 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);
+ }
+ }
+ }
+}
+
+
+BOOLEAN
+EthFindMulticast(
+ 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/ndis40/ffilter.c b/private/ntos/ndis/ndis40/ffilter.c
new file mode 100644
index 000000000..a3661d791
--- /dev/null
+++ b/private/ntos/ndis/ndis40/ffilter.c
@@ -0,0 +1,3869 @@
+/*++
+
+Copyright (c) 1990-1995 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.
+ Jameel Hyder (JameelH) Re-organization
+
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_FFILTER
+
+
+//
+// VOID
+// FDDI_FILTER_ALLOC_OPEN(
+// IN PFDDI_FILTER Filter,
+// OUT PUINT FilterIndex
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Allocates an open block. This only allocates 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:
+//
+// None
+//
+//--*/
+#define FDDI_FILTER_FREE_OPEN(Filter, LocalOpen) \
+{ \
+ SET_BIT_IN_MASK(((LocalOpen)->FilterIndex), &((Filter)->FreeBindingMask)); \
+ FreePhys((LocalOpen), sizeof(FDDI_BINDING_INFO)); \
+}
+
+#define FDDI_CHECK_FOR_INVALID_BROADCAST_INDICATION(_F) \
+IF_DBG(DBG_COMP_FILTER, DBG_LEVEL_WARN) \
+{ \
+ if (!((_F)->CombinedPacketFilter & NDIS_PACKET_TYPE_BROADCAST)) \
+ { \
+ /* \
+ We should never receive broadcast packets \
+ to someone else unless in p-mode. \
+ */ \
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_ERR, \
+ ("Bad driver, indicating broadcast packets when not set to.\n"));\
+ DBGBREAK(DBG_COMP_FILTER, DBG_LEVEL_ERR); \
+ } \
+}
+
+#define FDDI_CHECK_FOR_INVALID_DIRECTED_INDICATION(_F, _A, _AL) \
+IF_DBG(DBG_COMP_FILTER, DBG_LEVEL_WARN) \
+{ \
+ /* \
+ 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 (FDDI_LENGTH_OF_LONG_ADDRESS == (_AL)) \
+ { \
+ FDDI_COMPARE_NETWORK_ADDRESSES_EQ( \
+ (_F)->AdapterLongAddress, \
+ (_A), \
+ FDDI_LENGTH_OF_LONG_ADDRESS, \
+ &Result); \
+ } \
+ else if (FDDI_LENGTH_OF_SHORT_ADDRESS == (_AL)) \
+ { \
+ FDDI_COMPARE_NETWORK_ADDRESSES_EQ( \
+ (_F)->AdapterShortAddress, \
+ (_A), \
+ FDDI_LENGTH_OF_SHORT_ADDRESS, \
+ &Result); \
+ } \
+ if (Result != 0) \
+ { \
+ /* \
+ We should never receive directed packets \
+ to someone else unless in p-mode. \
+ */ \
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_ERR, \
+ ("Bad driver, indicating packets to another station when not in promiscuous mode.\n"));\
+ DBGBREAK(DBG_COMP_FILTER, DBG_LEVEL_ERR); \
+ } \
+}
+
+
+VOID
+fddiRemoveBindingFromLists(
+ IN PFDDI_FILTER Filter,
+ IN PFDDI_BINDING_INFO Binding
+ )
+/*++
+
+Routine Description:
+
+ This routine will remove a binding from all of the list in a
+ filter database. These lists include the list of bindings,
+ the directed filter list and the broadcast/multicast filter list.
+
+Arguments:
+
+ Filter - Pointer to the filter database to remove the binding from.
+ Binding - Pointer to the binding to remove.
+
+--*/
+
+{
+ PFDDI_BINDING_INFO *ppBI;
+
+ //
+ // Remove the binding from the filter's list
+ // of all bindings.
+ //
+ for (ppBI = &Filter->OpenList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextOpen)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextOpen;
+ break;
+ }
+ }
+ ASSERT(*ppBI == Binding->NextOpen);
+
+ //
+ // Remove it from the directed binding list - conditionally
+ //
+ for (ppBI = &Filter->DirectedList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextDirected)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextDirected;
+ break;
+ }
+ }
+
+ //
+ // Remove it from the broadcast/multicast binding list - conditionally
+ //
+ for (ppBI = &Filter->BMSList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextBMS)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextBMS;
+ break;
+ }
+ }
+
+ //
+ // Sanity checks.
+ //
+ Binding->NextDirected = NULL;
+ Binding->NextBMS = NULL;
+ Binding->NextOpen = NULL;
+}
+
+VOID
+fddiRemoveAndFreeBinding(
+ IN PFDDI_FILTER Filter,
+ IN PFDDI_BINDING_INFO Binding,
+ IN BOOLEAN fCallCloseAction
+ )
+/*++
+
+Routine Description:
+
+ This routine will remove a binding from the filter database and
+ indicate a receive complete if necessary. This was made a function
+ to remove code redundancey in following routines. Its not time
+ critical so it's cool.
+
+Arguments:
+
+ Filter - Pointer to the filter database to remove the binding from.
+ Binding - Pointer to the binding to remove.
+ fCallCloseAction - TRUE if we should call the filter's close
+ action routine. FALSE if not.
+
+--*/
+
+{
+ //
+ // Remove the binding.
+ //
+ fddiRemoveBindingFromLists(Filter, Binding);
+
+ //
+ // If we have received and packet indications then
+ // notify the binding of the indication completion.
+ //
+ if (Binding->ReceivedAPacket)
+ {
+ if (NULL != Filter->Miniport)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+ }
+ else
+ {
+ NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ }
+
+ FilterIndicateReceiveComplete(Binding->NdisBindingContext);
+
+ if (NULL != Filter->Miniport)
+ {
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+ }
+ else
+ {
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ }
+ }
+
+ //
+ // Should we call the close action routine?
+ //
+ if (fCallCloseAction)
+ {
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+ Filter->CloseAction(Binding->MacBindingHandle);
+ }
+
+ //
+ // Free the open.
+ //
+ FDDI_FILTER_FREE_OPEN(Filter, Binding);
+}
+
+
+
+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);
+ }
+
+ //
+ // Zero out the memory allocated.
+ //
+ ZeroMemory(LocalFilter, sizeof(FDDI_FILTER));
+
+ //
+ // Determine the number of long multicast addresses to allocate.
+ //
+ 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;
+ }
+
+ //
+ // Allocate the in-use long multicast address list.
+ //
+ AllocStatus = AllocPhys(&LocalFilter->MulticastLongAddresses,
+ FDDI_LENGTH_OF_LONG_ADDRESS * MaximumMulticastLongAddresses);
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ FddiDeleteFilter(LocalFilter);
+ return(FALSE);
+ }
+
+ //
+ // Zero it out.
+ //
+ ZeroMemory(LocalFilter->MulticastLongAddresses,
+ FDDI_LENGTH_OF_LONG_ADDRESS * MaximumMulticastLongAddresses);
+
+ //
+ // Allocate the old long multicast address list.
+ //
+ AllocStatus = AllocPhys(&LocalFilter->OldMulticastLongAddresses,
+ FDDI_LENGTH_OF_LONG_ADDRESS * MaximumMulticastLongAddresses);
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ FddiDeleteFilter(LocalFilter);
+ return(FALSE);
+ }
+
+ //
+ // Zero it out.
+ //
+ ZeroMemory(LocalFilter->OldMulticastLongAddresses,
+ FDDI_LENGTH_OF_LONG_ADDRESS * MaximumMulticastLongAddresses);
+
+ //
+ // Allocate the in-use FDDI mask list.
+ //
+ AllocStatus = AllocPhys(&LocalFilter->BindingsUsingLongAddress,
+ sizeof(FDDI_MASK) * MaximumMulticastLongAddresses);
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ FddiDeleteFilter(LocalFilter);
+ return(FALSE);
+ }
+
+ //
+ // Zero it out.
+ //
+ ZeroMemory(LocalFilter->BindingsUsingLongAddress,
+ sizeof(FDDI_MASK) * MaximumMulticastLongAddresses);
+
+ //
+ // Allocate the old FDDI mask list.
+ //
+ AllocStatus = AllocPhys(&LocalFilter->OldBindingsUsingLongAddress,
+ sizeof(FDDI_MASK) * MaximumMulticastLongAddresses);
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ FddiDeleteFilter(LocalFilter);
+ return(FALSE);
+ }
+
+ //
+ // Zero it out.
+ //
+ ZeroMemory(LocalFilter->OldBindingsUsingLongAddress,
+ sizeof(FDDI_MASK) * MaximumMulticastLongAddresses);
+
+ //
+ // Determine the number of short multicast addresses to allocate.
+ //
+ 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;
+ }
+
+ //
+ // Allocate the in-use short multicast address list.
+ //
+ AllocStatus = AllocPhys(&LocalFilter->MulticastShortAddresses,
+ FDDI_LENGTH_OF_SHORT_ADDRESS * MaximumMulticastShortAddresses);
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ FddiDeleteFilter(LocalFilter);
+ return(FALSE);
+ }
+
+ //
+ // Zero it out.
+ //
+ ZeroMemory(LocalFilter->MulticastShortAddresses,
+ FDDI_LENGTH_OF_SHORT_ADDRESS * MaximumMulticastShortAddresses);
+
+ //
+ // Allocate the old shortmulticast address list.
+ //
+ AllocStatus = AllocPhys(&LocalFilter->OldMulticastShortAddresses,
+ FDDI_LENGTH_OF_SHORT_ADDRESS * MaximumMulticastShortAddresses);
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ FddiDeleteFilter(LocalFilter);
+ return(FALSE);
+ }
+
+ //
+ // Zero it out.
+ //
+ ZeroMemory(LocalFilter->OldMulticastShortAddresses,
+ FDDI_LENGTH_OF_SHORT_ADDRESS * MaximumMulticastShortAddresses);
+
+ //
+ // Allocate the in-use FDDI mask list.
+ //
+ AllocStatus = AllocPhys(&LocalFilter->BindingsUsingShortAddress,
+ sizeof(FDDI_MASK) * MaximumMulticastShortAddresses);
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ FddiDeleteFilter(LocalFilter);
+ return(FALSE);
+ }
+
+ //
+ // Zero it out.
+ //
+ ZeroMemory(LocalFilter->BindingsUsingShortAddress,
+ sizeof(FDDI_MASK) * MaximumMulticastShortAddresses);
+
+ //
+ // Allocate the old FDDI mask list.
+ //
+ AllocStatus = AllocPhys(&LocalFilter->OldBindingsUsingShortAddress,
+ sizeof(FDDI_MASK) * MaximumMulticastShortAddresses);
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ {
+ FddiDeleteFilter(LocalFilter);
+ return(FALSE);
+ }
+
+ //
+ // Zero it out.
+ //
+ ZeroMemory(LocalFilter->OldBindingsUsingShortAddress,
+ sizeof(FDDI_MASK) * MaximumMulticastShortAddresses);
+
+ FddiReferencePackage();
+
+ LocalFilter->FreeBindingMask = (ULONG)(-1);
+
+ 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->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);
+
+ //
+ // Kill the long address information.
+ //
+ if (Filter->MulticastLongAddresses)
+ {
+ FreePhys(Filter->MulticastLongAddresses,
+ FDDI_LENGTH_OF_LONG_ADDRESS*Filter->MaximumMulticastLongAddresses);
+ }
+
+ if (Filter->OldMulticastLongAddresses)
+ {
+ FreePhys(Filter->OldMulticastLongAddresses,
+ FDDI_LENGTH_OF_LONG_ADDRESS * Filter->MaximumMulticastLongAddresses);
+ }
+
+ if (Filter->BindingsUsingLongAddress)
+ {
+ FreePhys(Filter->BindingsUsingLongAddress,
+ sizeof(FDDI_MASK)*Filter->MaximumMulticastLongAddresses);
+ }
+
+ if (Filter->OldBindingsUsingLongAddress)
+ {
+ FreePhys(Filter->OldBindingsUsingLongAddress,
+ sizeof(FDDI_MASK) * Filter->MaximumMulticastLongAddresses);
+ }
+
+ //
+ // Kill the short address information.
+ //
+ if (Filter->MulticastShortAddresses)
+ {
+ FreePhys(Filter->MulticastShortAddresses,
+ FDDI_LENGTH_OF_SHORT_ADDRESS*Filter->MaximumMulticastShortAddresses);
+ }
+
+ if (Filter->OldMulticastShortAddresses)
+ {
+ FreePhys(Filter->OldMulticastShortAddresses,
+ FDDI_LENGTH_OF_SHORT_ADDRESS*Filter->MaximumMulticastShortAddresses);
+ }
+
+ if (Filter->BindingsUsingShortAddress)
+ {
+ FreePhys(Filter->BindingsUsingShortAddress,
+ sizeof(FDDI_MASK)*Filter->MaximumMulticastShortAddresses);
+ }
+
+ if (Filter->OldBindingsUsingShortAddress)
+ {
+ FreePhys(Filter->OldBindingsUsingShortAddress,
+ 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);
+
+ //
+ // Allocate memory for the new binding.
+ //
+ AllocStatus = AllocPhys(&LocalOpen, sizeof(FDDI_BINDING_INFO));
+ if (AllocStatus != NDIS_STATUS_SUCCESS)
+ return(FALSE);
+
+ //
+ // Zero the memory
+ //
+ ZeroMemory(LocalOpen, sizeof(FDDI_BINDING_INFO));
+
+ //
+ // Get place for the open and insert it.
+ //
+ FDDI_FILTER_ALLOC_OPEN(Filter, &LocalIndex);
+
+ LocalOpen->NextOpen = Filter->OpenList;
+ Filter->OpenList = LocalOpen;
+
+ LocalOpen->References = 1;
+ LocalOpen->FilterIndex = (UCHAR)LocalIndex;
+ LocalOpen->MacBindingHandle = MacBindingHandle;
+ LocalOpen->NdisBindingContext = NdisBindingContext;
+
+ *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;
+
+ //
+ // Set the filter classes to NONE.
+ //
+ StatusToReturn = FddiFilterAdjust(Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ (UINT)0,
+ FALSE);
+ if ((StatusToReturn == NDIS_STATUS_SUCCESS) ||
+ (StatusToReturn == NDIS_STATUS_PENDING))
+ {
+ NDIS_STATUS StatusToReturn2;
+
+ //
+ // Remove the long multicast addresses.
+ //
+ 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.
+ //
+ fddiRemoveAndFreeBinding(Filter, LocalOpen, FALSE);
+ }
+ 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);
+}
+
+
+VOID
+fddiUndoChangeFilterLongAddresses(
+ IN PFDDI_FILTER Filter
+)
+{
+ //
+ // Restore the original number of long addresses.
+ //
+ Filter->NumberOfLongAddresses = Filter->OldNumberOfLongAddresses;
+
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+ MoveMemory((PVOID)Filter->MulticastLongAddresses,
+ (PVOID)Filter->OldMulticastLongAddresses,
+ Filter->NumberOfLongAddresses * FDDI_LENGTH_OF_LONG_ADDRESS);
+
+ MoveMemory((PVOID)Filter->BindingsUsingLongAddress,
+ (PVOID)Filter->OldBindingsUsingLongAddress,
+ Filter->NumberOfLongAddresses * sizeof(FDDI_MASK));
+
+}
+
+
+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;
+
+ //
+ // Set true when the address array changes
+ //
+ BOOLEAN AddressesChanged = FALSE;
+
+ //
+ // Simple iteration variables.
+ //
+ UINT ArrayIndex;
+ UINT i;
+
+ //
+ // Simple Temp variable
+ //
+ PCHAR CurrentAddress;
+
+ PFDDI_BINDING_INFO LocalOpen = (PFDDI_BINDING_INFO)NdisFilterHandle;
+
+ //
+ // 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((PVOID)Filter->OldBindingsUsingLongAddress,
+ (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((PVOID)Filter->OldMulticastLongAddresses,
+ (PVOID)Filter->MulticastLongAddresses,
+ Filter->NumberOfLongAddresses * FDDI_LENGTH_OF_LONG_ADDRESS);
+
+ //
+ // Save the current number of multicast addresses.
+ //
+ Filter->OldNumberOfLongAddresses = Filter->NumberOfLongAddresses;
+
+ //
+ // 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]));
+ }
+
+ //
+ // 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]))
+ {
+ AddressesChanged = TRUE;
+
+ //
+ // yes it is clear, so we have to shift everything
+ // above it down one.
+ //
+#ifdef NDIS_NT
+ MoveMemory(Filter->MulticastLongAddresses[ArrayIndex],
+ Filter->MulticastLongAddresses[ArrayIndex+1],
+ (Filter->NumberOfLongAddresses-(ArrayIndex+1)) * FDDI_LENGTH_OF_LONG_ADDRESS);
+#else // NDIS_WIN
+ MoveOverlappedMemory(Filter->MulticastLongAddresses[ArrayIndex],
+ Filter->MulticastLongAddresses[ArrayIndex+1],
+ (Filter->NumberOfLongAddresses-(ArrayIndex+1)) * FDDI_LENGTH_OF_LONG_ADDRESS);
+#endif
+
+#ifdef NDIS_NT
+ MoveMemory(&Filter->BindingsUsingLongAddress[ArrayIndex],
+ &Filter->BindingsUsingLongAddress[ArrayIndex+1],
+ (Filter->NumberOfLongAddresses - (ArrayIndex + 1)) * (sizeof(FDDI_MASK)));
+#else // NDIS_WIN
+ MoveOverlappedMemory(&Filter->BindingsUsingLongAddress[ArrayIndex],
+ &Filter->BindingsUsingLongAddress[ArrayIndex+1],
+ (Filter->NumberOfLongAddresses - (ArrayIndex + 1)) * (sizeof(FDDI_MASK)));
+#endif
+
+ Filter->NumberOfLongAddresses--;
+ }
+ 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*FDDI_LENGTH_OF_LONG_ADDRESS);
+
+ if (FddiFindMulticastLongAddress(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)
+ {
+ AddressesChanged = TRUE;
+
+ //
+ // Save the address array if it hasn't been.
+ //
+#ifdef NDIS_NT
+ MoveMemory(Filter->MulticastLongAddresses[ArrayIndex + 1],
+ Filter->MulticastLongAddresses[ArrayIndex],
+ (Filter->NumberOfLongAddresses - ArrayIndex) * FDDI_LENGTH_OF_LONG_ADDRESS);
+#else // NDIS_WIN
+ MoveOverlappedMemory(Filter->MulticastLongAddresses[ArrayIndex + 1],
+ Filter->MulticastLongAddresses[ArrayIndex],
+ (Filter->NumberOfLongAddresses - ArrayIndex) * FDDI_LENGTH_OF_LONG_ADDRESS);
+#endif
+
+ FDDI_COPY_NETWORK_ADDRESS(Filter->MulticastLongAddresses[ArrayIndex],
+ CurrentAddress,
+ FDDI_LENGTH_OF_LONG_ADDRESS);
+
+#ifdef NDIS_NT
+ MoveMemory(&(Filter->BindingsUsingLongAddress[ArrayIndex + 1]),
+ &(Filter->BindingsUsingLongAddress[ArrayIndex]),
+ (Filter->NumberOfLongAddresses-ArrayIndex)*sizeof(FDDI_MASK));
+#else // NDIS_WIN
+ MoveOverlappedMemory(&(Filter->BindingsUsingLongAddress[ArrayIndex + 1]),
+ &(Filter->BindingsUsingLongAddress[ArrayIndex]),
+ (Filter->NumberOfLongAddresses-ArrayIndex)*sizeof(FDDI_MASK));
+#endif
+
+ CLEAR_MASK(&Filter->BindingsUsingLongAddress[ArrayIndex]);
+
+ SET_BIT_IN_MASK(LocalOpen->FilterIndex, &Filter->BindingsUsingLongAddress[ArrayIndex]);
+
+ Filter->NumberOfLongAddresses++;
+ }
+ else
+ {
+ //
+ // No room in the array, oh well.
+ //
+ fddiUndoChangeFilterLongAddresses(Filter);
+
+ return(NDIS_STATUS_MULTICAST_FULL);
+ }
+ }
+ }
+
+
+ //
+ // 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->OldNumberOfLongAddresses,
+ Filter->OldMulticastLongAddresses,
+ 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.
+ //
+ fddiUndoChangeFilterLongAddresses(Filter);
+ }
+ }
+ else
+ {
+ StatusOfChange = NDIS_STATUS_SUCCESS;
+ }
+
+ return(StatusOfChange);
+}
+
+
+VOID
+fddiUndoChangeFilterShortAddresses(
+ IN PFDDI_FILTER Filter
+)
+{
+ //
+ // Restore the original number of short addresses.
+ //
+ Filter->NumberOfShortAddresses = Filter->OldNumberOfShortAddresses;
+
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+ MoveMemory((PVOID)Filter->MulticastShortAddresses,
+ (PVOID)Filter->OldMulticastShortAddresses,
+ Filter->NumberOfShortAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS);
+
+ MoveMemory((PVOID)Filter->BindingsUsingShortAddress,
+ (PVOID)Filter->OldBindingsUsingShortAddress,
+ Filter->NumberOfShortAddresses * sizeof(FDDI_MASK));
+}
+
+
+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;
+
+ //
+ // Set true when the address array changes
+ //
+ BOOLEAN AddressesChanged = FALSE;
+
+ //
+ // Simple iteration variables.
+ //
+ UINT ArrayIndex;
+ UINT i;
+
+
+ //
+ // Simple Temp variable
+ //
+ PCHAR CurrentAddress;
+
+ PFDDI_BINDING_INFO LocalOpen = (PFDDI_BINDING_INFO)NdisFilterHandle;
+
+ //
+ // 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((PVOID)Filter->OldBindingsUsingShortAddress,
+ (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((PVOID)Filter->OldMulticastShortAddresses,
+ (PVOID)Filter->MulticastShortAddresses,
+ Filter->NumberOfShortAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS);
+
+ Filter->OldNumberOfShortAddresses = 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 (FddiFindMulticastShortAddress(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;
+
+#ifdef NDIS_NT
+ MoveMemory(Filter->MulticastShortAddresses[ArrayIndex+1],
+ Filter->MulticastShortAddresses[ArrayIndex],
+ (Filter->NumberOfShortAddresses-ArrayIndex)*FDDI_LENGTH_OF_SHORT_ADDRESS);
+#else // NDIS_WIN
+ MoveOverlappedMemory(Filter->MulticastShortAddresses[ArrayIndex+1],
+ Filter->MulticastShortAddresses[ArrayIndex],
+ (Filter->NumberOfShortAddresses-ArrayIndex)*FDDI_LENGTH_OF_SHORT_ADDRESS);
+#endif
+
+ FDDI_COPY_NETWORK_ADDRESS(Filter->MulticastShortAddresses[ArrayIndex],
+ CurrentAddress,
+ FDDI_LENGTH_OF_SHORT_ADDRESS);
+
+#ifdef NDIS_NT
+ MoveMemory(&(Filter->BindingsUsingShortAddress[ArrayIndex+1]),
+ &(Filter->BindingsUsingShortAddress[ArrayIndex]),
+ (Filter->NumberOfShortAddresses-ArrayIndex)*sizeof(FDDI_MASK));
+#else // NDIS_WIN
+ MoveOverlappedMemory(&(Filter->BindingsUsingShortAddress[ArrayIndex+1]),
+ &(Filter->BindingsUsingShortAddress[ArrayIndex]),
+ (Filter->NumberOfShortAddresses-ArrayIndex)*sizeof(FDDI_MASK));
+#endif
+
+ CLEAR_MASK(&Filter->BindingsUsingShortAddress[ArrayIndex]);
+
+ SET_BIT_IN_MASK(LocalOpen->FilterIndex, &Filter->BindingsUsingShortAddress[ArrayIndex]);
+
+ Filter->NumberOfShortAddresses++;
+ }
+ else
+ {
+ //
+ // No room in the array, oh well.
+ //
+ fddiUndoChangeFilterShortAddresses(Filter);
+
+ 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;
+
+#ifdef NDIS_NT
+ MoveMemory(Filter->MulticastShortAddresses[ArrayIndex],
+ Filter->MulticastShortAddresses[ArrayIndex+1],
+ (Filter->NumberOfShortAddresses-(ArrayIndex+1)) *FDDI_LENGTH_OF_SHORT_ADDRESS);
+#else // NDIS_WIN
+ MoveOverlappedMemory(Filter->MulticastShortAddresses[ArrayIndex],
+ Filter->MulticastShortAddresses[ArrayIndex+1],
+ (Filter->NumberOfShortAddresses-(ArrayIndex+1)) *FDDI_LENGTH_OF_SHORT_ADDRESS);
+#endif
+
+#ifdef NDIS_NT
+ MoveMemory(&Filter->BindingsUsingShortAddress[ArrayIndex],
+ &Filter->BindingsUsingShortAddress[ArrayIndex+1],
+ (Filter->NumberOfShortAddresses-(ArrayIndex+1))*(sizeof(FDDI_MASK)));
+#else // NDIS_WIN
+ MoveOverlappedMemory(&Filter->BindingsUsingShortAddress[ArrayIndex],
+ &Filter->BindingsUsingShortAddress[ArrayIndex+1],
+ (Filter->NumberOfShortAddresses-(ArrayIndex+1))*(sizeof(FDDI_MASK)));
+#endif
+
+ 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,
+ Filter->OldNumberOfShortAddresses,
+ Filter->OldMulticastShortAddresses,
+ 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.
+ //
+ fddiUndoChangeFilterShortAddresses(Filter);
+ }
+ }
+ else
+ {
+ StatusOfChange = NDIS_STATUS_SUCCESS;
+ }
+
+ return(StatusOfChange);
+}
+
+
+VOID
+fddiUpdateDirectedBindingList(
+ IN OUT PFDDI_FILTER Filter,
+ IN PFDDI_BINDING_INFO Binding,
+ IN BOOLEAN fAddToList
+ )
+/*++
+
+Routine Description:
+
+ This routine will either add or remove a binding to or from the
+ directed filter list.
+
+Arguments:
+
+ Filter - Pointer to the filter database to add/remove the binding from.
+ Binding - Pointer to the binding.
+ fAdd - TRUE if we are to add the binding,
+ FALSE if we are removeing it.
+
+--*/
+{
+ PFDDI_BINDING_INFO CurrentBinding;
+ BOOLEAN AlreadyOnList;
+
+ //
+ // Do we need to add it to the directed list?
+ //
+ if (fAddToList)
+ {
+ //
+ // First we need to see if it is already on the
+ // directed list.
+ //
+ for (CurrentBinding = Filter->DirectedList, AlreadyOnList = FALSE;
+ CurrentBinding != NULL;
+ CurrentBinding = CurrentBinding->NextDirected)
+ {
+ if (CurrentBinding == Binding)
+ {
+ AlreadyOnList = TRUE;
+ }
+ }
+
+ if (!AlreadyOnList)
+ {
+ Binding->NextDirected = Filter->DirectedList;
+ Filter->DirectedList = Binding;
+ }
+ }
+ else
+ {
+ PFDDI_BINDING_INFO *ppBI;
+
+ for (ppBI = &Filter->DirectedList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextDirected)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextDirected;
+ break;
+ }
+ }
+ Binding->NextDirected = NULL;
+ }
+}
+
+
+VOID
+fddiUpdateBroadcastBindingList(
+ IN OUT PFDDI_FILTER Filter,
+ IN PFDDI_BINDING_INFO Binding,
+ IN BOOLEAN fAddToList
+ )
+/*++
+
+Routine Description:
+ This routine will either add or remove a binding to or from the
+ broadcast/multicast filter list.
+
+Arguments:
+
+ Filter - Pointer to the filter database to add/remove the binding from.
+ Binding - Pointer to the binding.
+ fAdd - TRUE if we are to add the binding,
+ FALSE if we are removeing it.
+--*/
+{
+ PFDDI_BINDING_INFO CurrentBinding;
+ BOOLEAN AlreadyOnList;
+
+ //
+ // Do we need to add it to the directed list?
+ //
+ if (fAddToList)
+ {
+ //
+ // First we need to see if it is already on the
+ // directed list.
+ //
+ for (CurrentBinding = Filter->BMSList, AlreadyOnList = FALSE;
+ CurrentBinding != NULL;
+ CurrentBinding = CurrentBinding->NextBMS)
+ {
+ if (CurrentBinding == Binding)
+ {
+ AlreadyOnList = TRUE;
+ }
+ }
+
+ if (!AlreadyOnList)
+ {
+ Binding->NextBMS = Filter->BMSList;
+ Filter->BMSList = Binding;
+ }
+ }
+ else
+ {
+ PFDDI_BINDING_INFO *ppBI;
+
+ for (ppBI = &Filter->BMSList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextBMS)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextBMS;
+ break;
+ }
+ }
+
+ Binding->NextBMS = NULL;
+ }
+}
+
+
+VOID
+fddiUpdateSpecificBindingLists(
+ IN OUT PFDDI_FILTER Filter,
+ IN PFDDI_BINDING_INFO Binding
+ )
+/*++
+
+Routine Description:
+
+ This routine will determine if we should add or remove a binding from
+ one of the filter lists (directed and broadcast).
+
+Arguments:
+
+ Filter - Pointer to the filter database that the binding belongs to.
+ Binding - Pointer to the binding to add or remove to lists.
+
+--*/
+{
+ BOOLEAN fOnDirectedList = FALSE;
+ BOOLEAN fOnBMSList = FALSE;
+ BOOLEAN fAddToDirectedList = FALSE;
+ BOOLEAN fAddToBMSList = FALSE;
+
+ //
+ // If the old filter is promsicuous then it is currently on
+ // both lists.
+ //
+ if (Binding->OldPacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL))
+ {
+ fOnDirectedList = TRUE;
+ fOnBMSList = TRUE;
+ }
+ else
+ {
+ //
+ // If the binding had the directed bit set then it is on
+ // the directed list.
+ //
+ if (Binding->OldPacketFilters & NDIS_PACKET_TYPE_DIRECTED)
+ {
+ fOnDirectedList = TRUE;
+ }
+
+ //
+ // If the binding had the broadcast/multicast bit set then it is on
+ // the broadcast/multicast list.
+ //
+ if (Binding->OldPacketFilters & (NDIS_PACKET_TYPE_BROADCAST |
+ NDIS_PACKET_TYPE_SMT |
+ NDIS_PACKET_TYPE_MULTICAST |
+ NDIS_PACKET_TYPE_ALL_MULTICAST))
+ {
+ fOnBMSList = TRUE;
+ }
+ }
+
+ //
+ // If the current filter has the promsicuous bit set then we
+ // need to add it to both lists.
+ //
+ if (Binding->PacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL))
+ {
+ fAddToDirectedList = TRUE;
+ fAddToBMSList = TRUE;
+ }
+ else
+ {
+ //
+ // Was the directed bit set?
+ //
+ if (Binding->PacketFilters & NDIS_PACKET_TYPE_DIRECTED)
+ {
+ fAddToDirectedList = TRUE;
+ }
+
+ //
+ // Was the broadcast bit set?
+ //
+ if (Binding->PacketFilters & (NDIS_PACKET_TYPE_BROADCAST |
+ NDIS_PACKET_TYPE_SMT |
+ NDIS_PACKET_TYPE_MULTICAST |
+ NDIS_PACKET_TYPE_ALL_MULTICAST))
+ {
+ fAddToBMSList = TRUE;
+ }
+ }
+
+ //
+ // Determine if the binding should be added or removed from
+ // the directed list.
+ //
+ if (!fOnDirectedList && fAddToDirectedList)
+ {
+ //
+ // Add the binding to the directed list.
+ //
+ fddiUpdateDirectedBindingList(Filter, Binding, TRUE);
+ }
+ else if (fOnDirectedList && !fAddToDirectedList)
+ {
+ //
+ // Remove it from the directed list.
+ //
+ fddiUpdateDirectedBindingList(Filter, Binding, FALSE);
+ }
+
+ //
+ // Determine if the binding should be added or removed from
+ // the broadcast/multicast list.
+ //
+ if (!fOnBMSList && fAddToBMSList)
+ {
+ //
+ // Add the binding to the broadcast/multicast list.
+ //
+ fddiUpdateBroadcastBindingList(Filter, Binding, TRUE);
+ }
+ else if (fOnBMSList && !fAddToBMSList)
+ {
+ //
+ // Remove the binding from the broadcast/multicast list.
+ //
+ fddiUpdateBroadcastBindingList(Filter, Binding, FALSE);
+ }
+}
+
+
+VOID
+fddiUndoFilterAdjust(
+ IN PFDDI_FILTER Filter,
+ IN PFDDI_BINDING_INFO Binding
+ )
+/*++
+
+Routine Description:
+
+ This routine will restore the original filter settings.
+
+Arguments:
+
+ Filter - Pointer to the filter database that the binding belongs to.
+ Binding - Pointer to the binding.
+
+--*/
+{
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+ Binding->PacketFilters = Binding->OldPacketFilters;
+ Filter->CombinedPacketFilter = Filter->OldCombinedPacketFilter;
+
+ //
+ // Update the filter lists.
+ //
+ fddiUpdateSpecificBindingLists(Filter, Binding);
+}
+
+
+
+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.
+
+--*/
+
+{
+ PFDDI_BINDING_INFO LocalOpen = (PFDDI_BINDING_INFO)NdisFilterHandle;
+ PFDDI_BINDING_INFO OpenList;
+
+ //
+ // 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->OldPacketFilters = LocalOpen->PacketFilters;
+ LocalOpen->PacketFilters = FilterClasses;
+
+ Filter->OldCombinedPacketFilter = Filter->CombinedPacketFilter;
+
+ //
+ // 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;
+ }
+
+ //
+ // Update the filter lists.
+ //
+ fddiUpdateSpecificBindingLists(Filter, LocalOpen);
+
+ if ((Filter->OldCombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL) !=
+ (Filter->CombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL))
+ {
+ StatusOfAdjust = Filter->FilterChangeAction(Filter->OldCombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL,
+ Filter->CombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL,
+ 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.
+ //
+ fddiUndoFilterAdjust(Filter, LocalOpen);
+ }
+ }
+ 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;
+}
+
+
+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;
+}
+
+
+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
+FddiFilterDprIndicateReceiveFullMac(
+ 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;
+
+ //
+ // Current Open to indicate to.
+ //
+ PFDDI_BINDING_INFO LocalOpen, NextOpen;
+
+ //
+ // 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))
+ {
+ BOOLEAN fDirected;
+
+ fDirected = FALSE;
+ FDDI_IS_SMT(*((PCHAR)HeaderBuffer), &ResultOfAddressCheck);
+ if (!ResultOfAddressCheck)
+ {
+ fDirected = (((UCHAR)Address[0] & 0x01) == 0);
+ }
+
+ //
+ // Handle the directed packet case first
+ //
+ if (fDirected)
+ {
+ BOOLEAN IsNotOurs;
+
+ //
+ // If it is a directed packet, then check if the combined packet
+ // filter is PROMISCUOUS, if it is check if it is directed towards
+ // us. Eliminate the SMT case.
+ //
+ IsNotOurs = FALSE; // Assume it is
+ if (Filter->CombinedPacketFilter & (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_LOCAL |
+ NDIS_PACKET_TYPE_ALL_MULTICAST))
+ {
+ FDDI_COMPARE_NETWORK_ADDRESSES_EQ((AddressLength == FDDI_LENGTH_OF_LONG_ADDRESS) ?
+ Filter->AdapterLongAddress :
+ Filter->AdapterShortAddress,
+ Address,
+ AddressLength,
+ &IsNotOurs);
+ }
+
+ //
+ // Walk the directed list and indicate up the packets.
+ //
+ for (LocalOpen = Filter->DirectedList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextDirected;
+
+ //
+ // Ignore if not directed to us or if the binding is not promiscuous
+ //
+ if (((LocalOpen->PacketFilters & NDIS_PACKET_TYPE_PROMISCUOUS) == 0) &&
+ IsNotOurs)
+ {
+ continue;
+ }
+
+ LocalOpen->References++;
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ //
+ // Indicate the packet to the binding.
+ //
+ ProtocolFilterIndicateReceive(&StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize,
+ NdisMediumFddi);
+
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ --LocalOpen->References;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ fddiRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+
+ return;
+ }
+
+ //
+ // Determine whether the input address is a simple direct,
+ // a broadcast, a multicast, or an SMT address.
+ //
+ FDDI_IS_SMT(*((PCHAR)HeaderBuffer), &ResultOfAddressCheck);
+ if (ResultOfAddressCheck)
+ {
+ AddressType = NDIS_PACKET_TYPE_SMT;
+ }
+ else
+ {
+ //
+ // 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)
+ {
+ FDDI_CHECK_FOR_INVALID_BROADCAST_INDICATION(Filter);
+
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+ }
+ else
+ {
+ AddressType = NDIS_PACKET_TYPE_MULTICAST;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Runt Packet
+ AddressType = NDIS_PACKET_TYPE_PROMISCUOUS;
+ }
+
+ //
+ // At this point we know that the packet is either:
+ // - Runt packet - indicated by AddressType = NDIS_PACKET_TYPE_PROMISCUOUS (OR)
+ // - Broadcast packet - indicated by AddressType = NDIS_PACKET_TYPE_BROADCAST (OR)
+ // - Multicast packet - indicated by AddressType = NDIS_PACKET_TYPE_MULTICAST
+ // - SMT Packet - indicated by AddressType = NDIS_PACKET_TYPE_SMT
+ //
+ // Walk the broadcast/multicast/SMT list and indicate up the packets.
+ //
+ // The packet is indicated if it meets the following criteria:
+ //
+ // if ((Binding is promiscuous) OR
+ // ((Packet is broadcast) AND (Binding is Broadcast)) OR
+ // ((Packet is SMT) AND (Binding is SMT)) OR
+ // ((Packet is multicast) AND
+ // ((Binding is all-multicast) OR
+ // ((Binding is multicast) AND (address in approp. multicast list)))))
+ //
+ //
+ // Is this a directed packet?
+ //
+ for (LocalOpen = Filter->BMSList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ UINT LocalFilter = LocalOpen->PacketFilters;
+ UINT IndexOfAddress;
+
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextBMS;
+
+ if ((LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_BROADCAST) &&
+ (LocalFilter & NDIS_PACKET_TYPE_BROADCAST)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_SMT) &&
+ (LocalFilter & NDIS_PACKET_TYPE_SMT)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_MULTICAST) &&
+ ((LocalFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) ||
+ ((LocalFilter & NDIS_PACKET_TYPE_MULTICAST) &&
+ (((AddressLength == FDDI_LENGTH_OF_LONG_ADDRESS) &&
+ FddiFindMulticastLongAddress(Filter->NumberOfLongAddresses,
+ Filter->MulticastLongAddresses,
+ Address,
+ &IndexOfAddress) &&
+ IS_BIT_SET_IN_MASK(LocalOpen->FilterIndex,
+ Filter->BindingsUsingLongAddress[IndexOfAddress])
+ ) ||
+ ((AddressLength == FDDI_LENGTH_OF_SHORT_ADDRESS) &&
+ FddiFindMulticastShortAddress(Filter->NumberOfShortAddresses,
+ Filter->MulticastShortAddresses,
+ Address,
+ &IndexOfAddress) &&
+ IS_BIT_SET_IN_MASK(LocalOpen->FilterIndex,
+ Filter->BindingsUsingLongAddress[IndexOfAddress])
+ )
+ )
+ )
+ )
+ )
+ )
+ {
+ LocalOpen->References++;
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ //
+ // Indicate the packet to the binding.
+ //
+
+ ProtocolFilterIndicateReceive(&StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize,
+ NdisMediumFddi);
+
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ LocalOpen->References--;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ fddiRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+ }
+}
+
+
+
+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;
+
+ NDIS_ACQUIRE_SPIN_LOCK(Filter->Lock, &OldIrql);
+
+ FddiFilterDprIndicateReceiveFullMac(Filter,
+ MacReceiveContext,
+ Address,
+ AddressLength,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize);
+
+ NDIS_RELEASE_SPIN_LOCK(Filter->Lock, OldIrql);
+}
+
+
+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;
+
+ //
+ // Current Open to indicate to.
+ //
+ PFDDI_BINDING_INFO LocalOpen, NextOpen;
+
+ //
+ // 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))
+ {
+ BOOLEAN fDirected;
+
+ fDirected = FALSE;
+ FDDI_IS_SMT(*((PCHAR)HeaderBuffer), &ResultOfAddressCheck);
+ if (!ResultOfAddressCheck)
+ {
+ fDirected = (((UCHAR)Address[0] & 0x01) == 0);
+ }
+
+ //
+ // Handle the directed packet case first
+ //
+ if (fDirected)
+ {
+ BOOLEAN IsNotOurs;
+
+ //
+ // If it is a directed packet, then check if the combined packet
+ // filter is PROMISCUOUS, if it is check if it is directed towards
+ // us. Eliminate the SMT case.
+ //
+ IsNotOurs = FALSE; // Assume it is
+ if (Filter->CombinedPacketFilter & (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_LOCAL |
+ NDIS_PACKET_TYPE_ALL_MULTICAST))
+ {
+ FDDI_COMPARE_NETWORK_ADDRESSES_EQ((AddressLength == FDDI_LENGTH_OF_LONG_ADDRESS) ?
+ Filter->AdapterLongAddress :
+ Filter->AdapterShortAddress,
+ Address,
+ AddressLength,
+ &IsNotOurs);
+ }
+
+ //
+ // Walk the directed list and indicate up the packets.
+ //
+ for (LocalOpen = Filter->DirectedList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextDirected;
+
+ //
+ // Ignore if not directed to us or if the binding is not promiscuous
+ //
+ if (((LocalOpen->PacketFilters & NDIS_PACKET_TYPE_PROMISCUOUS) == 0) &&
+ IsNotOurs)
+ {
+ continue;
+ }
+
+ LocalOpen->References++;
+
+// NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ //
+ // Indicate the packet to the binding.
+ //
+ ProtocolFilterIndicateReceive(&StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize,
+ NdisMediumFddi);
+
+// NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ --LocalOpen->References;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ fddiRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+
+ return;
+ }
+
+ //
+ // Determine whether the input address is a simple direct,
+ // a broadcast, a multicast, or an SMT address.
+ //
+ FDDI_IS_SMT(*((PCHAR)HeaderBuffer), &ResultOfAddressCheck);
+ if (ResultOfAddressCheck)
+ {
+ AddressType = NDIS_PACKET_TYPE_SMT;
+ }
+ else
+ {
+ //
+ // 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)
+ {
+ FDDI_CHECK_FOR_INVALID_BROADCAST_INDICATION(Filter);
+
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+ }
+ else
+ {
+ AddressType = NDIS_PACKET_TYPE_MULTICAST;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Runt Packet
+ AddressType = NDIS_PACKET_TYPE_PROMISCUOUS;
+ }
+
+ //
+ // At this point we know that the packet is either:
+ // - Runt packet - indicated by AddressType = NDIS_PACKET_TYPE_PROMISCUOUS (OR)
+ // - Broadcast packet - indicated by AddressType = NDIS_PACKET_TYPE_BROADCAST (OR)
+ // - Multicast packet - indicated by AddressType = NDIS_PACKET_TYPE_MULTICAST
+ // - SMT Packet - indicated by AddressType = NDIS_PACKET_TYPE_SMT
+ //
+ // Walk the broadcast/multicast/SMT list and indicate up the packets.
+ //
+ // The packet is indicated if it meets the following criteria:
+ //
+ // if ((Binding is promiscuous) OR
+ // ((Packet is broadcast) AND (Binding is Broadcast)) OR
+ // ((Packet is SMT) AND (Binding is SMT)) OR
+ // ((Packet is multicast) AND
+ // ((Binding is all-multicast) OR
+ // ((Binding is multicast) AND (address in approp. multicast list)))))
+ //
+ //
+ // Is this a directed packet?
+ //
+ for (LocalOpen = Filter->BMSList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ UINT LocalFilter = LocalOpen->PacketFilters;
+ UINT IndexOfAddress;
+
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextBMS;
+
+ if ((LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_BROADCAST) &&
+ (LocalFilter & NDIS_PACKET_TYPE_BROADCAST)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_SMT) &&
+ (LocalFilter & NDIS_PACKET_TYPE_SMT)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_MULTICAST) &&
+ ((LocalFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) ||
+ ((LocalFilter & NDIS_PACKET_TYPE_MULTICAST) &&
+ (((AddressLength == FDDI_LENGTH_OF_LONG_ADDRESS) &&
+ FddiFindMulticastLongAddress(Filter->NumberOfLongAddresses,
+ Filter->MulticastLongAddresses,
+ Address,
+ &IndexOfAddress) &&
+ IS_BIT_SET_IN_MASK(LocalOpen->FilterIndex,
+ Filter->BindingsUsingLongAddress[IndexOfAddress])
+ ) ||
+ ((AddressLength == FDDI_LENGTH_OF_SHORT_ADDRESS) &&
+ FddiFindMulticastShortAddress(Filter->NumberOfShortAddresses,
+ Filter->MulticastShortAddresses,
+ Address,
+ &IndexOfAddress) &&
+ IS_BIT_SET_IN_MASK(LocalOpen->FilterIndex,
+ Filter->BindingsUsingLongAddress[IndexOfAddress])
+ )
+ )
+ )
+ )
+ )
+ )
+ {
+ LocalOpen->References++;
+
+// NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ //
+ // Indicate the packet to the binding.
+ //
+
+ ProtocolFilterIndicateReceive(&StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize,
+ NdisMediumFddi);
+
+// NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ LocalOpen->References--;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ fddiRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+ }
+}
+
+
+VOID
+FddiFilterDprIndicateReceivePacket(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+)
+
+/*++
+
+Routine Description:
+
+ This routine is called by the Miniport to indicate packets to
+ all bindings. The packets will be filtered so that only the
+ appropriate bindings will receive the individual packets.
+ This is the code path for ndis 4.0 miniport drivers.
+
+Arguments:
+
+ Miniport - The Miniport block.
+
+ PacketArray - An array of Packets indicated by the miniport.
+
+ NumberOfPackets - Self-explanatory.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // The Filter of interest
+ //
+ PFDDI_FILTER Filter = Miniport->FddiDB;
+
+ //
+ // Current packet being processed
+ //
+ PPNDIS_PACKET pPktArray = PacketArray;
+
+ //
+ // Pointer to the buffer in the ndispacket
+ //
+ PNDIS_BUFFER Buffer;
+
+ //
+ // Total packet length
+ //
+ UINT i, LASize, PacketSize, NumIndicates = 0;
+
+ //
+ // Pointer to the 1st segment of the buffer, points to dest address
+ //
+ PUCHAR Address, Hdr;
+
+ UINT AddressLength;
+
+ //
+ // 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;
+
+ //
+ // Decides whether we use the protocol's revpkt handler or fall
+ // back to old rcvindicate handler
+ //
+ BOOLEAN fFallBack, fPmode, FixRef;
+
+ //
+ // Current Open to indicate to.
+ //
+ PFDDI_BINDING_INFO LocalOpen, NextOpen;
+ PNDIS_OPEN_BLOCK pOpenBlock; \
+
+ //
+ // Holds the result of address determinations.
+ //
+ INT ResultOfAddressCheck;
+
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
+
+ // Walk all the packets
+ for (i = 0; i < NumberOfPackets; i++, pPktArray++)
+ {
+ PNDIS_PACKET Packet = *pPktArray;
+ PNDIS_PACKET_OOB_DATA pOob;
+
+ ASSERT(Packet != NULL);
+
+ pOob = NDIS_OOB_DATA_FROM_PACKET(Packet);
+
+ NdisGetFirstBufferFromPacket(Packet,
+ &Buffer,
+ &Address,
+ &LASize,
+ &PacketSize);
+ ASSERT(Buffer != NULL);
+
+ Hdr = Address++;
+
+ AddressLength = (*Hdr & 0x40) ?
+ FDDI_LENGTH_OF_LONG_ADDRESS :
+ FDDI_LENGTH_OF_SHORT_ADDRESS;
+ ASSERT(pOob->HeaderSize == (AddressLength * 2 + 1));
+
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount = 0;
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->Miniport = Miniport;
+
+ //
+ // Set the status here that nobody is holding the packet. This will get
+ // overwritten by the real status from the protocol. Pay heed to what
+ // the miniport is saying.
+ //
+ if (pOob->Status != NDIS_STATUS_RESOURCES)
+ {
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount --;
+ pOob->Status = NDIS_STATUS_SUCCESS;
+ fFallBack = FALSE;
+ FixRef = TRUE;
+ }
+ else
+ {
+ fFallBack = TRUE;
+ FixRef = FALSE;
+ }
+
+ //
+ // Ensure that we force re-calculation.
+ //
+ Packet->Private.ValidCounts = FALSE;
+
+ //
+ // A quick check for Runt packets. These are only indicated to Promiscuous bindings
+ //
+ if (PacketSize > pOob->HeaderSize)
+ {
+ BOOLEAN fDirected;
+
+ fDirected = FALSE;
+ FDDI_IS_SMT(*Address, &ResultOfAddressCheck);
+ if (!ResultOfAddressCheck)
+ {
+ fDirected = (((UCHAR)Address[0] & 0x01) == 0);
+ }
+
+ //
+ // Handle the directed packet case first
+ //
+ if (fDirected)
+ {
+ BOOLEAN IsNotOurs;
+ //
+ // If it is a directed packet, then check if the combined packet
+ // filter is PROMISCUOUS, if it is check if it is directed towards
+ // us. Eliminate the SMT case.
+ //
+ IsNotOurs = FALSE; // Assume it is
+ if (Filter->CombinedPacketFilter & (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_LOCAL |
+ NDIS_PACKET_TYPE_ALL_MULTICAST))
+ {
+ FDDI_COMPARE_NETWORK_ADDRESSES_EQ((AddressLength == FDDI_LENGTH_OF_LONG_ADDRESS) ?
+ Filter->AdapterLongAddress :
+ Filter->AdapterShortAddress,
+ Address,
+ AddressLength,
+ &IsNotOurs);
+ }
+
+ //
+ // We definitely have a directed packet so lets indicate it now.
+ //
+ // Walk the directed list and indicate up the packets.
+ //
+ for (LocalOpen = Filter->DirectedList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextDirected;
+
+ //
+ // Ignore if not directed to us or if the binding is not promiscuous
+ //
+ if (((LocalOpen->PacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) == 0) &&
+ IsNotOurs)
+ {
+ continue;
+ }
+
+ pOpenBlock = (PNDIS_OPEN_BLOCK)(LocalOpen->NdisBindingContext);
+ LocalOpen->ReceivedAPacket = TRUE;
+ LocalOpen->References++;
+ NumIndicates ++;
+
+ fPmode = (LocalOpen->PacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_LOCAL)) ?
+ TRUE : FALSE;
+ IndicateToProtocol(Miniport,
+ Filter,
+ pOpenBlock,
+ Packet,
+ Hdr,
+ PacketSize,
+ pOob->HeaderSize,
+ &fFallBack,
+ fPmode,
+ NdisMediumFddi);
+
+ LocalOpen->References--;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ fddiRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+
+ if (FixRef)
+ {
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount++;
+ if (PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount != 0)
+ {
+ NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_PENDING);
+ }
+ }
+ continue; // Done with this packet
+ }
+
+ //
+ // Determine whether the input address is a simple direct,
+ // a broadcast, a multicast, or an SMT address.
+ //
+ FDDI_IS_SMT(*Address, &ResultOfAddressCheck);
+ if (ResultOfAddressCheck)
+ {
+ AddressType = NDIS_PACKET_TYPE_SMT;
+ }
+ else
+ {
+ //
+ // 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)
+ {
+ FDDI_CHECK_FOR_INVALID_BROADCAST_INDICATION(Filter);
+
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+ }
+ else
+ {
+ AddressType = NDIS_PACKET_TYPE_MULTICAST;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Runt Packet
+ AddressType = NDIS_PACKET_TYPE_PROMISCUOUS;
+ }
+
+ //
+ // At this point we know that the packet is either:
+ // - Runt packet - indicated by AddressType = NDIS_PACKET_TYPE_PROMISCUOUS (OR)
+ // - Broadcast packet - indicated by AddressType = NDIS_PACKET_TYPE_BROADCAST (OR)
+ // - Multicast packet - indicated by AddressType = NDIS_PACKET_TYPE_MULTICAST
+ // - SMT Packet - indicated by AddressType = NDIS_PACKET_TYPE_SMT
+ //
+ // Walk the broadcast/multicast/SMT list and indicate up the packets.
+ //
+ // The packet is indicated if it meets the following criteria:
+ //
+ // if ((Binding is promiscuous) OR
+ // ((Packet is broadcast) AND (Binding is Broadcast)) OR
+ // ((Packet is SMT) AND (Binding is SMT)) OR
+ // ((Packet is multicast) AND
+ // ((Binding is all-multicast) OR
+ // ((Binding is multicast) AND (address in approp. multicast list)))))
+ //
+ //
+ // Is this a directed packet?
+ //
+ for (LocalOpen = Filter->BMSList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ UINT LocalFilter = LocalOpen->PacketFilters;
+ UINT IndexOfAddress;
+
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextBMS;
+
+ if ((LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_BROADCAST) &&
+ (LocalFilter & NDIS_PACKET_TYPE_BROADCAST)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_SMT) &&
+ (LocalFilter & NDIS_PACKET_TYPE_SMT)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_MULTICAST) &&
+ ((LocalFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) ||
+ ((LocalFilter & NDIS_PACKET_TYPE_MULTICAST) &&
+ (((AddressLength == FDDI_LENGTH_OF_LONG_ADDRESS) &&
+ FddiFindMulticastLongAddress(Filter->NumberOfLongAddresses,
+ Filter->MulticastLongAddresses,
+ Address,
+ &IndexOfAddress) &&
+ IS_BIT_SET_IN_MASK(LocalOpen->FilterIndex,
+ Filter->BindingsUsingLongAddress[IndexOfAddress])
+ ) ||
+ ((AddressLength == FDDI_LENGTH_OF_SHORT_ADDRESS) &&
+ FddiFindMulticastShortAddress(Filter->NumberOfShortAddresses,
+ Filter->MulticastShortAddresses,
+ Address,
+ &IndexOfAddress) &&
+ IS_BIT_SET_IN_MASK(LocalOpen->FilterIndex,
+ Filter->BindingsUsingLongAddress[IndexOfAddress])
+ )
+ )
+ )
+ )
+ )
+ )
+ {
+ pOpenBlock = (PNDIS_OPEN_BLOCK)(LocalOpen->NdisBindingContext);
+ LocalOpen->ReceivedAPacket = TRUE;
+ LocalOpen->References++;
+ NumIndicates ++;
+
+ fPmode = (LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ?
+ TRUE : FALSE;
+ IndicateToProtocol(Miniport,
+ Filter,
+ pOpenBlock,
+ Packet,
+ Hdr,
+ PacketSize,
+ pOob->HeaderSize,
+ &fFallBack,
+ fPmode,
+ NdisMediumFddi);
+
+ LocalOpen->References--;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ fddiRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+ }
+
+ if (FixRef)
+ {
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount++;
+ if (PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount != 0)
+ {
+ NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_PENDING);
+ }
+ }
+ }
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
+
+ if (NumIndicates > 0)
+ {
+ FddiFilterDprIndicateReceiveComplete(Filter);
+ }
+}
+
+
+VOID
+FddiFilterDprIndicateReceiveCompleteFullMac(
+ 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, NextOpen;
+
+ //
+ // We need to aquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+ for (LocalOpen = Filter->OpenList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ NextOpen = LocalOpen->NextOpen;
+
+ if (LocalOpen->ReceivedAPacket)
+ {
+ //
+ // Indicate the binding.
+ //
+
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ LocalOpen->References++;
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ if ((--(LocalOpen->References)) == 0)
+ {
+ //
+ // This binding is shutting down. We have to kill it.
+ //
+ fddiRemoveBindingFromLists(Filter, LocalOpen);
+
+ //
+ // 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);
+ }
+ }
+ }
+}
+
+
+
+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;
+
+ NDIS_ACQUIRE_SPIN_LOCK(Filter->Lock, &OldIrql);
+
+ FddiFilterDprIndicateReceiveCompleteFullMac(Filter);
+
+ NDIS_RELEASE_SPIN_LOCK(Filter->Lock, OldIrql);
+}
+
+
+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, NextOpen;
+
+ //
+ // We need to aquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+ for (LocalOpen = Filter->OpenList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ NextOpen = LocalOpen->NextOpen;
+
+ if (LocalOpen->ReceivedAPacket)
+ {
+ //
+ // Indicate the binding.
+ //
+
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ LocalOpen->References++;
+
+// NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+// NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ if ((--(LocalOpen->References)) == 0)
+ {
+ //
+ // This binding is shutting down. We have to kill it.
+ //
+ fddiRemoveBindingFromLists(Filter, LocalOpen);
+
+ //
+ // 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);
+ }
+ }
+ }
+}
+
+
+BOOLEAN
+FddiFindMulticastLongAddress(
+ 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
+FddiFindMulticastShortAddress(
+ 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/ndis40/filter.h b/private/ntos/ndis/ndis40/filter.h
new file mode 100644
index 000000000..416f57d0c
--- /dev/null
+++ b/private/ntos/ndis/ndis40/filter.h
@@ -0,0 +1,181 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ filter.h
+
+Abstract:
+
+ MACRO for protocol filters.
+
+Author:
+
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Jun-95 Jameel Hyder New functionality
+--*/
+
+#define IndicateToProtocol(_Miniport, \
+ _Filter, \
+ _pOpenBlock, \
+ _Packet, \
+ _Hdr, \
+ _PktSize, \
+ _HdrSize, \
+ _fFallBack, \
+ _Pmode, \
+ _Medium) \
+{ \
+ UINT NumRef; \
+ UINT LookaheadBufferSize; \
+ \
+ /* \
+ * We indicate this via the IndicatePacketHandler if all of the following \
+ * conditions are met: \
+ * - The binding is not p-mode or all-local \
+ * - The binding specifies a ReceivePacketHandler \
+ * - The miniport indicates that it is willing to let go of the packet \
+ * - No binding has already claimed the packet \
+ */ \
+ \
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC((_Miniport)); \
+ \
+ /* \
+ * Indicate the packet to the binding. \
+ */ \
+ if (*(_fFallBack) || (_Pmode) || \
+ ((_pOpenBlock)->ReceivePacketHandler == NULL)) \
+ { \
+ /* \
+ * Revert back to old-style indication in this case \
+ */ \
+ NumRef = 0; \
+ NdisQueryBuffer((_Packet)->Private.Head, NULL, &LookaheadBufferSize); \
+ ProtocolFilterIndicateReceive(&StatusOfReceive, \
+ (_pOpenBlock), \
+ (_Packet), \
+ (_Hdr), \
+ (_HdrSize), \
+ (_Hdr) + (_HdrSize), \
+ LookaheadBufferSize - (_HdrSize), \
+ (_PktSize) - (_HdrSize), \
+ Medium); \
+ } \
+ else \
+ { \
+ NumRef = (*(_pOpenBlock)->ReceivePacketHandler)( \
+ (_pOpenBlock)->ProtocolBindingContext, \
+ (_Packet)); \
+ ASSERT(NumRef >= 0); \
+ } \
+ \
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC((_Miniport)); \
+ \
+ /* \
+ * Manipulate refcount on the packet with miniport lock held \
+ * Set the reference count on the packet to what the protocol \
+ * asked for. See NdisReturnPackets for how this is handled \
+ * when the packets are retrned. \
+ */ \
+ if (NumRef > 0) \
+ { \
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET((_Packet))->RefCount += NumRef; \
+ \
+ /* \
+ * Now that a binding has claimed it, make sure others do not get a chance \
+ * except if this protocol promises to behave and not use the protocol rsvd \
+ */ \
+ if ((_pOpenBlock)->NoProtRsvdOnRcvPkt == FALSE) \
+ { \
+ *(_fFallBack) = TRUE; \
+ } \
+ } \
+}
+
+#ifdef _PROTOCOL_FILTERS
+
+#define ProtocolFilterIndicateReceive(_pStatus, \
+ _OpenB, \
+ _MacReceiveContext, \
+ _HeaderBuffer, \
+ _HeaderBufferSize, \
+ _LookaheadBuffer, \
+ _LookaheadBufferSize, \
+ _PacketSize, \
+ _Medium) \
+ { \
+ PNDIS_PROTOCOL_BLOCK Prot; \
+ \
+ Prot = ((PNDIS_OPEN_BLOCK)(_OpenB))->ProtocolHandle; \
+ \
+ if ((Prot->ProtocolFilter == NULL) || \
+ (Prot->MaxPatternSize > (_LookaheadBufferSize))) \
+ { \
+ /* For protocols that do not set filters */ \
+ /* Or if the patten size exceeds the lookahead size */ \
+ FilterIndicateReceive(_pStatus, \
+ (_OpenB), \
+ _MacReceiveContext, \
+ _HeaderBuffer, \
+ _HeaderBufferSize, \
+ _LookaheadBuffer, \
+ _LookaheadBufferSize, \
+ _PacketSize); \
+ } \
+ else \
+ { \
+ PNDIS_PROTOCOL_FILTER pF; \
+ \
+ for (pF = Prot->ProtocolFilter; \
+ pF != NULL; \
+ pF = pF->Next) \
+ { \
+ if (RtlEqualMemory((PUCHAR)pF + sizeof(NDIS_PROTOCOL_FILTER), \
+ (PUCHAR)(_LookaheadBuffer) + pF->Offset, \
+ pF->Size)) \
+ { \
+ *(_pStatus) = (pF->ReceiveHandler)(((PNDIS_OPEN_BLOCK)(_OpenB))->ProtocolBindingContext,\
+ (_MacReceiveContext), \
+ (_HeaderBuffer), \
+ (_HeaderBufferSize), \
+ (_LookaheadBuffer), \
+ (_LookaheadBufferSize), \
+ (_PacketSize)); \
+ \
+ break; \
+ } \
+ } \
+ } \
+ }
+
+#else
+
+#define ProtocolFilterIndicateReceive(_pStatus, \
+ _OpenB, \
+ _MacReceiveContext, \
+ _HeaderBuffer, \
+ _HeaderBufferSize, \
+ _LookaheadBuffer, \
+ _LookaheadBufferSize, \
+ _PacketSize, \
+ _Medium) \
+ { \
+ FilterIndicateReceive(_pStatus, \
+ (_OpenB), \
+ _MacReceiveContext, \
+ _HeaderBuffer, \
+ _HeaderBufferSize, \
+ _LookaheadBuffer, \
+ _LookaheadBufferSize, \
+ _PacketSize); \
+ }
+
+#endif
+
diff --git a/private/ntos/ndis/ndis40/init.c b/private/ntos/ndis/ndis40/init.c
new file mode 100644
index 000000000..32661748e
--- /dev/null
+++ b/private/ntos/ndis/ndis40/init.c
@@ -0,0 +1,1415 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ init.c
+
+Abstract:
+
+ NDIS wrapper functions initializing drivers.
+
+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
+ 01-Jun-1995 JameelH Re-organized
+
+--*/
+
+#include <precomp.h>
+#include <atm.h>
+#pragma hdrstop
+
+#include <stdarg.h>
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_INIT
+
+//
+// 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)
+ {
+ HandleToReturn->KeyQueryTable = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->ParametersQueryTable;
+ HandleToReturn->ParameterList = NULL;
+ *ConfigurationHandle = (NDIS_HANDLE)HandleToReturn;
+ }
+}
+
+
+VOID
+NdisOpenConfigurationKeyByName(
+ OUT PNDIS_STATUS Status,
+ IN PNDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING KeyName,
+ OUT PNDIS_HANDLE KeyHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to open a subkey relative to the configuration handle.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ ConfigurationHandle - Handle to an already open section of the registry
+
+ KeyName - Name of the subkey to open
+
+ KeyHandle - Placeholder for the handle to the sub-key.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Handle to be returned
+ //
+ PNDIS_CONFIGURATION_HANDLE SKHandle, ConfigHandle = (PNDIS_CONFIGURATION_HANDLE)ConfigurationHandle;
+ PNDIS_WRAPPER_CONFIGURATION_HANDLE WConfigHandle;
+ UNICODE_STRING Parent, Child, Sep;
+#define PQueryTable WConfigHandle->ParametersQueryTable
+
+ ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+ //
+ // Allocate the configuration handle
+ //
+ RtlInitUnicodeString(&Parent, ConfigHandle->KeyQueryTable[3].Name);
+ RtlInitUnicodeString(&Sep, L"\\");
+ Child.Length = 0;
+ Child.MaximumLength = KeyName->Length + Parent.Length + Sep.Length + sizeof(WCHAR);
+ *Status = NdisAllocateMemory((PVOID*)&SKHandle,
+ sizeof(NDIS_CONFIGURATION_HANDLE) +
+ sizeof(NDIS_WRAPPER_CONFIGURATION_HANDLE) +
+ Child.MaximumLength,
+ 0,
+ HighestAcceptableMax);
+
+ if (*Status != NDIS_STATUS_SUCCESS)
+ {
+ *KeyHandle = (NDIS_HANDLE)NULL;
+ return;
+ }
+
+ WConfigHandle = (PNDIS_WRAPPER_CONFIGURATION_HANDLE)((PUCHAR)SKHandle + sizeof(NDIS_CONFIGURATION_HANDLE));
+ Child.Buffer = (PWSTR)((PUCHAR)WConfigHandle + sizeof(NDIS_WRAPPER_CONFIGURATION_HANDLE));
+
+ RtlCopyUnicodeString(&Child, &Parent);
+ RtlAppendUnicodeStringToString(&Child, &Sep);
+ RtlAppendUnicodeStringToString(&Child, KeyName);
+
+ SKHandle->KeyQueryTable = WConfigHandle->ParametersQueryTable;
+
+
+ //
+ // 1.
+ // Call ndisSaveParameter for a parameter, which will allocate storage for it.
+ //
+ PQueryTable[0].QueryRoutine = ndisSaveParameters;
+ PQueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ PQueryTable[0].DefaultType = REG_NONE;
+
+ //
+ // PQueryTable[0].Name and PQueryTable[0].EntryContext
+ // are filled in inside ReadConfiguration, in preparation
+ // for the callback.
+ //
+ // PQueryTable[0].Name = KeywordBuffer;
+ // PQueryTable[0].EntryContext = ParameterValue;
+
+ //
+ // 2.
+ // Stop
+ //
+ PQueryTable[1].QueryRoutine = NULL;
+ PQueryTable[1].Flags = 0;
+ PQueryTable[1].Name = NULL;
+
+ //
+ // NOTE: Some fields in ParametersQueryTable[3] are used to store information for later retrieval.
+ //
+ PQueryTable[3].QueryRoutine = NULL;
+ PQueryTable[3].Name = Child.Buffer;
+ PQueryTable[3].EntryContext = NULL;
+ PQueryTable[3].DefaultData = NULL;
+
+ SKHandle->ParameterList = NULL;
+ *KeyHandle = (NDIS_HANDLE)SKHandle;
+#undef PQueryTable
+}
+
+
+VOID
+NdisOpenConfigurationKeyByIndex(
+ OUT PNDIS_STATUS Status,
+ IN PNDIS_HANDLE ConfigurationHandle,
+ IN ULONG Index,
+ OUT PNDIS_STRING KeyName,
+ OUT PNDIS_HANDLE KeyHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to open a subkey relative to the configuration handle.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ ConfigurationHandle - Handle to an already open section of the registry
+
+ Index - Index of the sub-key to open
+
+ KeyName - Placeholder for the name of subkey being opened
+
+ KeyHandle - Placeholder for the handle to the sub-key.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_CONFIGURATION_HANDLE ConfigHandle = (PNDIS_CONFIGURATION_HANDLE)ConfigurationHandle;
+ HANDLE Handle;
+ OBJECT_ATTRIBUTES ObjAttr;
+ UNICODE_STRING KeyPath, Services, AbsolutePath;
+ PKEY_BASIC_INFORMATION InfoBuf = NULL;
+ ULONG Len;
+
+ ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+ *KeyHandle = NULL;
+
+ do
+ {
+ //
+ // Open the current key and lookup the Nth subkey. But first conver the service relative
+ // path to absolute since this is what ZwOpenKey expects.
+ //
+ RtlInitUnicodeString(&KeyPath, ConfigHandle->KeyQueryTable[3].Name);
+ RtlInitUnicodeString(&Services, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
+ AbsolutePath.MaximumLength = KeyPath.Length + Services.Length + sizeof(WCHAR);
+ AbsolutePath.Buffer = (PWSTR)ALLOC_FROM_POOL(AbsolutePath.MaximumLength, NDIS_TAG_DEFAULT);
+ if (AbsolutePath.Buffer == NULL)
+ {
+ break;
+ }
+ NdisMoveMemory(AbsolutePath.Buffer, Services.Buffer, Services.Length);
+ AbsolutePath.Length = Services.Length;
+ RtlAppendUnicodeStringToString(&AbsolutePath, &KeyPath);
+
+ InitializeObjectAttributes(&ObjAttr,
+ &AbsolutePath,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ *Status = ZwOpenKey(&Handle,
+ GENERIC_READ | MAXIMUM_ALLOWED,
+ &ObjAttr);
+ if (*Status != STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ //
+ // Allocate memory for the call to ZwEnumerateKey
+ //
+ Len = sizeof(KEY_BASIC_INFORMATION) + 256;
+ InfoBuf = (PKEY_BASIC_INFORMATION)ALLOC_FROM_POOL(Len, NDIS_TAG_DEFAULT);
+ if (InfoBuf == NULL)
+ {
+ ZwClose(Handle);
+ *Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ //
+ // Get the Index(th) key, if it exists
+ //
+ *Status = ZwEnumerateKey(Handle,
+ Index,
+ KeyValueBasicInformation,
+ InfoBuf,
+ Len,
+ &Len);
+ ZwClose(Handle);
+ if (*Status == STATUS_SUCCESS)
+ {
+ //
+ // This worked. Now simply pick up the name and do a NdisOpenConfigurationKeyByName on it.
+ //
+ KeyPath.Length = KeyPath.MaximumLength = (USHORT)InfoBuf->NameLength;
+ KeyPath.Buffer = InfoBuf->Name;
+ NdisOpenConfigurationKeyByName(Status,
+ ConfigurationHandle,
+ &KeyPath,
+ KeyHandle);
+ if (*Status == NDIS_STATUS_SUCCESS)
+ {
+ PNDIS_CONFIGURATION_HANDLE NewHandle = *(PNDIS_CONFIGURATION_HANDLE *)KeyHandle;
+
+ //
+ // The path in the new handle has the name of the key. Extract it and return to caller
+ //
+ RtlInitUnicodeString(KeyName, NewHandle->KeyQueryTable[3].Name);
+ KeyName->Buffer = (PWSTR)((PUCHAR)KeyName->Buffer + KeyName->Length - KeyPath.Length);
+ KeyName->Length = KeyPath.Length;
+ KeyName->MaximumLength = KeyPath.MaximumLength;
+ }
+ }
+
+ } while (FALSE);
+
+ if (AbsolutePath.Buffer != NULL)
+ {
+ FREE_POOL(AbsolutePath.Buffer);
+ }
+
+ if (InfoBuf != NULL)
+ {
+ FREE_POOL(InfoBuf);
+ }
+}
+
+
+VOID
+NdisOpenGlobalConfiguration(
+ OUT PNDIS_STATUS Status,
+ IN PNDIS_HANDLE NdisWrapperHandle,
+ OUT PNDIS_HANDLE ConfigurationHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to open global (as opposed to per-adapter) configuration key for an adapter.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ WrapperHandle - Handle returned by NdisInitializeWrapper.
+
+ ConfigurationHandle - Handle returned. Points to the global parameter subkey.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_WRAPPER_HANDLE WrapperHandle = (PNDIS_WRAPPER_HANDLE)NdisWrapperHandle;
+ PNDIS_CONFIGURATION_HANDLE HandleToReturn;
+ PNDIS_WRAPPER_CONFIGURATION_HANDLE ConfigHandle;
+ UNICODE_STRING Us, Params;
+ PWSTR pWch;
+ USHORT i;
+
+ //
+ // Extract the base name from the reg path and setup for open config handle
+ //
+ Us = *(PUNICODE_STRING)(WrapperHandle->NdisWrapperConfigurationHandle);
+ RtlInitUnicodeString(&Params, L"\\Parameters");
+ for (i = Us.Length/sizeof(WCHAR), pWch = Us.Buffer + i - 1;
+ i > 0;
+ pWch --, i--)
+ {
+ if (*pWch == L'\\')
+ {
+ Us.Buffer = pWch + 1;
+ Us.Length -= i*sizeof(WCHAR);
+ Us.MaximumLength = Us.Length + Params.Length + sizeof(WCHAR);
+ break;
+ }
+ }
+
+ //
+ // Allocate the configuration handle
+ //
+ *Status = NdisAllocateMemory((PVOID *)&HandleToReturn,
+ sizeof(NDIS_CONFIGURATION_HANDLE) +
+ sizeof(NDIS_WRAPPER_CONFIGURATION_HANDLE) +
+ Us.MaximumLength,
+ 0,
+ HighestAcceptableMax);
+
+ if (*Status == NDIS_STATUS_SUCCESS)
+ {
+#define PQueryTable ConfigHandle->ParametersQueryTable
+ NdisZeroMemory(HandleToReturn,
+ sizeof(NDIS_CONFIGURATION_HANDLE) + sizeof(NDIS_WRAPPER_CONFIGURATION_HANDLE) + Us.MaximumLength);
+ ConfigHandle = (PNDIS_WRAPPER_CONFIGURATION_HANDLE)((PUCHAR)HandleToReturn + sizeof(NDIS_CONFIGURATION_HANDLE));
+ pWch = (PWSTR)((PUCHAR)ConfigHandle + sizeof(NDIS_WRAPPER_CONFIGURATION_HANDLE));
+ NdisMoveMemory(pWch, Us.Buffer, Us.Length);
+ Us.Buffer = pWch;
+ RtlAppendUnicodeStringToString(&Us, &Params);
+ HandleToReturn->KeyQueryTable = ConfigHandle->ParametersQueryTable;
+ HandleToReturn->ParameterList = NULL;
+
+ //
+ // Setup the query-table appropriately
+ //
+ PQueryTable[0].QueryRoutine = ndisSaveParameters;
+ PQueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ PQueryTable[0].DefaultType = REG_NONE;
+
+ //
+ // The following fields are filled in during NdisReadConfiguration
+ //
+ // PQueryTable[0].Name = KeywordBuffer;
+ // PQueryTable[0].EntryContext = ParameterValue;
+
+ //
+ // NOTE: Some fields in ParametersQueryTable[3 & 4] are used to
+ // store information for later retrieval.
+ //
+ PQueryTable[3].Name = pWch;
+
+ *ConfigurationHandle = (NDIS_HANDLE)HandleToReturn;
+#undef PQueryTable
+ }
+}
+
+
+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;
+
+ //
+ // Holds a null-terminated version of the keyword.
+ //
+ PWSTR KeywordBuffer;
+
+ //
+ // index variable
+ //
+ UINT i;
+
+ //
+ // Obtain the actual configuration handle structure
+ //
+ PNDIS_CONFIGURATION_HANDLE ConfigHandle = (PNDIS_CONFIGURATION_HANDLE)ConfigurationHandle;
+#define PQueryTable ConfigHandle->KeyQueryTable
+
+ //
+ // 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 3
+
+ //
+ // The names of the built-in parameters.
+ //
+ static NDIS_STRING BuiltInStrings[BUILT_IN_COUNT] =
+ {
+ NDIS_STRING_CONST ("Environment"),
+ NDIS_STRING_CONST ("ProcessorType"),
+ NDIS_STRING_CONST ("NdisVersion")
+ };
+
+ //
+ // 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
+ },
+ { NdisParameterInteger, 0x00040001 }
+ };
+
+ ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+ do
+ {
+ //
+ // 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];
+ break;
+ }
+ }
+ if (i < BUILT_IN_COUNT)
+ break;
+
+ //
+ // Allocate room for a null-terminated version of the keyword
+ //
+ KeywordBuffer = Keyword->Buffer;
+ if (Keyword->MaximumLength < (Keyword->Length + sizeof(WCHAR)))
+ {
+ KeywordBuffer = (PWSTR)ALLOC_FROM_POOL(Keyword->Length + sizeof(WCHAR), NDIS_TAG_DEFAULT);
+ if (KeywordBuffer == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+ CopyMemory(KeywordBuffer, Keyword->Buffer, Keyword->Length);
+ }
+ *(PWCHAR)(((PUCHAR)KeywordBuffer)+Keyword->Length) = (WCHAR)L'\0';
+
+ //
+ // Finish initializing the table for this query.
+ //
+ PQueryTable[0].Name = KeywordBuffer;
+ PQueryTable[0].EntryContext = ParameterValue;
+
+ //
+ // Get the value from the registry; this chains it on to the
+ // parameter list at NdisConfigHandle.
+ //
+
+ RegistryStatus = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
+ PQueryTable[3].Name,
+ PQueryTable,
+ ConfigHandle, // context
+ NULL);
+
+ if (KeywordBuffer != Keyword->Buffer)
+ {
+ FREE_POOL(KeywordBuffer); // no longer needed
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+ if (!NT_SUCCESS(RegistryStatus))
+ {
+ *Status = NDIS_STATUS_FAILURE;
+ }
+ } while (FALSE);
+#undef PQueryTable
+}
+
+
+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;
+
+ //
+ // Holds a null-terminated version of the keyword.
+ //
+ PWSTR KeywordBuffer;
+
+ //
+ // Variables describing the parameter value.
+ //
+ PVOID ValueData;
+ ULONG ValueLength;
+ ULONG ValueType;
+
+ ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+ *Status == NDIS_STATUS_SUCCESS;
+ do
+ {
+ //
+ // Get the value data.
+ //
+ switch (ParameterValue->ParameterType)
+ {
+ case NdisParameterInteger:
+ ValueData = &ParameterValue->ParameterData.IntegerData;
+ ValueLength = sizeof(ParameterValue->ParameterData.IntegerData);
+ ValueType = REG_DWORD;
+ break;
+
+ case NdisParameterString:
+ ValueData = ParameterValue->ParameterData.StringData.Buffer;
+ ValueLength = ParameterValue->ParameterData.StringData.Length;
+ ValueType = REG_SZ;
+ break;
+
+ case NdisParameterMultiString:
+ ValueData = ParameterValue->ParameterData.StringData.Buffer;
+ ValueLength = ParameterValue->ParameterData.StringData.Length;
+ ValueType = REG_MULTI_SZ;
+ break;
+
+ case NdisParameterBinary:
+ ValueData = ParameterValue->ParameterData.BinaryData.Buffer;
+ ValueLength = ParameterValue->ParameterData.BinaryData.Length;
+ ValueType = REG_BINARY;
+ break;
+
+ default:
+ *Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if (*Status != NDIS_STATUS_SUCCESS)
+ break;
+
+ KeywordBuffer = Keyword->Buffer;
+ if (Keyword->MaximumLength <= (Keyword->MaximumLength + sizeof(WCHAR)))
+ {
+ KeywordBuffer = (PWSTR)ALLOC_FROM_POOL(Keyword->Length + sizeof(WCHAR), NDIS_TAG_DEFAULT);
+ if (KeywordBuffer == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+ CopyMemory(KeywordBuffer, Keyword->Buffer, Keyword->Length);
+ }
+ *(PWCHAR)(((PUCHAR)KeywordBuffer)+Keyword->Length) = (WCHAR)L'\0';
+
+ //
+ // Write the value to the registry.
+ //
+ RegistryStatus = RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,
+ NdisConfigHandle->KeyQueryTable[3].Name,
+ KeywordBuffer,
+ ValueType,
+ ValueData,
+ ValueLength);
+
+ if (KeywordBuffer != Keyword->Buffer)
+ {
+ FREE_POOL(KeywordBuffer); // no longer needed
+ }
+
+ if (!NT_SUCCESS(RegistryStatus))
+ {
+ *Status = NDIS_STATUS_FAILURE;
+ }
+ } while (FALSE);
+}
+
+
+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;
+
+ ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+ //
+ // deallocate the parameter nodes
+ //
+ ParameterNode = NdisConfigHandle->ParameterList;
+
+ while (ParameterNode != NULL)
+ {
+ NdisConfigHandle->ParameterList = ParameterNode->Next;
+
+ 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.
+
+--*/
+{
+ NDIS_STRING NetAddrStr = NDIS_STRING_CONST("NetworkAddress");
+ PNDIS_CONFIGURATION_PARAMETER ParameterValue;
+ NTSTATUS NtStatus;
+ UCHAR ConvertArray[3];
+ PWSTR CurrentReadLoc;
+ PWSTR AddressEnd;
+ PUCHAR CurrentWriteLoc;
+ UINT TotalBytesRead;
+ ULONG TempUlong;
+ ULONG AddressLength;
+
+ ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+ do
+ {
+ //
+ // First read the "NetworkAddress" from the registry
+ //
+ NdisReadConfiguration(Status, &ParameterValue, ConfigurationHandle, &NetAddrStr, NdisParameterString);
+
+ if ((*Status != NDIS_STATUS_SUCCESS) ||
+ (ParameterValue->ParameterType != NdisParameterString))
+ {
+ *Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // If there is not an address specified then exit now.
+ //
+ if (0 == ParameterValue->ParameterData.StringData.Length)
+ {
+ *Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // 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;
+ break;
+ }
+
+ *(CurrentWriteLoc++) = (UCHAR)TempUlong;
+ ++AddressLength;
+
+ //
+ // If the next character is a hyphen, skip it.
+ //
+ if (CurrentReadLoc < AddressEnd)
+ {
+ if (*CurrentReadLoc == (WCHAR)L'-')
+ {
+ ++CurrentReadLoc;
+ }
+ }
+ }
+
+ if (NtStatus != NDIS_STATUS_SUCCESS)
+ break;
+
+ *Status = STATUS_SUCCESS;
+ *NetworkAddress = ParameterValue->ParameterData.StringData.Buffer;
+ *NetworkAddressLength = AddressLength;
+ if (AddressLength == 0)
+ {
+ *Status = NDIS_STATUS_FAILURE;
+ }
+ } while (FALSE);
+}
+
+
+VOID
+NdisConvertStringToAtmAddress(
+ OUT PNDIS_STATUS Status,
+ IN PNDIS_STRING String,
+ OUT PATM_ADDRESS AtmAddress
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ String - String representation of the atm address.
+
+ * Format defined in Section 5.4,
+ * "Example Master File Format" in ATM95-1532R4 ATM Name System:
+ *
+ * AESA format: a string of hexadecimal digits, with '.' characters for punctuation, e.g.
+ *
+ * 39.246f.00.0e7c9c.0312.0001.0001.000012345678.00
+ *
+ * E164 format: A '+' character followed by a string of
+ * decimal digits, with '.' chars for punctuation, e.g.:
+ *
+ * +358.400.1234567
+
+ AtmAddress - The converted Atm address is returned here.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ USHORT i, j, NumDigits;
+ PWSTR p, q;
+ UNICODE_STRING Us;
+ ANSI_STRING As;
+
+ //
+ // Start off by stripping the punctuation characters from the string. We do this in place.
+ //
+ for (i = NumDigits = 0, j = String->Length/sizeof(WCHAR), p = q = String->Buffer;
+ (i < j) && (*p != 0);
+ i++, p++)
+ {
+ if ((*p == ATM_ADDR_BLANK_CHAR) ||
+ (*p == ATM_ADDR_PUNCTUATION_CHAR))
+ {
+ continue;
+ }
+ *q++ = *p;
+ NumDigits ++;
+ }
+
+ //
+ // Look at the first character to determine if the address is E.164 or NSAP
+ //
+ p = String->Buffer;
+ if (*p == ATM_ADDR_E164_START_CHAR)
+ {
+ p ++;
+ NumDigits --;
+ if ((NumDigits == 0) || (NumDigits > ATM_ADDRESS_LENGTH))
+ {
+ *Status = NDIS_STATUS_INVALID_LENGTH;
+ return;
+ }
+ AtmAddress->AddressType = ATM_E164;
+ AtmAddress->NumberOfDigits = NumDigits;
+ }
+ else
+ {
+ if (NumDigits != 2*ATM_ADDRESS_LENGTH)
+ {
+ *Status = NDIS_STATUS_INVALID_LENGTH;
+ return;
+ }
+ AtmAddress->AddressType = ATM_NSAP;
+ AtmAddress->NumberOfDigits = NumDigits/sizeof(WCHAR);
+ }
+
+ //
+ // Convert the address to Ansi now
+ //
+ Us.Buffer = p;
+ Us.Length = Us.MaximumLength = NumDigits*sizeof(WCHAR);
+ As.Buffer = ALLOC_FROM_POOL(NumDigits + 1, NDIS_TAG_CO);
+ As.Length = 0;
+ As.MaximumLength = NumDigits + 1;
+ if (As.Buffer == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ *Status = NdisUnicodeStringToAnsiString(&As, &Us);
+ if (*Status != STATUS_SUCCESS)
+ {
+ FREE_POOL(As.Buffer);
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ //
+ // Now get the bytes into the destination ATM Address structure.
+ //
+ if (AtmAddress->AddressType == ATM_E164)
+ {
+ //
+ // We just need to copy in the digits in ANSI form.
+ //
+ NdisMoveMemory(AtmAddress->Address, As.Buffer, NumDigits);
+ }
+ else
+ {
+ //
+ // This is in NSAP form. We need to pack the hex digits.
+ //
+ UCHAR xxString[3];
+ ULONG val;
+
+ xxString[2] = 0;
+ for (i = 0; i < ATM_ADDRESS_LENGTH; i++)
+ {
+ xxString[0] = As.Buffer[i*2];
+ xxString[1] = As.Buffer[i*2+1];
+ *Status = CHAR_TO_INT(xxString, 16, &val);
+ if (*Status != STATUS_SUCCESS)
+ {
+ FREE_POOL(As.Buffer);
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+ AtmAddress->Address[i] = (UCHAR)val;
+ }
+ }
+
+ FREE_POOL(As.Buffer);
+ *Status = NDIS_STATUS_SUCCESS;
+}
+
+
+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.
+ //
+
+ do
+ {
+ if (NdisConfigHandle->KeyQueryTable[3].EntryContext == NULL)
+ {
+ *Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // Allocate our parameter node
+ //
+ *Status = NdisAllocateMemory((PVOID*)&ParameterNode,
+ sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE),
+ 0,
+ HighestAcceptableMax);
+
+ if (*Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ //
+ // 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;
+ } while (FALSE);
+}
+
+
+NTSTATUS
+ndisSaveParameters(
+ 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;
+
+ //
+ // Size of memory to allocate for parameter node
+ //
+ UINT Size;
+
+ //
+ // Allocate our parameter node
+ //
+ Size = sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE);
+ if ((ValueType == REG_SZ) || (ValueType == REG_MULTI_SZ) || (ValueType == REG_BINARY))
+ {
+ Size += ValueLength;
+ }
+ Status = NdisAllocateMemory((PVOID*)&ParameterNode,
+ Size,
+ 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 = (PWSTR)((PUCHAR)ParameterNode + sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE));
+
+ CopyMemory((*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 if (ValueType == REG_BINARY)
+ {
+ (*ParameterValue)->ParameterType = NdisParameterBinary;
+ (*ParameterValue)->ParameterData.BinaryData.Buffer = ValueData;
+ (*ParameterValue)->ParameterData.BinaryData.Length = (USHORT)ValueLength;
+ }
+ 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;
+}
+
+
+NTSTATUS
+ndisCheckRoute(
+ 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 then 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;
+}
+
+
+NTSTATUS
+ndisSaveLinkage(
+ 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 = ALLOC_FROM_POOL(ValueLength, NDIS_TAG_DEFAULT);
+
+ if (*Data == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ CopyMemory(*Data, ValueData, ValueLength);
+
+ return STATUS_SUCCESS;
+
+}
+
+
+
diff --git a/private/ntos/ndis/ndis40/initpnp.c b/private/ntos/ndis/ndis40/initpnp.c
new file mode 100644
index 000000000..e604be48a
--- /dev/null
+++ b/private/ntos/ndis/ndis40/initpnp.c
@@ -0,0 +1,2463 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ initpnp.c
+
+Abstract:
+
+ NDIS wrapper functions initializing drivers.
+
+Author:
+
+ Jameel Hyder (jameelh) 11-Aug-1995
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+--*/
+
+
+#include <precomp.h>
+#pragma hdrstop
+
+#include <stdarg.h>
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_INITPNP
+
+NDIS_STATUS
+ndisInitializeAllAdapterInstances(
+ IN PNDIS_MAC_BLOCK MacBlock,
+ IN PNDIS_STRING DeviceInstance OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ Reads the driver registry bindings and calls add adapter for each one.
+
+Arguments:
+
+ MacBlock - Pointer to NDIS_MAC_BLOCK allocated for this Mac.
+ or NDIS_M_DRIVER_BLOCK for the miniport.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Number of adapters added successfully
+ //
+ UINT i, AdaptersAdded = 0;
+
+ //
+ // Status of registry requests.
+ //
+ NTSTATUS RegistryStatus;
+ NDIS_STATUS Status;
+
+ //
+ // These hold the REG_MULTI_SZ read from "Bind"
+ //
+ PWSTR BindData, ExportData, RouteData;
+
+ //
+ // These hold our place in the REG_MULTI_SZ read for "Bind".
+ //
+ PWSTR CurBind, CurExport, CurRoute;
+
+ //
+ // The path to our configuration data.
+ //
+ PUNICODE_STRING BaseNameString;
+
+ //
+ // Used to instruct RtlQueryRegistryValues to read the
+ // Linkage\Bind and Linkage\Export keys
+ //
+ RTL_QUERY_REGISTRY_TABLE LQueryTable[5];
+
+ PNDIS_M_DRIVER_BLOCK MiniBlock;
+
+ UNICODE_STRING BindString, ExportString, RouteString;
+ UNICODE_STRING InstanceString;
+ PWCHAR pPath, BaseFileName;
+ USHORT Len;
+ UINT Instances = 0;
+
+ MiniBlock = (PNDIS_M_DRIVER_BLOCK)MacBlock;
+
+ //
+ // Set up LQueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Linkage key below this driver's key
+ //
+ LQueryTable[0].QueryRoutine = NULL;
+ LQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ LQueryTable[0].Name = L"Linkage";
+
+ //
+ // 2) Call ndisSaveLinkage for "Bind" (as a single multi-string),
+ // which will allocate storage and save the data in BindData.
+ //
+ LQueryTable[1].QueryRoutine = ndisSaveLinkage;
+ LQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ LQueryTable[1].Name = L"Bind";
+ LQueryTable[1].EntryContext = (PVOID)&BindData;
+ LQueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 3) Call ndisSaveLinkage for "Export" (as a single multi-string),
+ // which will allocate storage and save the data in BindData.
+ //
+ LQueryTable[2].QueryRoutine = ndisSaveLinkage;
+ LQueryTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ LQueryTable[2].Name = L"Export";
+ LQueryTable[2].EntryContext = (PVOID)&ExportData;
+ LQueryTable[2].DefaultType = REG_NONE;
+
+ //
+ // 4) Call ndisSaveLinkage for "Route" (as a single multi-string),
+ // which will allocate storage and save the data in BindData.
+ //
+ LQueryTable[3].QueryRoutine = ndisSaveLinkage;
+ LQueryTable[3].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ LQueryTable[3].Name = L"Route";
+ LQueryTable[3].EntryContext = (PVOID)&RouteData;
+ LQueryTable[3].DefaultType = REG_NONE;
+
+ //
+ // 5) Stop
+ //
+ LQueryTable[4].QueryRoutine = NULL;
+ LQueryTable[4].Flags = 0;
+ LQueryTable[4].Name = NULL;
+
+
+ //
+ // Allocate room for a null-terminated version of the config path
+ //
+ if ((MiniBlock->MiniportIdField == (NDIS_HANDLE)0x01))
+ {
+ BaseNameString = &MiniBlock->BaseName;
+ }
+ else
+ {
+ BaseNameString = &MacBlock->BaseName;
+ }
+
+ BindData = NULL;
+ RouteData = NULL;
+ ExportData = NULL;
+
+ RegistryStatus = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
+ BaseNameString->Buffer,
+ LQueryTable,
+ (PVOID)NULL, // no context needed
+ NULL);
+
+ do
+ {
+ if (!NT_SUCCESS(RegistryStatus))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("Could not read Bind for %Z: %lx\n",
+ BaseNameString, RegistryStatus));
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // For each binding, initiate loading the driver
+ //
+
+ for (CurBind = BindData, CurExport = ExportData, CurRoute = RouteData;
+ *CurBind != 0;
+ CurBind = (PWCHAR)((PUCHAR)CurBind + BindString.MaximumLength),
+ CurExport = (PWCHAR)((PUCHAR)CurExport + ExportString.MaximumLength),
+ CurRoute = (PWCHAR)((PUCHAR)CurRoute + RouteString.MaximumLength))
+ {
+ RtlInitUnicodeString (&BindString, CurBind);
+ RtlInitUnicodeString (&ExportString, CurExport);
+ RtlInitUnicodeString (&RouteString, CurRoute);
+
+ Len = BindString.Length / sizeof(WCHAR);
+ pPath = BindString.Buffer + Len - 1;
+
+ //
+ // CurBindString is of the form '\Device\<DriverName><DriverInstance>
+ // e.g. \Device\Lance1.
+ // Get basename ("Lance1" in this example) from this and call
+ // ndisInitializeAdapter() to do the rest
+ //
+ BaseFileName = BindString.Buffer;
+
+ for (i = Len; i > 0; i--, pPath--)
+ {
+ //
+ // If pPath points to a directory separator, set fileBaseName to
+ // the character after the separator.
+ //
+
+ if (*pPath == OBJ_NAME_PATH_SEPARATOR)
+ {
+ BaseFileName = pPath + 1;
+ break;
+ }
+ }
+
+ RtlInitUnicodeString(&InstanceString, BaseFileName);
+ if ((DeviceInstance == NULL) ||
+ NDIS_EQUAL_UNICODE_STRING(DeviceInstance, &InstanceString))
+ {
+ Status = ndisUpdateDriverInstance(&InstanceString,
+ &BindString,
+ &ExportString,
+ &RouteString);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ Status = ndisInitializeAdapter(MiniBlock, &InstanceString);
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ ++Instances;
+
+ //
+ // Set the next available processor for the next
+ // NIC to use.
+ //
+ if (0 == ndisCurrentProcessor--)
+ {
+ ndisCurrentProcessor = ndisMaximumProcessor;
+ }
+ }
+ }
+ }
+ }
+ } while (FALSE);
+
+ if (BindData != NULL)
+ FREE_POOL(BindData);
+ if (ExportData != NULL)
+ FREE_POOL(ExportData);
+ if (RouteData != NULL)
+ FREE_POOL(RouteData);
+
+ return ((Instances > 0) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE);
+}
+
+NDIS_STATUS
+ndisInitializeAdapter(
+ IN PNDIS_M_DRIVER_BLOCK pMiniBlock,
+ IN PUNICODE_STRING ServiceName // Relative to Services key
+ )
+{
+ PNDIS_MAC_BLOCK pMacBlock;
+ NDIS_WRAPPER_CONFIGURATION_HANDLE ConfigurationHandle;
+#define PQueryTable ConfigurationHandle.ParametersQueryTable
+#define Db ConfigurationHandle.Db
+ NDIS_CONFIGURATION_HANDLE TmpConfigHandle;
+ NDIS_STRING BusTypeStr = NDIS_STRING_CONST("BusType");
+ NDIS_STRING BusNumberStr = NDIS_STRING_CONST("BusNumber");
+ NDIS_STRING SlotNumberStr = NDIS_STRING_CONST("SlotNumber");
+ NDIS_STRING PcmciaStr = NDIS_STRING_CONST("Pcmcia");
+ NDIS_STRING PciIdStr = NDIS_STRING_CONST("AdapterCFID");
+ NDIS_STRING EisaIdStr = NDIS_STRING_CONST("EisaCompressedId");
+ NDIS_STRING McaIdStr = NDIS_STRING_CONST("McaPosId");
+ PWSTR Bind = NULL, Export = NULL;
+ UNICODE_STRING ExportName, ParmPath;
+ NDIS_STATUS NdisStatus;
+ NTSTATUS RegistryStatus;
+ BOOLEAN IsAMiniport, LayeredDriver, Pcmcia = FALSE;
+ PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
+#define LQueryTable ConfigurationHandle.ParametersQueryTable
+
+ do
+ {
+ pMacBlock = (PNDIS_MAC_BLOCK)pMiniBlock;
+ IsAMiniport = (pMiniBlock->MiniportIdField == (NDIS_HANDLE)0x01);
+
+ //
+ // Set up LQueryTable to do the following:
+ //
+
+ //
+ // 1.
+ // Switch to the Linkage key below this driver instance key
+ //
+
+ LQueryTable[0].QueryRoutine = NULL;
+ LQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ LQueryTable[0].Name = L"Linkage";
+
+ //
+ // 2.
+ // Call ndisSaveLinkage for "Bind" (as a single multi-string),
+ // which will allocate storage and save the data in Bind.
+ //
+
+ LQueryTable[1].QueryRoutine = ndisSaveLinkage;
+ LQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ LQueryTable[1].Name = L"Bind";
+ LQueryTable[1].EntryContext = (PVOID)&Bind;
+ LQueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 3.
+ // Call ndisSaveLinkage for "Export" (as a single multi-string)
+ // which will allocate storage and save the data in Export.
+ //
+
+ LQueryTable[2].QueryRoutine = ndisSaveLinkage;
+ LQueryTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ LQueryTable[2].Name = L"Export";
+ LQueryTable[2].EntryContext = (PVOID)&Export;
+ LQueryTable[2].DefaultType = REG_NONE;
+
+ //
+ // 4.
+ // Call ndisCheckRoute for "Route" (as a single multi-string)
+ // which will set LayeredDriver to TRUE for a layered driver (this
+ // is optional, the default is FALSE).
+ //
+
+ LQueryTable[3].QueryRoutine = ndisCheckRoute;
+ LQueryTable[3].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
+ LQueryTable[3].Name = L"Route";
+ LQueryTable[3].EntryContext = (PVOID)&LayeredDriver;
+ LQueryTable[3].DefaultType = REG_NONE;
+
+ LayeredDriver = FALSE;
+
+ //
+ // 5.
+ // Stop
+ //
+
+ LQueryTable[4].QueryRoutine = NULL;
+ LQueryTable[4].Flags = 0;
+ LQueryTable[4].Name = NULL;
+
+ LayeredDriver = FALSE;
+ ParmPath.Buffer = NULL;
+
+ RegistryStatus = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
+ ServiceName->Buffer,
+ LQueryTable,
+ (PVOID)NULL, // no context needed
+ NULL);
+
+ if (!NT_SUCCESS(RegistryStatus))
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("Could not read Bind/Export/Route for %Z: %lx\n",
+ IsAMiniport ?
+ pMiniBlock->BaseName.Buffer :
+ pMacBlock->BaseName.Buffer,
+ RegistryStatus));
+ NdisStatus = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // 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
+ // "Driver1" for the first call to AddAdapter, "Driver2" for the
+ // second, etc., and parameters are read from
+ // "..\Services\Driver1\Parameters" for the first call to
+ // AddAdapter, "...\Services\Driver2\Parameters" for the second
+ // call, etc.
+ //
+ // Set up ParametersQueryTable. We set most of it up here,
+ // then call the MAC's AddAdapter (or Miniport's Initialize)
+ // 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 ndisSaveParameter) to read the value
+ // specified.
+ //
+
+ //
+ // 1.
+ // Allocate space for the string "DriverInstance\Parameters" which is passed as a
+ // parameter to RtlQueryRegistryValues. Construct this string in that buffer and
+ // setup PQueryTable[3].
+ //
+ RtlInitUnicodeString(&ExportName, L"\\Parameters");
+ ParmPath.MaximumLength = ServiceName->Length + ExportName.Length + sizeof(WCHAR);
+ ParmPath.Length = 0;
+ if ((ParmPath.Buffer = (PWSTR)ALLOC_FROM_POOL(ParmPath.MaximumLength, NDIS_TAG_NAME_BUF)) == NULL)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
+ ("Could not read allocate space for path to parameters\n"));
+ NdisStatus = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ RtlCopyUnicodeString(&ParmPath, ServiceName);
+ RtlAppendUnicodeStringToString(&ParmPath, &ExportName);
+
+ //
+ // 2) Call ndisSaveParameter 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.
+ //
+
+ PQueryTable[0].QueryRoutine = ndisSaveParameters;
+ PQueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ PQueryTable[0].DefaultType = REG_NONE;
+ //
+ // The following fields are filled in during NdisReadConfiguration
+ //
+ // PQueryTable[0].Name = KeywordBuffer;
+ // PQueryTable[0].EntryContext = ParameterValue;
+
+ //
+ // 3.
+ // Stop
+ //
+
+ PQueryTable[1].QueryRoutine = NULL;
+ PQueryTable[1].Flags = 0;
+ PQueryTable[1].Name = NULL;
+
+ //
+ // NOTE: Some fields in ParametersQueryTable[3 & 4] are used to
+ // store information for later retrieval.
+ //
+ PQueryTable[3].QueryRoutine = NULL;
+ PQueryTable[3].Name = ParmPath.Buffer;
+ PQueryTable[3].EntryContext = NULL;
+ PQueryTable[3].DefaultData = NULL;
+
+ //
+ // Save the driver name here; later we will use this as
+ // a parameter to RtlQueryRegistryValues.
+ //
+ if (LayeredDriver)
+ {
+ //
+ // This will be returned by NdisReadBindingInformation.
+ //
+ PQueryTable[3].EntryContext = Bind;
+ }
+
+ // Now read bustype/busnumber for this adapter and save it
+ TmpConfigHandle.KeyQueryTable = PQueryTable;
+ TmpConfigHandle.ParameterList = NULL;
+
+ Db.BusNumber = (ULONG)(-1);
+ Db.BusType = (NDIS_INTERFACE_TYPE)(-1);
+ Db.SlotNumber = (ULONG)(-1);
+ Db.BusId = 0;
+
+ //
+ // Read Bus Number
+ //
+ NdisReadConfiguration(&NdisStatus,
+ &ReturnedValue,
+ &TmpConfigHandle,
+ &BusNumberStr,
+ NdisParameterInteger);
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS)
+ {
+ Db.BusNumber = ReturnedValue->ParameterData.IntegerData;
+ }
+
+ //
+ // Read Slot Number
+ //
+ NdisReadConfiguration(&NdisStatus,
+ &ReturnedValue,
+ &TmpConfigHandle,
+ &SlotNumberStr,
+ NdisParameterInteger);
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS)
+ {
+ Db.SlotNumber = ReturnedValue->ParameterData.IntegerData;
+ }
+
+ //
+ // Read Bus Type
+ //
+ NdisReadConfiguration(&NdisStatus,
+ &ReturnedValue,
+ &TmpConfigHandle,
+ &BusTypeStr,
+ NdisParameterInteger);
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS)
+ {
+ Db.BusType = (NDIS_INTERFACE_TYPE)(ReturnedValue->ParameterData.IntegerData);
+ if (Db.BusType == NdisInterfacePcMcia)
+ Db.BusType = NdisInterfaceIsa; // Fix the folks who chose Pcmcia
+
+ //
+ // Now read the bus-id for Pci/Mca/Eisa
+ //
+ switch (Db.BusType)
+ {
+ case NdisInterfaceEisa:
+ NdisReadConfiguration(&NdisStatus,
+ &ReturnedValue,
+ &TmpConfigHandle,
+ &EisaIdStr,
+ NdisParameterInteger);
+ break;
+ case NdisInterfaceMca:
+ NdisReadConfiguration(&NdisStatus,
+ &ReturnedValue,
+ &TmpConfigHandle,
+ &McaIdStr,
+ NdisParameterInteger);
+ break;
+ case NdisInterfacePci:
+ NdisReadConfiguration(&NdisStatus,
+ &ReturnedValue,
+ &TmpConfigHandle,
+ &PciIdStr,
+ NdisParameterInteger);
+ break;
+ }
+ if (NdisStatus == NDIS_STATUS_SUCCESS)
+ {
+ Db.BusId = ReturnedValue->ParameterData.IntegerData;
+ }
+ }
+
+ if (Db.BusId != 0)
+ {
+ switch (Db.BusType)
+ {
+ case NdisInterfaceEisa:
+ case NdisInterfaceMca:
+ case NdisInterfacePci:
+ NdisStatus = ndisFixBusInformation(&TmpConfigHandle, &Db);
+ break;
+ default:
+ NdisStatus = NDIS_STATUS_SUCCESS;
+ break;
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+ }
+
+ //
+ // Check if this is pcmcia ?
+ //
+ NdisReadConfiguration(&NdisStatus,
+ &ReturnedValue,
+ &TmpConfigHandle,
+ &PcmciaStr,
+ NdisParameterInteger);
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS)
+ {
+ Pcmcia = (ReturnedValue->ParameterData.IntegerData != 0);
+ }
+
+ if (Pcmcia)
+ {
+ NdisStatus = ndisCheckIfPcmciaCardPresent(pMiniBlock);
+ if (NdisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+ }
+
+ PQueryTable[3].DefaultType = Db.BusType;
+ PQueryTable[3].DefaultLength = Db.BusNumber;
+ PQueryTable[3].DefaultData = NULL;
+ PQueryTable[3].Flags = 0;
+
+ PQueryTable[4].DefaultLength = Db.SlotNumber;
+
+ //
+ // 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();
+ MacReferencePackage();
+ CoReferencePackage();
+
+ RtlInitUnicodeString (&ExportName, Export);
+ ConfigurationHandle.DriverBaseName = ServiceName;
+
+ NdisStatus = NDIS_STATUS_SUCCESS;
+
+ if (IsAMiniport)
+ {
+ NdisStatus = ndisMInitializeAdapter(pMiniBlock,
+ &ConfigurationHandle,
+ &ExportName,
+ &Db);
+ }
+ else
+ {
+ //
+ // Save the Driver Object with the Configuration Handle.
+ //
+ ConfigurationHandle.DriverObject = pMacBlock->NdisMacInfo->NdisWrapperDriver;
+
+ //
+ // NDIS 3.0 MAC
+ //
+ NdisStatus = (pMacBlock->MacCharacteristics.AddAdapterHandler)(pMacBlock->MacMacContext,
+ &ConfigurationHandle,
+ &ExportName);
+ //
+ // Free the slot information buffer
+ //
+ if (PQueryTable[3].DefaultData != NULL)
+ {
+ FREE_POOL(PQueryTable[3].DefaultData);
+ }
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Update the Db from the Config context
+ //
+ Db.SlotNumber= PQueryTable[4].DefaultLength;
+ Db.BusNumber = PQueryTable[3].DefaultLength;
+ }
+ }
+
+ //
+ // If the initialization failed, cleanup
+ //
+ if ((NdisStatus != NDIS_STATUS_SUCCESS) && (Db.BusId != 0))
+ {
+ ndisDeleteGlobalDb(Db.BusType,
+ Db.BusId,
+ Db.BusNumber,
+ Db.SlotNumber);
+ }
+ else if ((NdisStatus == NDIS_STATUS_SUCCESS) &&
+ (Db.BusId == 0))
+ {
+ //
+ // If this adapter did not have a bus-id in the registry,
+ // do it a favor and write it.
+ //
+ switch (Db.BusType)
+ {
+ case NdisInterfaceEisa:
+ case NdisInterfaceMca:
+ case NdisInterfacePci:
+ ndisAddBusInformation(&TmpConfigHandle, &Db);
+ break;
+ }
+ }
+
+ //
+ // 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();
+ MacDereferencePackage();
+ CoDereferencePackage();
+
+ } while (FALSE);
+
+ if (ParmPath.Buffer != NULL)
+ {
+ FREE_POOL(ParmPath.Buffer);
+ }
+
+ if (Bind != NULL)
+ {
+ FREE_POOL(Bind);
+ }
+
+ if (Export != NULL)
+ {
+ FREE_POOL(Export);
+ }
+
+ return NdisStatus;
+}
+
+NDIS_STATUS
+ndisMInitializeAdapter(
+ IN PNDIS_M_DRIVER_BLOCK pMiniBlock,
+ IN PNDIS_WRAPPER_CONFIGURATION_HANDLE pConfigurationHandle,
+ IN PUNICODE_STRING pExportName,
+ IN PBUS_SLOT_DB pDb
+ )
+{
+ BOOLEAN FreeDevice;
+ BOOLEAN DerefDriver;
+ BOOLEAN FreeBuffer;
+ BOOLEAN FreeArcnetLookaheadBuffer;
+ BOOLEAN Dequeue;
+ BOOLEAN ExtendedError;
+ BOOLEAN FreeWorkItemStorage;
+ BOOLEAN FreeDeferredTimer;
+ BOOLEAN FreePacketArray;
+ PDEVICE_OBJECT pTmpDevice;
+ NTSTATUS NtStatus;
+ LONG ErrorCode;
+ PNDIS_MINIPORT_BLOCK Miniport = NULL;
+ UNICODE_STRING SymbolicLink;
+ WCHAR SymLnkBuf[40];
+ NDIS_STATUS MiniportInitializeStatus = NDIS_STATUS_SUCCESS;
+ NDIS_STATUS OpenErrorStatus;
+ NDIS_STATUS NdisStatus;
+
+ UINT SelectedMediumIndex;
+
+ ULONG MaximumLongAddresses;
+ UCHAR CurrentLongAddress[6];
+ ULONG MaximumShortAddresses;
+ UCHAR CurrentShortAddress[2];
+ UINT PacketFilter;
+ UCHAR i;
+ BOOLEAN LocalLock;
+ PARC_BUFFER_LIST Buffer;
+ PVOID DataBuffer;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+ PSINGLE_LIST_ENTRY Link;
+
+ //
+ // Initialize device.
+ //
+ if (!ndisReferenceDriver((PNDIS_M_DRIVER_BLOCK)pMiniBlock))
+ {
+ //
+ // The driver is closing.
+ //
+ return NDIS_STATUS_FAILURE;
+ }
+
+ //
+ // Initialize locals.
+ //
+ ErrorCode = 0;
+ FreeDevice = FALSE;
+ DerefDriver = FALSE;
+ FreeBuffer = FALSE;
+ FreeArcnetLookaheadBuffer = FALSE;
+ Dequeue = FALSE;
+ ExtendedError = FALSE;
+ FreeWorkItemStorage = FALSE;
+ FreeDeferredTimer = FALSE;
+ FreePacketArray = FALSE;
+ PacketFilter = 0x1;
+
+ do
+ {
+ //
+ // Save the Driver Object with the configuration handle.
+ //
+ pConfigurationHandle->DriverObject = pMiniBlock->NdisDriverInfo->NdisWrapperDriver;
+
+ DerefDriver = TRUE;
+ NtStatus = IoCreateDevice(pMiniBlock->NdisDriverInfo->NdisWrapperDriver,
+ sizeof(NDIS_MINIPORT_BLOCK) +
+ sizeof(NDIS_WRAPPER_CONTEXT) +
+ pConfigurationHandle->DriverBaseName->Length,
+ pExportName,
+ FILE_DEVICE_PHYSICAL_NETCARD,
+ 0,
+ FALSE, // exclusive flag
+ &pTmpDevice);
+ if (NtStatus != STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ FreeDevice = TRUE;
+
+ //
+ // 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)pTmpDevice->DeviceExtension + 1);
+ ZeroMemory(Miniport, sizeof(PNDIS_MINIPORT_BLOCK));
+
+ //
+ // Setup debug information if needed.
+ //
+ ndisMInitializeDebugInformation(Miniport);
+
+ Miniport->WrapperContext = pTmpDevice->DeviceExtension;
+ Miniport->BaseName.Buffer = (PWSTR)((PUCHAR)Miniport + sizeof(NDIS_MINIPORT_BLOCK));
+ Miniport->BaseName.MaximumLength =
+ Miniport->BaseName.Length = pConfigurationHandle->DriverBaseName->Length;
+ RtlUpcaseUnicodeString(&Miniport->BaseName,
+ pConfigurationHandle->DriverBaseName,
+ FALSE);
+
+ //
+ // Create symbolic link for the device
+ //
+ SymbolicLink.Buffer = SymLnkBuf;
+ SymbolicLink.Length = sizeof(L"\\DosDevices\\") - sizeof(WCHAR);
+ SymbolicLink.MaximumLength = sizeof(SymLnkBuf);
+ RtlCopyMemory(SymLnkBuf, L"\\DosDevices\\", sizeof(L"\\DosDevices\\"));
+ RtlAppendUnicodeStringToString(&SymbolicLink, &Miniport->BaseName);
+ IoCreateSymbolicLink(&SymbolicLink, pExportName);
+
+ Miniport->BusType = pDb->BusType;
+ Miniport->BusId = pDb->BusId;
+ Miniport->SlotNumber = pDb->SlotNumber;
+ Miniport->BusNumber = pDb->BusNumber;
+ Miniport->DeviceObject = pTmpDevice;
+ Miniport->DriverHandle = pMiniBlock;
+ Miniport->MiniportName.Buffer = (PWSTR)ALLOC_FROM_POOL(pExportName->MaximumLength,
+ NDIS_TAG_NAME_BUF);
+ if (Miniport->MiniportName.Buffer == NULL)
+ {
+ break;
+ }
+ FreeBuffer = TRUE;
+
+ Miniport->MiniportName.MaximumLength = pExportName->MaximumLength;
+ Miniport->MiniportName.Length = pExportName->Length;
+
+ CopyMemory(Miniport->MiniportName.Buffer,
+ pExportName->Buffer,
+ pExportName->MaximumLength);
+
+ Miniport->AssignedProcessor = ndisValidProcessors[ndisCurrentProcessor];
+ Miniport->SendResourcesAvailable = 0x00FFFFFF;
+ NdisAllocateSpinLock(&Miniport->Lock);
+
+ // Start off with the null filter
+ Miniport->PacketIndicateHandler = ndisMIndicatePacket;
+
+ //
+ // Initialize the handlers to non-full duplex
+ //
+ Miniport->ProcessDeferredHandler = ndisMProcessDeferred;
+ Miniport->QueueWorkItemHandler = ndisMQueueWorkItem;
+ Miniport->QueueNewWorkItemHandler = ndisMQueueNewWorkItem;
+ Miniport->DeQueueWorkItemHandler = ndisMDeQueueWorkItem;
+
+ Miniport->SendCompleteHandler = NdisMSendComplete;
+ Miniport->SendResourcesHandler = NdisMSendResourcesAvailable;
+ Miniport->ResetCompleteHandler = NdisMResetComplete;
+
+ //
+ // And optimize Dpc/Isr stuff
+ //
+ Miniport->HandleInterruptHandler = Miniport->DriverHandle->MiniportCharacteristics.HandleInterruptHandler;
+ Miniport->DisableInterruptHandler = Miniport->DriverHandle->MiniportCharacteristics.DisableInterruptHandler;
+ Miniport->EnableInterruptHandler = Miniport->DriverHandle->MiniportCharacteristics.EnableInterruptHandler;
+ Miniport->DeferredSendHandler = ndisMStartSends;
+
+ //
+ // Set some flags describing the miniport.
+ //
+ if (pMiniBlock->MiniportCharacteristics.MajorNdisVersion == 4)
+ {
+ if (pMiniBlock->MiniportCharacteristics.MinorNdisVersion >= 0)
+ {
+ //
+ // This is an NDIS 4.0 miniport.
+ //
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_IS_NDIS_4_0);
+
+ //
+ // Does this miniport indicate packets?
+ //
+ if (pMiniBlock->MiniportCharacteristics.ReturnPacketHandler)
+ {
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_INDICATES_PACKETS);
+ }
+
+ //
+ // Can this miniport handle multiple sends?
+ //
+ if (pMiniBlock->MiniportCharacteristics.SendPacketsHandler)
+ {
+ MINIPORT_SET_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY);
+ Miniport->DeferredSendHandler = ndisMStartSendPackets;
+ }
+ }
+
+ if (pMiniBlock->MiniportCharacteristics.MinorNdisVersion == 1)
+ {
+ //
+ // This is an NDIS 4.1 miniport.
+ //
+ MINIPORT_SET_FLAG(Miniport, (fMINIPORT_IS_NDIS_4_1 | fMINIPORT_INDICATES_PACKETS));
+ if (pMiniBlock->MiniportCharacteristics.CoCreateVcHandler != NULL)
+ {
+ //
+ // This is a connection-oriented miniport.
+ //
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_IS_CO);
+ }
+ }
+ }
+
+ NdisInitializeRef(&Miniport->Ref);
+
+ INITIALIZE_DPC(&Miniport->Dpc,
+ (Miniport->Flags & fMINIPORT_IS_CO) ?
+ ndisMCoDpcTimer : ndisMDpcTimer,
+ Miniport);
+
+ Miniport->CheckForHangTimeout = 2000;
+ NdisInitializeTimer(&Miniport->WakeUpDpcTimer, ndisMWakeUpDpc, Miniport);
+
+ //
+ // Allocate a pool of work items to start with.
+ //
+ for (i = 0, WorkItem = NULL; i < 10; i++)
+ {
+ //
+ // Allocate a work item.
+ //
+ WorkItem = ALLOC_FROM_POOL(sizeof(NDIS_MINIPORT_WORK_ITEM), NDIS_TAG_WORK_ITEM);
+ if (NULL == WorkItem)
+ {
+ break;
+ }
+
+ //
+ // Initialize the work item.
+ //
+ NdisZeroMemory(WorkItem, sizeof(NDIS_MINIPORT_WORK_ITEM));
+
+ //
+ // Place the work item on the free queue.
+ //
+ PushEntryList(&Miniport->WorkItemFreeQueue, &WorkItem->Link);
+ }
+
+ //
+ // Did we get work items allocate?
+ //
+ if (Miniport->WorkItemFreeQueue.Next != NULL)
+ {
+ FreeWorkItemStorage = TRUE;
+ }
+
+ //
+ // Did we get enough work items allocated?
+ // WorkItem will be NULL if we failed to allocate
+ // one of them.
+ //
+ if (NULL == WorkItem)
+ {
+ break;
+ }
+
+ //
+ // Set up the list of workitems that only require one
+ // workitem at any given time.
+ //
+ for (i = 0; i < NUMBER_OF_SINGLE_WORK_ITEMS; i++)
+ {
+ Link = PopEntryList(&Miniport->WorkItemFreeQueue);
+ PushEntryList(&Miniport->SingleWorkItems[i], Link);
+ }
+
+ //
+ // Enqueue the miniport on the driver block.
+ //
+ if (!ndisQueueMiniportOnDriver(Miniport, pMiniBlock))
+ {
+ //
+ // The Driver is closing, undo what we have done.
+ //
+ break;
+ }
+ Dequeue = TRUE;
+
+ //
+ // Allocate memory for a timer structure.
+ //
+ Miniport->DeferredTimer = ALLOC_FROM_POOL(sizeof(NDIS_TIMER), NDIS_TAG_DFRD_TMR);
+ ASSERT(Miniport->DeferredTimer != NULL);
+ if (NULL == Miniport->DeferredTimer)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Failed to allocate memory for the full-duplex timer.\n"));
+ break;
+ }
+
+ FreeDeferredTimer = TRUE;
+
+ //
+ // Initialize the timer with the
+ //
+ NdisInitializeTimer(Miniport->DeferredTimer,
+ (PVOID)ndisMDeferredTimerDpc,
+ (PVOID)Miniport);
+
+ //
+ // Initialize work-item for returning orphaned packets
+ //
+ INITIALIZE_WORK_ITEM(&Miniport->WorkItem, ndisMLazyReturnPackets, Miniport);
+
+ //
+ // 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)) ||
+ !TrCreateFilter(ndisMChangeFunctionalAddress,
+ ndisMChangeGroupAddress,
+ ndisMChangeClass,
+ ndisMCloseAction,
+ CurrentLongAddress,
+ &Miniport->Lock,
+ &(Miniport->TrDB)) ||
+ !FddiCreateFilter(1,
+ 1,
+ ndisMChangeFddiAddresses,
+ ndisMChangeClass,
+ ndisMCloseAction,
+ CurrentLongAddress,
+ CurrentShortAddress,
+ &Miniport->Lock,
+ &(Miniport->FddiDB)) ||
+ !ArcCreateFilter(Miniport,
+ ndisMChangeClass,
+ ndisMCloseAction,
+ CurrentLongAddress[0],
+ &Miniport->Lock,
+ &(Miniport->ArcDB)))
+ {
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0);
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Could not create the dummy filter!\n"));
+
+ break;
+ }
+
+ //
+ // Save the miniport block with the filter libraries.
+ //
+ Miniport->EthDB->Miniport = Miniport;
+ Miniport->TrDB->Miniport = Miniport;
+ Miniport->FddiDB->Miniport = Miniport;
+
+ //
+ // Call adapter callback. The current value for "Export"
+ // is what we tell him to name this device.
+ //
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
+
+ MiniportInitializeStatus =
+ (pMiniBlock->MiniportCharacteristics.InitializeHandler)(
+ &OpenErrorStatus,
+ &SelectedMediumIndex,
+ ndisMediumArray,
+ ndisMediumArraySize/sizeof(NDIS_MEDIUM),
+ (NDIS_HANDLE)(Miniport),
+ (NDIS_HANDLE)pConfigurationHandle);
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ //
+ // Free the slot information buffer
+ //
+ if (pConfigurationHandle->ParametersQueryTable[3].DefaultData != NULL)
+ {
+ FREE_POOL(pConfigurationHandle->ParametersQueryTable[3].DefaultData);
+ }
+
+ if (MiniportInitializeStatus == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Update the Db from the Miniport
+ //
+ pDb->BusNumber = Miniport->BusNumber;
+ pDb->SlotNumber = Miniport->SlotNumber;
+
+ ASSERT(SelectedMediumIndex < (ndisMediumArraySize/sizeof(NDIS_MEDIUM)));
+
+ Miniport->MediaType = ndisMediumArray[SelectedMediumIndex];
+
+ INITIALIZE_EVENT(&Miniport->RequestEvent);
+
+ RESET_EVENT(&Miniport->RequestEvent);
+
+ //
+ // Set Maximumlookahead to 0 as default. For lan media query the real
+ // stuff.
+ //
+ if ((Miniport->MediaType < NdisMediumMax) &&
+ ndisMediaTypeCl[Miniport->MediaType])
+ {
+ //
+ // Query maximum lookahead
+ //
+ ErrorCode = ndisMDoMiniportOp(Miniport,
+ TRUE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ &MaximumLongAddresses,
+ sizeof(MaximumLongAddresses),
+ 0x1);
+ if (ErrorCode != 0)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error querying the OID_GEN_MAXIMUM_LOOKAHEAD\n"));
+
+ break;
+ }
+ }
+
+ //
+ // 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;
+
+ //
+ // Assume we will succeed with the lookahead allocation.
+ //
+ ExtendedError = FALSE;
+
+ //
+ // allocate a lookahead buffer for arcnet.
+ //
+ Miniport->ArcnetLookaheadBuffer = ALLOC_FROM_POOL(
+ NDIS_M_MAX_LOOKAHEAD,
+ NDIS_TAG_LA_BUF);
+
+ ASSERT(Miniport->ArcnetLookaheadBuffer != NULL);
+ if (Miniport->ArcnetLookaheadBuffer == NULL)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Could not allocate arcnet lookahead buffer\n"));
+
+ ExtendedError = TRUE;
+ }
+ else
+ {
+ FreeArcnetLookaheadBuffer = TRUE;
+
+ NdisZeroMemory(Miniport->ArcnetLookaheadBuffer,
+ Miniport->MaximumLookahead);
+ }
+
+ break;
+
+ case NdisMediumWan:
+ Miniport->MaximumLookahead = 1514;
+ break;
+
+ case NdisMediumIrda:
+ case NdisMediumWirelessWan:
+ case NdisMediumLocalTalk:
+ Miniport->MaximumLookahead = MaximumLongAddresses;
+ break;
+ }
+
+ //
+ // Was there an error?
+ //
+ if (ExtendedError)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Extended error when processing OID_GEN_MAXIMUM_LOOOKAHEAD\n"));
+ break;
+ }
+
+ //
+ // Set MacOptions to 0 as default. For lan media query the real
+ // stuff. We also need to call this for lan drivers.
+ //
+ Miniport->MacOptions = 0;
+ if (((Miniport->MediaType < NdisMediumMax) &&
+ ndisMediaTypeCl[Miniport->MediaType]) ||
+ (NdisMediumWan == Miniport->MediaType))
+ {
+ //
+ // Query mac options
+ //
+ ErrorCode = ndisMDoMiniportOp(Miniport,
+ TRUE,
+ OID_GEN_MAC_OPTIONS,
+ &MaximumLongAddresses,
+ sizeof(MaximumLongAddresses),
+ 0x3);
+ if (ErrorCode != 0)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error querying OID_GEN_MAC_OPTIONS\n"));
+
+ break;
+ }
+
+ Miniport->MacOptions = (UINT)MaximumLongAddresses;
+ }
+ else
+ {
+ KIRQL OldIrql;
+
+ //
+ // We can't call process deferred at a low irql and
+ // we need to get the local lock.
+ //
+ RAISE_IRQL_TO_DISPATCH(&OldIrql);
+ BLOCK_LOCK_MINIPORT_DPC(Miniport, LocalLock);
+
+ //
+ // Queue a dpc to fire.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemDpc, &Miniport->Dpc, NULL);
+ NDISM_PROCESS_DEFERRED(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ LOWER_IRQL(OldIrql);
+ }
+
+ //
+ // This is a full duplex driver if the miniport says it is
+ // and they say they are going to handle loopback and the
+ // number of system processors is more than one.
+ //
+ if (((Miniport->MacOptions & NDIS_MAC_OPTION_FULL_DUPLEX) &&
+ (NdisSystemProcessorCount() > 1))
+ ||
+ MINIPORT_TEST_FLAG(Miniport, fMINIPORT_INTERMEDIATE_DRIVER))
+ {
+ //
+ // Allocate a workitem lock.
+ //
+ INITIALIZE_SPIN_LOCK(&Miniport->WorkLock);
+
+ //
+ // Is this an intermediate driver?
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_INTERMEDIATE_DRIVER))
+ {
+ Miniport->ProcessDeferredHandler = ndisMProcessDeferredFullDuplex;
+ Miniport->QueueWorkItemHandler = ndisIMQueueWorkItem;
+ Miniport->QueueNewWorkItemHandler = ndisIMQueueNewWorkItem;
+ }
+ else
+ {
+ //
+ // Regular full-duplex miniport.
+ //
+ Miniport->ProcessDeferredHandler = ndisMProcessDeferredFullDuplex;
+ Miniport->QueueWorkItemHandler = ndisMQueueWorkItemFullDuplex;
+ Miniport->QueueNewWorkItemHandler = ndisMQueueNewWorkItemFullDuplex;
+ }
+
+ //
+ // Allocate a separate spin lock for the send path.
+ //
+ NdisAllocateSpinLock(&Miniport->SendLock);
+
+ //
+ // Use the full duplex send complete and resources
+ // available handler.
+ //
+ Miniport->SendCompleteHandler = ndisMSendCompleteFullDuplex;
+ Miniport->SendResourcesHandler = ndisMSendResourcesAvailableFullDuplex;
+ Miniport->ResetCompleteHandler = ndisMResetCompleteFullDuplex;
+
+ //
+ // Do we need a send packets handler or a send handler?
+ //
+ if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY))
+ {
+ Miniport->DeferredSendHandler = ndisMStartSendPacketsFullDuplex;
+ }
+ else
+ {
+ Miniport->DeferredSendHandler = ndisMStartSendsFullDuplex;
+ }
+
+ //
+ // Set the full duplex flag.
+ //
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_FULL_DUPLEX);
+ }
+ else
+ {
+ //
+ // Make sure this is clear if something doesn't match.
+ //
+ Miniport->MacOptions &= ~NDIS_MAC_OPTION_FULL_DUPLEX;
+ }
+
+ if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY))
+ {
+ //
+ // If this is a NDIS 4.0 miniport that supports the
+ // SendPacketsHandler then we need to query the number of
+ // packets that the miniport supports.
+ //
+ ErrorCode = ndisMDoMiniportOp(Miniport,
+ TRUE,
+ OID_GEN_MAXIMUM_SEND_PACKETS,
+ &MaximumLongAddresses,
+ sizeof(MaximumLongAddresses),
+ 0x3);
+ if (ErrorCode != 0)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error querying OID_GEN_MAXIMUM_SEND_PACKETS\n"));
+
+ break;
+ }
+
+ Miniport->MaximumSendPackets = (UINT)MaximumLongAddresses;
+
+ //
+ // Allocate memory for the send packet array.
+ //
+ Miniport->PacketArray = ALLOC_FROM_POOL(
+ sizeof(PNDIS_PACKET) * MaximumLongAddresses,
+ NDIS_TAG_DEFAULT);
+ if (NULL == Miniport->PacketArray)
+ {
+ break;
+ }
+
+ ZeroMemory(Miniport->PacketArray,
+ sizeof(PNDIS_PACKET) * Miniport->MaximumSendPackets);
+
+ FreePacketArray = TRUE;
+ }
+
+
+ //
+ // Create filter package
+ //
+ switch(Miniport->MediaType)
+ {
+ case NdisMedium802_3:
+
+ //
+ // Query maximum MulticastAddress
+ //
+ ErrorCode = ndisMDoMiniportOp(Miniport,
+ TRUE,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ &MaximumLongAddresses,
+ sizeof(MaximumLongAddresses),
+ 0x5);
+ if (ErrorCode != 0)
+ {
+ ExtendedError = TRUE;
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error querying OID_802_3_MAXIMUM_LIST_SIZE\n"));
+
+ break;
+ }
+
+ if (MaximumLongAddresses > NDIS_M_MAX_MULTI_LIST)
+ {
+ MaximumLongAddresses = NDIS_M_MAX_MULTI_LIST;
+ }
+
+ Miniport->MaximumLongAddresses = MaximumLongAddresses;
+
+ ErrorCode = ndisMDoMiniportOp(Miniport,
+ TRUE,
+ OID_802_3_CURRENT_ADDRESS,
+ &CurrentLongAddress,
+ sizeof(CurrentLongAddress),
+ 0x7);
+ if (ErrorCode != 0)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error querying OID_802_3_CURRENT_ADDRESS\n"));
+
+ ExtendedError = TRUE;
+ break;
+ }
+
+ //
+ // Now undo the bogus filter package. We lock
+ // the miniport so that no dpcs will get queued.
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
+
+ ndisMUndoBogusFilters(Miniport);
+
+ if (!EthCreateFilter(MaximumLongAddresses,
+ ndisMChangeEthAddresses,
+ ndisMChangeClass,
+ ndisMCloseAction,
+ CurrentLongAddress,
+ &Miniport->Lock,
+ &Miniport->EthDB))
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error creating the Ethernet filter database\n"));
+
+
+ //
+ // Halt the miniport driver
+ //
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ ErrorCode = 0x9;
+ ExtendedError = TRUE;
+ break;
+ }
+
+ //
+ // Save the miniport block with the filter library.
+ //
+ Miniport->EthDB->Miniport = Miniport;
+
+ // Set the indicate handler
+ Miniport->PacketIndicateHandler = EthFilterDprIndicateReceivePacket;
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ break;
+
+ case NdisMedium802_5:
+
+ ErrorCode = ndisMDoMiniportOp(
+ Miniport,
+ TRUE,
+ OID_802_5_CURRENT_ADDRESS,
+ &CurrentLongAddress,
+ sizeof(CurrentLongAddress),
+ 0xA);
+ if (ErrorCode != 0)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error querying OID_802_5_CURRENT_ADDRESS\n"));
+
+ ExtendedError = TRUE;
+ break;
+ }
+
+ //
+ // Now undo the bogus filter package. We lock
+ // the miniport so that no dpcs will get queued.
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
+
+ ndisMUndoBogusFilters(Miniport);
+
+ if (!TrCreateFilter(
+ ndisMChangeFunctionalAddress,
+ ndisMChangeGroupAddress,
+ ndisMChangeClass,
+ ndisMCloseAction,
+ CurrentLongAddress,
+ &Miniport->Lock,
+ &Miniport->TrDB))
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error creating the Token Ring filter database\n"));
+
+ //
+ // Halt the miniport driver
+ //
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ ErrorCode = 0xC;
+ ExtendedError = TRUE;
+ break;
+ }
+
+ //
+ // Save the miniport block with the filter library.
+ //
+ Miniport->TrDB->Miniport = Miniport;
+
+ // Set the indicate handler
+ Miniport->PacketIndicateHandler = TrFilterDprIndicateReceivePacket;
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ break;
+
+ case NdisMediumFddi:
+
+ //
+ // Query maximum MulticastAddress
+ //
+ ErrorCode = ndisMDoMiniportOp(
+ Miniport,
+ TRUE,
+ OID_FDDI_LONG_MAX_LIST_SIZE,
+ &MaximumLongAddresses,
+ sizeof(MaximumLongAddresses),
+ 0xD);
+ if (ErrorCode != 0)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error querying OID_FDDI_LONG_MAX_LIST_SIZE\n"));
+
+ ExtendedError = TRUE;
+ break;
+ }
+
+ if (MaximumLongAddresses > NDIS_M_MAX_MULTI_LIST)
+ {
+ MaximumLongAddresses = NDIS_M_MAX_MULTI_LIST;
+ }
+
+ Miniport->MaximumLongAddresses = MaximumLongAddresses;
+
+ //
+ // Query maximum MulticastAddress
+ //
+ ErrorCode = ndisMDoMiniportOp(Miniport,
+ TRUE,
+ OID_FDDI_SHORT_MAX_LIST_SIZE,
+ &MaximumShortAddresses,
+ sizeof(MaximumShortAddresses),
+ 0xF);
+ if (ErrorCode != 0)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error querying OID_FDDI_SHORT_MAX_LIST_SIZE\n"));
+
+ ExtendedError = TRUE;
+ break;
+ }
+
+ if (MaximumShortAddresses > NDIS_M_MAX_MULTI_LIST)
+ {
+ MaximumShortAddresses = NDIS_M_MAX_MULTI_LIST;
+ }
+
+ Miniport->MaximumShortAddresses = MaximumShortAddresses;
+
+ ErrorCode = ndisMDoMiniportOp(Miniport,
+ TRUE,
+ OID_FDDI_LONG_CURRENT_ADDR,
+ &CurrentLongAddress,
+ sizeof(CurrentLongAddress),
+ 0x11);
+ if (ErrorCode != 0)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error querying OID_FDDI_LONG_CURRENT_ADDR\n"));
+
+ ExtendedError = TRUE;
+ break;
+ }
+
+ ErrorCode = ndisMDoMiniportOp(Miniport,
+ TRUE,
+ OID_FDDI_SHORT_CURRENT_ADDR,
+ &CurrentShortAddress,
+ sizeof(CurrentShortAddress),
+ 0x13);
+ if (ErrorCode != 0)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error querying OID_FDDI_SHORT_CURRENT_ADDR\n"));
+
+ ExtendedError = TRUE;
+ break;
+ }
+
+ //
+ // Now undo the bogus filter package. We lock
+ // the miniport so that no dpcs will get queued.
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
+
+ ndisMUndoBogusFilters(Miniport);
+
+ if (!FddiCreateFilter(MaximumLongAddresses,
+ MaximumShortAddresses,
+ ndisMChangeFddiAddresses,
+ ndisMChangeClass,
+ ndisMCloseAction,
+ CurrentLongAddress,
+ CurrentShortAddress,
+ &Miniport->Lock,
+ &Miniport->FddiDB))
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error creating the FDDI filter database\n"));
+
+ //
+ // Halt the miniport driver
+ //
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ ErrorCode = 0x15;
+ ExtendedError = TRUE;
+ break;
+ }
+
+ //
+ // Save the miniport block with the filter library.
+ //
+ Miniport->FddiDB->Miniport = Miniport;
+
+ // Set the indicate handler
+ Miniport->PacketIndicateHandler = FddiFilterDprIndicateReceivePacket;
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
+ 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)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Failed to allocate buffer pool for arcnet\n"));
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ ErrorCode = 0x16;
+ ExtendedError = TRUE;
+ break;
+ }
+
+ NdisAllocateMemory((PVOID)&Buffer,
+ sizeof(ARC_BUFFER_LIST) * WRAPPER_ARC_BUFFERS,
+ 0,
+ HighestAcceptableMax);
+ if (Buffer == NULL)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Failed to allocate memory for arcnet buffers\n"));
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisFreeBufferPool(Miniport->ArcnetBufferPool);
+ ErrorCode = 0x17;
+ ExtendedError = TRUE;
+ break;
+ }
+
+ NdisAllocateMemory((PVOID)&DataBuffer,
+ WRAPPER_ARC_HEADER_SIZE * WRAPPER_ARC_BUFFERS,
+ 0,
+ HighestAcceptableMax);
+ if (DataBuffer == NULL)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Failed to allocate memory for arcnet data buffers\n"));
+
+ //
+ // Halt the miniport driver.
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler)(
+ Miniport->MiniportAdapterContext);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisFreeMemory(
+ Buffer,
+ sizeof(ARC_BUFFER_LIST) * WRAPPER_ARC_BUFFERS,
+ 0);
+ NdisFreeBufferPool(Miniport->ArcnetBufferPool);
+ ErrorCode = 0x18;
+ ExtendedError = TRUE;
+ break;
+ }
+
+ 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
+ //
+ ErrorCode = ndisMDoMiniportOp(Miniport,
+ TRUE,
+ OID_ARCNET_CURRENT_ADDRESS,
+ &CurrentLongAddress[5], // address = 00-00-00-00-00-XX
+ 1,
+ 0x19);
+ if (ErrorCode != 0)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error querying OID_ARCNET_CURRENT_ADDRESS\n"));
+
+ NdisFreeMemory(Buffer,
+ sizeof(ARC_BUFFER_LIST) * WRAPPER_ARC_BUFFERS,
+ 0);
+ NdisFreeMemory(DataBuffer,
+ WRAPPER_ARC_HEADER_SIZE * WRAPPER_ARC_BUFFERS,
+ 0);
+ NdisFreeBufferPool(Miniport->ArcnetBufferPool);
+ ExtendedError = TRUE;
+ break;
+ }
+
+ 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_SET_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
+
+ ndisMUndoBogusFilters(Miniport);
+
+ if (!ArcCreateFilter(Miniport,
+ ndisMChangeClass,
+ ndisMCloseAction,
+ CurrentLongAddress[5],
+ &Miniport->Lock,
+ &(Miniport->ArcDB)))
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error creating the Arcnet filter database\n"));
+
+ //
+ // Halt the miniport driver
+ //
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisFreeMemory(Buffer,
+ sizeof(ARC_BUFFER_LIST) * WRAPPER_ARC_BUFFERS,
+ 0);
+ NdisFreeMemory(DataBuffer,
+ WRAPPER_ARC_HEADER_SIZE * WRAPPER_ARC_BUFFERS,
+ 0);
+ NdisFreeBufferPool(Miniport->ArcnetBufferPool);
+ ErrorCode = 0x1B;
+ ExtendedError = TRUE;
+ break;
+ }
+
+ // 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))
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error creating the Arcnet filter database for encapsulated ethernet\n"));
+
+ //
+ // Delete the arcnet filter.
+ //
+ ArcDeleteFilter(Miniport->ArcDB);
+
+ //
+ // Halt the miniport driver
+ //
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisFreeMemory(Buffer,
+ sizeof(ARC_BUFFER_LIST) * WRAPPER_ARC_BUFFERS,
+ 0);
+ NdisFreeMemory(DataBuffer,
+ WRAPPER_ARC_HEADER_SIZE * WRAPPER_ARC_BUFFERS,
+ 0);
+ NdisFreeBufferPool(Miniport->ArcnetBufferPool);
+ ErrorCode = 0x1C;
+ ExtendedError = TRUE;
+ break;
+ }
+
+ //
+ // Save a pointer to the miniport block with the
+ // ethernet filter.
+ //
+ Miniport->EthDB->Miniport = Miniport;
+
+ // Set the indicate handler
+ Miniport->PacketIndicateHandler = EthFilterDprIndicateReceivePacket;
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ break;
+
+ case NdisMediumWan:
+
+ ErrorCode = ndisMDoMiniportOp(Miniport,
+ TRUE,
+ OID_WAN_CURRENT_ADDRESS,
+ &CurrentLongAddress,
+ sizeof(CurrentLongAddress),
+ 0x1D);
+ if (ErrorCode != 0)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Error querying OID_WAN_CURRENT_ADDRESS\n"));
+
+ ExtendedError = TRUE;
+ break;
+ }
+
+ //
+ // Fall through
+ //
+ case NdisMediumAtm:
+ //
+ // Now undo the bogus filter package. We lock
+ // the miniport so that no dpcs will get queued.
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
+
+ ndisMUndoBogusFilters(Miniport);
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ break;
+ }
+
+ //
+ // Do we need to log an error?
+ //
+ if (ExtendedError)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("Extended error while initializing the miniport\n"));
+
+ NdisWriteErrorLogEntry((NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ ErrorCode);
+ break;
+ }
+
+ //
+ // Done with adding this MINIPORT!!!
+ //
+ Miniport->MiniportRequest = NULL;
+
+ IoRegisterShutdownNotification(Miniport->DeviceObject);
+
+ // Set to not cleanup
+ FreeDevice = DerefDriver = FreeBuffer = Dequeue = FALSE;
+ FreeWorkItemStorage = FALSE;
+ FreeArcnetLookaheadBuffer = FALSE;
+ FreeDeferredTimer = FALSE;
+ FreePacketArray = FALSE;
+
+ //
+ // Finally mark the device as *NOT* initializing. This is to let
+ // layered miniports initialize their device instance *OUTSIDE*
+ // of their driver entry. If this flag is on, then NdisOpenAdapter
+ // to this device will not work. This is also true of subsequent
+ // instances of a driver initializing outside of its DriverEntry
+ // as a result of a PnP event.
+ //
+ Miniport->DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+ }
+ else
+ {
+ ErrorCode = MiniportInitializeStatus;
+ }
+ } while (FALSE);
+
+ if ((Miniport != NULL) && (Miniport->Resources != NULL) && (ErrorCode != 0))
+ {
+ ndisMReleaseResources(Miniport);
+ }
+
+ //
+ // Perform any necessary cleanup.
+ //
+ //
+ if (FreeDevice)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("INIT FAILURE: Deleting the device.\n"));
+
+ IoDeleteDevice(pTmpDevice);
+ }
+
+ if (DerefDriver)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("INIT FAILURE: Dereferencing the miniport block.\n"));
+
+ ndisDereferenceDriver(pMiniBlock);
+ }
+
+ if (FreeBuffer)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("INIT FAILURE: Freeing the miniport name.\n"));
+
+ (Miniport->MiniportName.Buffer);
+ }
+
+ if (FreeArcnetLookaheadBuffer)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("INIT FAILURE: Freeing the arcnet lookahead buffer.\n"));
+
+ FREE_POOL(Miniport->ArcnetLookaheadBuffer);
+ }
+
+ if (FreeWorkItemStorage)
+ {
+ PSINGLE_LIST_ENTRY Link;
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("INIT FAILURE: Freeing the workitems.\n"));
+
+ //
+ // Walk the list and free the work items that
+ // were allocated.
+ //
+ while (Miniport->WorkItemFreeQueue.Next != NULL)
+ {
+ Link = PopEntryList(&Miniport->WorkItemFreeQueue);
+ WorkItem = CONTAINING_RECORD(Link, NDIS_MINIPORT_WORK_ITEM, Link);
+ FREE_POOL(WorkItem);
+ }
+
+ //
+ // Free the single workitem list.
+ //
+ for (i = 0; i < NUMBER_OF_SINGLE_WORK_ITEMS; i++)
+ {
+ //
+ // Is there a work item here?
+ //
+ Link = PopEntryList(&Miniport->SingleWorkItems[i]);
+ if (Link != NULL)
+ {
+ WorkItem = CONTAINING_RECORD(Link, NDIS_MINIPORT_WORK_ITEM, Link);
+ FREE_POOL(WorkItem);
+ }
+ }
+ }
+
+ if (FreeDeferredTimer)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("INIT FAILURE: Freeing memory allocated for the Full-Duplex timer.\n"));
+ FREE_POOL(Miniport->DeferredTimer);
+ }
+
+ if (FreePacketArray)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("INIT FAILURE: Freeing memory for the miniport's packet array\n"));
+ FREE_POOL(Miniport->PacketArray);
+ }
+
+ if (Dequeue)
+ {
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
+ ("INIT FAILURE: Dequeueing the miniport from the driver block.\n"));
+
+ ndisDequeueMiniportOnDriver(Miniport, pMiniBlock);
+ }
+
+ return ErrorCode;
+}
+
+BOOLEAN
+ndisCheckProtocolBinding(
+ IN PNDIS_PROTOCOL_BLOCK Protocol,
+ IN PUNICODE_STRING DeviceName,
+ IN PUNICODE_STRING BaseName,
+ OUT PUNICODE_STRING ProtocolSection
+ )
+{
+ RTL_QUERY_REGISTRY_TABLE LinkQueryTable[3];
+ NTSTATUS Status;
+ BOOLEAN rc = FALSE;
+ PWSTR Bind = NULL;
+
+ //
+ // Set up LinkQueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Linkage key below the xports registry key
+ //
+
+ LinkQueryTable[0].QueryRoutine = NULL;
+ LinkQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ LinkQueryTable[0].Name = L"Linkage";
+
+ //
+ // 2) Call ndisSaveLinkage for "Bind" (as a single multi-string),
+ // which will allocate storage and save the data in Bind.
+ //
+
+ LinkQueryTable[1].QueryRoutine = ndisSaveLinkage;
+ LinkQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ LinkQueryTable[1].Name = L"Bind";
+ LinkQueryTable[1].EntryContext = (PVOID)&Bind;
+ LinkQueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 3) Stop
+ //
+
+ LinkQueryTable[2].QueryRoutine = NULL;
+ LinkQueryTable[2].Flags = 0;
+ LinkQueryTable[2].Name = NULL;
+
+ do
+ {
+ UNICODE_STRING Us, Parms;
+ PWSTR CurBind;
+
+ RtlInitUnicodeString(&Parms, L"\\Parameters\\");
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
+ Protocol->ProtocolCharacteristics.Name.Buffer,
+ LinkQueryTable,
+ (PVOID)NULL, // no context needed
+ NULL);
+ if (!NT_SUCCESS(Status))
+ break;
+
+ // Walk the list of bindings and see if any match
+ for (CurBind = Bind;
+ *CurBind != 0;
+ CurBind = (PWCHAR)((PUCHAR)CurBind + Us.MaximumLength))
+ {
+ RtlInitUnicodeString (&Us, CurBind);
+
+ if (RtlEqualUnicodeString(&Us, DeviceName, TRUE))
+ {
+ //
+ // Allocate space for the protocol section under the adapter
+ // to pass to the protocol. The string looks like this.
+ //
+ // Sonic1\Parameters\tcpip
+ //
+ ProtocolSection->MaximumLength = BaseName->Length + // "Sonic1"
+ Parms.Length + // "\Parameters\"
+ Protocol->ProtocolCharacteristics.Name.Length +// "tcpip"
+ sizeof(WCHAR);
+ ProtocolSection->Length = BaseName->Length;
+ ProtocolSection->Buffer = (PWSTR)ALLOC_FROM_POOL(ProtocolSection->MaximumLength,
+ NDIS_TAG_DEFAULT);
+ if (ProtocolSection->Buffer != NULL)
+ {
+ ZeroMemory(ProtocolSection->Buffer, ProtocolSection->MaximumLength);
+ CopyMemory(ProtocolSection->Buffer,
+ BaseName->Buffer,
+ BaseName->Length);
+ RtlAppendUnicodeStringToString(ProtocolSection,
+ &Parms);
+ RtlAppendUnicodeStringToString(ProtocolSection,
+ &Protocol->ProtocolCharacteristics.Name);
+ rc = TRUE;
+ }
+ break;
+ }
+ }
+ } while (FALSE);
+
+ if (Bind != NULL)
+ FREE_POOL(Bind);
+
+ return rc;
+}
+
+BOOLEAN
+ndisProtocolAlreadyBound(
+ IN PNDIS_PROTOCOL_BLOCK Protocol,
+ IN PUNICODE_STRING AdapterName
+ )
+{
+ PNDIS_OPEN_BLOCK pOpen;
+ BOOLEAN rc = FALSE;
+ KIRQL OldIrql;
+
+ NDIS_ACQUIRE_SPIN_LOCK(&Protocol->Ref.SpinLock, &OldIrql);
+
+ for (pOpen = Protocol->OpenQueue;
+ pOpen != NULL;
+ pOpen = pOpen->ProtocolNextOpen)
+ {
+ if (NDIS_EQUAL_UNICODE_STRING(AdapterName, &pOpen->AdapterName))
+ {
+ rc = TRUE;
+ break;
+ }
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&Protocol->Ref.SpinLock, OldIrql);
+ return rc;
+}
+
+NDIS_STATUS
+ndisUpdateDriverInstance(
+ IN PUNICODE_STRING BaseString,
+ IN PUNICODE_STRING BindString,
+ IN PUNICODE_STRING ExportString,
+ IN PUNICODE_STRING RouteString
+ )
+{
+ UNICODE_STRING Path, Linkage;
+ UINT SavedLen;
+ NDIS_STATUS Status = NDIS_STATUS_RESOURCES;
+
+ RtlInitUnicodeString(&Linkage, L"\\Linkage");
+ Path.MaximumLength = BaseString->Length + Linkage.Length + sizeof(WCHAR);
+ Path.Length = 0;
+ Path.Buffer = (PWSTR)ALLOC_FROM_POOL(Path.MaximumLength, NDIS_TAG_DEFAULT);
+ if (Path.Buffer != NULL)
+ {
+ //
+ // Add the Bind/Route/Linkage sections to the driver instance
+ //
+ ZeroMemory(Path.Buffer, Path.MaximumLength);
+ RtlCopyUnicodeString(&Path, BaseString);
+ RtlAppendUnicodeStringToString(&Path, &Linkage);
+
+ RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,
+ Path.Buffer,
+ L"Bind",
+ REG_MULTI_SZ,
+ BindString->Buffer,
+ BindString->Length);
+ RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,
+ Path.Buffer,
+ L"Export",
+ REG_MULTI_SZ,
+ ExportString->Buffer,
+ ExportString->Length);
+ RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,
+ Path.Buffer,
+ L"Route",
+ REG_MULTI_SZ,
+ RouteString->Buffer,
+ RouteString->Length);
+ FREE_POOL(Path.Buffer);
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ return Status;
+}
+
+NDIS_STATUS
+ndisCheckIfPcmciaCardPresent(
+ IN PNDIS_M_DRIVER_BLOCK pMiniBlock
+ )
+{
+ PNDIS_MAC_BLOCK pMacBlock = (PNDIS_MAC_BLOCK)pMiniBlock;
+ NTSTATUS RegStatus;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+ BOOLEAN Found = FALSE;
+#define PCMCIA_HW_SECTION L"\\Registry\\Machine\\Hardware\\Description\\System\\PCMCIA PCCARDs"
+
+ //
+ // Setup to enumerate the values in the registry section (shown above).
+ // For each such value, we'll check against the driver name.
+ //
+ QueryTable[0].QueryRoutine = ndisValidatePcmciaDriver;
+ QueryTable[0].DefaultType = REG_FULL_RESOURCE_DESCRIPTOR;
+ QueryTable[0].DefaultLength = 0;
+ QueryTable[0].EntryContext = &Found;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
+ QueryTable[0].Name = (pMiniBlock->MiniportIdField == (NDIS_HANDLE)0x01) ?
+ pMiniBlock->BaseName.Buffer : pMacBlock->BaseName.Buffer;
+
+ //
+ // Query terminator
+ //
+ QueryTable[1].QueryRoutine = NULL;
+ QueryTable[1].Flags = 0;
+ QueryTable[1].Name = NULL;
+
+ RegStatus = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
+ PCMCIA_HW_SECTION,
+ QueryTable,
+ (PVOID)NULL, // no context needed
+ NULL);
+ return(Found ? NDIS_STATUS_SUCCESS : NDIS_STATUS_ADAPTER_NOT_FOUND);
+#undef PCMCIA_HW_SECTION
+}
+
+NTSTATUS
+ndisValidatePcmciaDriver(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+{
+ if (ValueLength != 0)
+ *(BOOLEAN *)EntryContext = TRUE;
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+VOID
+ndisQueuedBindNotification(
+ IN PQUEUED_PROTOCOL_NOTIFICATION pQPN
+ )
+{
+ KIRQL OldIrql;
+ PNDIS_M_DRIVER_BLOCK MiniBlock = pQPN->MiniBlock;
+ PNDIS_MINIPORT_BLOCK Miniport, NextMiniport;
+
+ //
+ // Initiate upcalls to protocols to bind to it. First reference the
+ // miniport.
+ //
+ NDIS_ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
+
+ for (Miniport = MiniBlock->MiniportQueue;
+ Miniport != NULL;
+ Miniport = NextMiniport)
+ {
+ if (NDIS_EQUAL_UNICODE_STRING(&pQPN->UpCaseDeviceInstance, &Miniport->BaseName) &&
+ ndisReferenceMiniport(Miniport))
+ {
+ NDIS_RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
+
+ ndisInitializeBindings(&Miniport->MiniportName,
+ &Miniport->BaseName,
+ FALSE);
+
+ NDIS_ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
+ break;
+ }
+ else
+ {
+ NextMiniport = Miniport->NextMiniport;
+ }
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
+}
+
+
+NDIS_STATUS
+NdisIMInitializeDeviceInstance(
+ IN NDIS_HANDLE DriverHandle,
+ IN PNDIS_STRING DeviceInstance
+ )
+/*++
+
+Routine Description:
+
+ Initialize an instance of a miniport device.
+
+Arguments:
+
+ DriverHandle - Handle returned by NdisMRegisterLayeredMiniport.
+ It is a pointer to NDIS_M_DRIVER_BLOCK.
+ DeviceInstance -Points to the instance of the driver that must now
+ be initialized.
+
+Return Value:
+
+
+--*/
+{
+ NDIS_STATUS Status;
+ PNDIS_M_DRIVER_BLOCK MiniBlock = (PNDIS_M_DRIVER_BLOCK)DriverHandle;
+
+ Status = ndisInitializeAllAdapterInstances((PNDIS_MAC_BLOCK)MiniBlock,
+ DeviceInstance);
+
+ //
+ // Queue a thread to do protocol notifications
+ //
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ NTSTATUS s;
+ PQUEUED_PROTOCOL_NOTIFICATION pQPN;
+
+ pQPN = (PQUEUED_PROTOCOL_NOTIFICATION)ALLOC_FROM_POOL(sizeof(QUEUED_PROTOCOL_NOTIFICATION) +
+ DeviceInstance->MaximumLength,
+ NDIS_TAG_DEFAULT);
+ if (pQPN == NULL)
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("Cannot allocate memory for protocol notifications for intermediate driver %Z\n",
+ DeviceInstance));
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ pQPN->MiniBlock = MiniBlock;
+ pQPN->UpCaseDeviceInstance.Buffer = pQPN->Buffer;
+ pQPN->UpCaseDeviceInstance.Length = DeviceInstance->MaximumLength;
+ pQPN->UpCaseDeviceInstance.MaximumLength = DeviceInstance->MaximumLength;
+
+ s = RtlUpcaseUnicodeString(&pQPN->UpCaseDeviceInstance, DeviceInstance, FALSE);
+ if (!NT_SUCCESS(s))
+ {
+ return s;
+ }
+
+ INITIALIZE_WORK_ITEM(&pQPN->WorkItem, ndisQueuedBindNotification, pQPN);
+ QUEUE_WORK_ITEM(&pQPN->WorkItem, DelayedWorkQueue);
+ }
+
+ return Status;
+}
+
+
diff --git a/private/ntos/ndis/ndis40/mac.c b/private/ntos/ndis/ndis40/mac.c
new file mode 100644
index 000000000..9579d5e8e
--- /dev/null
+++ b/private/ntos/ndis/ndis40/mac.c
@@ -0,0 +1,3591 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ mac.c
+
+Abstract:
+
+ NDIS wrapper functions for full mac drivers
+
+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
+ 01-Jun-1995 JameelH Re-organized
+
+--*/
+
+
+#include <precomp.h>
+#pragma hdrstop
+
+#include <stdarg.h>
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_MAC
+
+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);
+
+ SET_EVENT((PKEVENT)DeferredContext);
+}
+
+
+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;
+ KIRQL OldIrql;
+
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+
+ //
+ // Search for the MacP
+ //
+
+ MacP = ndisMacDriverList;
+
+ while (MacP != (PNDIS_MAC_BLOCK)NULL)
+ {
+ if (MacP->NdisMacInfo->NdisWrapperDriver == DriverObject)
+ {
+ break;
+ }
+
+ MacP = MacP->NextMac;
+ }
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ 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.
+ //
+
+ WAIT_FOR_OBJECT(&MacP->AdaptersRemovedEvent, NULL);
+
+ RESET_EVENT(&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(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN 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);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>ndisShutdown\n"));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(Irp))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ (": Null Irp\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(Irp))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ (": Irp not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+
+ if (WrapperContext->ShutdownHandler != NULL)
+ {
+ //
+ // Call the shutdown routine
+ //
+
+ WrapperContext->ShutdownHandler(WrapperContext->ShutdownContext);
+ }
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==ndisShutdown\n"));
+
+ return STATUS_SUCCESS;
+}
+
+
+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
+ NdisAllocateDmaChannel 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.
+ //
+
+ SET_EVENT(&DmaBlock->AllocationEvent);
+
+ return KeepObject;
+}
+
+
+
+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;
+
+ RAISE_IRQL_TO_DISPATCH(&oldIrql);
+
+ //
+ // Find protocol binding context and get associated open for it.
+ //
+ Open = ndisGetOpenBlockFromProtocolBindingContext(ProtocolBindingContext);
+ ASSERT(Open != NULL);
+
+ Status = (Open->PostNt31ReceiveHandler)(ProtocolBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize);
+ LOWER_IRQL(oldIrql);
+ return Status;
+}
+
+
+VOID
+ndisMacReceiveCompleteHandler(
+ IN NDIS_HANDLE ProtocolBindingContext
+ )
+{
+ PNDIS_OPEN_BLOCK Open;
+ KIRQL oldIrql;
+
+ RAISE_IRQL_TO_DISPATCH(&oldIrql);
+ //
+ // Find protocol binding context and get associated open for it.
+ //
+ Open = ndisGetOpenBlockFromProtocolBindingContext(ProtocolBindingContext);
+ ASSERT(Open != NULL);
+
+ (Open->PostNt31ReceiveCompleteHandler)(ProtocolBindingContext);
+ LOWER_IRQL(oldIrql);
+}
+
+
+PNDIS_OPEN_BLOCK
+ndisGetOpenBlockFromProtocolBindingContext(
+ IN NDIS_HANDLE ProtocolBindingContext
+ )
+{
+ PNDIS_OPEN_BLOCK *ppOpen;
+
+ ACQUIRE_SPIN_LOCK_DPC(&ndisGlobalOpenListLock);
+
+ for (ppOpen = &ndisGlobalOpenList;
+ *ppOpen != NULL;
+ ppOpen = &(*ppOpen)->NextGlobalOpen)
+ {
+ if ((*ppOpen)->ProtocolBindingContext == ProtocolBindingContext)
+ {
+ break;
+ }
+ }
+
+ RELEASE_SPIN_LOCK_DPC(&ndisGlobalOpenListLock);
+
+ return *ppOpen;
+}
+
+
+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.
+ //
+
+ SET_EVENT(((AdaptP->DeviceObject == NULL) ?
+ &Miniport->AllocationEvent :
+ &AdaptP->AllocationEvent));
+
+ return DeallocateObjectKeepRegisters;
+}
+
+
+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);
+}
+
+
+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;
+ PDEVICE_OBJECT DeviceObject;
+ ULONG i;
+ ULONG StringSize;
+ PWCH baseFileName;
+
+ if (AdapterBlock == NULL)
+ {
+ return;
+ }
+
+ DeviceObject = AdapterBlock->DeviceObject;
+
+ if (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 < ((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 (((DeviceObject != NULL) ?
+ AdapterBlock->AdapterName.Buffer[i] :
+ Miniport->MiniportName.Buffer[i]) == OBJ_NAME_PATH_SEPARATOR)
+ {
+ baseFileName = ((DeviceObject != NULL) ?
+ &(AdapterBlock->AdapterName.Buffer[++i]) :
+ &(Miniport->MiniportName.Buffer[++i]));
+ }
+
+ }
+
+ StringSize = ((DeviceObject != NULL) ?
+ AdapterBlock->AdapterName.MaximumLength :
+ Miniport->MiniportName.MaximumLength) -
+ (((ULONG)baseFileName) -
+ ((DeviceObject != NULL) ?
+ ((ULONG)AdapterBlock->AdapterName.Buffer) :
+ ((ULONG)Miniport->MiniportName.Buffer)));
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ ((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);
+
+
+ CopyMemory(((PUCHAR)errorLogEntry) + (sizeof(IO_ERROR_LOG_PACKET) +
+ NumberOfErrorValues * sizeof(ULONG)),
+ 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;
+ PQUEUED_OPEN_CLOSE pQoC = NULL;
+ QUEUED_OPEN_CLOSE QoC;
+ KIRQL OldIrql;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("==>NdisCompleteOpenAdapter\n"));
+
+ IF_DBG(DBG_COMP_OPEN, DBG_LEVEL_ERR)
+ {
+ if (!DbgIsNonPaged(NdisBindingContext))
+ {
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_ERR,
+ ("NdisCompleteOpenAdapter: Handle not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_OPEN, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(NdisBindingContext))
+ {
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_ERR,
+ ("NdisCompleteOpenAdapter: Binding Context not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_OPEN, DBG_LEVEL_ERR);
+ }
+ }
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (!NdisFinishOpen(OpenP))
+ {
+ Status = NDIS_STATUS_CLOSING;
+ }
+ }
+
+ if (KeGetCurrentIrql() == DISPATCH_LEVEL)
+ {
+ pQoC = (PQUEUED_OPEN_CLOSE)ALLOC_FROM_POOL(sizeof(QUEUED_OPEN_CLOSE), NDIS_TAG_DEFAULT);
+ if (pQoC != NULL)
+ {
+ pQoC->FreeIt = TRUE;
+ }
+ }
+
+ if (pQoC == NULL)
+ {
+ pQoC = &QoC;
+ pQoC->FreeIt = FALSE;
+ }
+
+ pQoC->OpenP = OpenP;
+ pQoC->Status = Status;
+ pQoC->OpenErrorStatus = OpenErrorStatus;
+
+ if (pQoC->FreeIt)
+ {
+ INITIALIZE_WORK_ITEM(&pQoC->WorkItem,
+ ndisQueuedCompleteOpenAdapter,
+ pQoC);
+ QUEUE_WORK_ITEM(&pQoC->WorkItem, HyperCriticalWorkQueue);
+ }
+ else
+ {
+ ndisQueuedCompleteOpenAdapter(pQoC);
+ }
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("<==NdisCompleteOpenAdapter\n"));
+}
+
+
+VOID
+ndisQueuedCompleteOpenAdapter(
+ IN PQUEUED_OPEN_CLOSE pQoC
+ )
+{
+ PNDIS_OPEN_BLOCK *ppOpen;
+ KIRQL OldIrql;
+
+ (pQoC->OpenP->ProtocolHandle->ProtocolCharacteristics.OpenAdapterCompleteHandler)(
+ pQoC->OpenP->ProtocolBindingContext,
+ pQoC->Status,
+ pQoC->OpenErrorStatus);
+
+ if (pQoC->Status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Something went wrong, clean up and exit.
+ //
+
+ ACQUIRE_SPIN_LOCK(&ndisGlobalOpenListLock, &OldIrql);
+
+ for (ppOpen = &ndisGlobalOpenList;
+ *ppOpen != NULL;
+ ppOpen = &(*ppOpen)->NextGlobalOpen)
+ {
+ if (*ppOpen == pQoC->OpenP)
+ {
+ *ppOpen = pQoC->OpenP->NextGlobalOpen;
+ break;
+ }
+ }
+
+ RELEASE_SPIN_LOCK(&ndisGlobalOpenListLock, OldIrql);
+
+ ObDereferenceObject(pQoC->OpenP->FileObject);
+ ndisDereferenceAdapter(pQoC->OpenP->AdapterHandle);
+ ndisDereferenceProtocol(pQoC->OpenP->ProtocolHandle);
+ FREE_POOL(pQoC->OpenP);
+ }
+
+ if (pQoC->FreeIt)
+ {
+ FREE_POOL(pQoC);
+ }
+}
+
+VOID
+NdisCompleteCloseAdapter(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS Status
+ )
+
+{
+ PNDIS_OPEN_BLOCK Open = (PNDIS_OPEN_BLOCK) NdisBindingContext;
+ PQUEUED_OPEN_CLOSE pQoC = NULL;
+ QUEUED_OPEN_CLOSE QoC;
+ KIRQL OldIrql;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("==>NdisCompleteCloseAdapter\n"));
+
+ IF_DBG(DBG_COMP_OPEN, DBG_LEVEL_ERR)
+ {
+ if (!DbgIsNonPaged(NdisBindingContext))
+ {
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_ERR,
+ ("NdisCompleteCloseAdapter: Handle not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_OPEN, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(NdisBindingContext))
+ {
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_ERR,
+ ("NdisCompleteCloseAdapter: Binding Context not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_OPEN, DBG_LEVEL_ERR);
+ }
+ }
+
+ if (KeGetCurrentIrql() == DISPATCH_LEVEL)
+ {
+ pQoC = (PQUEUED_OPEN_CLOSE)ALLOC_FROM_POOL(sizeof(QUEUED_OPEN_CLOSE), NDIS_TAG_DEFAULT);
+ if (pQoC != NULL)
+ {
+ pQoC->FreeIt = TRUE;
+ }
+ }
+
+ if (pQoC == NULL)
+ {
+ pQoC = &QoC;
+ pQoC->FreeIt = FALSE;
+ }
+
+ pQoC->OpenP = Open;
+ pQoC->Status = Status;
+
+ if (pQoC->FreeIt)
+ {
+ INITIALIZE_WORK_ITEM(&pQoC->WorkItem,
+ ndisQueuedCompleteCloseAdapter,
+ pQoC);
+ QUEUE_WORK_ITEM(&pQoC->WorkItem, CriticalWorkQueue);
+ }
+ else
+ {
+ ndisQueuedCompleteCloseAdapter(pQoC);
+ }
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("<==NdisCompleteCloseAdapter\n"));
+}
+
+
+VOID
+ndisQueuedCompleteCloseAdapter(
+ IN PQUEUED_OPEN_CLOSE pQoC
+ )
+{
+ PNDIS_OPEN_BLOCK OpenP, *ppOpen;
+ KIRQL OldIrql;
+
+ OpenP = pQoC->OpenP;
+
+ (OpenP->ProtocolHandle->ProtocolCharacteristics.CloseAdapterCompleteHandler) (
+ OpenP->ProtocolBindingContext,
+ pQoC->Status);
+
+ ndisDeQueueOpenOnAdapter(OpenP, OpenP->AdapterHandle);
+ ndisDeQueueOpenOnProtocol(OpenP, OpenP->ProtocolHandle);
+
+ ndisDereferenceProtocol(OpenP->ProtocolHandle);
+ ndisDereferenceAdapter(OpenP->AdapterHandle);
+ NdisFreeSpinLock(&OpenP->SpinLock);
+
+ //
+ // This sends an IRP_MJ_CLOSE IRP.
+ //
+ ObDereferenceObject((OpenP->FileObject));
+
+ //
+ // Remove from global list
+ //
+ ACQUIRE_SPIN_LOCK(&ndisGlobalOpenListLock, &OldIrql);
+
+ for (ppOpen = &ndisGlobalOpenList;
+ *ppOpen != NULL;
+ ppOpen = &(*ppOpen)->NextGlobalOpen)
+ {
+ if (*ppOpen == pQoC->OpenP)
+ {
+ *ppOpen = pQoC->OpenP->NextGlobalOpen;
+ break;
+ }
+ }
+
+ RELEASE_SPIN_LOCK(&ndisGlobalOpenListLock, OldIrql);
+
+ FREE_POOL(pQoC->OpenP);
+
+ if (pQoC->FreeIt)
+ {
+ FREE_POOL(pQoC);
+ }
+}
+
+
+#undef NdisSend
+
+VOID
+NdisSend(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ )
+{
+ *Status = (((PNDIS_OPEN_BLOCK)NdisBindingHandle)->SendHandler)(
+ ((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacBindingHandle,
+ Packet);
+}
+
+#undef NdisSendPackets
+
+VOID
+NdisSendPackets(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ )
+{
+ (((PNDIS_OPEN_BLOCK)NdisBindingHandle)->SendPacketsHandler)(
+ ((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacBindingHandle,
+ PacketArray,
+ NumberOfPackets);
+}
+
+#undef NdisTransferData
+
+VOID
+NdisTransferData(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+{
+ *Status = (((PNDIS_OPEN_BLOCK)NdisBindingHandle)->TransferDataHandler)(
+ ((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacBindingHandle,
+ MacReceiveContext,
+ ByteOffset,
+ BytesToTransfer,
+ Packet,
+ BytesTransferred);
+}
+
+#undef NdisReset
+
+VOID
+NdisReset(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle
+ )
+{
+ *Status = (((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacHandle->MacCharacteristics.ResetHandler)(
+ ((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacBindingHandle);
+
+}
+
+#undef NdisRequest
+
+VOID
+NdisRequest(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+{
+ *Status = (((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacHandle->MacCharacteristics.RequestHandler)(
+ ((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacBindingHandle,
+ NdisRequest);
+}
+
+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.
+
+--*/
+
+{
+ BOOLEAN rc = TRUE;
+ KIRQL OldIrql;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisReferenceRef\n"));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(RefP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NdisReferenceRef: NULL Reference address\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(RefP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NdisReferenceRef: Reference not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+ NDIS_ACQUIRE_SPIN_LOCK(&RefP->SpinLock, &OldIrql);
+
+ if (RefP->Closing)
+ {
+ rc = FALSE;
+ }
+ else
+ {
+ ++(RefP->ReferenceCount);
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&RefP->SpinLock, OldIrql);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisReferenceRef\n"));
+
+ return(rc);
+}
+
+
+BOOLEAN
+NdisDereferenceRef(
+ IN 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.
+
+--*/
+
+{
+ BOOLEAN rc = FALSE;
+ KIRQL OldIrql;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisDereferenceRef\n"));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(RefP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NdisDereferenceRef: NULL Reference address\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(RefP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NdisDereferenceRef: Reference not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+
+ NDIS_ACQUIRE_SPIN_LOCK(&RefP->SpinLock, &OldIrql);
+
+ --(RefP->ReferenceCount);
+
+ if (RefP->ReferenceCount == 0)
+ {
+ rc = TRUE;
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&RefP->SpinLock, OldIrql);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisDereferenceRef\n"));
+ return rc;
+}
+
+
+VOID
+NdisInitializeRef(
+ IN PREFERENCE RefP
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize a reference count structure.
+
+Arguments:
+
+ RefP - The structure to be initialized.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisInitializeRef\n"));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(RefP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NdisInitializeRef: NULL Reference address\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(RefP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NdisInitializeRef: Reference not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+
+ RefP->Closing = FALSE;
+ RefP->ReferenceCount = 1;
+ NdisAllocateSpinLock(&RefP->SpinLock);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisInitializeRef\n"));
+}
+
+
+BOOLEAN
+NdisCloseRef(
+ IN 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.
+
+--*/
+
+{
+ KIRQL OldIrql;
+ BOOLEAN rc = TRUE;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisCloseRef\n"));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(RefP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NdisCloseRef: NULL Reference address\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(RefP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NdisCloseRef: Reference not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+
+ NDIS_ACQUIRE_SPIN_LOCK(&RefP->SpinLock, &OldIrql);
+
+ if (RefP->Closing)
+ {
+ rc = FALSE;
+ }
+ else RefP->Closing = TRUE;
+
+ NDIS_RELEASE_SPIN_LOCK(&RefP->SpinLock, OldIrql);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisCloseRef\n"));
+ return rc;
+}
+
+
+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.
+ //
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisFinishOpen\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ (" Protocol %wZ is being bound to Adapter %wZ\n",
+ &(OpenP->ProtocolHandle)->ProtocolCharacteristics.Name,
+ &OpenP->AdapterHandle->AdapterName));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(OpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NdisFinishOpen: Null Open Block\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(OpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("NdisFinishOpen: Open Block not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+
+ if (!ndisQueueOpenOnAdapter(OpenP, OpenP->AdapterHandle))
+ {
+ //
+ // The adapter is closing.
+ //
+ // Call MacCloseAdapter(), don't worry about it completing.
+ //
+
+ (OpenP->MacHandle->MacCharacteristics.CloseAdapterHandler) (
+ OpenP->MacBindingHandle);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==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);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisFinishOpen\n"));
+ return FALSE;
+ }
+
+
+ //
+ // Both queueings succeeded.
+ //
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisFinishOpen\n"));
+ return TRUE;
+}
+
+
+NTSTATUS
+ndisCreateIrpHandler(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN 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;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ BOOLEAN IsAMiniport;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>ndisCreateIrpHandler\n"));
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(Irp))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ (": Null Irp\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(Irp))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ (": Irp not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+
+ AdapterBlock = (PNDIS_ADAPTER_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1);
+ Miniport = (PNDIS_MINIPORT_BLOCK)AdapterBlock;
+ 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)ALLOC_FROM_POOL(sizeof(NDIS_USER_OPEN_CONTEXT),
+ NDIS_TAG_DEFAULT);
+
+ if (OpenContext == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ OpenContext->DeviceObject = DeviceObject;
+
+ OpenContext->AdapterBlock = AdapterBlock;
+ OpenContext->OidCount = 0;
+ OpenContext->FullOidCount = 0;
+ OpenContext->OidArray = NULL;
+ OpenContext->FullOidArray = NULL;
+
+ IrpSp->FileObject->FsContext = OpenContext;
+ IrpSp->FileObject->FsContext2 = (PVOID)NDIS_OPEN_QUERY_STATISTICS;
+
+ if (IsAMiniport && !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
+ {
+ Status = ndisMQueryOidList(OpenContext, Irp);
+ }
+ else
+ {
+ //
+ // Handle full-macs and 4.1 miniports here
+ //
+ Status = ndisQueryOidList(OpenContext, Irp);
+ }
+
+ if (Status != STATUS_SUCCESS)
+ {
+ FREE_POOL(OpenContext);
+ }
+ else
+ {
+ PnPReferencePackage();
+ }
+ }
+ }
+ else
+ {
+ //
+ // This is an internal open, verify the EA.
+ //
+
+ if ((IrpEaInfo->EaNameLength != sizeof(ndisInternalEaName)) ||
+ (!RtlEqualMemory(IrpEaInfo->EaName, ndisInternalEaName, sizeof(ndisInternalEaName))) ||
+ (IrpEaInfo->EaValueLength != sizeof(ndisInternalEaValue)) ||
+ (!RtlEqualMemory(&IrpEaInfo->EaName[IrpEaInfo->EaNameLength+1],
+ 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);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisCreateIrplHandler\n"));
+ return Status;
+}
+
+
+NTSTATUS
+ndisQueryOidList(
+ IN PNDIS_USER_OPEN_CONTEXT OpenContext,
+ IN 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.
+
+ NOTE: We also handle co-ndis miniports here.
+
+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.
+
+--*/
+
+{
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PNDIS_COREQ_RESERVED ReqRsvd;
+ NDIS_QUERY_OPEN_REQUEST OpenRequest;
+ NDIS_STATUS NdisStatus;
+ PNDIS_OID TmpBuffer;
+ ULONG TmpBufferLength;
+
+ //
+ // First query the OID list with no buffer, to find out
+ // how big it should be.
+ //
+ INITIALIZE_EVENT(&OpenRequest.Event);
+
+ 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;
+ Miniport = (PNDIS_MINIPORT_BLOCK)OpenContext->AdapterBlock;
+
+ if (OpenContext->AdapterBlock->DeviceObject != NULL)
+ {
+ NdisStatus = (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler)(
+ OpenContext->AdapterBlock->MacAdapterContext,
+ &OpenRequest.Request);
+ }
+ else
+ {
+ OpenRequest.Request.RequestType = NdisRequestQueryInformation;
+ ReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(&OpenRequest.Request);
+
+ ReqRsvd->Open = NULL;
+ ReqRsvd->RequestCompleteHandler = NULL;
+ ReqRsvd->VcContext = NULL;
+ ReqRsvd->Flags = COREQ_QUERY_OIDS;
+ ReqRsvd->RealRequest = NULL;
+
+ //
+ // Call the miniport's CoRequest Handler
+ //
+ NdisStatus = (*Miniport->DriverHandle->MiniportCharacteristics.CoRequestHandler)(
+ Miniport->MiniportAdapterContext,
+ NULL,
+ &OpenRequest.Request);
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING)
+ {
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+ WAIT_FOR_OBJECT(&OpenRequest.Event, 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 = ALLOC_FROM_POOL(TmpBufferLength, NDIS_TAG_DEFAULT);
+
+ if (TmpBuffer == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // ...and query the real list.
+ //
+ RESET_EVENT(&OpenRequest.Event);
+
+
+ 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;
+
+ if (OpenContext->AdapterBlock->DeviceObject != NULL)
+ {
+ NdisStatus = (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler)(
+ OpenContext->AdapterBlock->MacAdapterContext,
+ &OpenRequest.Request);
+ }
+ else
+ {
+ //
+ // Call the miniport's CoRequest Handler
+ //
+ NdisStatus = (*Miniport->DriverHandle->MiniportCharacteristics.CoRequestHandler)(
+ Miniport->MiniportAdapterContext,
+ NULL,
+ &OpenRequest.Request);
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING)
+ {
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+ WAIT_FOR_OBJECT(&OpenRequest.Event, NULL);
+
+ NdisStatus = OpenRequest.NdisStatus;
+ }
+
+ ASSERT (NdisStatus == NDIS_STATUS_SUCCESS);
+
+ NdisStatus = ndisSplitStatisticsOids(OpenContext,
+ TmpBuffer,
+ TmpBufferLength/sizeof(NDIS_OID));
+ FREE_POOL(TmpBuffer);
+
+ return NdisStatus;
+}
+
+
+NDIS_STATUS
+ndisSplitStatisticsOids(
+ IN PNDIS_USER_OPEN_CONTEXT OpenContext,
+ IN PNDIS_OID OidList,
+ IN ULONG NumOids
+ )
+{
+ ULONG i, j;
+
+ //
+ // Go through the buffer, counting the statistics OIDs.
+ //
+ OpenContext->FullOidCount = NumOids;
+ for (i = 0; i < NumOids; i++)
+ {
+ if ((OidList[i] & 0x00ff0000) == 0x00020000)
+ {
+ ++OpenContext->OidCount;
+ }
+ }
+
+ //
+ // Now allocate storage for the stat and non-stat OID arrays.
+ //
+ OpenContext->OidArray = ALLOC_FROM_POOL(OpenContext->OidCount*sizeof(NDIS_OID),
+ NDIS_TAG_DEFAULT);
+ if (OpenContext->OidArray == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ OpenContext->FullOidArray = ALLOC_FROM_POOL(OpenContext->FullOidCount*sizeof(NDIS_OID),
+ NDIS_TAG_DEFAULT);
+ if (OpenContext->FullOidArray == NULL)
+ {
+ FREE_POOL(OpenContext->OidArray);
+ OpenContext->OidArray = NULL;
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Now go through the buffer, copying the statistics and non-stat OIDs separately.
+ //
+ for (i = j = 0; i< NumOids; i++)
+ {
+ if ((OidList[i] & 0x00ff0000) == 0x00020000)
+ {
+ OpenContext->OidArray[j++] = OidList[i];
+ }
+ OpenContext->FullOidArray[i] = OidList[i];
+ }
+
+ ASSERT (j == OpenContext->OidCount);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+#define NDIS_STATISTICS_HEADER_SIZE FIELD_OFFSET(NDIS_STATISTICS_VALUE,Data[0])
+
+VOID
+ndisCancelLogIrp(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION IrpSp;
+ PNDIS_USER_OPEN_CONTEXT OpenContext;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PNDIS_LOG Log;
+ KIRQL OldIrql;
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+ OpenContext = IrpSp->FileObject->FsContext;
+ Miniport = (PNDIS_MINIPORT_BLOCK)(OpenContext->AdapterBlock);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ ASSERT (Miniport->Log != NULL);
+ ASSERT (Miniport->Log->Irp == Irp);
+
+ Miniport->Log->Irp = NULL;
+ Irp->IoStatus.Status = STATUS_REQUEST_ABORTED;
+ Irp->IoStatus.Information = 0;
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+}
+
+NTSTATUS
+ndisDeviceControlIrpHandler(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN 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;
+ PSINGLE_LIST_ENTRY Link;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>ndisDeviceControlIrpHandler\n"));
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(Irp))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ (": Null Irp\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(Irp))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ (": Irp not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+
+ 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;
+ }
+
+ PnPReferencePackage();
+
+ OpenContext = IrpSp->FileObject->FsContext;
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
+ {
+ case IOCTL_NDIS_GET_LOG_DATA:
+
+ //
+ // First verify that we have a miniport. This IOCTL is only
+ // valid for a miniport
+ //
+ if (OpenContext->AdapterBlock->DeviceObject != NULL)
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ break;
+ }
+
+ Miniport = (PNDIS_MINIPORT_BLOCK)(OpenContext->AdapterBlock);
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ {
+ PNDIS_LOG Log;
+ UINT AmtToCopy;
+
+ if ((Log = Miniport->Log) != NULL)
+ {
+ ACQUIRE_SPIN_LOCK_DPC(&Log->LogLock);
+
+ if (Log->CurrentSize != 0)
+ {
+ //
+ // If the InPtr is lagging the OutPtr. then we can simply
+ // copy the data over in one shot.
+ //
+ AmtToCopy = MDL_SIZE(Irp->MdlAddress);
+ if (AmtToCopy > Log->CurrentSize)
+ AmtToCopy = Log->CurrentSize;
+ if ((Log->TotalSize - Log->OutPtr) >= AmtToCopy)
+ {
+ CopyMemory(MDL_ADDRESS(Irp->MdlAddress),
+ Log->LogBuf+Log->OutPtr,
+ AmtToCopy);
+ }
+ else
+ {
+ CopyMemory(MDL_ADDRESS(Irp->MdlAddress),
+ Log->LogBuf+Log->OutPtr,
+ Log->TotalSize-Log->OutPtr);
+ CopyMemory((PUCHAR)MDL_ADDRESS(Irp->MdlAddress)+Log->TotalSize-Log->OutPtr,
+ Log->LogBuf,
+ AmtToCopy - (Log->TotalSize-Log->OutPtr));
+ }
+ Log->CurrentSize -= AmtToCopy;
+ Log->OutPtr += AmtToCopy;
+ if (Log->OutPtr >= Log->TotalSize)
+ Log->OutPtr -= Log->TotalSize;
+ Irp->IoStatus.Information = AmtToCopy;
+ Status = STATUS_SUCCESS;
+ }
+ else if (Log->Irp != NULL)
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ }
+ else
+ {
+ KIRQL OldIrql;
+
+ IoAcquireCancelSpinLock(&OldIrql);
+ IoSetCancelRoutine(Irp, ndisCancelLogIrp);
+ IoReleaseCancelSpinLock(OldIrql);
+ Log->Irp = Irp;
+ Status = STATUS_PENDING;
+ }
+
+ RELEASE_SPIN_LOCK_DPC(&Log->LogLock);
+ }
+ }
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+ break;
+
+ case IOCTL_NDIS_QUERY_GLOBAL_STATS:
+
+ if (!ndisValidOid(OpenContext,
+ *((PULONG)(Irp->AssociatedIrp.SystemBuffer))))
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ //
+ // Allocate a request.
+ //
+ GlobalRequest = (PNDIS_QUERY_GLOBAL_REQUEST)ALLOC_FROM_POOL(sizeof(NDIS_QUERY_GLOBAL_REQUEST),
+ NDIS_TAG_DEFAULT);
+
+ if (GlobalRequest == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ GlobalRequest->Irp = Irp;
+
+ if (OpenContext->AdapterBlock->DeviceObject == NULL)
+ {
+ Miniport = (PNDIS_MINIPORT_BLOCK)(OpenContext->AdapterBlock);
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
+ {
+ //
+ // Do this for CL miniports only
+ //
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+ 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 = MDL_ADDRESS (Irp->MdlAddress);
+ GlobalRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength = MDL_SIZE (Irp->MdlAddress);
+ GlobalRequest->Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
+ GlobalRequest->Request.DATA.QUERY_INFORMATION.BytesNeeded = 0;
+
+
+ if (Miniport != NULL)
+ {
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
+ {
+ //
+ // Place the request on the queue.
+ //
+ ndisMQueueRequest(Miniport, &GlobalRequest->Request, NULL);
+
+ //
+ // Queue a work item if there is not one already queue'd.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+
+ //
+ // If we were able to grab the local lock then we can do some
+ // deferred processing now.
+ //
+
+ if (LocalLock)
+ {
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+ }
+ else
+ {
+ PNDIS_COREQ_RESERVED ReqRsvd;
+
+ ReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(&GlobalRequest->Request);
+
+ ReqRsvd->Open = NULL;
+ ReqRsvd->RequestCompleteHandler = NULL;
+ ReqRsvd->VcContext = NULL;
+ ReqRsvd->Flags = COREQ_GLOBAL_REQ;
+ ReqRsvd->RealRequest = NULL;
+
+ //
+ // Call the miniport's CoRequest Handler
+ //
+ Status = (*Miniport->DriverHandle->MiniportCharacteristics.CoRequestHandler)(
+ Miniport->MiniportAdapterContext,
+ NULL,
+ &GlobalRequest->Request);
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisMCoRequestComplete(Status,
+ Miniport,
+ &GlobalRequest->Request);
+ }
+ }
+ }
+ 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(OpenContext->AdapterBlock,
+ &GlobalRequest->Request,
+ NdisStatus);
+ }
+
+ }
+
+ Status = STATUS_PENDING;
+
+ break;
+
+ case IOCTL_NDIS_QUERY_ALL_STATS:
+
+
+ //
+ // Allocate a request.
+ //
+
+ AllRequest = (PNDIS_QUERY_ALL_REQUEST)ALLOC_FROM_POOL(sizeof(NDIS_QUERY_ALL_REQUEST),
+ NDIS_TAG_DEFAULT);
+
+ if (AllRequest == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ if (OpenContext->AdapterBlock->DeviceObject == NULL)
+ {
+ Miniport = (PNDIS_MINIPORT_BLOCK)(OpenContext->AdapterBlock);
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
+ {
+ //
+ // Do this for CL miniports only
+ //
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+ LOCK_MINIPORT(Miniport, LocalLock);
+ }
+ }
+ else
+ {
+ Miniport = NULL;
+ }
+
+ AllRequest->Irp = Irp;
+
+ Buffer = (PUCHAR)MDL_ADDRESS (Irp->MdlAddress);
+ BufferLength = MDL_SIZE (Irp->MdlAddress);
+ BytesWritten = 0;
+
+ INITIALIZE_EVENT(&AllRequest->Event);
+
+ 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)
+ {
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
+ {
+ //
+ // Queue the request.
+ //
+ ndisMQueueRequest(Miniport, &AllRequest->Request, NULL);
+
+ //
+ // Queue a work item if there is not one already queue'd.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+
+ //
+ // If we were able to grab the local lock then we can do some
+ // deferred processing now.
+ //
+ if (LocalLock)
+ {
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ NdisStatus = NDIS_STATUS_PENDING;
+ }
+ else
+ {
+ PNDIS_COREQ_RESERVED ReqRsvd;
+
+ ReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(&AllRequest->Request);
+
+ ReqRsvd->Open = NULL;
+ ReqRsvd->RequestCompleteHandler = NULL;
+ ReqRsvd->VcContext = NULL;
+ ReqRsvd->Flags = COREQ_QUERY_STATS;
+ ReqRsvd->RealRequest = NULL;
+
+ //
+ // Call the miniport's CoRequest Handler
+ //
+ NdisStatus = (*Miniport->DriverHandle->MiniportCharacteristics.CoRequestHandler)(
+ Miniport->MiniportAdapterContext,
+ NULL,
+ &AllRequest->Request);
+ if (NdisStatus == NDIS_STATUS_PENDING)
+ {
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+ WAIT_FOR_OBJECT(&AllRequest->Event, NULL);
+
+ NdisStatus = AllRequest->NdisStatus;
+ }
+ }
+ }
+ else
+ {
+ NdisStatus = (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler)(
+ OpenContext->AdapterBlock->MacAdapterContext,
+ &AllRequest->Request);
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING)
+ {
+ if ((Miniport != NULL) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
+ {
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+ }
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+ WAIT_FOR_OBJECT(&AllRequest->Event, NULL);
+
+ NdisStatus = AllRequest->NdisStatus;
+
+ if (Miniport != NULL)
+ {
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+ 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;
+ }
+
+ RESET_EVENT(&AllRequest->Event);
+
+ }
+
+ if (Miniport != NULL)
+ {
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, 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;
+
+ }
+
+ PnPDereferencePackage();
+ if (Status != STATUS_PENDING)
+ {
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ }
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==ndisDeviceControlIrpHandler\n"));
+
+ return Status;
+}
+
+
+BOOLEAN
+ndisValidOid(
+ IN PNDIS_USER_OPEN_CONTEXT OpenContext,
+ IN NDIS_OID Oid
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+ TRUE if OID is valid, FALSE otherwise
+
+--*/
+{
+ UINT i;
+
+ for (i = 0; i < OpenContext->FullOidCount; i++)
+ {
+ if (OpenContext->FullOidArray[i] == Oid)
+ {
+ break;
+ }
+ }
+
+ return (i < OpenContext->FullOidCount);
+}
+
+
+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_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;
+ SET_EVENT(&OpenRequest->Event);
+ 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;
+ }
+
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ FREE_POOL(GlobalRequest);
+ break;
+
+ case IOCTL_NDIS_QUERY_ALL_STATS:
+
+ //
+ // An "all" query.
+ //
+
+ AllRequest = (PNDIS_QUERY_ALL_REQUEST)GlobalRequest;
+
+ AllRequest->NdisStatus = Status;
+ SET_EVENT(&AllRequest->Event);
+
+ break;
+ }
+
+ break;
+ }
+}
+
+
+NTSTATUS
+ndisCloseIrpHandler(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN 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;
+
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>ndisCloseIrpHandler\n"));
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(Irp))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ (": Null Irp\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(Irp))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ (": Irp not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ if (IrpSp->FileObject->FsContext2 == (PVOID)NDIS_OPEN_QUERY_STATISTICS)
+ {
+ //
+ // Free the query context.
+ //
+
+ ASSERT (IrpSp->FileObject->FsContext2 == (PVOID)NDIS_OPEN_QUERY_STATISTICS);
+
+ OpenContext = IrpSp->FileObject->FsContext;
+ if (OpenContext->OidArray != NULL)
+ {
+ FREE_POOL(OpenContext->OidArray);
+ }
+ if (OpenContext->FullOidArray != NULL)
+ {
+ FREE_POOL(OpenContext->FullOidArray);
+ }
+ FREE_POOL(OpenContext);
+ PnPDereferencePackage();
+ }
+
+ Irp->IoStatus.Status = Status;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisCloseIrpHandler\n"));
+ return Status;
+}
+
+
+NTSTATUS
+ndisSuccessIrpHandler(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN 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
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisSuccessIrpHandler\n"));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(Irp))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ (": Null Irp\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(Irp))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ (": Irp not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisSuccessIrpHandler\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.
+ //
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>ndisKillOpenAndNotifyProtocol\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ (" Closing Adapter %wZ and notifying Protocol %wZ\n",
+ &OldOpenP->AdapterHandle->AdapterName,
+ &(OldOpenP->ProtocolHandle)->ProtocolCharacteristics.Name));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(OldOpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisKillOpenAndNotifyProtocol: Null Open Block\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(OldOpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisKillOpenAndNotifyProtocol: Open Block not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+
+ (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);
+ }
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==ndisKillOpenAndNotifyProtocol\n"));
+}
+
+
+BOOLEAN
+ndisKillOpen(
+ IN 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.
+
+--*/
+
+{
+ KIRQL OldIrql;
+ PNDIS_OPEN_BLOCK *ppOpen;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>ndisKillOpen\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ (" Closing Adapter %wZ as requested by %wZ\n",
+ &OldOpenP->AdapterHandle->AdapterName,
+ &(OldOpenP->ProtocolHandle)->ProtocolCharacteristics.Name));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(OldOpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisKillOpen: Null Open Block\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(OldOpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisKillOpen: Open Block not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+
+ ACQUIRE_SPIN_LOCK(&OldOpenP->SpinLock, &OldIrql);
+
+ //
+ // See if this open is already closing.
+ //
+
+ if (OldOpenP->Closing)
+ {
+ RELEASE_SPIN_LOCK(&OldOpenP->SpinLock, OldIrql);
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==ndisKillOpen\n"));
+ return TRUE;
+ }
+
+ //
+ // Indicate to others that this open is closing.
+ //
+
+ OldOpenP->Closing = TRUE;
+ RELEASE_SPIN_LOCK(&OldOpenP->SpinLock, OldIrql);
+
+ //
+ // Inform the MAC.
+ //
+
+ if ((OldOpenP->MacHandle->MacCharacteristics.CloseAdapterHandler)(
+ OldOpenP->MacBindingHandle) == NDIS_STATUS_PENDING)
+ {
+ //
+ // MacCloseAdapter pended, will complete later.
+ //
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==ndisKillOpen\n"));
+ return FALSE;
+ }
+
+ //
+ // Remove the reference for this open.
+ //
+ ObDereferenceObject(OldOpenP->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 open list
+ //
+ ACQUIRE_SPIN_LOCK(&ndisGlobalOpenListLock, &OldIrql);
+
+ for (ppOpen = &ndisGlobalOpenList;
+ *ppOpen != NULL;
+ ppOpen = &(*ppOpen)->NextGlobalOpen)
+ {
+ if (*ppOpen == OldOpenP)
+ {
+ *ppOpen = OldOpenP->NextGlobalOpen;
+ break;
+ }
+ }
+
+ ASSERT (*ppOpen == OldOpenP->NextGlobalOpen);
+
+ RELEASE_SPIN_LOCK(&ndisGlobalOpenListLock, OldIrql);
+
+ FREE_POOL(OldOpenP);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==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.
+
+--*/
+
+{
+ KIRQL OldIrql;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>ndisQueueAdapterOnMac\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ (" Adapter %wZ being added to MAC list\n",
+ &AdaptP->MacHandle->MacCharacteristics.Name));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ BOOLEAN f = FALSE;
+ if (DbgIsNull(AdaptP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisQueueAdapterOnMac: Null Adapter Block\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(AdaptP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisQueueAdapterOnMac: Adapter Block not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(MacP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisQueueAdapterOnMac: Null Mac Block\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(MacP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisQueueAdapterOnMac: Mac Block not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (f)
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ NDIS_ACQUIRE_SPIN_LOCK(&MacP->Ref.SpinLock, &OldIrql);
+
+ //
+ // Make sure the MAC is not closing.
+ //
+
+ if (MacP->Ref.Closing)
+ {
+ NDIS_RELEASE_SPIN_LOCK(&MacP->Ref.SpinLock, OldIrql);
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==ndisQueueAdapterOnMac\n"));
+ return FALSE;
+ }
+
+
+ //
+ // Add this adapter at the head of the queue
+ //
+
+ AdaptP->NextAdapter = MacP->AdapterQueue;
+ MacP->AdapterQueue = AdaptP;
+
+ NDIS_RELEASE_SPIN_LOCK(&MacP->Ref.SpinLock, OldIrql);
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==ndisQueueAdapterOnMac\n"));
+ return TRUE;
+}
+
+
+VOID
+ndisDeQueueAdapterOnMac(
+ IN PNDIS_ADAPTER_BLOCK AdaptP,
+ IN 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.
+
+--*/
+
+{
+ KIRQL OldIrql;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>ndisDeQueueAdapterOnMac\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ (" Adapter %wZ being removed from MAC list\n",
+ &AdaptP->MacHandle->MacCharacteristics.Name));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ BOOLEAN f = FALSE;
+
+ if (DbgIsNull(AdaptP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisDeQueueAdapterOnMac: Null Adapter Block\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(AdaptP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisDeQueueAdapterOnMac: Adapter Block not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(MacP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisDeQueueAdapterOnMac: Null Mac Block\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(MacP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisDeQueueAdapterOnMac: Mac Block not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (f)
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ NDIS_ACQUIRE_SPIN_LOCK(&MacP->Ref.SpinLock, &OldIrql);
+
+ //
+ // 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;
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&MacP->Ref.SpinLock, OldIrql);
+
+ if (MacP->Unloading && (MacP->AdapterQueue == (PNDIS_ADAPTER_BLOCK)NULL))
+ {
+ SET_EVENT(&MacP->AdaptersRemovedEvent);
+
+ }
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==ndisDeQueueAdapterOnMac\n"));
+}
+
+
+VOID
+ndisKillAdapter(
+ IN 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.
+ //
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>ndisKillAdapter\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ (" Removing Adapter %s\n",OldAdaptP->AdapterName.Buffer));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(OldAdaptP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisKillAdapter: Null Adapter Block\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(OldAdaptP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisKillAdapter: Adapter Block not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+ if (!NdisCloseRef(&OldAdaptP->Ref))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==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);
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==ndisKillAdapter\n"));
+}
+
+
+VOID
+ndisDereferenceAdapter(
+ IN 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)
+ {
+ NdisReleaseAdapterResources(AdaptP);
+ FREE_POOL(AdaptP->Resources);
+ }
+
+ FREE_POOL(AdaptP->AdapterName.Buffer);
+
+ if (AdaptP->Master)
+ {
+ UINT i;
+ ULONG MapRegistersPerChannel =
+ ((AdaptP->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2;
+ KIRQL OldIrql;
+
+ RAISE_IRQL_TO_DISPATCH(&OldIrql);
+
+ for (i=0; i<AdaptP->PhysicalMapRegistersNeeded; i++)
+ {
+ IoFreeMapRegisters(
+ AdaptP->SystemAdapterObject,
+ AdaptP->MapRegisters[i].MapRegister,
+ MapRegistersPerChannel);
+ }
+
+ LOWER_IRQL(OldIrql);
+ }
+
+ if ((AdaptP->NumberOfPorts > 0) && AdaptP->InitialPortMapped)
+ {
+ MmUnmapIoSpace (AdaptP->InitialPortMapping, AdaptP->NumberOfPorts);
+ }
+
+ //
+ // Delete the global db entry
+ //
+ if (AdaptP->BusId != 0)
+ {
+ ndisDeleteGlobalDb(AdaptP->BusType,
+ AdaptP->BusId,
+ AdaptP->BusNumber,
+ AdaptP->SlotNumber);
+ }
+
+ 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.
+
+--*/
+
+{
+ KIRQL OldIrql;
+
+ // attach ourselves to the adapter object linked list of opens
+ NDIS_ACQUIRE_SPIN_LOCK(&AdaptP->Ref.SpinLock, &OldIrql);
+
+ //
+ // Make sure the adapter is not closing.
+ //
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisQueueAdapterOnAdapter\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ (" Open being added to list for Adapter %s\n",AdaptP->AdapterName.Buffer));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ BOOLEAN f = FALSE;
+ if (DbgIsNull(OpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisQueueOpenOnAdapter: Null Open Block\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(OpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisQueueOpenOnAdapter: Open Block not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(AdaptP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisQueueOpenOnAdapter: Null Adapter Block\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(AdaptP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisQueueOpenOnAdapter: Adapter Block not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (f)
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (AdaptP->Ref.Closing)
+ {
+ NDIS_RELEASE_SPIN_LOCK(&AdaptP->Ref.SpinLock, OldIrql);
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisQueueAdapterOnAdapter\n"));
+ return FALSE;
+ }
+
+
+ //
+ // Attach this open at the head of the queue.
+ //
+
+ OpenP->AdapterNextOpen = AdaptP->OpenQueue;
+ AdaptP->OpenQueue = OpenP;
+
+
+ NDIS_RELEASE_SPIN_LOCK(&AdaptP->Ref.SpinLock, OldIrql);
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisQueueAdapterOnAdapter\n"));
+ return TRUE;
+}
+
+
+VOID
+ndisDeQueueOpenOnAdapter(
+ IN PNDIS_OPEN_BLOCK OpenP,
+ IN 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.
+
+--*/
+
+{
+ KIRQL OldIrql;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisDeQueueAdapterOnAdapter\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ (" Open being removed from list for Adapter %s\n",AdaptP->AdapterName.Buffer));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ BOOLEAN f = FALSE;
+ if (DbgIsNull(OpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisDeQueueOpenOnAdapter: Null Open Block\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(OpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisDeQueueOpenOnAdapter: Open Block not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(AdaptP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisDeQueueOpenOnAdapter: Null Adapter Block\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(AdaptP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisDeQueueOpenOnAdapter: Adapter Block not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (f)
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+
+ NDIS_ACQUIRE_SPIN_LOCK(&AdaptP->Ref.SpinLock, &OldIrql);
+ //
+ // 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;
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&AdaptP->Ref.SpinLock, OldIrql);
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisDeQueueAdapterOnAdapter\n"));
+}
+
+
+VOID
+ndisDereferenceMac(
+ IN 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.
+
+--*/
+{
+ KIRQL OldIrql;
+
+ if (NdisDereferenceRef(&(MacP)->Ref))
+ {
+ //
+ // Remove it from the global list.
+ //
+
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+
+ if (ndisMacDriverList == MacP)
+ {
+ ndisMacDriverList = MacP->NextMac;
+ }
+ else
+ {
+ PNDIS_MAC_BLOCK TmpMacP = ndisMacDriverList;
+
+ while(TmpMacP->NextMac != MacP)
+ {
+ TmpMacP = TmpMacP->NextMac;
+ }
+
+ TmpMacP->NextMac = TmpMacP->NextMac->NextMac;
+ }
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ if (MacP->PciAssignedResources != NULL)
+ {
+ FREE_POOL(MacP->PciAssignedResources);
+ }
+
+ FREE_POOL(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;
+}
+
+
+
+NDIS_STATUS
+ndisUnloadMac(
+ IN PNDIS_ADAPTER_BLOCK Mac
+ )
+/*++
+
+Routine Description:
+
+ Unbind all protocols from this mac and finally unload it.
+
+Arguments:
+
+ Mac - The Mac to unload.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ KIRQL OldIrql;
+ PNDIS_OPEN_BLOCK Open;
+ NDIS_BIND_CONTEXT UnbindContext;
+ NDIS_STATUS UnbindStatus;
+
+ //
+ // Walk the list of open bindings on this mac and ask the protocols to
+ // unbind from them. For down-level protocols, DEVICE A WAY TO HANDLE THEM.
+ //
+ NDIS_ACQUIRE_SPIN_LOCK(&Mac->Ref.SpinLock, &OldIrql);
+
+ next:
+ for (Open = Mac->OpenQueue;
+ Open != NULL;
+ Open = Open->NextGlobalOpen)
+ {
+ if (!Open->Closing && !Open->Unloading &&
+ (Open->ProtocolHandle->ProtocolCharacteristics.UnbindAdapterHandler != NULL))
+ {
+ Open->Unloading = TRUE;
+ break;
+ }
+ }
+
+ if (Open != NULL)
+ {
+ NDIS_RELEASE_SPIN_LOCK(&Mac->Ref.SpinLock, OldIrql);
+
+ INITIALIZE_EVENT(&UnbindContext.Event);
+
+ WAIT_FOR_OBJECT(&Open->ProtocolHandle->Mutex, NULL);
+
+ (*Open->ProtocolHandle->ProtocolCharacteristics.UnbindAdapterHandler)(
+ &UnbindStatus,
+ Open->ProtocolBindingContext,
+ &UnbindContext);
+
+ if (UnbindStatus == NDIS_STATUS_PENDING)
+ {
+ WAIT_FOR_OBJECT(&UnbindContext.Event, NULL);
+ }
+
+ RELEASE_MUTEX(&Open->ProtocolHandle->Mutex);
+
+ NDIS_ACQUIRE_SPIN_LOCK(&Mac->Ref.SpinLock, &OldIrql);
+
+ goto next;
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&Mac->Ref.SpinLock, OldIrql);
+
+ //
+ // The halt handler must be called when the last reference
+ // on the driver block goes away
+ //
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+NDIS_STATUS
+ndisTranslateMacName(
+ IN PNDIS_ADAPTER_BLOCK Mac,
+ IN PUCHAR Buffer,
+ IN UINT BufferLength,
+ OUT PUINT AmountCopied
+
+ )
+/*++
+
+Routine Description:
+
+ Calls the PnP protocols to enumerate PnP ids for the given miniport.
+
+Arguments:
+
+ Mac - The Mac in question.
+ Buffer, BufferLength - Buffer for a list of PnP Ids.
+ AmountCopied - How much buffer was used up.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ KIRQL OldIrql;
+ PNDIS_OPEN_BLOCK Open;
+ NDIS_STATUS Status;
+ UINT AmtCopied = 0, TotalAmtCopied = 0;
+
+ //
+ // Walk the list of open bindings on this mac and ask the protocols to
+ // unbind from them. For down-level protocols, DEVICE A WAY TO HANDLE THEM.
+ //
+ NDIS_ACQUIRE_SPIN_LOCK(&Mac->Ref.SpinLock, &OldIrql);
+
+ for (Open = Mac->OpenQueue;
+ Open != NULL;
+ Open = Open->NextGlobalOpen)
+ {
+ if (!Open->Closing && !Open->Unloading &&
+ (Open->ProtocolHandle->ProtocolCharacteristics.TranslateHandler != NULL))
+ {
+ break;
+ }
+ }
+
+ if (Open != NULL)
+ {
+ NDIS_RELEASE_SPIN_LOCK(&Mac->Ref.SpinLock, OldIrql);
+
+ (*Open->ProtocolHandle->ProtocolCharacteristics.TranslateHandler)(
+ &Status,
+ Open->ProtocolBindingContext,
+ (PNET_PNP_ID)(Buffer + TotalAmtCopied),
+ BufferLength - TotalAmtCopied,
+ &AmtCopied);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ TotalAmtCopied += AmtCopied;
+ }
+
+ NDIS_ACQUIRE_SPIN_LOCK(&Mac->Ref.SpinLock, &OldIrql);
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&Mac->Ref.SpinLock, OldIrql);
+
+ *AmountCopied = TotalAmtCopied;
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+#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.
+
+--*/
+{
+ KIRQL OldIrql;
+ PNDIS_LOOKAHEAD_ELEMENT TmpElement;
+
+ ACQUIRE_SPIN_LOCK(&ndisLookaheadBufferLock, &OldIrql);
+
+ if (ndisLookaheadBufferLength < (LookaheadLength +
+ sizeof(NDIS_LOOKAHEAD_ELEMENT)))
+ {
+ //
+ // Free current list
+ //
+ while (ndisLookaheadBufferList != NULL)
+ {
+ TmpElement = ndisLookaheadBufferList;
+ ndisLookaheadBufferList = ndisLookaheadBufferList->Next;
+
+ FREE_POOL(TmpElement);
+ }
+
+ ndisLookaheadBufferLength = LookaheadLength +
+ sizeof(NDIS_LOOKAHEAD_ELEMENT);
+ }
+
+ if (ndisLookaheadBufferList == NULL)
+ {
+ ndisLookaheadBufferList = (PNDIS_LOOKAHEAD_ELEMENT)ALLOC_FROM_POOL(ndisLookaheadBufferLength,
+ NDIS_TAG_LA_BUF);
+
+ if (ndisLookaheadBufferList == NULL)
+ {
+ *pLookaheadBuffer = NULL;
+ RELEASE_SPIN_LOCK(&ndisLookaheadBufferLock, OldIrql);
+ return;
+ }
+
+ ndisLookaheadBufferList->Next = NULL;
+ ndisLookaheadBufferList->Length = ndisLookaheadBufferLength;
+ }
+
+
+ //
+ // Get the buffer
+ //
+
+ *pLookaheadBuffer = (ndisLookaheadBufferList + 1);
+ ndisLookaheadBufferList = ndisLookaheadBufferList->Next;
+
+ RELEASE_SPIN_LOCK(&ndisLookaheadBufferLock, OldIrql);
+
+ //
+ // 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;
+ KIRQL OldIrql;
+
+ Element--;
+
+ if (Element->Length != ndisLookaheadBufferLength)
+ {
+ FREE_POOL(Element);
+ }
+ else
+ {
+ ACQUIRE_SPIN_LOCK(&ndisLookaheadBufferLock, &OldIrql);
+
+ Element->Next = ndisLookaheadBufferList;
+ ndisLookaheadBufferList = Element;
+
+ RELEASE_SPIN_LOCK(&ndisLookaheadBufferLock, OldIrql);
+ }
+}
+
+#endif // _ALPHA_
+
diff --git a/private/ntos/ndis/ndis40/mac.h b/private/ntos/ndis/ndis40/mac.h
new file mode 100644
index 000000000..a46096e23
--- /dev/null
+++ b/private/ntos/ndis/ndis40/mac.h
@@ -0,0 +1,48 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ mac.h
+
+Abstract:
+
+ NDIS wrapper definitions
+
+Author:
+
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Jun-95 Jameel Hyder Split up from a monolithic file
+--*/
+
+//
+// The following are counters used for debugging
+//
+
+extern PNDIS_MAC_BLOCK ndisMacDriverList;
+extern const NDIS_PHYSICAL_ADDRESS HighestAcceptableMax;
+extern ULONG ndisDmaAlignment;
+
+//
+// For tracking memory allocated for shared memory
+//
+extern ERESOURCE SharedMemoryResource;
+
+//
+// For tracking on NT 3.1 protocols that do not use any of the filter packages.
+//
+extern PNDIS_OPEN_BLOCK ndisGlobalOpenList;
+extern KSPIN_LOCK ndisGlobalOpenListLock;
+extern KSPIN_LOCK ndisLookaheadBufferLock;
+extern ULONG ndisLookaheadBufferLength;
+#if defined(_ALPHA_)
+extern PNDIS_LOOKAHEAD_ELEMENT ndisLookaheadBufferList;
+#endif
+
diff --git a/private/ntos/ndis/ndis40/makefile b/private/ntos/ndis/ndis40/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/ndis40/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/ndis40/makefile.inc b/private/ntos/ndis/ndis40/makefile.inc
new file mode 100644
index 000000000..bc3f05082
--- /dev/null
+++ b/private/ntos/ndis/ndis40/makefile.inc
@@ -0,0 +1,11 @@
+obj\i386\ndis.def: ndis.src
+ cl386 /EP -Di386 $(C_DEFINES) $(386_DBG_DEFINES) ndis.src > obj\i386\ndis.def
+
+obj\mips\ndis.def: ndis.src
+ rcpp -P -f ndis.src -DMIPS=1 $(C_DEFINES) $(MIPS_DBG_DEFINES) -g obj\mips\ndis.def
+
+obj\ppc\ndis.def: ndis.src
+ rcpp -P -f ndis.src -DPPC=1 $(C_DEFINES) $(PPC_DBG_DEFINES) -g obj\ppc\ndis.def
+
+obj\alpha\ndis.def: ndis.src
+ rcpp -P -f ndis.src -DALPHA=1 $(C_DEFINES) $(ALPHA_DBG_DEFINES) -g obj\alpha\ndis.def
diff --git a/private/ntos/ndis/ndis40/mini.h b/private/ntos/ndis/ndis40/mini.h
new file mode 100644
index 000000000..e210962d5
--- /dev/null
+++ b/private/ntos/ndis/ndis40/mini.h
@@ -0,0 +1,251 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ mini.h
+
+Abstract:
+
+ NDIS miniport wrapper definitions
+
+Author:
+
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Jun-95 Jameel Hyder Split up from a monolithic file
+--*/
+
+#ifndef __MINI_H
+#define __MINI_H
+
+//
+// Macros for setting, clearing, and testing bits in the Miniport Flags.
+//
+#define MINIPORT_SET_FLAG(m, f) ((m)->Flags |= (f))
+#define MINIPORT_CLEAR_FLAG(m, f) ((m)->Flags &= ~(f))
+#define MINIPORT_TEST_FLAG(m, f) (((m)->Flags & (f)) != 0)
+
+#define MINIPORT_SET_SEND_FLAG(m, f) ((m)->SendFlags |= (f))
+#define MINIPORT_CLEAR_SEND_FLAG(m, f) ((m)->SendFlags &= ~(f))
+#define MINIPORT_TEST_SEND_FLAG(m, f) (((m)->SendFlags & (f)) != 0)
+
+//
+// Flags for packet information.
+//
+#define MINIPORT_SET_PACKET_FLAG(p, f) ((p)->Private.NdisPacketFlags |= (f))
+#define MINIPORT_CLEAR_PACKET_FLAG(p, f) ((p)->Private.NdisPacketFlags &= ~(f))
+#define MINIPORT_TEST_PACKET_FLAG(p, f) (((p)->Private.NdisPacketFlags & (f)) != 0)
+
+#define fPACKET_HAS_BEEN_LOOPED_BACK 0x01
+#define fPACKET_HAS_TIMED_OUT 0x02
+#define fPACKET_IS_IN_NDIS 0x04
+
+
+#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_DEFERRED_TIMEOUT 15 // Deferred timer
+#define NDIS_MINIPORT_TR_RESET_TIMEOUT 15 // Number of WakeUps per reset attempt
+
+//
+// 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))
+
+//
+// This structure is used by IndicatePacket/ReturnPacket code
+// to keep track of references.
+//
+typedef struct _NDIS_PACKET_REFERENCE
+{
+ PNDIS_MINIPORT_BLOCK Miniport;
+ union
+ {
+ UINT RefCount;
+ PNDIS_PACKET NextPacket;
+ };
+} NDIS_PACKET_REFERENCE, *PNDIS_PACKET_REFERENCE;
+
+#define PNDIS_REFERENCE_FROM_PNDIS_PACKET(_packet) \
+ ((PNDIS_PACKET_REFERENCE)((_packet)->WrapperReserved))
+
+//
+// Used by the NdisCoRequest api to keep context information in the Request->NdisReserved
+//
+typedef struct _NDIS_COREQ_RESERVED
+{
+ union
+ {
+ REQUEST_COMPLETE_HANDLER RequestCompleteHandler;
+ CO_REQUEST_COMPLETE_HANDLER CoRequestCompleteHandler;
+ };
+ NDIS_HANDLE VcContext;
+ union
+ {
+ NDIS_HANDLE AfContext;
+ PNDIS_M_OPEN_BLOCK Open;
+ };
+ NDIS_HANDLE PartyContext;
+ ULONG Flags;
+ PNDIS_REQUEST RealRequest;
+} NDIS_COREQ_RESERVED, *PNDIS_COREQ_RESERVED;
+
+#define COREQ_DOWNLEVEL 0x00000001
+#define COREQ_GLOBAL_REQ 0x00000002
+#define COREQ_QUERY_OIDS 0x00000004
+#define COREQ_QUERY_STATS 0x00000008
+#define COREQ_QUERY_SET 0x00000010
+
+#define PNDIS_COREQ_RESERVED_FROM_REQUEST(_request) \
+ (PNDIS_COREQ_RESERVED)((_request)->NdisReserved)
+
+#define MINIPORT_ENABLE_INTERRUPT(_M_) \
+{ \
+ if ((_M_)->EnableInterruptHandler != NULL) \
+ { \
+ ((_M_)->EnableInterruptHandler)((_M_)->MiniportAdapterContext); \
+ } \
+}
+
+#define MINIPORT_SYNC_ENABLE_INTERRUPT(_M_) \
+{ \
+ if ((_M_)->EnableInterruptHandler != NULL) \
+ { \
+ SYNC_WITH_ISR(((_M_))->Interrupt->InterruptObject, \
+ ((_M_)->EnableInterruptHandler), \
+ (_M_)->MiniportAdapterContext); \
+ } \
+}
+
+#define MINIPORT_DISABLE_INTERRUPT(_M_) \
+{ \
+ ASSERT((_M_)->DisableInterruptHandler != NULL); \
+ ((_M_)->DriverHandle->MiniportCharacteristics.DisableInterruptHandler)( \
+ (_M_)->MiniportAdapterContext); \
+}
+
+#define MINIPORT_SYNC_DISABLE_INTERRUPT(_M_) \
+{ \
+ if ((_M_)->DisableInterruptHandler != NULL) \
+ { \
+ SYNC_WITH_ISR(((_M_))->Interrupt->InterruptObject, \
+ ((_M_)->DisableInterruptHandler), \
+ (_M_)->MiniportAdapterContext); \
+ } \
+}
+
+#define CHECK_FOR_NORMAL_INTERRUPTS(_M_) \
+ if ((((_M_)->Flags & (fMINIPORT_HALTING | fMINIPORT_IN_INITIALIZE)) == 0)&& \
+ ((_M_)->Interrupt != NULL) && \
+ !(_M_)->Interrupt->IsrRequested && \
+ !(_M_)->Interrupt->SharedInterrupt) \
+ { \
+ (_M_)->Flags |= fMINIPORT_NORMAL_INTERRUPTS; \
+ } \
+ else \
+ { \
+ (_M_)->Flags &= ~fMINIPORT_NORMAL_INTERRUPTS; \
+ }
+
+
+#define EXPERIMENTAL_SIZE 4
+extern PNDIS_M_DRIVER_BLOCK ndisMiniDriverList;
+extern KSPIN_LOCK ndisDriverListLock;
+extern NDIS_MEDIUM * ndisMediumArray,
+ ndisMediumBuffer[NdisMediumMax + EXPERIMENTAL_SIZE];
+extern UINT ndisMediumArraySize, ndisMediumArrayMaxSize;
+
+//
+// Filter package callback handlers
+//
+#define PNDIS_M_OPEN_FROM_BINDING_HANDLE(_handle) ((PNDIS_M_OPEN_BLOCK)(_handle))
+
+typedef
+NDIS_STATUS
+(*WAN_RECEIVE_HANDLER) (
+ IN NDIS_HANDLE NdisLinkContext,
+ IN PUCHAR Packet,
+ IN ULONG PacketSize
+ );
+
+typedef
+NDIS_STATUS
+(*PNDIS_M_WAN_SEND)(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE NdisLinkHandle,
+ IN PVOID Packet
+ );
+
+VOID
+ndisLastCountRemovedFunction(
+ IN struct _KDPC *Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+typedef struct _AsyncWorkItem
+{
+ WORK_QUEUE_ITEM ExWorkItem;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ ULONG Length;
+ BOOLEAN Cached;
+ PVOID VAddr;
+ PVOID Context;
+ NDIS_PHYSICAL_ADDRESS PhyAddr;
+} ASYNC_WORKITEM, *PASYNC_WORKITEM;
+
+
+VOID
+ndisMQueuedAllocateSharedHandler(
+ IN PASYNC_WORKITEM pWorkItem
+ );
+
+VOID
+ndisMQueuedFreeSharedHandler(
+ IN PASYNC_WORKITEM pWorkItem
+ );
+
+//
+// Macro for the deferred send handler.
+//
+#define NDISM_START_SENDS(_M) (_M)->DeferredSendHandler((_M))
+
+#define NDISM_DEFER_PROCESS_DEFERRED(_M) NdisSetTimer((_M)->DeferredTimer, NDIS_MINIPORT_DEFERRED_TIMEOUT);
+
+//
+// A list of registered address families are maintained here.
+//
+typedef struct _NDIS_AF_LIST
+{
+ struct _NDIS_AF_LIST *NextGlobal; // Global. Head at ndisAfList;
+ struct _NDIS_AF_LIST *NextOpen; // For this miniport Head at NDIS_MINIPORT_BLOCK
+
+ PNDIS_M_OPEN_BLOCK Open; // Back pointer to the open-block
+
+ NDIS_AF AddressFamily;
+
+ NDIS_CALL_MANAGER_CHARACTERISTICS CmChars;
+} NDIS_AF_LIST, *PNDIS_AF_LIST;
+
+extern PNDIS_AF_LIST ndisAfList;
+
+#endif // __MINI_H
diff --git a/private/ntos/ndis/ndis40/minint.c b/private/ntos/ndis/ndis40/minint.c
new file mode 100644
index 000000000..ff87c1aca
--- /dev/null
+++ b/private/ntos/ndis/ndis40/minint.c
@@ -0,0 +1,1293 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ miniport.c
+
+Abstract:
+
+ NDIS miniport wrapper functions
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 05-Oct-93
+ Jameel Hyder (JameelH) Re-organization 01-Jun-95
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_MININT
+
+/////////////////////////////////////////////////////////////////////
+//
+// HALT / CLOSE CODE
+//
+/////////////////////////////////////////////////////////////////////
+
+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, rc = TRUE;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+
+ //
+ // Find the Miniport open block
+ //
+
+ for (MiniportOpen = Miniport->OpenQueue;
+ MiniportOpen != NULL;
+ MiniportOpen = MiniportOpen->MiniportNextOpen)
+ {
+ if (MiniportOpen->FakeOpen == OldOpenP)
+ {
+ break;
+ }
+ }
+
+ ASSERT(MiniportOpen != NULL);
+ RAISE_IRQL_TO_DISPATCH(&OldIrql);
+
+ do
+ {
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(&MiniportOpen->SpinLock);
+
+ if (MiniportOpen->Flags & fMINIPORT_OPEN_PMODE)
+ {
+ Miniport->PmodeOpens --;
+ }
+
+ //
+ // See if this open is already closing.
+ //
+ if (MINIPORT_TEST_FLAG(MiniportOpen, fMINIPORT_OPEN_CLOSING))
+ {
+ NDIS_RELEASE_SPIN_LOCK_DPC(&MiniportOpen->SpinLock);
+ break;
+ }
+
+ //
+ // Indicate to others that this open is closing.
+ //
+ MINIPORT_SET_FLAG(MiniportOpen, fMINIPORT_OPEN_CLOSING);
+ NDIS_RELEASE_SPIN_LOCK_DPC(&MiniportOpen->SpinLock);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Remove us from the filter package
+ //
+ switch (Miniport->MediaType)
+ {
+ case NdisMediumArcnet878_2:
+ if (!MINIPORT_TEST_FLAG(MiniportOpen,
+ fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
+ {
+ 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;
+
+ case NdisMediumAtm:
+ //
+ // there is no filter database for ATM medium so we have to handle
+ // this differently. Specifically we do not need to know of there
+ // is an indication occuring now or not since the indication
+ // routine checks if the reference count goes to zero and it
+ // also checks the Closing flag. In addition if there is an active
+ // indication going on, then there must be an open connection
+ // which has the ref count above zero. Since a close on the
+ // connection will not run during a receive indication (because
+ // the miniport is locked), there should be no special code
+ // required for this case.
+ //
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+ }
+
+ if (Status != NDIS_STATUS_CLOSING_INDICATING)
+ {
+ //
+ // Otherwise the close action routine will fix this up.
+ //
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("- Open 0x%x Reference 0x%x\n", MiniportOpen, MiniportOpen->References));
+
+ MiniportOpen->References--;
+
+ //
+ // If the status that was returned from the filter library
+ // was NDIS_STATUS_PENDING then we need to do some set information
+ // calls to clean up the opens filter & address settings....
+ //
+ switch (Miniport->MediaType)
+ {
+ case NdisMedium802_3:
+ case NdisMedium802_5:
+ case NdisMediumFddi:
+ case NdisMediumArcnet878_2:
+ ndisMRestoreFilterSettings(Miniport, MiniportOpen);
+ break;
+ }
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("!=0 Open 0x%x References 0x%x\n", MiniportOpen, MiniportOpen->References));
+
+ if (MiniportOpen->References != 0)
+ {
+ //
+ // Wait for close to complete, reference count will drop to 0.
+ //
+ NDISM_DEFER_PROCESS_DEFERRED(Miniport);
+
+ rc = FALSE;
+ }
+ else
+ {
+ //
+ // Free Vc datastructures are queued to be reused, but when the
+ // Open closes we must clean up these free Vcs
+ //
+ ndisMCoFreeResources(MiniportOpen);
+
+ //
+ // This sends an IRP_MJ_CLOSE IRP.
+ //
+ ObDereferenceObject(OldOpenP->FileObject);
+
+ //
+ // Remove us from the adapter and protocol open queues.
+ //
+ ndisDeQueueOpenOnProtocol(OldOpenP, OldOpenP->ProtocolHandle);
+ ndisDeQueueOpenOnMiniport(MiniportOpen, MiniportOpen->MiniportHandle);
+
+ ndisDereferenceProtocol(OldOpenP->ProtocolHandle);
+ ndisDereferenceMiniport(MiniportOpen->MiniportHandle);
+
+ NdisFreeSpinLock(&MiniportOpen->SpinLock);
+ FREE_POOL(MiniportOpen);
+ FREE_POOL(OldOpenP);
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ } while (FALSE);
+
+ LOWER_IRQL(OldIrql);
+ return rc;
+}
+
+
+VOID
+ndisMFinishClose(
+ 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.
+
+
+--*/
+{
+ //
+ // free any memory allocated to Vcs
+ //
+ ndisMCoFreeResources(Open);
+
+ ASSERT(MINIPORT_TEST_FLAG(Open, fMINIPORT_OPEN_CLOSING));
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.CloseAdapterCompleteHandler) (
+ Open->ProtocolBindingContext,
+ NDIS_STATUS_SUCCESS);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ ndisDeQueueOpenOnProtocol(Open->FakeOpen, Open->ProtocolHandle);
+ ndisDeQueueOpenOnMiniport(Open, Open->MiniportHandle);
+ FREE_POOL(Open->FakeOpen);
+
+ ndisDereferenceMiniport(Open->MiniportHandle);
+ ndisDereferenceProtocol(Open->ProtocolHandle);
+
+ NdisFreeSpinLock(&Open->SpinLock);
+
+ //
+ // This sends an IRP_MJ_CLOSE IRP.
+ //
+
+ ObDereferenceObject(Open->FileObject);
+
+ FREE_POOL(Open);
+}
+
+
+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.
+
+--*/
+
+{
+ KIRQL OldIrql;
+
+ NDIS_ACQUIRE_SPIN_LOCK(&Miniport->Ref.SpinLock, &OldIrql);
+
+ //
+ // 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;
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&Miniport->Ref.SpinLock, OldIrql);
+}
+
+
+BOOLEAN
+ndisQueueMiniportOnDriver(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_M_DRIVER_BLOCK MiniBlock
+ )
+
+/*++
+
+Routine Description:
+
+ Adds an mini-port to a list of mini-port for a driver.
+
+Arguments:
+
+ Miniport - The mini-port block to queue.
+ MiniBlock - The driver block to queue it to.
+
+Return Value:
+
+ FALSE if the driver is closing.
+ TRUE otherwise.
+
+--*/
+
+{
+ KIRQL OldIrql;
+
+ NDIS_ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
+
+ DBGPRINT(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
+ ("Enter queue mini-port on driver\n"));
+ DBGPRINT(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
+ ("queue mini-port 0x%x\n", Miniport));
+ DBGPRINT(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
+ ("driver 0x%x\n", MiniBlock));
+
+ //
+ // Make sure the driver is not closing.
+ //
+
+ if (MiniBlock->Ref.Closing)
+ {
+ DBGPRINT(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
+ ("Exit queue mini-port on driver\n"));
+
+ NDIS_RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
+ return FALSE;
+ }
+
+ //
+ // Add this adapter at the head of the queue
+ //
+
+ Miniport->NextMiniport = MiniBlock->MiniportQueue;
+ MiniBlock->MiniportQueue = Miniport;
+
+ DBGPRINT(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
+ ("Exit queue mini-port on driver\n"));
+
+ NDIS_RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
+ return TRUE;
+}
+
+
+VOID
+ndisDequeueMiniportOnDriver(
+ PNDIS_MINIPORT_BLOCK Miniport,
+ PNDIS_M_DRIVER_BLOCK MiniBlock
+ )
+
+/*++
+
+Routine Description:
+
+ Removes an mini-port from a list of mini-port for a driver.
+
+Arguments:
+
+ Miniport - The mini-port block to dequeue.
+ MiniBlock - The driver block to dequeue it from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_MINIPORT_BLOCK *ppQ;
+ KIRQL OldIrql;
+
+ NDIS_ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
+
+ DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO,
+ ("Dequeue on driver\n"));
+ DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO,
+ ("dequeue mini-port 0x%x\n", Miniport));
+ DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO,
+ ("driver 0x%x\n", MiniBlock));
+
+ //
+ // Find the driver on the queue, and remove it.
+ //
+ for (ppQ = &MiniBlock->MiniportQueue;
+ *ppQ != NULL;
+ ppQ = &(*ppQ)->NextMiniport)
+ {
+ if (*ppQ == Miniport)
+ {
+ *ppQ = Miniport->NextMiniport;
+ break;
+ }
+ }
+
+ ASSERT(*ppQ == Miniport->NextMiniport);
+
+ NDIS_RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
+
+ if (MiniBlock->Unloading && (MiniBlock->MiniportQueue == (PNDIS_MINIPORT_BLOCK)NULL))
+ {
+ SET_EVENT(&MiniBlock->MiniportsRemovedEvent);
+ }
+
+ DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO,
+ ("Exit dequeue mini-port on driver\n"));
+}
+
+
+VOID
+ndisDereferenceDriver(
+ PNDIS_M_DRIVER_BLOCK MiniBlock
+ )
+/*++
+
+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.
+
+--*/
+{
+ KIRQL OldIrql;
+
+ if (NdisDereferenceRef(&(MiniBlock)->Ref))
+ {
+ //
+ // Remove it from the global list.
+ //
+
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+
+ if (ndisMiniDriverList == MiniBlock)
+ {
+ ndisMiniDriverList = MiniBlock->NextDriver;
+ }
+ else
+ {
+ PNDIS_M_DRIVER_BLOCK TmpDriver = ndisMiniDriverList;
+
+ while(TmpDriver->NextDriver != MiniBlock)
+ {
+ TmpDriver = TmpDriver->NextDriver;
+ }
+
+ TmpDriver->NextDriver = TmpDriver->NextDriver->NextDriver;
+ }
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ FREE_POOL(MiniBlock);
+ }
+}
+
+
+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.
+
+--*/
+{
+ PSINGLE_LIST_ENTRY Link;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+ UINT c;
+ BOOLEAN TimerQueued;
+
+ 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 (Miniport->Resources)
+ {
+ ndisMReleaseResources(Miniport);
+ }
+
+ if (((PNDIS_WRAPPER_CONTEXT)Miniport->WrapperContext)->AssignedSlotResources != NULL)
+ {
+ FREE_POOL(((PNDIS_WRAPPER_CONTEXT)Miniport->WrapperContext)->AssignedSlotResources);
+ }
+
+ //
+ // Do we need to acquire the work queue lock?
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+ }
+
+ //
+ // Free work items
+ //
+ while (Miniport->WorkItemFreeQueue.Next != NULL)
+ {
+ Link = PopEntryList(&Miniport->WorkItemFreeQueue);
+ WorkItem = CONTAINING_RECORD(Link, NDIS_MINIPORT_WORK_ITEM, Link);
+ FREE_POOL(WorkItem);
+ }
+
+ //
+ // Free the work items that are currently on the work queue.
+ //
+ for (c = 0; c < NUMBER_OF_WORK_ITEM_TYPES; c++)
+ {
+ //
+ // Free all work items on the current queue.
+ //
+ while (Miniport->WorkQueue[c].Next != NULL)
+ {
+ Link = PopEntryList(&Miniport->WorkQueue[c]);
+ WorkItem = CONTAINING_RECORD(Link, NDIS_MINIPORT_WORK_ITEM, Link);
+ FREE_POOL(WorkItem);
+ }
+ }
+
+ //
+ // Free the single workitem list.
+ //
+ for (c = 0; c < NUMBER_OF_SINGLE_WORK_ITEMS; c++)
+ {
+ //
+ // Is there a work item here?
+ //
+ Link = PopEntryList(&Miniport->SingleWorkItems[c]);
+ if (Link != NULL)
+ {
+ WorkItem = CONTAINING_RECORD(Link, NDIS_MINIPORT_WORK_ITEM, Link);
+ FREE_POOL(WorkItem);
+ }
+ }
+
+ //
+ // Do we need to release the work queue lock?
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+ NdisFreeSpinLock(&Miniport->SendLock);
+ }
+
+ //
+ // Did we allocate an array of packets?
+ //
+ if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY))
+ {
+ FREE_POOL(Miniport->PacketArray);
+ }
+
+ //
+ // Cancel the timer from firing.
+ //
+ NdisCancelTimer(Miniport->DeferredTimer, &TimerQueued);
+ if (TimerQueued)
+ {
+ NdisStallExecution(NDIS_MINIPORT_DEFERRED_TIMEOUT);
+ }
+
+ //
+ // Free the memory allocated for the timer.
+ //
+ FREE_POOL(Miniport->DeferredTimer);
+
+ //
+ // Is there an arcnet lookahead buffer allocated?
+ //
+ if (Miniport->ArcnetLookaheadBuffer != NULL)
+ {
+ FREE_POOL(Miniport->ArcnetLookaheadBuffer);
+ }
+
+ //
+ // Delete the global db entry
+ //
+ if (Miniport->BusId != 0)
+ {
+ ndisDeleteGlobalDb(Miniport->BusType,
+ Miniport->BusId,
+ Miniport->BusNumber,
+ Miniport->SlotNumber);
+ }
+
+ if (Miniport->FakeMac != NULL)
+ {
+ FREE_POOL(Miniport->FakeMac);
+ }
+
+ MiniportDereferencePackage();
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
+ {
+ CoDereferencePackage();
+ }
+
+ ndisDequeueMiniportOnDriver(Miniport, Miniport->DriverHandle);
+ ndisDereferenceDriver(Miniport->DriverHandle);
+ NdisMDeregisterAdapterShutdownHandler(Miniport);
+ IoUnregisterShutdownNotification(Miniport->DeviceObject);
+ IoDeleteDevice(Miniport->DeviceObject);
+ }
+}
+
+
+VOID
+ndisMHaltMiniport(
+ 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;
+ KIRQL OldIrql;
+ BOOLEAN Canceled;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ LOCK_MINIPORT(Miniport, LocalLock);
+ while (!LocalLock)
+ {
+ //
+ // This can only happen on an MP system. We must now
+ // wait for the other processor to exit the mini-port.
+ //
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ NdisStallExecution(1000);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+ LOCK_MINIPORT(Miniport, LocalLock);
+ }
+
+ //
+ // We can now release safely
+ //
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ NdisCancelTimer(&Miniport->WakeUpDpcTimer, &Canceled);
+ if (!Canceled)
+ {
+ NdisStallExecution(500000);
+ }
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler)(
+ Miniport->MiniportAdapterContext);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ ndisMAbortPacketsAndRequests(Miniport);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ //
+ // If a shutdown handler was registered then deregister it.
+ //
+
+ NdisMDeregisterAdapterShutdownHandler(Miniport);
+
+ ndisDereferenceMiniport(Miniport);
+}
+
+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 MiniBlock;
+ PNDIS_MINIPORT_BLOCK Miniport, NextMiniport;
+ KIRQL OldIrql;
+
+ DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO,
+ ("Enter unload\n"));
+
+ //
+ // Search for the driver
+ //
+
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+
+ MiniBlock = ndisMiniDriverList;
+
+ while (MiniBlock != (PNDIS_M_DRIVER_BLOCK)NULL)
+ {
+ if (MiniBlock->NdisDriverInfo->NdisWrapperDriver == DriverObject)
+ {
+ break;
+ }
+
+ MiniBlock = MiniBlock->NextDriver;
+ }
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ if (MiniBlock == (PNDIS_M_DRIVER_BLOCK)NULL)
+ {
+ //
+ // It is already gone. Just return.
+ //
+
+ DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO,
+ ("Exit unload\n"));
+
+ return;
+ }
+
+ MiniBlock->Unloading = TRUE;
+
+ DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO,
+ ("Halting mini-port\n"));
+
+ //
+ // Now call MiniportHalt() for each Miniport.
+ //
+
+ Miniport = MiniBlock->MiniportQueue;
+
+ while (Miniport != (PNDIS_MINIPORT_BLOCK)NULL)
+ {
+ NextMiniport = Miniport->NextMiniport; // since queue may change
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO,
+ ("Enter shutdown\n"));
+
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_HALTING);
+ MINIPORT_SET_SEND_FLAG(Miniport, fMINIPORT_SEND_HALTING);
+
+ //
+ // Queue the halt work item.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemHalt, NULL, NULL);
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ ndisMHaltMiniport(Miniport);
+
+ Miniport = NextMiniport;
+ }
+
+ //
+ // Wait for all adapters to be gonzo.
+ //
+ WAIT_FOR_OBJECT(&MiniBlock->MiniportsRemovedEvent, NULL);
+
+ RESET_EVENT(&MiniBlock->MiniportsRemovedEvent);
+
+ //
+ // Now remove the last reference (this will remove it from the list)
+ //
+
+ ASSERT(MiniBlock->Ref.ReferenceCount == 1);
+
+ ndisDereferenceDriver(MiniBlock);
+
+ DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO, ("Exit unload\n"));
+}
+
+
+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;
+ BOOLEAN LocalLock;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>ndisMShutdown\n"));
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ //
+ // Mark the miniport as halting and NOT using normal interrupts.
+ //
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_HALTING);
+ MINIPORT_SET_SEND_FLAG(Miniport, fMINIPORT_SEND_HALTING);
+
+ //
+ // Queue a halt work item.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemHalt, NULL, NULL);
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
+
+ if (WrapperContext->ShutdownHandler != NULL)
+ {
+ LOCK_MINIPORT(Miniport, LocalLock);
+ while (!LocalLock)
+ {
+ //
+ // This can only happen on an MP system. We must now
+ // wait for the other processor to exit the mini-port.
+ //
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ NdisStallExecution(1000);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+ LOCK_MINIPORT(Miniport, LocalLock);
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ //
+ // Call the shutdown routine.
+ //
+
+ if (WrapperContext->ShutdownHandler != NULL)
+ {
+ WrapperContext->ShutdownHandler(WrapperContext->ShutdownContext);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ }
+ else
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+ }
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==ndisMShutdown\n"));
+
+ return STATUS_SUCCESS;
+}
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// PLUG-N-PLAY CODE
+//
+/////////////////////////////////////////////////////////////////////
+
+
+NDIS_STATUS
+ndisUnloadMiniport(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ )
+/*++
+
+Routine Description:
+
+ Unbind all protocols from this miniport and finally unload it.
+
+Arguments:
+
+ Miniport - The Miniport to unload.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ KIRQL OldIrql;
+ PNDIS_M_OPEN_BLOCK Open;
+ NDIS_BIND_CONTEXT UnbindContext;
+ NDIS_STATUS UnbindStatus;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ // Start off by stopping all activity on this miniport
+ // MINIPORT_SET_FLAG(Miniport, fMINIPORT_HALTING);
+
+ //
+ // Walk the list of open bindings on this miniport and ask the protocols to
+ // unbind from them. For down-level protocols, DEVICE A WAY TO HANDLE THEM.
+ //
+ next:
+ for (Open = Miniport->OpenQueue;
+ Open != NULL;
+ Open = Open->MiniportNextOpen)
+ {
+ if (!MINIPORT_TEST_FLAG(Open, (fMINIPORT_OPEN_CLOSING | fMINIPORT_UNLOADING)) &&
+ (Open->ProtocolHandle->ProtocolCharacteristics.UnbindAdapterHandler != NULL))
+ {
+ MINIPORT_SET_FLAG(Open, fMINIPORT_UNLOADING);
+ break;
+ }
+ }
+
+ if (Open != NULL)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ INITIALIZE_EVENT(&UnbindContext.Event);
+
+ WAIT_FOR_OBJECT(&Open->ProtocolHandle->Mutex, NULL);
+ (*Open->ProtocolHandle->ProtocolCharacteristics.UnbindAdapterHandler)(
+ &UnbindStatus,
+ Open->ProtocolBindingContext,
+ &UnbindContext);
+
+ if (UnbindStatus == NDIS_STATUS_PENDING)
+ {
+ WAIT_FOR_OBJECT(&UnbindContext.Event, NULL);
+ }
+
+ RELEASE_MUTEX(&Open->ProtocolHandle->Mutex);
+
+ if (UnbindStatus == NDIS_STATUS_PENDING)
+ {
+ WAIT_FOR_OBJECT(&UnbindContext.Event, NULL);
+ }
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ goto next;
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ //
+ // The halt handler must be called when the last reference
+ // on the driver block goes away
+ //
+ return NDIS_STATUS_SUCCESS;
+}
+
+NDIS_STATUS
+ndisTranslateMiniportName(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PUCHAR Buffer,
+ IN UINT BufferLength,
+ OUT PUINT AmountCopied
+ )
+/*++
+
+Routine Description:
+
+ Calls the PnP protocols to enumerate PnP ids for the given miniport.
+
+Arguments:
+
+ Miniport - The Miniport in question.
+ Buffer, BufferLength - Buffer for a list of PnP Ids.
+ AmountCopied - How much buffer was used up.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ KIRQL OldIrql;
+ PNDIS_M_OPEN_BLOCK Open, NextOpen;
+ NDIS_STATUS Status;
+ UINT AmtCopied = 0, TotalAmtCopied = 0;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ //
+ // Walk the list of open bindings on this miniport and ask the
+ // protocols to enumerate the PnP ids for that binding
+ //
+ for (Open = Miniport->OpenQueue;
+ Open != NULL;
+ Open = NextOpen)
+ {
+ NextOpen = Open->MiniportNextOpen;
+
+ if (!MINIPORT_TEST_FLAG(Open, (fMINIPORT_OPEN_CLOSING | fMINIPORT_UNLOADING)) &&
+ (Open->ProtocolHandle->ProtocolCharacteristics.TranslateHandler != NULL))
+ {
+ // Reference this open block
+ if (TotalAmtCopied < BufferLength)
+ {
+ Open->References ++;
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ (*Open->ProtocolHandle->ProtocolCharacteristics.TranslateHandler)(
+ &Status,
+ Open->ProtocolBindingContext,
+ (PNET_PNP_ID)(Buffer + TotalAmtCopied),
+ BufferLength - TotalAmtCopied,
+ &AmtCopied);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ TotalAmtCopied += AmtCopied;
+ }
+
+ Open->References --;
+ if (Open->References == 0)
+ {
+ NextOpen = Open->MiniportNextOpen;
+ ndisMFinishClose(Miniport, Open);
+ }
+ }
+ }
+ }
+
+ *AmountCopied = TotalAmtCopied;
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+VOID
+NdisMSetPeriodicTimer(
+ IN PNDIS_MINIPORT_TIMER Timer,
+ IN UINT MillisecondsPeriod
+ )
+/*++
+
+Routine Description:
+
+ Sets up a periodic timer.
+
+Arguments:
+
+ Timer - The timer to Set.
+
+ MillisecondsPeriod - The timer will fire once every so often.
+
+Return Value:
+
+--*/
+{
+ LARGE_INTEGER FireUpTime;
+
+ FireUpTime.QuadPart = Int32x32To64((LONG)MillisecondsPeriod, -10000);
+
+ //
+ // Set the timer
+ //
+ SET_PERIODIC_TIMER(&Timer->Timer, FireUpTime, MillisecondsPeriod, &Timer->Dpc);
+}
+
+
+VOID
+NdisMSleep(
+ IN ULONG MicrosecondsToSleep
+ )
+/*++
+
+ Routine Description:
+
+ Blocks the caller for specified duration of time. Callable at Irql < DISPATCH_LEVEL.
+
+ Arguments:
+
+ MicrosecondsToSleep - The caller will be blocked for this much time.
+
+ Return Value:
+
+ NONE
+
+--*/
+{
+ KTIMER SleepTimer;
+ LARGE_INTEGER TimerValue;
+
+ ASSERT (KeGetCurrentIrql() == LOW_LEVEL);
+
+ INITIALIZE_TIMER_EX(&SleepTimer, SynchronizationTimer);
+
+ TimerValue.QuadPart = Int32x32To64(MicrosecondsToSleep, -10);
+ SET_TIMER(&SleepTimer, TimerValue, NULL);
+
+ WAIT_FOR_OBJECT(&SleepTimer, NULL);
+}
+
+VOID
+ndisMReleaseResources(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PCM_RESOURCE_LIST Resources;
+ BOOLEAN Conflict;
+ NTSTATUS NtStatus;
+
+ Resources = (PCM_RESOURCE_LIST)ALLOC_FROM_POOL(
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NDIS_TAG_RSRC_LIST);
+ if (NULL == Resources)
+ {
+ return;
+ }
+
+ MoveMemory(
+ Resources,
+ Miniport->Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
+
+ //
+ // Clear count
+ //
+ Resources->List->PartialResourceList.Count = 0;
+
+ //
+ // Make the call
+ //
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver,
+ NULL,
+ 0,
+ Miniport->DeviceObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ TRUE,
+ &Conflict);
+
+ FREE_POOL(Resources);
+ FREE_POOL(Miniport->Resources);
+ Miniport->Resources = NULL;
+}
diff --git a/private/ntos/ndis/ndis40/miniport.c b/private/ntos/ndis/ndis40/miniport.c
new file mode 100644
index 000000000..859c55be1
--- /dev/null
+++ b/private/ntos/ndis/ndis40/miniport.c
@@ -0,0 +1,3180 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ miniport.c
+
+Abstract:
+
+ NDIS miniport wrapper functions
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 05-Oct-93
+ Jameel Hyder (JameelH) Re-organization 01-Jun-95
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_MINIPORT
+
+/////////////////////////////////////////////////////////////////////
+//
+// WORK-ITEM CODE
+//
+/////////////////////////////////////////////////////////////////////
+
+
+BOOLEAN
+NdisIMSwitchToMiniport(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ OUT PNDIS_HANDLE SwitchHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine will attempt to synchronously grab the miniport's (specified
+ by MiniportAdapterHandle) spin-lock and local lock. If it succeeds
+ it will return TRUE, otherwise it will return FALSE.
+
+Arguments:
+
+ MiniportAdapterHandle - Pointer to the NDIS_MINIPORT_BLOCK whose
+ context we should nail down.
+ SwitchHandle - Pointer to storage for the current irql.
+ This is returned to the caller as a handle,
+ need-to-know basis baby.
+
+Return Value:
+
+ TRUE if we obtain both locks, FALSE otherwise.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ BOOLEAN LocalLock;
+ LONG Thread;
+
+ //
+ // Did we already acuqire the lock with this thread?
+ //
+ Thread = InterlockedExchangeAdd(&Miniport->MiniportThread, 0);
+ if (CURRENT_THREAD == Thread)
+ {
+ //
+ // We've already acquired the lock...
+ //
+ ASSERT(Miniport->LockAcquired);
+
+ *SwitchHandle = (NDIS_HANDLE)-1;
+
+ return(TRUE);
+ }
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, (PKIRQL)SwitchHandle);
+
+ LOCK_MINIPORT(Miniport, LocalLock);
+ if (!LocalLock)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, (KIRQL)*SwitchHandle);
+
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+VOID
+NdisIMRevertBack(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE SwitchHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine will undo what NdisMLockMiniport did. It will release the
+ local lock and free the spin lock.
+
+Arguments:
+
+ MiniportAdapterHandle - Pointer to the NDIS_MINIPORT_BLOCK whose
+ context we are releasing.
+ SwitchHandle - This is the original irql from the NdisMLockMiniport
+ call.
+
+Return Value:
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+
+ //
+ // Before we unlock the miniport's context we need to pick up any
+ // stray workitems for this miniport that may have been generated by
+ // the caller.
+ //
+
+#if _SEND_PRIORITY
+ //
+ // If we are not reseting and not halting then give priority to sends
+ // at this point.
+ //
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_REQUESTED) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ ndisMProcessDeferredFullDuplexPrioritySends(Miniport);
+ }
+ else
+ {
+ ndisMProcessDeferredPrioritySends(Miniport);
+ }
+ }
+ else
+#endif
+ {
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ if ((NDIS_HANDLE)-1 == SwitchHandle)
+ {
+ return;
+ }
+
+ UNLOCK_MINIPORT(Miniport, TRUE);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, (KIRQL)SwitchHandle);
+}
+
+NDIS_STATUS
+NdisIMQueueMiniportCallback(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN W_MINIPORT_CALLBACK CallbackRoutine,
+ IN PVOID CallbackContext
+ )
+/*++
+
+Routine Description:
+
+ This routine will attempt to acquire the specified MiniportAdapterHandle's
+ miniport lock and local lock and call the callback routine with the context
+ information. If it cannot do so then it will queue a workitem to do it
+ later.
+
+Arguments:
+
+ MiniportAdapterHandle - PNDIS_MINIPORT_BLOCK of the miniport whose
+ context we are attempting to acquire.
+ CallbackRoutine - Pointer to the routine that we are to call.
+ CallbackContext - Context information for the callback routine.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS - If we were able to do this synchronously.
+ NDIS_STATUS_PENDING - If it will be called at a later time.
+ NDIS_STATUS_FAILURE - If the work item could not be queue'd.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ BOOLEAN LocalLock;
+ KIRQL OldIrql;
+ LONG Thread;
+ BOOLEAN LockAcquired;
+
+ //
+ // Did we already acuqire the lock with this thread?
+ //
+ Thread = InterlockedExchangeAdd(&Miniport->MiniportThread, 0);
+ if (CURRENT_THREAD == Thread)
+ {
+ //
+ // We've already acquired the lock...
+ //
+ ASSERT(Miniport->LockAcquired);
+ LockAcquired = FALSE;
+ LocalLock = TRUE;
+ }
+ else
+ {
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+ LOCK_MINIPORT(Miniport, LocalLock);
+ LockAcquired = TRUE;
+ }
+
+ if (!LocalLock)
+ {
+ NDIS_STATUS Status;
+
+ //
+ // Queue the work item to do this later.
+ //
+ Status = NDISM_QUEUE_NEW_WORK_ITEM(
+ Miniport,
+ NdisWorkItemMiniportCallback,
+ CallbackRoutine,
+ CallbackContext);
+
+ if (LockAcquired)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+ }
+
+ return((NDIS_STATUS_SUCCESS == Status) ? NDIS_STATUS_PENDING : NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Call the callback routine.
+ //
+ (*CallbackRoutine)(Miniport->MiniportAdapterContext, CallbackContext);
+
+#if _SEND_PRIORITY
+ //
+ // If we are not reseting and not halting then give priority to sends
+ // at this point.
+ //
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_REQUESTED) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ ndisMProcessDeferredFullDuplexPrioritySends(Miniport);
+ }
+ else
+ {
+ ndisMProcessDeferredPrioritySends(Miniport);
+ }
+ }
+ else
+#endif
+ {
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ if (LockAcquired)
+ {
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+/////////////////////////////////////////////////////////////////////
+//
+// WORKITEM CODE FOR INTERMEDIATE MINIPORTS
+//
+/////////////////////////////////////////////////////////////////////
+
+
+NDIS_STATUS
+FASTCALL
+ndisIMQueueWorkItem(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ IN PVOID WorkItemContext1,
+ IN PVOID WorkItemContext2
+ )
+/*++
+
+Routine Description:
+
+ Queue's the specific workitem on the work queue.
+
+ NOTE!!!!!
+
+ This routine assumes that you have the correct lock acquire to
+ touch the SingleWorkItem that you requested to be queued.
+
+ NdisWorkItemSend - SendLock
+ NdisWorkItemResetRequested - Miniport lock
+ NdisWorkItemRequest - Miniport lock
+ NdisWorkItemDpc - Miniport lock
+ NdisWorkItemHalt - Miniport lock
+
+Arguments:
+
+ Miniport - Pointer to the miniport block.
+ WorkItemType - Type of work item to queue.
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+#ifdef NDIS_NT
+
+ NDISM_QUEUE_WORK_ITEM_FULL_DUPLEX_MACRO(
+ Miniport,
+ WorkItemType,
+ WorkItemContext1,
+ WorkItemContext2,
+ &Status);
+
+ //
+ // If the status is not accepted then it means that there is already
+ // a workitem of this type queued and there should be a timer fired
+ // to process it.
+ //
+ if (Status != NDIS_STATUS_NOT_ACCEPTED)
+ {
+ NDISM_DEFER_PROCESS_DEFERRED(Miniport);
+ }
+
+#endif
+ return(Status);
+}
+
+
+NDIS_STATUS
+FASTCALL
+ndisIMQueueNewWorkItem(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ IN PVOID WorkItemContext1,
+ IN PVOID WorkItemContext2
+ )
+/*++
+
+Routine Description:
+
+ This routine will queue a workitem in the work queue even if there
+ are already work items queue for it.
+
+ THE WORK QUEUE LOCK MUST BE HELD WHEN CALLING THIS ROUTINE!!!!
+
+Arguments:
+
+ Miniport - Miniport block to queue the workitem to.
+ WorkItem - Workitem to place on the queue.
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+#ifdef NDIS_NT
+
+ NDISM_QUEUE_NEW_WORK_ITEM_FULL_DUPLEX_MACRO(
+ Miniport,
+ WorkItemType,
+ WorkItemContext1,
+ WorkItemContext2,
+ &Status);
+
+ //
+ // Since we can have any number of these work items queued we
+ // need to be sure that they all get processed.
+ //
+ NDISM_DEFER_PROCESS_DEFERRED(Miniport);
+
+#endif
+ return(Status);
+}
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// WORKITEM CODE FOR HARDWARE MINIPORTS
+//
+/////////////////////////////////////////////////////////////////////
+
+
+VOID
+FASTCALL
+ndisMDeQueueWorkItem(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ OUT PVOID *WorkItemContext1,
+ OUT PVOID *WorkItemContext2
+ )
+/*++
+
+Routine Description:
+
+ This routine will dequeue a workitem of the given type and return any context
+ information that is associated with it.
+
+ NOTE:
+
+ FOR FULL-DUPLEX USAGE THE WORK LOCK MUST BE ACQUIRED BEFORE THIS ROUTINE IS CALLED !!!!
+
+Arguments:
+
+ Miniport - Pointer to the miniport block.
+ WorkItemType - Type of workitem to dequeue.
+ WorkItemContext1 - Pointer to storage space for first piece of context information.
+ WorkItemContext2 - Pointer to storage space for second piece of context information.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PSINGLE_LIST_ENTRY Link;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+
+ //
+ // Grab the first workitem of the given type.
+ //
+ Link = PopEntryList(&Miniport->WorkQueue[WorkItemType]);
+ if (Link != NULL)
+ {
+ //
+ // Get a pointer to the context information.
+ //
+ WorkItem = CONTAINING_RECORD(Link, NDIS_MINIPORT_WORK_ITEM, Link);
+
+ if (WorkItemContext1 != NULL)
+ {
+ *WorkItemContext1 = WorkItem->WorkItemContext1;
+ }
+
+ if (WorkItemContext2 != NULL)
+ {
+ *WorkItemContext2 = WorkItem->WorkItemContext2;
+ }
+
+ switch (WorkItemType)
+ {
+ case NdisWorkItemMiniportCallback:
+ case NdisWorkItemTimer:
+ case NdisWorkItemPendingOpen:
+
+ ASSERT(*WorkItemContext1 != NULL);
+ PushEntryList(&Miniport->WorkItemFreeQueue, Link);
+ break;
+
+ case NdisWorkItemResetInProgress:
+
+ PushEntryList(&Miniport->SingleWorkItems[NdisWorkItemResetRequested], Link);
+ break;
+
+ case NdisWorkItemResetRequested:
+
+ WorkItem->WorkItemType = NdisWorkItemResetInProgress;
+ PushEntryList(&Miniport->WorkQueue[NdisWorkItemResetInProgress], Link);
+ break;
+
+ default:
+ PushEntryList(&Miniport->SingleWorkItems[WorkItemType], Link);
+ break;
+ }
+ }
+}
+
+NDIS_STATUS
+FASTCALL
+ndisMQueueWorkItem(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ IN PVOID WorkItemContext1,
+ IN PVOID WorkItemContext2
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+
+ NDISM_QUEUE_WORK_ITEM_MACRO(
+ Miniport,
+ WorkItemType,
+ WorkItemContext1,
+ WorkItemContext2,
+ &Status);
+
+ return(Status);
+}
+
+NDIS_STATUS
+FASTCALL
+ndisMQueueWorkItemFullDuplex(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ IN PVOID WorkItemContext1,
+ IN PVOID WorkItemContext2
+ )
+/*++
+
+Routine Description:
+
+ Queue's the specific workitem on the work queue.
+
+ NOTE!!!!!
+
+ This routine assumes that you have the correct lock acquire to
+ touch the SingleWorkItem that you requested to be queued.
+
+ NdisWorkItemSend - SendLock
+ NdisWorkItemResetRequested - Miniport lock
+ NdisWorkItemRequest - Miniport lock
+ NdisWorkItemDpc - Miniport lock
+ NdisWorkItemHalt - Miniport lock
+
+Arguments:
+
+ Miniport - Pointer to the miniport block.
+ WorkItemType - Type of work item to queue.
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+#ifdef NDIS_NT
+
+ NDISM_QUEUE_WORK_ITEM_FULL_DUPLEX_MACRO(
+ Miniport,
+ WorkItemType,
+ WorkItemContext1,
+ WorkItemContext2,
+ &Status);
+
+#endif
+ return(Status);
+}
+
+
+NDIS_STATUS
+FASTCALL
+ndisMQueueNewWorkItem(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ IN PVOID WorkItemContext1,
+ IN PVOID WorkItemContext2
+ )
+/*++
+
+Routine Description:
+
+ This routine will queue a workitem in the work queue even if there
+ are already work items queue for it.
+
+ THE WORK QUEUE LOCK MUST BE HELD WHEN CALLING THIS ROUTINE!!!!
+
+Arguments:
+
+ Miniport - Miniport block to queue the workitem to.
+ WorkItem - Workitem to place on the queue.
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+
+ NDISM_QUEUE_NEW_WORK_ITEM_MACRO(
+ Miniport,
+ WorkItemType,
+ WorkItemContext1,
+ WorkItemContext2,
+ &Status);
+
+ return(Status);
+}
+
+NDIS_STATUS
+FASTCALL
+ndisMQueueNewWorkItemFullDuplex(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ IN PVOID WorkItemContext1,
+ IN PVOID WorkItemContext2
+ )
+/*++
+
+Routine Description:
+
+ This routine will queue a workitem in the work queue even if there
+ are already work items queue for it.
+
+ THE WORK QUEUE LOCK MUST BE HELD WHEN CALLING THIS ROUTINE!!!!
+
+Arguments:
+
+ Miniport - Miniport block to queue the workitem to.
+ WorkItem - Workitem to place on the queue.
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+#ifdef NDIS_NT
+
+ NDISM_QUEUE_NEW_WORK_ITEM_FULL_DUPLEX_MACRO(
+ Miniport,
+ WorkItemType,
+ WorkItemContext1,
+ WorkItemContext2,
+ &Status);
+
+#endif
+ return(Status);
+}
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// DEFERRED PROCESSING CODE
+//
+/////////////////////////////////////////////////////////////////////
+
+
+#if _SEND_PRIORITY
+
+VOID
+FASTCALL
+ndisMProcessDeferredFullDuplexPrioritySends(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Processes all outstanding operations.
+
+ CALLED WITH THE LOCK HELD!!
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+#ifdef NDIS_NT
+ NDIS_STATUS Status;
+ BOOLEAN ProcessWorkItems;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+ PSINGLE_LIST_ENTRY Link;
+ NDIS_WORK_ITEM_TYPE WorkItemType;
+ BOOLEAN AddressingReset;
+ PKDPC Dpc;
+ PMINIPORT_PENDING_OPEN PendingOpen;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("==>ndisMProcessDeferredFullDuplexPrioritySends\n"));
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // Are there any sends to process?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemSend].Next != NULL)
+ {
+ BOOLEAN fMoreSends;
+
+ //
+ // Process the sends.
+ //
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ NDISM_START_SENDS(Miniport);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+ }
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // Are there any loopback packets to indicate?
+ //
+ if ((Miniport->WorkQueue[NdisWorkItemMiniportCallback].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemSendLoopback].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemDpc].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemTimer].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemPendingOpen].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemRequest].Next != NULL))
+ {
+
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("<==ndisMProcessDeferredFullDuplexPrioritySends\n"));
+#endif
+}
+
+#endif
+
+VOID
+FASTCALL
+ndisMProcessDeferredFullDuplex(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Processes all outstanding operations.
+
+ CALLED WITH THE LOCK HELD!!
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+#ifdef NDIS_NT
+ NDIS_STATUS Status;
+ BOOLEAN ProcessWorkItems;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+ PSINGLE_LIST_ENTRY Link;
+ NDIS_WORK_ITEM_TYPE WorkItemType;
+ BOOLEAN AddressingReset;
+ PKDPC Dpc;
+ PMINIPORT_PENDING_OPEN PendingOpen;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("==>ndisMProcessDeferredFullDuplex\n"));
+
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // DO NOT CHANGE THE ORDER THAT THE WORKITEMS ARE PROCESSED!!!!!
+ //
+ do
+ {
+ ProcessWorkItems = FALSE;
+
+ //
+ // Is there a reset currently in progress?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemResetInProgress].Next != NULL)
+ {
+ //
+ // The only thing that can run during a reset in progress
+ // are the timers.
+ //
+ if (Miniport->WorkQueue[NdisWorkItemTimer].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Queuing dpc timer\n"));
+
+ //
+ // Grab the timer workitem.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemTimer, &Dpc, NULL);
+
+ //
+ // Queue the timer's dpc to fire.
+ //
+ QUEUE_DPC(Dpc);
+ }
+ else if (Miniport->WorkQueue[NdisWorkItemRequest].Next != NULL)
+ {
+ //
+ // We have requests to process that set up the packet
+ // filters.
+ //
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+ ndisMDoRequests(Miniport);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+ }
+
+ break;
+ }
+
+ //
+ // If the adapter is halting then get out of here.
+ //
+ if (Miniport->WorkQueue[NdisWorkItemHalt].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Miniport is halting\n"));
+
+ break;
+ }
+
+ //
+ // If an intermediate miniport wants a call back do it now...
+ //
+ if (Miniport->WorkQueue[NdisWorkItemMiniportCallback].Next != NULL)
+ {
+ W_MINIPORT_CALLBACK CallbackRoutine;
+ PVOID CallbackContext;
+
+ //
+ // Get the callback routine and the context information for it.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(
+ Miniport,
+ NdisWorkItemMiniportCallback,
+ (PVOID *)&CallbackRoutine,
+ &CallbackContext);
+
+ //
+ // Call the intermediate drivers callback routine.
+ //
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ (*CallbackRoutine)(Miniport->MiniportAdapterContext, CallbackContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ ProcessWorkItems = TRUE;
+ }
+
+ //
+ // Does a deferred dpc need to run?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemDpc].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Queuing DPC\n"));
+
+ //
+ // Queue the dpc to run.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemDpc, &Dpc, NULL);
+ QUEUE_DPC(Dpc);
+
+ break;
+ }
+
+ //
+ // Is there a timer to fire?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemTimer].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Queuing dpc timer\n"));
+
+ //
+ // Queue the timer's dpc to fire.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemTimer, &Dpc, NULL);
+ QUEUE_DPC(Dpc);
+
+ break;
+ }
+
+ //
+ // Finish any pending opens?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemPendingOpen].Next != NULL)
+ {
+ //
+ // Grab the pending open block.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemPendingOpen, &PendingOpen, NULL);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // Finish the pending open.
+ //
+ Status = ndisMFinishPendingOpen(PendingOpen);
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // Did it pend again?
+ //
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ NDISM_QUEUE_NEW_WORK_ITEM(
+ Miniport,
+ NdisWorkItemPendingOpen,
+ PendingOpen,
+ NULL);
+ }
+
+
+ //
+ // Process more work items.
+ //
+ ProcessWorkItems = TRUE;
+ }
+
+ //
+ // Was there a reset requested?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemResetRequested].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Reset requested\n"));
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // We need to release the work item lock to
+ // indicate the status to the bindings
+ // and to call down to the miniport driver.
+ //
+ Status = ndisMProcessResetRequested(Miniport,
+ &AddressingReset);
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Reset is pending\n"));
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // Do we need to run a dpc?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemDpc].Next != NULL)
+ {
+ //
+ // Queue the dpc to run.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemDpc, &Dpc, NULL);
+ QUEUE_DPC(Dpc);
+ }
+
+ //
+ // The reset is still in progress so we need to stop
+ // processing workitems and wait for the completion.
+ //
+ break;
+ }
+ else
+ {
+ //
+ // Do step1 of the reset complete.
+ //
+ ndisMResetCompleteCommonStep1(Miniport,
+ Status,
+ AddressingReset);
+ if (!AddressingReset || (Status != NDIS_STATUS_SUCCESS))
+ {
+ //
+ // If there is no addressing reset to be done or
+ // the reset failed in some way then we tell the
+ // bindings now.
+ //
+ ndisMResetCompleteCommonStep2(Miniport);
+ }
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ continue;
+ }
+ }
+
+ //
+ // Process any requests?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemRequest].Next != NULL)
+ {
+ //
+ // Process the requests.
+ //
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+ ndisMDoRequests(Miniport);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+
+ ProcessWorkItems = TRUE;
+ }
+
+ //
+ // Are there any loopback packets to indicate?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemSendLoopback].Next != NULL)
+ {
+ BOOLEAN fMoreLoopback;
+
+ //
+ // Process the loopback packets.
+ //
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+ fMoreLoopback = ndisMIndicateLoopback(Miniport);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ if (!fMoreLoopback)
+ {
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSendLoopback, NULL, NULL);
+ }
+
+ ProcessWorkItems = TRUE;
+ }
+
+ //
+ // Are there any sends to process?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemSend].Next != NULL)
+ {
+ BOOLEAN fMoreSends;
+
+ //
+ // Process the sends.
+ //
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ NDISM_START_SENDS(Miniport);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+
+ ProcessWorkItems = TRUE;
+ }
+ } while (ProcessWorkItems);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_PROCESS_DEFERRED);
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("<==ndisMProcessDeferredFullDuplex\n"));
+#endif
+}
+
+#if _SEND_PRIORITY
+
+VOID
+FASTCALL
+ndisMProcessDeferredPrioritySends(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Processes all outstanding operations.
+
+ CALLED WITH THE LOCK HELD!!
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("==>ndisMProcessDeferredPrioritySends\n"));
+
+ //
+ // Are there any sends to process?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemSend].Next != NULL)
+ {
+ //
+ // Process the sends.
+ //
+ NDISM_START_SENDS(Miniport);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+ }
+
+ //
+ // Are there any loopback packets to indicate?
+ //
+ if ((Miniport->WorkQueue[NdisWorkItemMiniportCallback].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemSendLoopback].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemDpc].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemTimer].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemPendingOpen].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemRequest].Next != NULL))
+ {
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("<==ndisMProcessDeferredPrioritySends\n"));
+}
+
+#endif
+
+VOID
+FASTCALL
+ndisMProcessDeferred(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Processes all outstanding operations.
+
+ CALLED WITH THE LOCK HELD!!
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS Status;
+ BOOLEAN ProcessWorkItems;
+ PSINGLE_LIST_ENTRY Link;
+ NDIS_WORK_ITEM_TYPE WorkItemType;
+ BOOLEAN AddressingReset;
+ PKDPC Dpc;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+ PMINIPORT_PENDING_OPEN PendingOpen;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("==>ndisMProcessDeferred\n"));
+
+ //
+ // DO NOT CHANGE THE ORDER THAT THE WORKITEMS ARE PROCESSED!!!!!
+ //
+ do
+ {
+ ProcessWorkItems = FALSE;
+
+ //
+ // Is there a reset currently in progress?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemResetInProgress].Next != NULL)
+ {
+ //
+ // The only thing that can run during a reset in progress
+ // are the timers.
+ //
+ if (Miniport->WorkQueue[NdisWorkItemTimer].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Queuing dpc timer\n"));
+
+ //
+ // Grab the timer workitem.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemTimer, &Dpc, NULL);
+
+ //
+ // Queue the timer's dpc to fire.
+ //
+ QUEUE_DPC(Dpc);
+ }
+ else if (Miniport->WorkQueue[NdisWorkItemRequest].Next != NULL)
+ {
+ //
+ // We have requests to process that set up the packet
+ // filters.
+ //
+ ndisMDoRequests(Miniport);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+ }
+
+ break;
+ }
+
+ //
+ // If the adapter is halting then get out of here.
+ //
+ if (Miniport->WorkQueue[NdisWorkItemHalt].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Miniport is halting\n"));
+
+ break;
+ }
+
+ //
+ // If an intermediate miniport wants a call back do it now...
+ //
+ if (Miniport->WorkQueue[NdisWorkItemMiniportCallback].Next != NULL)
+ {
+ W_MINIPORT_CALLBACK CallbackRoutine;
+ PVOID CallbackContext;
+
+ //
+ // Get the callback routine and the context information for it.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(
+ Miniport,
+ NdisWorkItemMiniportCallback,
+ (PVOID *)&CallbackRoutine,
+ &CallbackContext);
+
+ //
+ // Call the intermediate drivers callback routine.
+ //
+ (*CallbackRoutine)(Miniport->MiniportAdapterContext, CallbackContext);
+
+ ProcessWorkItems = TRUE;
+ }
+
+ //
+ // Does a deferred dpc need to run?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemDpc].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Queuing DPC\n"));
+
+ //
+ // Queue the dpc to run.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemDpc, &Dpc, NULL);
+ QUEUE_DPC(Dpc);
+
+ break;
+ }
+
+ //
+ // Is there a timer to fire?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemTimer].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Queuing dpc timer\n"));
+
+ //
+ // Queue the timer's dpc to fire.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemTimer, &Dpc, NULL);
+ QUEUE_DPC(Dpc);
+
+ break;
+ }
+
+ //
+ // Finish any pending opens?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemPendingOpen].Next != NULL)
+ {
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemPendingOpen, &PendingOpen, NULL);
+
+ //
+ // Finish the pending open.
+ //
+ Status = ndisMFinishPendingOpen(PendingOpen);
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ NDISM_QUEUE_NEW_WORK_ITEM(
+ Miniport,
+ NdisWorkItemPendingOpen,
+ PendingOpen,
+ NULL);
+ }
+
+ //
+ // Process more work items.
+ //
+ ProcessWorkItems = TRUE;
+ }
+
+ //
+ // Was there a reset requested?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemResetRequested].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Reset requested\n"));
+ //
+ // We need to release the work item lock to
+ // indicate the status to the bindings
+ // and to call down to the miniport driver.
+ //
+ Status = ndisMProcessResetRequested(Miniport,
+ &AddressingReset);
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Reset is pending\n"));
+ //
+ // Do we need to run a dpc?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemDpc].Next != NULL)
+ {
+ //
+ // Dequeue the dpc.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemDpc, &Dpc, NULL);
+
+ //
+ // Queue the dpc to run.
+ //
+ QUEUE_DPC(Dpc);
+ }
+
+ //
+ // The reset is still in progress so we need to stop
+ // processing workitems and wait for the completion.
+ //
+ break;
+ }
+ else
+ {
+ //
+ // Do step1 of the reset complete.
+ //
+ ndisMResetCompleteCommonStep1(Miniport,
+ Status,
+ AddressingReset);
+ if (!AddressingReset || (Status != NDIS_STATUS_SUCCESS))
+ {
+ //
+ // If there is no addressing reset to be done or
+ // the reset failed in some way then we tell the
+ // bindings now.
+ //
+ ndisMResetCompleteCommonStep2(Miniport);
+ }
+ else
+ {
+ //
+ // We MUST complete the filter requests within
+ // the reset in progress workitem. Mainly because
+ // we don't want to do any sends at this time.
+ //
+ ProcessWorkItems = TRUE;
+
+ continue;
+ }
+ }
+ }
+
+ //
+ // Process any requests?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemRequest].Next != NULL)
+ {
+ //
+ // Process the requests.
+ //
+ ndisMDoRequests(Miniport);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+
+ ProcessWorkItems = TRUE;
+ }
+
+ //
+ // Are there any loopback packets to indicate?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemSendLoopback].Next != NULL)
+ {
+ BOOLEAN fMoreLoopback;
+
+ //
+ // Process the loopback packets.
+ //
+ fMoreLoopback = ndisMIndicateLoopback(Miniport);
+
+ if (!fMoreLoopback)
+ {
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSendLoopback, NULL, NULL);
+ }
+
+ ProcessWorkItems = TRUE;
+ }
+
+ //
+ // Are there any sends to process?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemSend].Next != NULL)
+ {
+ //
+ // Process the sends.
+ //
+ NDISM_START_SENDS(Miniport);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+
+ ProcessWorkItems = TRUE;
+ }
+ } while (ProcessWorkItems);
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_PROCESS_DEFERRED);
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("<==ndisMProcessDeferred\n"));
+}
+
+/////////////////////////////////////////////////////////////////////
+//
+// INDICATE CODE
+//
+/////////////////////////////////////////////////////////////////////
+
+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
+ //
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.StatusHandler) (
+ Open->ProtocolBindingContext,
+ GeneralStatus,
+ StatusBuffer,
+ StatusBufferSize
+ );
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ 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
+ //
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.StatusCompleteHandler) (
+ Open->ProtocolBindingContext);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ Open = Open->MiniportNextOpen;
+ }
+}
+
+
+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
+ //
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ *Status = ((WAN_RECEIVE_HANDLER)(Open->ProtocolHandle->ProtocolCharacteristics.ReceiveHandler)) (
+ NdisLinkContext,
+ Packet,
+ PacketSize);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ 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
+ //
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.ReceiveCompleteHandler)(NdisLinkContext);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ Open = Open->MiniportNextOpen;
+ }
+}
+
+
+
+NDIS_STATUS
+NdisQueryReceiveInformation(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacContext,
+ OUT PLONGLONG TimeSent OPTIONAL,
+ OUT PLONGLONG TimeReceived OPTIONAL,
+ IN PUCHAR Buffer,
+ IN UINT BufferSize,
+ OUT PUINT SizeNeeded
+ )
+{
+ PNDIS_OPEN_BLOCK OpenBlock = ((PNDIS_OPEN_BLOCK)NdisBindingHandle);
+ PNDIS_M_OPEN_BLOCK MOpenBlock = (PNDIS_M_OPEN_BLOCK)(OpenBlock->MacBindingHandle);
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(MOpenBlock->MiniportHandle);
+ PNDIS_PACKET Packet = (PNDIS_PACKET)MacContext;
+ NDIS_STATUS Status = NDIS_STATUS_NOT_SUPPORTED;
+
+
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("NdisQueryReceiveInformation - Miniort %lx, Packet %lx\n",
+ Miniport, Packet));
+
+ //
+ // The following tests whether this is a mac or a miniport and also if we
+ // came here via a IndicatePacket or IndicateRecieve
+ //
+ if ((MOpenBlock->FakeOpen == OpenBlock) &&
+ (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID)))
+ {
+ PNDIS_PACKET_OOB_DATA pOob;
+
+ pOob = NDIS_OOB_DATA_FROM_PACKET(Packet);
+ *SizeNeeded = pOob->SizeMediaSpecificInfo;
+ if (BufferSize < *SizeNeeded)
+ {
+ Status = NDIS_STATUS_BUFFER_TOO_SHORT;
+ }
+ else
+ {
+ CopyMemory(Buffer, pOob->MediaSpecificInformation, *SizeNeeded);
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ if (ARGUMENT_PRESENT(TimeSent))
+ {
+ *TimeSent = pOob->TimeSent;
+ }
+ if (ARGUMENT_PRESENT(TimeReceived))
+ {
+ *TimeReceived = pOob->TimeReceived;
+ }
+ }
+
+ return Status;
+}
+
+
+VOID
+NdisReturnPackets(
+ IN PNDIS_PACKET *PacketsToReturn,
+ IN UINT NumberOfPackets
+ )
+/*++
+
+Routine Description:
+
+ Decrement the refcount for the packet and return back to the miniport if 0.
+ We take the Miniport lock here and hence are protected against other receives.
+
+Arguments:
+
+ NdisBindingHandle - Handle to the open binding
+ PacketsToReturn - Pointer to the set of packets to return to the miniport
+ NumberOfPackets - self descriptive
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UINT i;
+
+ for (i = 0; i < NumberOfPackets; i++)
+ {
+ KIRQL OldIrql;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ W_RETURN_PACKET_HANDLER Handler;
+ PNDIS_PACKET Packet;
+ BOOLEAN QueueWorkItem = FALSE;
+
+ Packet = PacketsToReturn[i];
+ ASSERT (Packet != NULL);
+
+ Miniport = PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->Miniport;
+ ASSERT (Miniport != NULL);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount --;
+ if (PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount == 0)
+ {
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID))
+ {
+ Handler = Miniport->DriverHandle->MiniportCharacteristics.ReturnPacketHandler;
+ (*Handler)(Miniport->MiniportAdapterContext, Packet);
+ }
+ else
+ {
+ ASSERT(NDIS_GET_PACKET_STATUS(Packet) != NDIS_STATUS_RESOURCES);
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->NextPacket =
+ Miniport->ReturnPacketsQueue;
+ Miniport->ReturnPacketsQueue = Packet;
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RP_WORK_ITEM_QUEUED))
+ {
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_RP_WORK_ITEM_QUEUED);
+ QueueWorkItem = TRUE;
+ }
+ }
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ if (QueueWorkItem)
+ {
+ ndisReferenceMiniport(Miniport);
+ QUEUE_WORK_ITEM(&Miniport->WorkItem, HyperCriticalWorkQueue);
+ }
+ }
+}
+
+
+VOID
+ndisMLazyReturnPackets(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ )
+{
+ KIRQL OldIrql;
+ PNDIS_PACKET Packet, NextPacket;
+ W_RETURN_PACKET_HANDLER Handler;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ ASSERT(MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RP_WORK_ITEM_QUEUED));
+
+ Packet = Miniport->ReturnPacketsQueue;
+ Miniport->ReturnPacketsQueue = NULL;
+
+ for (NOTHING;
+ Packet != NULL;
+ Packet = NextPacket)
+ {
+ NextPacket = PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->NextPacket;
+ Handler = Miniport->DriverHandle->MiniportCharacteristics.ReturnPacketHandler;
+ (*Handler)(Miniport->MiniportAdapterContext, Packet);
+ }
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_RP_WORK_ITEM_QUEUED);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ ndisDereferenceMiniport(Miniport);
+}
+
+
+VOID
+ndisMIndicatePacket(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by the Miniport to indicate packets to
+ all bindings. This is the code path for ndis 4.0 miniport drivers.
+
+Arguments:
+
+ Miniport - The Miniport block.
+
+ PacketArray - An array of Packets indicated by the miniport. Each packet consists of a
+ single buffer.
+
+ NumberOfPackets - Self-explanatory.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // The private structure to indicate up with
+ //
+ PPNDIS_PACKET pPktArray = PacketArray;
+
+ //
+ // Pointer to the buffer in the ndispacket
+ //
+ PNDIS_BUFFER Buffer;
+
+ //
+ // Pointer to the 1st segment of the buffer, points to dest address
+ //
+ PUCHAR Address;
+
+ //
+ // Total packet length
+ //
+ UINT i, LASize,PacketSize, NumIndicates = 0;
+
+ //
+ // Decides whether we use the protocol's revpkt handler or fall
+ // back to old rcvindicate handler
+ //
+ BOOLEAN fFallBack, FixRef;
+
+ //
+ // The current open block
+ //
+ PNDIS_M_OPEN_BLOCK pOpenBlock, NextOpen;
+
+ NDIS_STATUS StatusOfReceive;
+
+ //
+ // Define a NULL Fiter structure so that the IndicateToProtocol macro can be used.
+ //
+ struct _NullFilter
+ {
+ PNDIS_SPIN_LOCK Lock;
+ } Filter;
+
+ Filter.Lock = &Miniport->Lock;
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
+
+ // Walk all the packets
+ for (i = 0; i < NumberOfPackets; i++, pPktArray++)
+ {
+ PNDIS_PACKET Packet = *pPktArray;
+ PNDIS_PACKET_OOB_DATA pOob;
+
+ ASSERT(Packet != NULL);
+ pOob = NDIS_OOB_DATA_FROM_PACKET(Packet);
+
+ NdisGetFirstBufferFromPacket(Packet,
+ &Buffer,
+ &Address,
+ &LASize,
+ &PacketSize);
+ ASSERT(Buffer != NULL);
+
+ //
+ // Set the status here that nobody is holding the packet. This will get
+ // overwritten by the real status from the protocol. Pay heed to what
+ // the miniport is saying.
+ //
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount = 0;
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->Miniport = Miniport;
+
+ if (pOob->Status != NDIS_STATUS_RESOURCES)
+ {
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount --;
+ pOob->Status = NDIS_STATUS_SUCCESS;
+ fFallBack = FALSE;
+ FixRef = TRUE;
+ }
+ else
+ {
+ FixRef = FALSE;
+ fFallBack = TRUE;
+ }
+
+ //
+ // Ensure that we force re-calculation.
+ //
+ Packet->Private.ValidCounts = FALSE;
+
+ for (pOpenBlock = Miniport->OpenQueue;
+ pOpenBlock != NULL;
+ pOpenBlock = NextOpen)
+ {
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = pOpenBlock->MiniportNextOpen;
+ pOpenBlock->ReceivedAPacket = TRUE;
+ pOpenBlock->References++;
+ NumIndicates ++;
+
+ IndicateToProtocol(Miniport,
+ &Filter,
+ pOpenBlock->FakeOpen,
+ Packet,
+ Address,
+ PacketSize,
+ pOob->HeaderSize,
+ &fFallBack,
+ FALSE,
+ NdisMediumMax); // A dummy medium since it is unknown
+
+ pOpenBlock->References--;
+ if (pOpenBlock->References == 0)
+ {
+ // Anything to do here ?
+ }
+ }
+
+ if (FixRef)
+ {
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount++;
+ if (PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount != 0)
+ {
+ NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_PENDING);
+ }
+ }
+ }
+
+ if (NumIndicates > 0)
+ {
+ for (pOpenBlock = Miniport->OpenQueue;
+ pOpenBlock != NULL;
+ pOpenBlock = NextOpen)
+ {
+ if (pOpenBlock->ReceiveCompleteHandler)
+ {
+ pOpenBlock->References++;
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (*pOpenBlock->ReceiveCompleteHandler)(pOpenBlock->ProtocolBindingContext);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ if ((--(pOpenBlock->References)) == 0)
+ {
+ // Anything to do here ?
+ }
+ }
+ }
+ }
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
+}
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// TRANSFER DATA CODE
+//
+/////////////////////////////////////////////////////////////////////
+
+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;
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.TransferDataCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Packet,
+ Status,
+ BytesTransferred);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(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
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ PNDIS_PACKET_RESERVED Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ PNDIS_PACKET_OOB_DATA pOob;
+ NDIS_STATUS Status;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ 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);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ return Status;
+ }
+
+ //
+ // This packet is a loopback packet!
+ //
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ pOob = NDIS_OOB_DATA_FROM_PACKET((PNDIS_PACKET)MacReceiveContext);
+ NdisCopyFromPacketToPacket(Packet,
+ 0,
+ BytesToTransfer,
+ Miniport->LoopbackPacket,
+ ByteOffset + pOob->HeaderSize,
+ 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_OOB_DATA pOob;
+ PNDIS_PACKET PrevLast;
+ NDIS_STATUS Status;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ 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;
+ }
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ return Status;
+ }
+
+ //
+ // This packet is a loopback packet!
+ //
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ pOob = NDIS_OOB_DATA_FROM_PACKET((PNDIS_PACKET)MacReceiveContext);
+ NdisCopyFromPacketToPacket(Packet,
+ 0,
+ BytesToTransfer,
+ Miniport->LoopbackPacket,
+ ByteOffset + pOob->HeaderSize,
+ BytesTransferred);
+
+ if (*BytesTransferred == BytesToTransfer)
+ {
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ return NDIS_STATUS_FAILURE;
+}
+
+NDIS_STATUS
+ndisMDummyTransferData(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+{
+ PNDIS_PACKET_OOB_DATA pOob;
+
+ pOob = NDIS_OOB_DATA_FROM_PACKET((PNDIS_PACKET)MacReceiveContext);
+ NdisCopyFromPacketToPacket(Packet,
+ 0,
+ BytesToTransfer,
+ (PNDIS_PACKET)MacReceiveContext,
+ ByteOffset + pOob->HeaderSize,
+ BytesTransferred);
+
+ return ((*BytesTransferred == BytesToTransfer) ?
+ NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE);
+}
+
+
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// RESET CODE
+//
+/////////////////////////////////////////////////////////////////////
+
+VOID
+ndisMAbortPacketsAndRequests(
+ 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 NextPacket;
+ PNDIS_REQUEST MiniportRequest;
+ PNDIS_REQUEST PendingRequest;
+ PNDIS_REQUEST NextRequest;
+ PNDIS_M_OPEN_BLOCK Open;
+ PNDIS_PACKET ArcnetLimitPacket;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+ BOOLEAN fRestoreDeferredState = FALSE;
+ PSINGLE_LIST_ENTRY Link;
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Enter abort packets and requests\n"));
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ //
+ // Dequeue any send workitems and acquire the send spin lock
+ // if we are full duplex..
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ //
+ // Since we are full duplex we need to wrap the dequeue operation
+ // with spin lock acquire and release.
+ //
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // Acquire the spin lock.
+ //
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+ else
+ {
+ //
+ // non-full duplex miniports can just dequeue any send work items
+ // that are queued
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+ }
+
+ //
+ // Clear out the packet queues.
+ //
+ Packet = Miniport->FirstPacket;
+ ArcnetLimitPacket = Miniport->FirstPendingPacket;
+
+ Miniport->LastMiniportPacket = NULL;
+ Miniport->FirstPendingPacket = NULL;
+ Miniport->FirstPacket = NULL;
+ Miniport->LastPacket = NULL;
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'a');
+
+ //
+ // Go through the list of packets an return them to the
+ // bindings
+ //
+ while (Packet != NULL)
+ {
+ //
+ // Get a pointer to the next packet before we kill
+ // the current one.
+ //
+ NextPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next;
+
+ //
+ // Get the open that the packet came from.
+ //
+ 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)
+ {
+ ndisMFreeArcnetHeader(Miniport, Packet);
+ }
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'C');
+
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Packet,
+ NDIS_STATUS_REQUEST_ABORTED);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ //
+ // Re-acquire the send lock if we are full duplex.
+ // Note that the wrapper does NOT keep track of open
+ // references with regard to sends for full duplex miniports.
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+ else
+ {
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("- Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ Open->References--;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("==0 Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ if (Open->References == 0)
+ {
+ ndisMFinishClose(Miniport,Open);
+ }
+ }
+
+ //
+ // Get the next packet.
+ //
+ Packet = NextPacket;
+ }
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'A');
+
+ Miniport->SendResourcesAvailable = 0x00ffffff;
+
+ //
+ // Dequeue any request workitems.
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ //
+ // Release the send lock.
+ //
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+
+ //
+ // Since we are full duplex we need to wrap the dequeue operation
+ // with spin lock acquire and release.
+ //
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+ }
+ else
+ {
+ //
+ // non-full duplex miniports can just dequeue any send work items
+ // that are queued
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+ }
+
+
+ //
+ // Clear the request timeout flag.
+ //
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_REQUEST_TIMEOUT);
+
+ //
+ // We need to clear out the pending request queue before the currently in
+ // progress one so that when we complete the in-progress request we
+ // won't think that we have to process more requests.
+ //
+ PendingRequest = Miniport->PendingRequest;
+ Miniport->PendingRequest = NULL;
+
+ MiniportRequest = Miniport->MiniportRequest;
+
+ //
+ // If there is one then abort it.
+ //
+ if (MiniportRequest != NULL)
+ {
+ //
+ // Get a pointer to the open that the request came from.
+ //
+ Open = PNDIS_RESERVED_FROM_PNDIS_REQUEST(MiniportRequest)->Open;
+
+ //
+ // Was this a statistics request?
+ //
+ if ((Open != NULL) &&
+ (MiniportRequest->RequestType == NdisRequestQueryStatistics))
+ {
+ ndisMAbortQueryStatisticsRequest(MiniportRequest,
+ NDIS_STATUS_REQUEST_ABORTED);
+
+ Miniport->MiniportRequest = NULL;
+ }
+ else
+ {
+ if (MiniportRequest->RequestType == NdisRequestSetInformation)
+ {
+ ndisMSyncSetInformationComplete((NDIS_HANDLE)Miniport,
+ NDIS_STATUS_REQUEST_ABORTED);
+ }
+ else
+ {
+ ndisMSyncQueryInformationComplete((NDIS_HANDLE)Miniport,
+ NDIS_STATUS_REQUEST_ABORTED);
+ }
+ }
+ }
+
+ //
+ // Go through the pending request queue and clear it out.
+ //
+ while (PendingRequest != NULL)
+ {
+ //
+ // Get a pointer to the next request before we kill the
+ // current one.
+ //
+ NextRequest = PNDIS_RESERVED_FROM_PNDIS_REQUEST(PendingRequest)->Next;
+
+ //
+ // Get a pointer to the open that the request belongs to.
+ //
+ Open = PNDIS_RESERVED_FROM_PNDIS_REQUEST(PendingRequest)->Open;
+
+ if (PendingRequest->RequestType == NdisRequestQueryStatistics)
+ {
+ ndisMAbortQueryStatisticsRequest(
+ PendingRequest,
+ NDIS_STATUS_REQUEST_ABORTED);
+ }
+ else
+ {
+ //
+ // Make this request the request in progress.
+ //
+ Miniport->MiniportRequest = PendingRequest;
+
+ if (PendingRequest->RequestType == NdisRequestSetInformation)
+ {
+ ndisMSyncSetInformationComplete(Miniport,
+ NDIS_STATUS_REQUEST_ABORTED);
+ }
+ else
+ {
+ ndisMSyncQueryInformationComplete(Miniport,
+ NDIS_STATUS_REQUEST_ABORTED);
+ }
+ }
+
+ //
+ // Get the next request.
+ //
+ PendingRequest = NextRequest;
+ }
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Exit abort packets and requests\n"));
+}
+
+VOID
+ndisMResetCompleteCommonStep2(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PSINGLE_LIST_ENTRY Link;
+ PNDIS_M_OPEN_BLOCK Open;
+ PNDIS_M_OPEN_BLOCK tmpOpen;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+
+
+ //
+ // Dequeue the reset in progress work item.
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ //
+ // Acquire the work lock and dequeue the reset in progress work item.
+ //
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemResetInProgress, &Open, NULL);
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // Grab the send lock so that we can clear the reset in progress flag.
+ //
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS);
+
+ for (tmpOpen = Miniport->OpenQueue;
+ tmpOpen != NULL;
+ tmpOpen = tmpOpen->MiniportNextOpen)
+ {
+ //
+ // Restore the send handler
+ //
+ tmpOpen->FakeOpen->SendHandler = Miniport->FakeMac->MacCharacteristics.SendHandler;
+
+ //
+ // Restore the send packets handler.
+ //
+ if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY))
+ {
+ tmpOpen->FakeOpen->SendPacketsHandler = ndisMSendPacketsFullDuplex;
+ }
+ else
+ {
+ tmpOpen->FakeOpen->SendPacketsHandler = ndisMSendPacketsFullDuplexToSend;
+ }
+ }
+
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+ else
+ {
+ //
+ // For non full duplex miniports we don't need to acquire the work lock.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemResetInProgress, &Open, NULL);
+
+ //
+ // Clear the reset in progress flag.
+ //
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS);
+
+ for (tmpOpen = Miniport->OpenQueue;
+ tmpOpen != NULL;
+ tmpOpen = tmpOpen->MiniportNextOpen)
+ {
+ //
+ // Restore the send handler
+ //
+ tmpOpen->FakeOpen->SendHandler = Miniport->FakeMac->MacCharacteristics.SendHandler;
+
+ //
+ // Restore the send packets handler.
+ //
+ if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY))
+ {
+ tmpOpen->FakeOpen->SendPacketsHandler = ndisMSendPackets;
+ }
+ else
+ {
+ tmpOpen->FakeOpen->SendPacketsHandler = ndisMSendPacketsToSend;
+ }
+ }
+ }
+
+ ASSERT(Open != NULL);
+
+ //
+ // Indicate to Protocols the reset is complete
+ //
+ NdisMIndicateStatus(Miniport,
+ NDIS_STATUS_RESET_END,
+ &Miniport->ResetStatus,
+ sizeof(Miniport->ResetStatus));
+
+ NdisMIndicateStatusComplete(Miniport);
+
+ //
+ // If a protocol initiated the reset then notify it of the
+ // completion.
+ //
+ if (Open != (PNDIS_M_OPEN_BLOCK)Miniport)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.ResetCompleteHandler)(
+ Open->ProtocolBindingContext,
+ Miniport->ResetStatus);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("- Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ Open->References--;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("==0 Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ if (Open->References == 0)
+ {
+ ndisMFinishClose(Miniport,Open);
+ }
+ }
+}
+
+VOID
+ndisMResetCompleteCommonStep1(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_STATUS Status,
+ IN BOOLEAN AddressingReset
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ //
+ // Destroy all outstanding packets and requests.
+ //
+ ndisMAbortPacketsAndRequests(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_TEST_FLAG(Miniport, fMINIPORT_IGNORE_TOKEN_RING_ERRORS))
+ {
+ if (Miniport->TrResetRing == 1)
+ {
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ Miniport->TrResetRing = 0;
+ }
+ else
+ {
+ Miniport->TrResetRing = NDIS_MINIPORT_TR_RESET_TIMEOUT;
+ }
+ }
+ }
+
+ //
+ // If we need to reset the miniports filter settings then
+ // queue the necessary requests & work items.
+ //
+ if (AddressingReset &&
+ (Status == NDIS_STATUS_SUCCESS) &&
+ ((Miniport->EthDB != NULL) || (Miniport->TrDB != NULL) ||
+ (Miniport->FddiDB != NULL) || (Miniport->ArcDB != NULL)))
+ {
+ ndisMRestoreFilterSettings(Miniport, NULL);
+ }
+
+ //
+ // Save the reset status as it is now.
+ //
+ Miniport->ResetStatus = Status;
+}
+
+
+NDIS_STATUS
+ndisMProcessResetRequested(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ OUT PBOOLEAN pAddressingReset
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ //
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ //
+ // We need to acquire the work lock to dequeue the reset requsted work item.
+ //
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemResetRequested, NULL, NULL);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // We need to acquire the send lock to modify the reset requested and
+ // reset in progress flags.
+ //
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+
+ //
+ // Set the reset in progress bit so that the send path can see it.
+ //
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_RESET_REQUESTED);
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS);
+
+ //
+ // Replace the send handler for the open's
+ //
+ for (Open = Miniport->OpenQueue;
+ Open != NULL;
+ Open = Open->MiniportNextOpen)
+ {
+ if (NdisMediumWan == Miniport->MediaType)
+ {
+ Open->FakeOpen->SendHandler = (PVOID)ndisMResetWanSend;
+ }
+ else
+ {
+ Open->FakeOpen->SendHandler = ndisMResetSend;
+ }
+
+ Open->FakeOpen->SendPacketsHandler = ndisMResetSendPackets;
+ }
+
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+ else
+ {
+ //
+ // Dequeue the reset requested work item. this dequeuing will automatically
+ // queue the reset in progress work item.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemResetRequested, NULL, NULL);
+
+ //
+ // Set the reset in progress bit so that the send path can see it.
+ //
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_RESET_REQUESTED);
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS);
+
+ //
+ // Replace the send handler for the open's
+ //
+ for (Open = Miniport->OpenQueue;
+ Open != NULL;
+ Open = Open->MiniportNextOpen)
+ {
+ if (NdisMediumWan == Miniport->MediaType)
+ {
+ Open->FakeOpen->SendHandler = (PVOID)ndisMResetWanSend;
+ }
+ else
+ {
+ Open->FakeOpen->SendHandler = ndisMResetSend;
+ }
+
+ Open->FakeOpen->SendPacketsHandler = ndisMResetSendPackets;
+ }
+ }
+
+
+ //
+ // Indicate the reset status to the protocols.
+ //
+ NdisMIndicateStatus(Miniport, NDIS_STATUS_RESET_START, NULL, 0);
+ NdisMIndicateStatusComplete(Miniport);
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Calling miniport reset\n"));
+ //
+ // Call the miniport's reset handler.
+ //
+ Status = (Miniport->DriverHandle->MiniportCharacteristics.ResetHandler)(
+ pAddressingReset,
+ Miniport->MiniportAdapterContext);
+
+ return(Status);
+}
+
+
+VOID
+ndisMResetCompleteFullDuplex(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_STATUS Status,
+ IN BOOLEAN AddressingReset
+ )
+{
+#ifdef NDIS_NT
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("Enter reset complete\n"));
+
+ //
+ // Code that is common for synchronous and async resets.
+ //
+ ndisMResetCompleteCommonStep1(Miniport, Status, AddressingReset);
+ if (!AddressingReset || (Status != NDIS_STATUS_SUCCESS))
+ {
+ //
+ // If there is no addressing reset to be done or
+ // the reset failed in some way then we tell the
+ // bindings now.
+ //
+ ndisMResetCompleteCommonStep2(Miniport);
+ }
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("Exit reset complete\n"));
+#endif
+}
+
+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;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("Enter reset complete\n"));
+
+ //
+ // Code that is common for synchronous and async resets.
+ //
+ ndisMResetCompleteCommonStep1(Miniport, Status, AddressingReset);
+ if (!AddressingReset || (Status != NDIS_STATUS_SUCCESS))
+ {
+ //
+ // If there is no addressing reset to be done or
+ // the reset failed in some way then we tell the
+ // bindings now.
+ //
+ ndisMResetCompleteCommonStep2(Miniport);
+ }
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("Exit reset complete\n"));
+}
+
+NDIS_STATUS
+ndisMResetFullDuplex(
+ IN NDIS_HANDLE NdisBindingHandle
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+#ifdef NDIS_NT
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ KIRQL OldIrql;
+ BOOLEAN LocalLock;
+ PSINGLE_LIST_ENTRY Link;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ //
+ // Is there already a reset in progress?
+ //
+ Status = NDISM_QUEUE_WORK_ITEM(Miniport,
+ NdisWorkItemResetRequested,
+ NdisBindingHandle,
+ NULL);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ return(NDIS_STATUS_RESET_IN_PROGRESS);
+ }
+
+ //
+ // Update the open's references.
+ //
+ ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle,
+ ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References));
+
+ //
+ // The reset requested flag is used by both the send path and the
+ // dpc path.
+ //
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_RESET_REQUESTED);
+
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+
+ //
+ // Grab the local lock.
+ //
+ LOCK_MINIPORT(Miniport, LocalLock);
+ 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.
+ //
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+#endif
+ return(NDIS_STATUS_PENDING);
+}
+
+NDIS_STATUS
+ndisMReset(
+ IN NDIS_HANDLE NdisBindingHandle
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+ KIRQL OldIrql;
+ BOOLEAN LocalLock;
+ PSINGLE_LIST_ENTRY Link;
+ NDIS_STATUS Status;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ //
+ // Is there already a reset in progress?
+ //
+ Status = NDISM_QUEUE_WORK_ITEM(Miniport,
+ NdisWorkItemResetRequested,
+ NdisBindingHandle,
+ NULL);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+ return(NDIS_STATUS_RESET_IN_PROGRESS);
+ }
+
+ //
+ // Update the open's references.
+ //
+ ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle, ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References));
+
+ //
+ // Set the reset requested flag.
+ //
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_RESET_REQUESTED);
+
+ //
+ // Grab the local lock.
+ //
+ LOCK_MINIPORT(Miniport, LocalLock);
+ 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.
+ //
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ return(NDIS_STATUS_PENDING);
+}
+
+
diff --git a/private/ntos/ndis/ndis40/minisub.c b/private/ntos/ndis/ndis40/minisub.c
new file mode 100644
index 000000000..1b7e52201
--- /dev/null
+++ b/private/ntos/ndis/ndis40/minisub.c
@@ -0,0 +1,569 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ miniport.c
+
+Abstract:
+
+ NDIS wrapper functions
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 05-Oct-93
+ Jameel Hyder (JameelH) Re-organization 01-Jun-95
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_MINISUB
+
+#undef NdisAllocateSpinLock
+#undef NdisFreeSpinLock
+#undef NdisAcquireSpinLock
+#undef NdisReleaseSpinLock
+#undef NdisDprAcquireSpinLock
+#undef NdisDprReleaseSpinLock
+#undef NdisFreeBuffer
+#undef NdisQueryBuffer
+#undef NdisQueryBufferOffset
+#undef NdisGetFirstBufferFromPacket
+#undef NDIS_BUFFER_TO_SPAN_PAGES
+#undef NdisGetBufferPhysicalArraySize
+#undef NdisEqualString
+#undef NdisInitAnsiString
+#undef NdisAnsiStringToUnicodeString
+#undef NdisInitUnicodeString
+#undef NdisUnicodeStringToAnsiString
+#undef NdisInterlockedIncrement
+#undef NdisInterlockedDecrement
+#undef NdisInterlockedAddUlong
+#undef NdisInterlockedInsertHeadList
+#undef NdisInterlockedInsertTailList
+#undef NdisInterlockedRemoveHeadList
+#undef NdisInterlockedPushEntryList
+#undef NdisInterlockedPopEntryList
+
+VOID
+NdisAllocateSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ INITIALIZE_SPIN_LOCK(&SpinLock->SpinLock);
+}
+
+VOID
+NdisFreeSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ UNREFERENCED_PARAMETER(SpinLock);
+}
+
+VOID
+NdisAcquireSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ NDIS_ACQUIRE_SPIN_LOCK(SpinLock, &SpinLock->OldIrql);
+}
+
+VOID
+NdisReleaseSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ NDIS_RELEASE_SPIN_LOCK(SpinLock, SpinLock->OldIrql);
+}
+
+VOID
+NdisDprAcquireSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(SpinLock);
+ SpinLock->OldIrql = DISPATCH_LEVEL;
+}
+
+VOID
+NdisDprReleaseSpinLock(
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ NDIS_RELEASE_SPIN_LOCK_DPC(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 = MDL_ADDRESS(Buffer);
+ }
+ *Length = MDL_SIZE(Buffer);
+}
+
+VOID
+NdisQueryBufferOffset(
+ IN PNDIS_BUFFER Buffer,
+ OUT PUINT Offset,
+ OUT PUINT Length
+ )
+{
+ *Offset = MDL_OFFSET(Buffer);
+ *Length = MDL_SIZE(Buffer);
+}
+
+VOID
+NdisGetFirstBufferFromPacket(
+ IN PNDIS_PACKET Packet,
+ OUT PNDIS_BUFFER * FirstBuffer,
+ OUT PVOID * FirstBufferVA,
+ OUT PUINT FirstBufferLength,
+ OUT PUINT TotalBufferLength
+ )
+{
+ PNDIS_BUFFER pBuf;
+
+ pBuf = Packet->Private.Head;
+ *FirstBuffer = pBuf;
+ *FirstBufferVA = MmGetMdlVirtualAddress(pBuf);
+ *FirstBufferLength =
+ *TotalBufferLength = MmGetMdlByteCount(pBuf);
+ for (pBuf = pBuf->Next;
+ pBuf != NULL;
+ pBuf = pBuf->Next)
+ {
+ *TotalBufferLength += MmGetMdlByteCount(pBuf);
+ }
+}
+
+ULONG
+NDIS_BUFFER_TO_SPAN_PAGES(
+ IN PNDIS_BUFFER Buffer
+ )
+{
+ if (MDL_SIZE(Buffer) == 0)
+ {
+ return 1;
+ }
+ return COMPUTE_PAGES_SPANNED(MDL_VA(Buffer), MDL_SIZE(Buffer));
+}
+
+VOID
+NdisGetBufferPhysicalArraySize(
+ IN PNDIS_BUFFER Buffer,
+ OUT PUINT ArraySize
+ )
+{
+ if (MDL_SIZE(Buffer) == 0)
+ {
+ *ArraySize = 1;
+ }
+ else
+ {
+ *ArraySize = COMPUTE_PAGES_SPANNED(MDL_VA(Buffer), MDL_SIZE(Buffer));
+ }
+}
+
+BOOLEAN
+NdisEqualString(
+ IN PNDIS_STRING String1,
+ IN PNDIS_STRING String2,
+ IN BOOLEAN CaseInsensitive
+ )
+{
+ return RtlEqualUnicodeString(String1, String2, CaseInsensitive);
+}
+
+VOID
+NdisInitAnsiString(
+ IN OUT PANSI_STRING DestinationString,
+ IN PCSZ SourceString
+ )
+{
+ RtlInitAnsiString(DestinationString, SourceString);
+}
+
+VOID
+NdisInitUnicodeString(
+ IN OUT PUNICODE_STRING DestinationString,
+ IN PCWSTR SourceString
+ )
+{
+
+ RtlInitUnicodeString(DestinationString, SourceString);
+}
+
+NDIS_STATUS
+NdisAnsiStringToUnicodeString(
+ IN OUT PUNICODE_STRING DestinationString,
+ IN PANSI_STRING SourceString
+ )
+{
+ NDIS_STATUS Status;
+
+ Status = RtlAnsiStringToUnicodeString(DestinationString,
+ SourceString,
+ FALSE);
+ return Status;
+}
+
+NDIS_STATUS
+NdisUnicodeStringToAnsiString(
+ IN OUT PANSI_STRING DestinationString,
+ IN PUNICODE_STRING SourceString
+ )
+{
+ NDIS_STATUS Status;
+
+ Status = RtlUnicodeStringToAnsiString(DestinationString,
+ SourceString,
+ FALSE);
+ return Status;
+}
+
+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);
+}
+
+
+ULONG
+NdisInterlockedIncrement(
+ IN PULONG Addend
+ )
+/*++
+
+ Return Value:
+
+ (eax) < 0 (but not necessarily -1) if result of add < 0
+ (eax) == 0 if result of add == 0
+ (eax) > 0 (but not necessarily +1) if result of add > 0
+
+--*/
+{
+ return(InterlockedIncrement(Addend));
+}
+
+ULONG
+NdisInterlockedDecrement(
+ IN PULONG Addend
+ )
+/*++
+
+ Return Value:
+
+ (eax) < 0 (but not necessarily -1) if result of add < 0
+ (eax) == 0 if result of add == 0
+ (eax) > 0 (but not necessarily +1) if result of add > 0
+
+--*/
+{
+ return(InterlockedDecrement(Addend));
+}
+
+ULONG
+NdisInterlockedAddUlong(
+ IN PULONG Addend,
+ IN ULONG Increment,
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ return(ExInterlockedAddUlong(Addend,Increment, &SpinLock->SpinLock));
+
+}
+
+PLIST_ENTRY
+NdisInterlockedInsertHeadList(
+ IN PLIST_ENTRY ListHead,
+ IN PLIST_ENTRY ListEntry,
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+
+ return(ExInterlockedInsertHeadList(ListHead,ListEntry,&SpinLock->SpinLock));
+
+}
+
+PLIST_ENTRY
+NdisInterlockedInsertTailList(
+ IN PLIST_ENTRY ListHead,
+ IN PLIST_ENTRY ListEntry,
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ return(ExInterlockedInsertTailList(ListHead,ListEntry,&SpinLock->SpinLock));
+}
+
+PLIST_ENTRY
+NdisInterlockedRemoveHeadList(
+ IN PLIST_ENTRY ListHead,
+ IN PNDIS_SPIN_LOCK SpinLock
+ )
+{
+ return(ExInterlockedRemoveHeadList(ListHead, &SpinLock->SpinLock));
+}
+
+PSINGLE_LIST_ENTRY
+NdisInterlockedPushEntryList(
+ IN PSINGLE_LIST_ENTRY ListHead,
+ IN PSINGLE_LIST_ENTRY ListEntry,
+ IN PNDIS_SPIN_LOCK Lock
+ )
+{
+ return(ExInterlockedPushEntryList(ListHead, ListEntry, &Lock->SpinLock));
+}
+
+PSINGLE_LIST_ENTRY
+NdisInterlockedPopEntryList(
+ IN PSINGLE_LIST_ENTRY ListHead,
+ IN PNDIS_SPIN_LOCK Lock
+ )
+{
+ return(ExInterlockedPopEntryList(ListHead, &Lock->SpinLock));
+}
+
+//
+// Logging support for miniports
+//
+
+NDIS_STATUS
+NdisMCreateLog(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN UINT Size,
+ OUT PNDIS_HANDLE LogHandle
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_LOG Log = NULL;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ if (Miniport->Log != NULL)
+ {
+ Status = NDIS_STATUS_FAILURE;
+ }
+ else
+ {
+ Log = ALLOC_FROM_POOL(sizeof(NDIS_LOG) + Size, NDIS_TAG_DBG_LOG);
+ if (Log != NULL)
+ {
+ Status = NDIS_STATUS_SUCCESS;
+ Miniport->Log = Log;
+ INITIALIZE_SPIN_LOCK(&Log->LogLock);
+ Log->Miniport = Miniport;
+ Log->Irp = NULL;
+ Log->TotalSize = Size;
+ Log->CurrentSize = 0;
+ Log->InPtr = 0;
+ Log->OutPtr = 0;
+ }
+ else
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ }
+ }
+
+ *LogHandle = Log;
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ return Status;
+}
+
+
+VOID
+NdisMCloseLog(
+ IN NDIS_HANDLE LogHandle
+ )
+{
+ PNDIS_LOG Log = (PNDIS_LOG)LogHandle;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ KIRQL OldIrql;
+
+ Miniport = Log->Miniport;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+ Miniport->Log = NULL;
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ FREE_POOL(Log);
+}
+
+
+NDIS_STATUS
+NdisMWriteLogData(
+ IN NDIS_HANDLE LogHandle,
+ IN PVOID LogBuffer,
+ IN UINT LogBufferSize
+ )
+{
+ PNDIS_LOG Log = (PNDIS_LOG)LogHandle;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+ UINT AmtToCopy;
+
+ ACQUIRE_SPIN_LOCK(&Log->LogLock, &OldIrql);
+
+ if (LogBufferSize <= Log->TotalSize)
+ {
+ if (LogBufferSize <= (Log->TotalSize - Log->InPtr))
+ {
+ //
+ // Can copy the entire buffer
+ //
+ CopyMemory(Log->LogBuf+Log->InPtr, LogBuffer, LogBufferSize);
+ }
+ else
+ {
+ //
+ // We are going to wrap around. Copy it in two chunks.
+ //
+ AmtToCopy = Log->TotalSize - Log->InPtr;
+ CopyMemory(Log->LogBuf+Log->InPtr,
+ LogBuffer,
+ AmtToCopy);
+ CopyMemory(Log->LogBuf + 0,
+ (PUCHAR)LogBuffer+AmtToCopy,
+ LogBufferSize - AmtToCopy);
+ }
+
+ //
+ // Update the current size
+ //
+ Log->CurrentSize += LogBufferSize;
+ if (Log->CurrentSize > Log->TotalSize)
+ Log->CurrentSize = Log->TotalSize;
+
+ //
+ // Update the InPtr and possibly the outptr
+ //
+ Log->InPtr += LogBufferSize;
+ if (Log->InPtr >= Log->TotalSize)
+ {
+ Log->InPtr -= Log->TotalSize;
+ }
+
+ if (Log->CurrentSize == Log->TotalSize)
+ {
+ Log->OutPtr = Log->InPtr;
+ }
+
+ //
+ // Check if there is a pending Irp to complete
+ //
+ if (Log->Irp != NULL)
+ {
+ PIRP Irp = Log->Irp;
+
+ Log->Irp = NULL;
+
+ //
+ // If the InPtr is lagging the OutPtr. then we can simply
+ // copy the data over in one shot.
+ //
+ AmtToCopy = MDL_SIZE(Irp->MdlAddress);
+ if (AmtToCopy > Log->CurrentSize)
+ AmtToCopy = Log->CurrentSize;
+ if ((Log->TotalSize - Log->OutPtr) >= AmtToCopy)
+ {
+ CopyMemory(MDL_ADDRESS(Irp->MdlAddress),
+ Log->LogBuf+Log->OutPtr,
+ AmtToCopy);
+ }
+ else
+ {
+ CopyMemory(MDL_ADDRESS(Irp->MdlAddress),
+ Log->LogBuf+Log->OutPtr,
+ Log->TotalSize-Log->OutPtr);
+ CopyMemory((PUCHAR)MDL_ADDRESS(Irp->MdlAddress)+Log->TotalSize-Log->OutPtr,
+ Log->LogBuf,
+ AmtToCopy - (Log->TotalSize-Log->OutPtr));
+ }
+ Log->CurrentSize -= AmtToCopy;
+ Log->OutPtr += AmtToCopy;
+ if (Log->OutPtr >= Log->TotalSize)
+ Log->OutPtr -= Log->TotalSize;
+ Irp->IoStatus.Information = AmtToCopy;
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+ }
+ }
+ else
+ {
+ Status = NDIS_STATUS_BUFFER_OVERFLOW;
+ }
+
+ RELEASE_SPIN_LOCK(&Log->LogLock, OldIrql);
+
+ return Status;
+}
+
+VOID
+NdisMFlushLog(
+ IN NDIS_HANDLE LogHandle
+ )
+{
+ PNDIS_LOG Log = (PNDIS_LOG)LogHandle;
+ KIRQL OldIrql;
+
+ ACQUIRE_SPIN_LOCK(&Log->LogLock, &OldIrql);
+ Log->InPtr = 0;
+ Log->OutPtr = 0;
+ Log->CurrentSize = 0;
+ RELEASE_SPIN_LOCK(&Log->LogLock, OldIrql);
+}
+
diff --git a/private/ntos/ndis/ndis40/mp/makefile b/private/ntos/ndis/ndis40/mp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/ndis40/mp/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/ndis40/mp/ndis.prf b/private/ntos/ndis/ndis40/mp/ndis.prf
new file mode 100644
index 000000000..7c294f08e
--- /dev/null
+++ b/private/ntos/ndis/ndis40/mp/ndis.prf
@@ -0,0 +1,136 @@
+_allmul
+NdisQueryBuffer@12
+@InterlockedDecrement@4
+NdisQueryBufferOffset@12
+@InterlockedIncrement@4
+@InterlockedExchange@8
+NDIS_BUFFER_TO_SPAN_PAGES@4
+NdisAllocateBuffer@20
+NdisSetTimer@8
+NdisUnchainBufferAtFront@8
+@ndisMSyncSend@8
+@ndisMProcessDeferredPrioritySends@4
+ndisMIsr@8
+@ndisMQueueWorkItem@16
+ndisMDpc@16
+@ndisMIsLoopbackPacket@8
+@ndisMStartSends@4
+@ndisMProcessDeferred@4
+ndisMWakeUpDpc@16
+NdisMSendComplete@12
+@ndisMDeQueueWorkItem@16
+NdisMSendResourcesAvailable@4
+NdisMStartBufferPhysicalMapping@24
+NdisMCompleteBufferPhysicalMapping@12
+ndisMDeferredTimerDpc@16
+@ndisMIndicateLoopback@4
+ndisMCopyFromPacketToBuffer@20
+ndisMTimerDpc@16
+ndisMSend@8
+EthFilterDprIndicateReceiveComplete@4
+EthFilterDprIndicateReceivePacket@12
+NdisReturnPackets@8
+NdisAllocateMemory@20
+NdisWritePciSlotInformation@20
+NdisCopyBuffer@24
+NdisUnchainBufferAtBack@8
+NdisDereferenceRef@4
+ndisAllocationExecutionRoutine@16
+ndisDereferencePackage@4
+ndisReportResources@20
+ndisAddResource@28
+NdisFreeMemory@12
+ndisMFinishPendingOpen@4
+NdisAllocateBufferPool@12
+ndisMFinishQueuedPendingOpen@4
+NdisAllocateSharedMemory@20
+NdisSystemProcessorCount@0
+NdisInitializeTimer@12
+NdisMSetPeriodicTimer@8
+NdisInitializeRef@4
+NdisFreeBufferPool@4
+NdisAllocatePacket@12
+NdisAllocatePacketPool@16
+NdisCopyFromPacketToPacket@24
+ndisReferencePackage@4
+NdisReadPciSlotInformation@20
+NdisReferenceRef@4
+ndisMRequestQueryInformationPost@12
+DriverEntry@8
+ndisReadParameters@24
+ndisReadRegistry@0
+ArcCreateFilter@24
+ArcDeleteFilter@4
+ndisMQueryMaximumTotalSize@8
+TrCreateFilter@28
+NdisMRegisterMiniport@12
+ethUpdateBroadcastBindingList@12
+EthCreateFilter@28
+EthNoteFilterOpenAdapter@16
+EthDeleteFilter@4
+ethUpdateDirectedBindingList@12
+ethUpdateSpecificBindingLists@8
+NdisOpenAdapter@44
+ndisDereferenceProtocol@4
+NdisRegisterProtocol@16
+NdisMRegisterAdapterShutdownHandler@12
+ndisMSetInformation@8
+ndisMSyncQueryInformationComplete@8
+NdisIMRegisterLayeredMiniport@16
+ndisMQueryMaximumFrameSize@8
+ndisDereferenceMiniport@4
+ndisMDoRequests@4
+TrDeleteFilter@4
+ndisMQueueRequest@12
+NdisMInitializeTimer@16
+NdisMRegisterInterrupt@28
+ndisDereferenceDriver@4
+ndisQueueMiniportOnDriver@8
+NdisMAllocateSharedMemory@20
+ndisMChangeClass@20
+NdisMRegisterIoPortRange@16
+ndisMRequest@8
+FddiCreateFilter@36
+ndisMSetCurrentLookahead@8
+FddiDeleteFilter@4
+ndisMQueryNetworkAddress@8
+@ndisMQueueNewWorkItem@16
+ndisMSetPacketFilter@8
+EthFilterAdjust@20
+ndisMRequestSetInformationPost@12
+ndisMSyncSetInformationComplete@8
+ndisSaveParameters@24
+ndisQueueOpenOnProtocol@8
+NdisInitializeInterrupt@40
+ndisUpdateDriverInstance@16
+ndisMDummyTransferData@24
+ndisCheckRoute@24
+NdisOpenConfiguration@12
+NdisInitializeWrapper@16
+ndisProtocolAlreadyBound@8
+NdisOverrideBusNumber@12
+ndisSaveLinkage@24
+ndisMInitializeAdapter@16
+ndisMOpenAdapter@48
+ndisMDoMiniportOp@24
+NdisMAllocateMapRegisters@20
+ndisCreateIrpHandler@8
+ndisSuccessIrpHandler@8
+ndisInitializePackage@8
+ndisDispatchRequest@8
+NdisRegisterTdiCallBack@4
+ndisQueuedProtocolNotification@4
+ndisHandlePnPRequest@4
+ndisHandleLegacyTransport@4
+ndisHandleProtocolNotification@4
+NdisReadNetworkAddress@16
+NdisCloseConfiguration@4
+ndisInitializeAdapter@8
+NdisReadConfiguration@20
+ndisInitializeBindings@12
+ndisCheckProtocolBinding@16
+NdisMSetAttributes@16
+ndisMUndoBogusFilters@4
+ndisInitializeAllAdapterInstances@8
+ndisMQueryInformation@8
+ndisMDpcTimer@16
diff --git a/private/ntos/ndis/ndis40/mp/sources b/private/ntos/ndis/ndis40/mp/sources
new file mode 100644
index 000000000..dc48d81bb
--- /dev/null
+++ b/private/ntos/ndis/ndis40/mp/sources
@@ -0,0 +1,29 @@
+!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
+
+NT_UP=0
+
+TARGETPATH=\nt\public\sdk\lib
+
+!include ..\sources.inc
diff --git a/private/ntos/ndis/ndis40/ndis.c b/private/ntos/ndis/ndis40/ndis.c
new file mode 100644
index 000000000..4b5a8a83b
--- /dev/null
+++ b/private/ntos/ndis/ndis40/ndis.c
@@ -0,0 +1,1349 @@
+/*++
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ndis.c
+
+Abstract:
+
+ NDIS wrapper functions
+
+Author:
+
+ Adam Barr (adamba) 11-Jul-1990
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ 10-Jul-1995 JameelH Make NDIS.SYS a device-driver and add PnP support
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_NDIS
+
+#define NDIS_DEVICE_NAME L"\\Device\\Ndis"
+#define NDIS_SYMBOLIC_NAME L"\\DosDevices\\NDIS"
+
+PDEVICE_OBJECT ndisDeviceObject = NULL;
+PDRIVER_OBJECT ndisDriverObject = NULL;
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Description:
+
+ NDIS wrapper driver entry point.
+
+Arguments:
+
+ DriverObject - Pointer to the driver object created by the system.
+ RegistryPath - Pointer to the registry section where the parameters reside.
+
+Return Value:
+
+ Return value from IoCreateDevice
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ UNICODE_STRING DeviceName;
+ UINT i;
+
+ // Create the device object.
+ RtlInitUnicodeString(&DeviceName, NDIS_DEVICE_NAME);
+
+ ndisDriverObject = DriverObject;
+ Status = IoCreateDevice(DriverObject, // DriverObject
+ 0, // DeviceExtension
+ &DeviceName, // DeviceName
+ FILE_DEVICE_NETWORK,// DeviceType
+ 0, // DeviceCharacteristics
+ FALSE, // Exclusive
+ &ndisDeviceObject); // DeviceObject
+
+ if (NT_SUCCESS(Status))
+ {
+ UNICODE_STRING SymbolicLinkName;
+
+ // Create a symbolic link to this device
+ RtlInitUnicodeString(&SymbolicLinkName, NDIS_SYMBOLIC_NAME);
+ Status = IoCreateSymbolicLink(&SymbolicLinkName, &DeviceName);
+
+ // Initialize the driver object for this file system driver.
+ for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
+ {
+ DriverObject->MajorFunction[i] = ndisDispatchRequest;
+ }
+ // For now make this unloadable
+ DriverObject->DriverUnload = NULL;
+
+ INITIALIZE_SPIN_LOCK(&ndisDriverListLock);
+ INITIALIZE_SPIN_LOCK(&ndisGlobalDbLock);
+
+ ndisDmaAlignment = HalGetDmaAlignmentRequirement();
+ if (sizeof(ULONG) > ndisDmaAlignment)
+ {
+ ndisDmaAlignment = sizeof(ULONG);
+ }
+
+ ProtocolInitializePackage();
+ ArcInitializePackage();
+ EthInitializePackage();
+ FddiInitializePackage();
+ TrInitializePackage();
+ MiniportInitializePackage();
+ InitInitializePackage();
+ PnPInitializePackage();
+ MacInitializePackage();
+ CoInitializePackage();
+
+#if DBG
+ //
+ // set the offset to the debug information...
+ //
+ ndisDebugInformationOffset = FIELD_OFFSET(NDIS_MINIPORT_BLOCK, Reserved);
+#endif
+
+#if defined(_ALPHA_)
+ INITIALIZE_SPIN_LOCK(&ndisLookaheadBufferLock);
+#endif
+
+ ExInitializeResource(&SharedMemoryResource);
+
+ INITIALIZE_SPIN_LOCK(&ndisGlobalOpenListLock);
+
+ ndisReadRegistry();
+ Status = STATUS_SUCCESS;
+ }
+
+ return Status;
+}
+
+
+VOID
+ndisReadRegistry(
+ VOID
+ )
+{
+ NTSTATUS RegStatus;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[3];
+ UINT c;
+ ULONG DefaultZero = 0;
+
+ //
+ // First we need to initialize the processor information incase
+ // the registry is empty.
+ //
+ for (c = 0; c < **((PUCHAR *)&KeNumberProcessors); c++)
+ {
+ ndisValidProcessors[c] = c;
+ }
+
+ ndisCurrentProcessor = ndisMaximumProcessor = c - 1;
+
+ //
+ // 1) Switch to the MediaTypes key below the service (NDIS) key
+ //
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = L"MediaTypes";
+
+ //
+ // Setup to enumerate the values in the registry section (shown above).
+ // For each such value, we'll add it to the ndisMediumArray
+ //
+ QueryTable[1].QueryRoutine = ndisAddMediaTypeToArray;
+ QueryTable[1].DefaultType = REG_DWORD;
+ QueryTable[1].DefaultData = (PVOID)&DefaultZero;
+ QueryTable[1].DefaultLength = 0;
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ QueryTable[1].Name = NULL;
+
+ //
+ // Query terminator
+ //
+ QueryTable[2].QueryRoutine = NULL;
+ QueryTable[2].Flags = 0;
+ QueryTable[2].Name = NULL;
+
+ //
+ // The rest of the work is done in the callback routine ndisAddMediaTypeToArray.
+ //
+ RegStatus = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
+ L"NDIS",
+ QueryTable,
+ (PVOID)NULL, // no context needed
+ NULL);
+ //
+ // Switch to the parameters key below the service (NDIS) key and
+ // read the processor affinity.
+ //
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = L"Parameters";
+
+ QueryTable[1].QueryRoutine = ndisReadParameters;
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ QueryTable[1].DefaultData = (PVOID)&DefaultZero;
+ QueryTable[1].DefaultLength = 0;
+ QueryTable[1].DefaultType = REG_DWORD;
+ QueryTable[1].Name = L"ProcessorAffinityMask";
+
+ //
+ // Query terminator
+ //
+ QueryTable[2].QueryRoutine = NULL;
+ QueryTable[2].Flags = 0;
+ QueryTable[2].Name = NULL;
+
+ //
+ // The rest of the work is done in the callback routine ndisReadParameters
+ //
+ RegStatus = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
+ L"NDIS",
+ QueryTable,
+ (PVOID)NULL, // no context needed
+ NULL);
+}
+
+
+NTSTATUS
+ndisReadParameters(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ //
+ // If we have valid data then build our array of valid processors
+ // to use.... Treat the special case of 0 to signify no processor
+ // affinity - i.e. use defaults.
+ //
+ if ((REG_DWORD == ValueType) && (ValueData != NULL))
+ {
+ if (*(PULONG)ValueData == 0)
+ {
+ ndisSkipProcessorAffinity = TRUE;
+ }
+ else
+ {
+ ULONG ProcessorAffinity;
+ UINT c1, c2;
+
+ //
+ // Save the processor affinity.
+ //
+ ProcessorAffinity = *(PULONG)ValueData;
+
+ //
+ // Fill in the valid processor array.
+ //
+ for (c1 = c2 = 0;
+ (c1 <= ndisMaximumProcessor) && (ProcessorAffinity != 0);
+ c1++)
+ {
+ if (ProcessorAffinity & 1)
+ {
+ ndisValidProcessors[c2++] = c1;
+ }
+ ProcessorAffinity >>= 1;
+ }
+
+ ndisCurrentProcessor = ndisMaximumProcessor = c2 - 1;
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+ndisAddMediaTypeToArray(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+{
+#if DBG
+ NDIS_STRING Str;
+
+ RtlInitUnicodeString(&Str, ValueName);
+#endif
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("ExperimentalMediaType %Z - %x\n", &Str, *(PULONG)ValueData));
+
+ //
+ // Ignore all values that we already know about. These should not be in the
+ // registry anyway, but just in case somebody is messing with it.
+ //
+ if ((ValueType == REG_DWORD) && (ValueData != NULL) && (*(PULONG)ValueData > NdisMediumIrda))
+ {
+ NDIS_MEDIUM *pTemp;
+ ULONG size;
+
+ //
+ // See if we have enough space to add this value. If not allocate space for the
+ // new array, copy the old one into this (and free the old if not static).
+ //
+ ASSERT (ndisMediumArraySize <= ndisMediumArrayMaxSize);
+
+ //
+ // Check for duplicates. If so drop it
+ //
+ for (pTemp = ndisMediumArray, size = ndisMediumArraySize;
+ size > 0; pTemp ++, size -= sizeof(NDIS_MEDIUM))
+ {
+ if (*(NDIS_MEDIUM *)ValueData == *pTemp)
+ {
+ //
+ // Duplicate.
+ //
+ return STATUS_SUCCESS;
+ }
+ }
+
+ if (ndisMediumArraySize == ndisMediumArrayMaxSize)
+ {
+ //
+ // We do not have any space in the array. Need to re-alloc. Be generous.
+ //
+ pTemp = (NDIS_MEDIUM *)ALLOC_FROM_POOL(ndisMediumArraySize + EXPERIMENTAL_SIZE*sizeof(NDIS_MEDIUM),
+ NDIS_TAG_DEFAULT);
+ if (pTemp != NULL)
+ {
+ CopyMemory(pTemp, ndisMediumArray, ndisMediumArraySize);
+ if (ndisMediumArray != ndisMediumBuffer)
+ {
+ FREE_POOL(ndisMediumArray);
+ }
+ ndisMediumArray = pTemp;
+ }
+ }
+ if (ndisMediumArraySize < ndisMediumArrayMaxSize)
+ {
+ ndisMediumArray[ndisMediumArraySize/sizeof(NDIS_MEDIUM)] = *(NDIS_MEDIUM *)ValueData;
+ ndisMediumArraySize += sizeof(NDIS_MEDIUM);
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+ndisDispatchRequest(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ Dispatcher for Irps intended for the NDIS Device.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PIO_STACK_LOCATION pIrpSp;
+ static LONG OpenCount = 0;
+ static KSPIN_LOCK Lock = {0};
+
+ pDeviceObject; // prevent compiler warnings
+
+ PAGED_CODE( );
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pIrp->IoStatus.Status = STATUS_PENDING;
+ pIrp->IoStatus.Information = 0;
+
+ PnPReferencePackage();
+
+ switch (pIrpSp->MajorFunction)
+ {
+ case IRP_MJ_CREATE:
+ Increment(&OpenCount, &Lock);
+ break;
+
+ case IRP_MJ_CLEANUP:
+ Decrement(&OpenCount, &Lock);
+ break;
+
+ case IRP_MJ_CLOSE:
+ break;
+
+ case IRP_MJ_INTERNAL_DEVICE_CONTROL:
+ break;
+
+ case IRP_MJ_DEVICE_CONTROL:
+ Status = ndisHandlePnPRequest(pIrp);
+ break;
+
+ default:
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+ }
+
+ ASSERT (CURRENT_IRQL < DISPATCH_LEVEL);
+ ASSERT (Status != STATUS_PENDING);
+
+ pIrp->IoStatus.Status = Status;
+ IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
+
+ PnPDereferencePackage();
+
+ return Status;
+}
+
+
+NTSTATUS
+ndisHandlePnPRequest(
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ Handler for PnP ioctls.
+
+Arguments:
+
+ We get the following IOCTLS today.
+
+ - Load driver (and initiate bindings to transports)
+ - Unbind from all transports and unload driver
+ - Translate name
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PIO_STACK_LOCATION pIrpSp;
+ UNICODE_STRING Device;
+ ULONG Method;
+ PVOID pBuf;
+ UINT iBufLen, oBufLen;
+ UINT AmtCopied;
+
+ PAGED_CODE( );
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+ Method = pIrpSp->Parameters.DeviceIoControl.IoControlCode & 3;
+
+ // Ensure that the method is buffered - we always use that.
+ if (Method == METHOD_BUFFERED)
+ {
+ // Get the output buffer and its length. Input and Output buffers are
+ // both pointed to by the SystemBuffer
+ iBufLen = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
+ oBufLen = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+ pBuf = pIrp->AssociatedIrp.SystemBuffer;
+ }
+ else
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ RtlInitUnicodeString(&Device, pBuf);
+ }
+ except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return STATUS_ACCESS_VIOLATION;
+ }
+
+ switch (pIrpSp->Parameters.DeviceIoControl.IoControlCode)
+ {
+ case IOCTL_NDIS_ADD_DEVICE:
+ Status = ndisHandleLoadDriver(&Device);
+ break;
+
+ case IOCTL_NDIS_DELETE_DEVICE:
+ Status = ndisHandleUnloadDriver(&Device);
+ break;
+
+ case IOCTL_NDIS_ADD_TDI_DEVICE:
+ Status = ndisHandleLegacyTransport(&Device);
+ break;
+
+ case IOCTL_NDIS_NOTIFY_PROTOCOL:
+ Status = ndisHandleProtocolNotification(&Device);
+ break;
+
+ case IOCTL_NDIS_TRANSLATE_NAME:
+ Status = ndisHandleTranslateName(&Device,
+ pBuf,
+ oBufLen,
+ &AmtCopied);
+ pIrp->IoStatus.Information = AmtCopied;
+ break;
+
+ default:
+ break;
+ }
+
+ ASSERT (CURRENT_IRQL < DISPATCH_LEVEL);
+ return Status;
+}
+
+
+
+NTSTATUS
+ndisHandleLoadDriver(
+ IN PUNICODE_STRING pDevice
+ )
+/*++
+
+Routine Description:
+
+ Load the driver and initiate binding to all protocols bound to it.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ KIRQL OldIrql;
+ PNDIS_M_DRIVER_BLOCK MiniBlock;
+ PNDIS_MAC_BLOCK MacBlock;
+ UNICODE_STRING UpcaseDevice;
+ BOOLEAN fLoaded = FALSE;
+
+ //
+ // Map the device name to the driver. Search the miniport list first and then
+ // the mac list. The string passed to us is the name of the registry section
+ // of the specific driver to load. For e.g. if the driver being loaded is
+ // ELNK31, the string passed to us is: Elnk31. We first need to upper case the
+ // string before comparing since we cannot do case-insensitive comparisons at
+ // raised irql. The driver block has the registry path to the real driver -
+ // in this example Elnk3. The task is to correlate Elnk31 with Elnk3. We also
+ // cannot make an assumption about how many digits that follow. Also a prefix
+ // check itself is not enough since some drivers have a trailing digit at the
+ // end. Consider the case of two drivers in the system, IBMTOK and IBMTOK2.
+ // Single instances of these two in the machine could generate
+ // IBMTOK21 and IBMTOK2. So matching IBMTOK2 to IBMTOK2 is incorrect - IBMTOK2
+ // has to be matched with IBMTOK21. Oh, joy !!!
+ //
+ // Add to complicate matters further, the Service controller could call us
+ // to load a device that is already loaded. Ignore such requests.
+ //
+
+ Status = RtlUpcaseUnicodeString(&UpcaseDevice, pDevice, TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ do
+ {
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+
+ for (MiniBlock = ndisMiniDriverList;
+ MiniBlock != NULL;
+ MiniBlock = MiniBlock->NextDriver)
+ {
+ if ((UpcaseDevice.Length > MiniBlock->BaseName.Length) &&
+ RtlPrefixUnicodeString(&MiniBlock->BaseName, &UpcaseDevice, FALSE))
+ {
+ PNDIS_MINIPORT_BLOCK Miniport;
+
+ //
+ // Check if we already have this device
+ //
+
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(&MiniBlock->Ref.SpinLock);
+
+ for (Miniport = MiniBlock->MiniportQueue;
+ Miniport != NULL;
+ Miniport = Miniport->NextMiniport)
+ {
+ if (NDIS_EQUAL_UNICODE_STRING(&UpcaseDevice, &Miniport->BaseName))
+ {
+ fLoaded = TRUE;
+ break; // Found it.
+ }
+ }
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(&MiniBlock->Ref.SpinLock);
+
+ if (fLoaded || !ndisReferenceDriver(MiniBlock))
+ {
+ MiniBlock = NULL;
+ }
+ break; // Found it.
+ }
+ }
+
+ if (MiniBlock != NULL)
+ break;
+
+ for (MacBlock = ndisMacDriverList;
+ MacBlock != NULL;
+ MacBlock = MacBlock->NextMac)
+ {
+ if ((UpcaseDevice.Length > MacBlock->BaseName.Length) &&
+ RtlPrefixUnicodeString(&MacBlock->BaseName, &UpcaseDevice, FALSE))
+ {
+ PNDIS_ADAPTER_BLOCK Mac;
+
+ //
+ // Check if we already have this device
+ //
+
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(&MacBlock->Ref.SpinLock);
+
+ for (Mac = MacBlock->AdapterQueue;
+ Mac != NULL;
+ Mac = Mac->NextAdapter)
+ {
+ if (NDIS_EQUAL_UNICODE_STRING(&UpcaseDevice, &Mac->BaseName))
+ {
+ fLoaded = TRUE;
+ break; // Found it.
+ }
+ }
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(&MacBlock->Ref.SpinLock);
+
+ if (fLoaded || !ndisReferenceMac(MacBlock))
+ {
+ MacBlock = NULL;
+ }
+ break; // Found it.
+ }
+ }
+ } while (FALSE);
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ if (fLoaded)
+ {
+ return STATUS_SUCCESS;
+ }
+
+ if ((MiniBlock == NULL) && (MacBlock == NULL))
+ {
+ return STATUS_NO_SUCH_DEVICE;
+ }
+
+ Status = ndisInitializeAdapter((MiniBlock != NULL) ?
+ MiniBlock : (PNDIS_M_DRIVER_BLOCK)MacBlock,
+ &UpcaseDevice);
+
+ RtlFreeUnicodeString(&UpcaseDevice);
+
+ if (NT_SUCCESS(Status))
+ {
+ Status = ndisHandleProtocolNotification(pDevice);
+ }
+
+ if (MiniBlock != NULL)
+ {
+ ndisDereferenceDriver(MiniBlock);
+ }
+ else
+ {
+ ndisDereferenceMac(MacBlock);
+ }
+
+ return Status;
+}
+
+
+NTSTATUS
+ndisHandleUnloadDriver(
+ IN PUNICODE_STRING pDevice
+ )
+/*++
+
+Routine Description:
+
+ Unbind all transports from this adapter and unload the driver.
+
+Arguments:
+
+ pDevice - Base name (i.e. without the "\Device\") of the device being unloaded.
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PNDIS_ADAPTER_BLOCK Mac;
+
+ ndisReferenceAdapterOrMiniportByName(pDevice, &Miniport, &Mac);
+
+ if (Miniport != NULL)
+ {
+ Status = ndisUnloadMiniport(Miniport);
+ ndisDereferenceMiniport(Miniport);
+ }
+ else if (Mac != NULL)
+ {
+ Status = ndisUnloadMac(Mac);
+ ndisDereferenceAdapter(Mac);
+ }
+ else
+ {
+ Status = STATUS_NO_SUCH_DEVICE;
+ }
+
+ return Status;
+}
+
+
+NTSTATUS
+ndisHandleTranslateName(
+ IN PUNICODE_STRING pDevice,
+ IN PUCHAR Buffer,
+ IN UINT BufferLength,
+ OUT PUINT AmountCopied
+ )
+/*++
+
+Routine Description:
+
+ Calls the PnP protocols to enumerate PnP ids for the given adapter.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PNDIS_ADAPTER_BLOCK Mac;
+
+ ndisReferenceAdapterOrMiniportByName(pDevice, &Miniport, &Mac);
+
+ if (Miniport != NULL)
+ {
+ Status = ndisTranslateMiniportName(Miniport, Buffer, BufferLength, AmountCopied);
+ ndisDereferenceMiniport(Miniport);
+ }
+ else if (Mac != NULL)
+ {
+ Status = ndisTranslateMacName(Mac, Buffer, BufferLength, AmountCopied);
+ ndisDereferenceAdapter(Mac);
+ }
+ else
+ {
+ Status = STATUS_NO_SUCH_DEVICE;
+ }
+
+ return Status;
+}
+
+
+NTSTATUS
+ndisHandleProtocolNotification(
+ IN PUNICODE_STRING pDevice
+ )
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ KIRQL OldIrql;
+ PNDIS_M_DRIVER_BLOCK MiniBlock;
+ PNDIS_MAC_BLOCK MacBlock;
+ UNICODE_STRING UpcaseDevice;
+
+ Status = RtlUpcaseUnicodeString(&UpcaseDevice, pDevice, TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ //
+ // The device name passed to us is the 'base' name of the driver e.g. SONIC.
+ // First find the driver structure and walk thru its instances and notify
+ // the protocols bound to it
+ //
+ do
+ {
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+
+ //
+ // Try miniports first
+ //
+ for (MiniBlock = ndisMiniDriverList;
+ MiniBlock != NULL;
+ MiniBlock = MiniBlock->NextDriver)
+ {
+ if (NDIS_EQUAL_UNICODE_STRING(&UpcaseDevice, &MiniBlock->BaseName))
+ {
+ if (!ndisReferenceDriver(MiniBlock))
+ {
+ MiniBlock = NULL;
+ }
+ break;
+ }
+ }
+
+ if (MiniBlock != NULL)
+ {
+ PNDIS_MINIPORT_BLOCK Miniport, NextMiniport;
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ NDIS_ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
+
+ for (Miniport = MiniBlock->MiniportQueue;
+ Miniport != NULL;
+ Miniport = NextMiniport)
+ {
+ if (ndisReferenceMiniport(Miniport))
+ {
+ NDIS_RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
+
+ ndisInitializeBindings(&Miniport->MiniportName,
+ &Miniport->BaseName,
+ TRUE);
+
+ NDIS_ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
+ NextMiniport = Miniport->NextMiniport;
+ ndisDereferenceMiniport(Miniport);
+ }
+ else
+ {
+ NextMiniport = Miniport->NextMiniport;
+ }
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
+ ndisDereferenceDriver(MiniBlock);
+ break;
+ }
+
+ //
+ // Now try full nic drivers
+ //
+ for (MacBlock = ndisMacDriverList;
+ MacBlock != NULL;
+ MacBlock = MacBlock->NextMac)
+ {
+ if (NDIS_EQUAL_UNICODE_STRING(&UpcaseDevice, &MacBlock->BaseName))
+ {
+ if (!ndisReferenceMac(MacBlock))
+ {
+ MacBlock = NULL;
+ }
+ break;
+ }
+ }
+
+ if (MacBlock != NULL)
+ {
+ PNDIS_ADAPTER_BLOCK Mac, NextMac;
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ NDIS_ACQUIRE_SPIN_LOCK(&MacBlock->Ref.SpinLock, &OldIrql);
+
+ for (Mac = MacBlock->AdapterQueue;
+ Mac != NULL;
+ Mac = NextMac)
+ {
+ if (ndisReferenceAdapter(Mac))
+ {
+ NDIS_RELEASE_SPIN_LOCK(&MacBlock->Ref.SpinLock, OldIrql);
+
+ ndisInitializeBindings(&Mac->AdapterName,
+ &Mac->BaseName,
+ TRUE);
+
+ NextMac = Mac->NextAdapter;
+ NDIS_ACQUIRE_SPIN_LOCK(&MacBlock->Ref.SpinLock, &OldIrql);
+ ndisDereferenceAdapter(Mac);
+ }
+ else
+ {
+ NextMac = Mac->NextAdapter;
+ }
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&MacBlock->Ref.SpinLock, OldIrql);
+ ndisDereferenceMac(MacBlock);
+ break;
+ }
+ else
+ {
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+ }
+ Status = STATUS_NO_SUCH_DEVICE;
+
+ } while (FALSE);
+
+ RtlFreeUnicodeString(&UpcaseDevice);
+
+ return Status;
+}
+
+
+VOID
+ndisReferenceAdapterOrMiniportByName(
+ IN PUNICODE_STRING pDevice,
+ OUT PNDIS_MINIPORT_BLOCK * pMiniport,
+ OUT PNDIS_ADAPTER_BLOCK * pAdapter
+ )
+{
+ NTSTATUS Status;
+ KIRQL OldIrql;
+ PNDIS_M_DRIVER_BLOCK MiniBlock;
+ PNDIS_MINIPORT_BLOCK Miniport = NULL;
+ PNDIS_MAC_BLOCK MacBlock;
+ PNDIS_ADAPTER_BLOCK Mac = NULL;
+ UNICODE_STRING UpcaseDevice;
+
+ *pMiniport = NULL;
+ *pAdapter = NULL;
+
+ Status = RtlUpcaseUnicodeString(&UpcaseDevice, pDevice, TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ return;
+ }
+
+ do
+ {
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+
+ for (MiniBlock = ndisMiniDriverList;
+ MiniBlock != NULL;
+ MiniBlock = MiniBlock->NextDriver)
+ {
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(&MiniBlock->Ref.SpinLock);
+
+ for (Miniport = MiniBlock->MiniportQueue;
+ Miniport != NULL;
+ Miniport = Miniport->NextMiniport)
+ {
+ if (NDIS_EQUAL_UNICODE_STRING(&UpcaseDevice, &Miniport->BaseName))
+ {
+ if (!ndisReferenceMiniport(Miniport))
+ {
+ Miniport = NULL;
+ }
+ break; // Found it.
+ }
+ }
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(&MiniBlock->Ref.SpinLock);
+
+ if (Miniport != NULL)
+ {
+ *pMiniport = Miniport;
+ break; // Found it.
+ }
+ }
+
+ for (MacBlock = ndisMacDriverList;
+ (Miniport == NULL) && (MacBlock != NULL);
+ MacBlock = MacBlock->NextMac)
+ {
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(&MacBlock->Ref.SpinLock);
+
+ for (Mac = MacBlock->AdapterQueue;
+ Mac != NULL;
+ Mac = Mac->NextAdapter)
+ {
+ if (NDIS_EQUAL_UNICODE_STRING(&UpcaseDevice, &Mac->BaseName))
+ {
+ if (!ndisReferenceMac(Mac))
+ {
+ Mac = NULL;
+ }
+ break; // Found it.
+ }
+ }
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(&MacBlock->Ref.SpinLock);
+
+ if (Mac != NULL)
+ {
+ *pAdapter = Mac;
+ break; // Found it.
+ }
+ }
+ } while (FALSE);
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ RtlFreeUnicodeString(&UpcaseDevice);
+}
+
+NTSTATUS
+ndisHandleLegacyTransport(
+ IN PUNICODE_STRING pDevice
+ )
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ RTL_QUERY_REGISTRY_TABLE LinkQueryTable[3];
+ PWSTR Export = NULL;
+ HANDLE TdiHandle;
+
+ //
+ // Set up LinkQueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Linkage key below the xports registry key
+ //
+
+ LinkQueryTable[0].QueryRoutine = NULL;
+ LinkQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ LinkQueryTable[0].Name = L"Linkage";
+
+ //
+ // 2) Call ndisSaveLinkage for "Export" (as a single multi-string),
+ // which will allocate storage and save the data in Export.
+ //
+
+ LinkQueryTable[1].QueryRoutine = ndisSaveLinkage;
+ LinkQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ LinkQueryTable[1].Name = L"Export";
+ LinkQueryTable[1].EntryContext = (PVOID)&Export;
+ LinkQueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 3) Stop
+ //
+
+ LinkQueryTable[2].QueryRoutine = NULL;
+ LinkQueryTable[2].Flags = 0;
+ LinkQueryTable[2].Name = NULL;
+
+ do
+ {
+ UNICODE_STRING Us;
+ PWSTR CurExport;
+
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
+ pDevice->Buffer,
+ LinkQueryTable,
+ (PVOID)NULL, // no context needed
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ Status = STATUS_SUCCESS; // Do not complain about TDI drivers which do not
+ break; // have any linkages
+ }
+
+ //
+ // Walk the list of exports and call TdiRegisterDevice for each
+ //
+ for (CurExport = Export;
+ *CurExport != 0;
+ CurExport = (PWCHAR)((PUCHAR)CurExport + Us.MaximumLength))
+ {
+ RtlInitUnicodeString (&Us, CurExport);
+
+ if (ndisTdiRegisterCallback != NULL)
+ {
+ Status = (*ndisTdiRegisterCallback)(&Us, &TdiHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ break;
+ }
+ }
+ }
+ } while (FALSE);
+
+ if (Export != NULL)
+ FREE_POOL(Export);
+
+ return(Status);
+}
+
+
+VOID
+ndisInitializeBindings(
+ IN PUNICODE_STRING ExportName,
+ IN PUNICODE_STRING ServiceName,
+ IN BOOLEAN Synchronous
+ )
+{
+ KIRQL OldIrql;
+ PNDIS_PROTOCOL_BLOCK Protocol, NextProt;
+ PNDIS_BIND_CONTEXT pBindContext, pBindContextHead = NULL;
+ UNICODE_STRING UpcasedName;
+ NTSTATUS Status;
+
+ Status = RtlUpcaseUnicodeString(&UpcasedName, ExportName, TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ return;
+ }
+
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+
+ for (Protocol = ndisProtocolList;
+ Protocol != NULL;
+ Protocol = NextProt)
+ {
+ NextProt = Protocol->NextProtocol;
+
+ //
+ // Can only do if the protocol has a bind handler
+ // and we can reference it.
+ //
+ if ((Protocol->ProtocolCharacteristics.BindAdapterHandler != NULL) &&
+ ndisReferenceProtocol(Protocol))
+ {
+ UNICODE_STRING ProtocolSection;
+ BOOLEAN Sync;
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ //
+ // Check if this protocol has the binding to this adapter and it
+ // is not already bound.
+ //
+ if (ndisCheckProtocolBinding(Protocol,
+ ExportName,
+ ServiceName,
+ &ProtocolSection) &&
+ !ndisProtocolAlreadyBound(Protocol, &UpcasedName))
+ {
+ NDIS_BIND_CONTEXT BindContext; // To handle allocation failures
+
+ //
+ // Attempt to queue this to get the protocols initialzation going
+ // parallel. Always serialize the call-managers since we must wait
+ // for the call-managers to complete their initializations before
+ // indicating to non-call-manager protocols.
+ //
+ Sync = TRUE;
+ if (!Synchronous &&
+ (Protocol->ProtocolCharacteristics.Flags & NDIS_PROTOCOL_CALL_MANAGER) == 0)
+ {
+ pBindContext = ALLOC_FROM_POOL(sizeof(NDIS_BIND_CONTEXT), NDIS_TAG_DEFAULT);
+ Sync = (pBindContext == NULL);
+ }
+
+ if (Sync)
+ {
+ //
+ // Use the local version and do it synchronously
+ //
+ pBindContext = &BindContext;
+ pBindContext->Next = NULL;
+ }
+ else
+ {
+ //
+ // Link it into the list and queue a worker thread to do it
+ //
+ pBindContext->Next = pBindContextHead;
+ pBindContextHead = pBindContext;
+ }
+
+ pBindContext->Protocol = Protocol;
+ pBindContext->ProtocolSection = ProtocolSection;
+ pBindContext->DeviceName = ExportName;
+ INITIALIZE_EVENT(&pBindContext->Event);
+ INITIALIZE_EVENT(&pBindContext->ThreadDoneEvent);
+
+ if (Sync)
+ {
+ //
+ // Initiate binding now
+ //
+ ndisQueuedProtocolNotification(pBindContext);
+ }
+ else
+ {
+ //
+ // Initiate binding in a worker thread
+ //
+ INITIALIZE_WORK_ITEM(&pBindContext->WorkItem,
+ ndisQueuedProtocolNotification,
+ pBindContext);
+ QUEUE_WORK_ITEM(&pBindContext->WorkItem, DelayedWorkQueue);
+ }
+ }
+ else
+ {
+ ndisDereferenceProtocol(Protocol);
+ }
+
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+ }
+ }
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ //
+ // Done with the upcased name
+ //
+ RtlFreeUnicodeString(&UpcasedName);
+
+ //
+ // Wait for the worker threads to finish
+ //
+ for (pBindContext = pBindContextHead;
+ pBindContext != NULL;
+ NOTHING)
+ {
+ PNDIS_BIND_CONTEXT pNext;
+
+ pNext = pBindContext->Next;
+
+ WAIT_FOR_OBJECT(&pBindContext->ThreadDoneEvent, NULL);
+ FREE_POOL(pBindContext);
+
+ pBindContext = pNext;
+ }
+}
+
+
+VOID
+ndisQueuedProtocolNotification(
+ IN PNDIS_BIND_CONTEXT pContext
+ )
+{
+ NDIS_STATUS BindStatus;
+
+ //
+ // Call the protocol to bind to the adapter
+ //
+ WAIT_FOR_OBJECT(&pContext->Protocol->Mutex, NULL);
+
+ if (!pContext->Protocol->Ref.Closing)
+ {
+ (*pContext->Protocol->ProtocolCharacteristics.BindAdapterHandler)(&BindStatus,
+ pContext,
+ pContext->DeviceName,
+ &pContext->ProtocolSection,
+ NULL);
+ if (BindStatus == NDIS_STATUS_PENDING)
+ {
+ WAIT_FOR_OBJECT(&pContext->Event, NULL);
+ }
+ }
+
+ RELEASE_MUTEX(&pContext->Protocol->Mutex);
+
+ ndisDereferenceProtocol(pContext->Protocol);
+
+ FREE_POOL(pContext->ProtocolSection.Buffer);
+
+ SET_EVENT(&pContext->ThreadDoneEvent);
+}
+
+VOID
+NdisCompleteBindAdapter(
+ IN NDIS_HANDLE BindAdapterContext,
+ IN NDIS_STATUS Status,
+ IN NDIS_STATUS OpenStatus
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_BIND_CONTEXT pContext = (PNDIS_BIND_CONTEXT)BindAdapterContext;
+
+ pContext->BindStatus = Status;
+ SET_EVENT(&pContext->Event);
+}
+
+VOID
+NdisCompleteUnbindAdapter(
+ IN NDIS_HANDLE UnbindAdapterContext,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_BIND_CONTEXT pContext = (PNDIS_BIND_CONTEXT)UnbindAdapterContext;
+
+ pContext->BindStatus = Status;
+ SET_EVENT(&pContext->Event);
+}
+
+VOID
+NdisRegisterTdiCallBack(
+ IN TDI_REGISTER_CALLBACK RegisterCallback
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ if (ndisTdiRegisterCallback == NULL)
+ {
+ ndisTdiRegisterCallback = RegisterCallback;
+ }
+}
diff --git a/private/ntos/ndis/ndis40/ndis.rc b/private/ntos/ndis/ndis40/ndis.rc
new file mode 100644
index 000000000..3d5b057d2
--- /dev/null
+++ b/private/ntos/ndis/ndis40/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/ndis40/ndis.src b/private/ntos/ndis/ndis40/ndis.src
new file mode 100644
index 000000000..0969e3cbb
--- /dev/null
+++ b/private/ntos/ndis/ndis40/ndis.src
@@ -0,0 +1,328 @@
+NAME NDIS.SYS
+
+DESCRIPTION 'NDIS.SYS'
+
+EXPORTS
+ ArcFilterDprIndicateReceive
+ ArcFilterDprIndicateReceiveComplete
+
+ EthChangeFilterAddresses
+ EthCreateFilter
+ EthDeleteFilter
+ EthDeleteFilterOpenAdapter
+ EthFilterAdjust
+ EthFilterDprIndicateReceive
+ EthFilterDprIndicateReceivePacket
+ EthFilterDprIndicateReceiveComplete
+ EthFilterIndicateReceive
+ EthFilterIndicateReceiveComplete
+ EthNoteFilterOpenAdapter
+ EthNumberOfOpenFilterAddresses
+ EthQueryGlobalFilterAddresses
+ EthQueryOpenFilterAddresses
+ EthShouldAddressLoopBack
+
+ FddiChangeFilterLongAddresses
+ FddiChangeFilterShortAddresses
+ FddiCreateFilter
+ FddiDeleteFilter
+ FddiDeleteFilterOpenAdapter
+ FddiFilterAdjust
+ FddiFilterDprIndicateReceive
+ FddiFilterDprIndicateReceivePacket
+ FddiFilterDprIndicateReceiveComplete
+ FddiFilterIndicateReceive
+ FddiFilterIndicateReceiveComplete
+ FddiNoteFilterOpenAdapter
+ FddiNumberOfOpenFilterLongAddresses
+ FddiNumberOfOpenFilterShortAddresses
+ FddiQueryGlobalFilterLongAddresses
+ FddiQueryGlobalFilterShortAddresses
+ FddiQueryOpenFilterLongAddresses
+ FddiQueryOpenFilterShortAddresses
+ FddiShouldAddressLoopBack
+
+ TrChangeFunctionalAddress
+ TrChangeGroupAddress
+ TrCreateFilter
+ TrDeleteFilter
+ TrDeleteFilterOpenAdapter
+ TrFilterAdjust
+ TrFilterDprIndicateReceive
+ TrFilterDprIndicateReceivePacket
+ TrFilterDprIndicateReceiveComplete
+ TrFilterIndicateReceive
+ TrFilterIndicateReceiveComplete
+ TrNoteFilterOpenAdapter
+ TrShouldAddressLoopBack
+
+ NdisAllocateBuffer
+ NdisAllocateBufferPool
+ NdisAdjustBufferLength
+ NdisAllocateDmaChannel
+ NdisAllocateMemory
+ NdisAllocateMemoryWithTag
+ NdisAllocatePacket
+ NdisDprAllocatePacket
+ NdisDprAllocatePacketNonInterlocked
+ NdisFreePacket
+ NdisDprFreePacket
+ NdisDprFreePacketNonInterlocked
+ NdisAllocatePacketPool
+ NdisQueryReceiveInformation
+ NdisAllocateSharedMemory
+ NdisCloseConfiguration
+ NdisCloseFile
+ NdisCloseRef
+ NdisCompleteCloseAdapter
+ NdisCompleteDmaTransfer
+ NdisCompleteOpenAdapter
+ NdisCompleteQueryStatistics
+ NdisCopyBuffer
+ NdisCopyFromPacketToPacket
+ NdisDereferenceRef
+#if ALPHA
+ NdisCreateLookaheadBufferFromSharedMemory
+ NdisDestroyLookaheadBufferFromSharedMemory
+#endif
+ NdisDeregisterAdapter
+ NdisDeregisterAdapterShutdownHandler
+ NdisDeregisterMac
+ NdisDeregisterProtocol
+ NdisGetDriverHandle
+ NdisRegisterTdiCallBack
+
+ NdisFinishOpen
+ NdisFreeBufferPool
+ NdisFreePacketPool
+ NdisFreeDmaChannel
+ NdisFreeMemory
+ NdisFreeSharedMemory
+ NdisImmediateReadPciSlotInformation
+ NdisImmediateReadPortUchar
+ NdisImmediateReadPortUshort
+ NdisImmediateReadPortUlong
+ NdisImmediateReadSharedMemory
+ NdisImmediateWritePciSlotInformation
+ NdisImmediateWritePortUchar
+ NdisImmediateWritePortUshort
+ NdisImmediateWritePortUlong
+ NdisImmediateWriteSharedMemory
+ NdisInitializeInterrupt
+ NdisInitializePacketPool
+ NdisInitializeRef
+ NdisInitializeTimer
+ NdisInitializeWrapper
+ NdisMapFile
+ NdisMapIoSpace
+ NdisOpenConfiguration
+ NdisOpenGlobalConfiguration
+ NdisOpenConfigurationKeyByName
+ NdisOpenConfigurationKeyByIndex
+ NdisOpenFile
+ NdisPciAssignResources
+ NdisReadConfiguration
+ NdisReadBindingInformation
+ NdisReadEisaSlotInformation
+ NdisReadEisaSlotInformationEx
+ NdisReadMcaPosInformation
+ NdisReadNetworkAddress
+ NdisConvertStringToAtmAddress
+ NdisReadPciSlotInformation
+ NdisReferenceRef
+ NdisRegisterAdapter
+ NdisRegisterAdapterShutdownHandler
+ NdisRegisterMac
+ NdisRegisterProtocol
+ NdisReleaseAdapterResources
+ NdisRemoveInterrupt
+ NdisCancelTimer
+ NdisSetTimer
+ NdisSetupDmaTransfer
+ NdisTerminateWrapper
+ NdisUnchainBufferAtFront
+ NdisUnchainBufferAtBack
+ NdisUnmapFile
+ NdisUpdateSharedMemory
+ NdisWriteErrorLogEntry
+ NdisWritePciSlotInformation
+
+ NdisOpenAdapter
+ NdisCloseAdapter
+ NdisCompleteBindAdapter
+ NdisCompleteUnbindAdapter
+ NdisOpenProtocolConfiguration
+ NdisSend
+ NdisSendPackets
+ NdisReturnPackets
+ NdisTransferData
+ NdisRequest
+ NdisReset
+ NdisWriteEventLogEntry
+
+ NdisMAllocateMapRegisters
+ NdisMCancelTimer
+ NdisMSetPeriodicTimer
+ NdisMDeregisterIoPortRange
+ NdisMFreeMapRegisters
+ NdisMIndicateStatus
+ NdisMIndicateStatusComplete
+ NdisMInitializeTimer
+ NdisMSleep
+ NdisMQueryInformationComplete
+ NdisMRegisterIoPortRange
+ NdisMRegisterMiniport
+ NdisIMRegisterLayeredMiniport
+ NdisIMInitializeDeviceInstance
+ NdisIMDeInitializeDeviceInstance
+ NdisMResetComplete
+ NdisMSendComplete
+ NdisMSendResourcesAvailable
+ NdisMSetAttributes
+ NdisMSetAttributesEx
+ NdisMSetInformationComplete
+ NdisMTransferDataComplete
+ NdisMMapIoSpace
+ NdisMUnmapIoSpace
+ NdisMRegisterInterrupt
+ NdisMDeregisterInterrupt
+ NdisMSynchronizeWithInterrupt
+ NdisMAllocateSharedMemory
+ NdisMAllocateSharedMemoryAsync
+ NdisMFreeSharedMemory
+ NdisMRegisterDmaChannel
+ NdisMDeregisterDmaChannel
+ NdisMReadDmaCounter
+ NdisMStartBufferPhysicalMapping
+ NdisMCompleteBufferPhysicalMapping
+ NdisMRegisterAdapterShutdownHandler
+ NdisMDeregisterAdapterShutdownHandler
+ NdisMPciAssignResources
+ NdisMQueryAdapterResources
+ NdisMCreateLog
+ NdisMCloseLog
+ NdisMFlushLog
+ NdisMWriteLogData
+
+ NdisMWanSendComplete
+ NdisMWanIndicateReceive
+ NdisMWanIndicateReceiveComplete
+
+ NdisAllocateSpinLock
+ NdisFreeSpinLock
+ NdisAcquireSpinLock
+ NdisReleaseSpinLock
+ NdisDprAcquireSpinLock
+ NdisDprReleaseSpinLock
+ NdisFreeBuffer
+ NdisQueryBuffer
+ NdisQueryBufferOffset
+ NdisGetFirstBufferFromPacket
+ NDIS_BUFFER_TO_SPAN_PAGES
+ NdisGetBufferPhysicalArraySize
+ NdisEqualString
+
+ NdisInterlockedIncrement
+ NdisInterlockedDecrement
+ NdisInterlockedAddUlong
+ NdisInterlockedInsertHeadList
+ NdisInterlockedInsertTailList
+ NdisInterlockedRemoveHeadList
+ NdisInterlockedPushEntryList
+ NdisInterlockedPopEntryList
+
+ NdisSystemProcessorCount
+ NdisWriteConfiguration
+
+ NdisOverrideBusNumber
+ NdisGetCurrentProcessorCpuUsage
+ NdisGetCurrentProcessorCounts
+ NdisGetCurrentSystemTime
+ NdisQueryMapRegisterCount
+ NdisGetSystemUpTime
+
+ NdisInitializeString
+ NdisInitAnsiString
+ NdisInitUnicodeString
+ NdisAnsiStringToUnicodeString
+ NdisUnicodeStringToAnsiString
+
+ NdisInitializeEvent
+ NdisSetEvent
+ NdisResetEvent
+ NdisWaitEvent
+
+ NdisSetProtocolFilter
+ NdisIMQueueMiniportCallback
+ NdisIMSwitchToMiniport
+ NdisIMRevertBack
+
+ //
+ // CoNdis entry points for clients as well as call-managers
+ //
+ NdisCoSendPackets
+ NdisCoRequest
+ NdisCoRequestComplete
+ NdisCoCreateVc
+ NdisCoDeleteVc
+
+ //
+ // CoNdis entry points for clients
+ //
+ NdisClOpenAddressFamily
+ NdisClCloseAddressFamily
+ NdisClRegisterSap
+ NdisClDeregisterSap
+ NdisClMakeCall
+ NdisClCloseCall
+ NdisClAddParty
+ NdisClDropParty
+ NdisClIncomingCallComplete
+ NdisClModifyCallQoS
+
+ //
+ // CoNdis entry points for call managers
+ //
+ NdisCmRegisterAddressFamily
+ NdisCmOpenAddressFamilyComplete
+ NdisCmCloseAddressFamilyComplete
+ NdisCmRegisterSapComplete
+ NdisCmDeregisterSapComplete
+ NdisCmMakeCallComplete
+ NdisCmCloseCallComplete
+ NdisCmAddPartyComplete
+ NdisCmDropPartyComplete
+ NdisCmDispatchIncomingCall
+ NdisCmDispatchCallConnected
+ NdisCmDispatchIncomingDropParty
+ NdisCmDispatchIncomingCloseCall
+ NdisCmDispatchIncomingDropParty
+ NdisCmActivateVc
+ NdisCmDeactivateVc
+ NdisCmModifyCallQoSComplete
+ NdisCmDispatchIncomingCallQoSChange
+
+ //
+ // CoNdis entry points for miniports
+ //
+ NdisMCoActivateVcComplete
+ NdisMCoDeactivateVcComplete
+ NdisMCoIndicateReceivePacket
+ NdisMCoReceiveComplete
+ NdisMCoIndicateStatus
+ NdisMCoSendComplete
+ NdisMCoRequestComplete
+
+ //
+ // CoNdis entry points for miniport-resident call-managers
+ //
+ NdisMCmRegisterAddressFamily
+ NdisMCmCreateVc
+ NdisMCmActivateVc
+ NdisMCmDeactivateVc
+
+#if _DBG && defined(_M_IX86) && defined(_NDIS_INTERNAL_DEBUG)
+ NdisMSetWriteBreakPoint
+ NdisMClearWriteBreakPoint
+#endif
+ \ No newline at end of file
diff --git a/private/ntos/ndis/ndis40/ndis_co.c b/private/ntos/ndis/ndis40/ndis_co.c
new file mode 100644
index 000000000..d3555de22
--- /dev/null
+++ b/private/ntos/ndis/ndis40/ndis_co.c
@@ -0,0 +1,3873 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ ndis_co.c
+
+Abstract:
+
+ CO-NDIS miniport wrapper functions
+
+Author:
+
+ Jameel Hyder (JameelH) 01-Feb-96
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+--*/
+
+#include <precomp.h>
+#include <atm.h>
+#pragma hdrstop
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_NDIS_CO
+
+/*
+ Connection-oriented section of NDIS exposes the following objects and apis to
+ manipulate these objects.
+
+ AF Address Family
+ SAP Service Access Point
+ VC Virtual Circuit
+ Party A node in a point-multipoint VC
+
+ There is a notion of a call-manager and a client on a per-binding basis. The
+ call manager acts as a helper dll for NDIS wrapper to manage the aforementioned
+ objects.
+
+ The concept of AF makes possible the existence of multiple call-managers. An
+ example of this is the UNI call-manager and a SPANS call-manager for the ATM
+ media.
+
+ SAPs provides a way for incoming calls to be routed to the right entity. A
+ protocol can register for more than one SAPs. Its upto the call-manager to
+ allow/dis-allow multiple protocol modules to register the same SAP.
+
+ VCs are created either by a protocol module requesting to make an outbound call
+ or by the call-manager dispatching an incoming call. VCs can either be point-point
+ or point-multi-point. Leaf nodes can be added to VCs at any time provided the first
+ leaf was created appropriately.
+
+ References:
+
+ An AF association results in the reference of file-object for the call-manager.
+
+ A SAP registration results in the reference of the AF.
+
+ A send or receive does not reference a VC. This is because miniports are required to
+ pend DeactivateVc calls till all I/O completes. So when it calls NdisMCoDeactivateVcComplete
+ no other packets will be indicated up and there are no sends outstanding.
+ */
+
+NDIS_STATUS
+NdisCmRegisterAddressFamily(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PCO_ADDRESS_FAMILY AddressFamily,
+ IN PNDIS_CALL_MANAGER_CHARACTERISTICS CmCharacteristics,
+ IN UINT SizeOfCmCharacteristics
+ )
+/*++
+
+Routine Description:
+ This is a call from the call-manager to register the address family
+ supported by this call-manager.
+
+Arguments:
+ NdisBindingHandle - Pointer to the call-managers NDIS_OPEN_BLOCK.
+ AddressFamily - The address family being registered.
+ CmCharacteristics - Call-Manager characteristics
+ SizeOfCmCharacteristics - Size of Call-Manager characteristics
+
+Return Value:
+ NDIS_STATUS_SUCCESS if the address family registration is successfully.
+ NDIS_STATUS_FAILURE if the caller is not a call-manager or this address
+ family is already registered for this miniport.
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ KIRQL OldIrql;
+ PNDIS_AF_LIST AfList;
+ PNDIS_PROTOCOL_BLOCK Protocol;
+ PNDIS_M_OPEN_BLOCK CallMgrOpen;
+ PNDIS_MINIPORT_BLOCK Miniport;
+
+ CallMgrOpen = (PNDIS_M_OPEN_BLOCK)(((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacBindingHandle);
+ Miniport = CallMgrOpen->MiniportHandle;
+ Protocol = CallMgrOpen->ProtocolHandle;
+
+ CoReferencePackage();
+
+ //
+ // Make sure that the miniport is a CoNdis miniport and
+ // there is no other module registering the same address family.
+ //
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ do
+ {
+ //
+ // Make sure the binding is not closing down
+ //
+ if (CallMgrOpen->Flags & fMINIPORT_OPEN_CLOSING)
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // Make sure that the miniport is a CoNdis miniport and
+ // protocol is also a NDIS 4.1 or later protocol.
+ //
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
+ {
+ //
+ // Not a NDIS 4.1 or later miniport
+ //
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ if ((Protocol->ProtocolCharacteristics.MajorNdisVersion < 4) ||
+ ((Protocol->ProtocolCharacteristics.MajorNdisVersion == 4) &&
+ (Protocol->ProtocolCharacteristics.MinorNdisVersion < 1)))
+ {
+ //
+ // Not a NDIS 4.1 or later protocol
+ //
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // Make sure that the call-manager characteristics are 4.1 or later
+ //
+ if ((CmCharacteristics->MajorVersion != 4) ||
+ (CmCharacteristics->MinorVersion != 1) ||
+ (SizeOfCmCharacteristics < sizeof(NDIS_CALL_MANAGER_CHARACTERISTICS)))
+ {
+ //
+ // Not a NDIS 4.1 or later protocol
+ //
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // Search registered call-managers for this miniport and make sure there is no
+ // clash. A call-manager can only register one address family per-open. This
+ // is due to the way we cache handlers. Can be over-come if the handlers are
+ // identical for each address-family - but decided not to since it is un-interesting.
+ //
+ for (AfList = Miniport->CallMgrAfList;
+ AfList != NULL;
+ AfList = AfList->NextOpen)
+ {
+ if ((AfList->AddressFamily == AddressFamily->AddressFamily) ||
+ (AfList->Open == CallMgrOpen))
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+ }
+
+ if (AfList == NULL)
+ {
+ //
+ // No other entity has claimed this address family.
+ //
+ AfList = (PNDIS_AF_LIST)ALLOC_FROM_POOL(sizeof(NDIS_AF_LIST), NDIS_TAG_CO);
+ if (AfList == NULL)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+ AfList->AddressFamily = AddressFamily->AddressFamily;
+ CopyMemory(&AfList->CmChars,
+ CmCharacteristics,
+ sizeof(NDIS_CALL_MANAGER_CHARACTERISTICS));
+
+ //
+ // link it in the miniport list
+ //
+ AfList->Open = CallMgrOpen;
+ AfList->NextOpen = Miniport->CallMgrAfList;
+ Miniport->CallMgrAfList = AfList;
+ //
+ // Now link it in the global list
+ //
+ ACQUIRE_SPIN_LOCK_DPC(&ndisGlobalOpenListLock);
+ AfList->NextGlobal = ndisAfList;
+ ndisAfList = AfList;
+ RELEASE_SPIN_LOCK_DPC(&ndisGlobalOpenListLock);
+
+ //
+ // Finally cache some handlers in the open-block
+ //
+ CallMgrOpen->CoCreateVcHandler = CmCharacteristics->CmCreateVcHandler;
+ CallMgrOpen->CoDeleteVcHandler = CmCharacteristics->CmDeleteVcHandler;
+ CallMgrOpen->CmActivateVcCompleteHandler = CmCharacteristics->CmActivateVcCompleteHandler;
+ CallMgrOpen->CmDeactivateVcCompleteHandler = CmCharacteristics->CmDeactivateVcCompleteHandler;
+
+ //
+ // Notify existing clients of this registration
+ //
+ ndisMNotifyAfRegistration(Miniport, AddressFamily);
+ }
+ } while (FALSE);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ if (!NT_SUCCESS(Status))
+ {
+ CoDereferencePackage();
+ }
+
+ return(Status);
+}
+
+
+NDIS_STATUS
+NdisMCmRegisterAddressFamily(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PCO_ADDRESS_FAMILY AddressFamily,
+ IN PNDIS_CALL_MANAGER_CHARACTERISTICS CmCharacteristics,
+ IN UINT SizeOfCmCharacteristics
+ )
+/*++
+
+Routine Description:
+ This is a call from the miniport supported call-manager to register the address family
+ supported by this call-manager.
+
+Arguments:
+ MiniportAdapterHandle - Pointer to the miniports NDIS_MINIPORT_BLOCK.
+ AddressFamily - The address family being registered.
+ CmCharacteristics - Call-Manager characteristics
+ SizeOfCmCharacteristics - Size of Call-Manager characteristics
+
+Return Value:
+ NDIS_STATUS_SUCCESS if the address family registration is successfully.
+ NDIS_STATUS_FAILURE if the caller is not a call-manager or this address
+ family is already registered for this miniport.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport;
+ NDIS_STATUS Status;
+ PNDIS_AF_LIST AfList;
+ KIRQL OldIrql;
+
+ CoReferencePackage();
+
+ Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+
+ //
+ // Make sure that the miniport is a CoNdis miniport and
+ // there is no other module registering the same address family.
+ //
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ do
+ {
+ //
+ // Make sure that the miniport is a CoNdis miniport
+ //
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
+ {
+ //
+ // Not a NDIS 4.1 or later miniport
+ //
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // Make sure that the call-manager characteristics are 4.1 or later
+ //
+ if ((CmCharacteristics->MajorVersion != 4) ||
+ (CmCharacteristics->MinorVersion != 1) ||
+ (SizeOfCmCharacteristics < sizeof(NDIS_CALL_MANAGER_CHARACTERISTICS)))
+ {
+ //
+ // Not a NDIS 4.1 or later protocol
+ //
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // Search registered call-managers for this miniport and make sure there is no
+ // clash. A call-manager can only register one address family per-open. This
+ // is due to the way we cache handlers. Can be over-come if the handlers are
+ // identical for each address-family - but decided not to since it is un-interesting.
+ //
+ for (AfList = Miniport->CallMgrAfList;
+ AfList != NULL;
+ AfList = AfList->NextOpen)
+ {
+ if ((AfList->AddressFamily == AddressFamily->AddressFamily) ||
+ (AfList->Open == NULL))
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+ }
+
+ if (AfList == NULL)
+ {
+ //
+ // No other entity has claimed this address family.
+ //
+ AfList = (PNDIS_AF_LIST)ALLOC_FROM_POOL(sizeof(NDIS_AF_LIST), NDIS_TAG_CO);
+ if (AfList == NULL)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+ AfList->AddressFamily = AddressFamily->AddressFamily;
+ CopyMemory(&AfList->CmChars,
+ CmCharacteristics,
+ sizeof(NDIS_CALL_MANAGER_CHARACTERISTICS));
+
+ //
+ // link it in the miniport list
+ //
+ AfList->Open = NULL;
+ AfList->NextOpen = Miniport->CallMgrAfList;
+ Miniport->CallMgrAfList = AfList;
+ //
+ // Now link it in the global list
+ //
+ ACQUIRE_SPIN_LOCK_DPC(&ndisGlobalOpenListLock);
+ AfList->NextGlobal = ndisAfList;
+ ndisAfList = AfList;
+ RELEASE_SPIN_LOCK_DPC(&ndisGlobalOpenListLock);
+ }
+ } while (FALSE);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ if (!NT_SUCCESS(Status))
+ {
+ CoDereferencePackage();
+ }
+
+ return Status;
+}
+
+VOID
+ndisMNotifyAfRegistration(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PCO_ADDRESS_FAMILY AddressFamily OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+ If a protocol has a handler for it, notify it that a new address family has
+ been registered.
+
+Arguments:
+ NdisBindingHandle - Pointer to the protocol's NDIS_OPEN_BLOCK.
+ AddressFamily - Address family in question. If not specified all address
+ families for the miniport are reported
+
+Return Value:
+ None.
+
+--*/
+{
+}
+
+NDIS_STATUS
+NdisClOpenAddressFamily(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PCO_ADDRESS_FAMILY AddressFamily,
+ IN NDIS_HANDLE ClientAfContext,
+ IN PNDIS_CLIENT_CHARACTERISTICS ClCharacteristics,
+ IN UINT SizeOfClCharacteristics,
+ OUT PNDIS_HANDLE NdisAfHandle
+ )
+/*++
+
+Routine Description:
+ This is a call from a NDIS 4.1 or later protocol to open a particular
+ address familty - in essence getting a handle to the call-manager.
+
+Arguments:
+ NdisBindingHandle - Pointer to the protocol's NDIS_OPEN_BLOCK.
+ PCO_ADDRESS_FAMILY - The address family being registered.
+ ClientAfContext - Protocol context associated with this handle.
+ NdisAfHandle - Handle returned by NDIS for this address family.
+
+Return Value:
+ NDIS_STATUS_SUCCESS if the address family open is successfully.
+ NDIS_STATUS_PENDING if the call-manager pends this call. The caller will get
+ called at the completion handler when done.
+ NDIS_STATUS_FAILURE if the caller is not a NDIS 4.1 prototcol or this address
+ family is not registered for this miniport.
+
+--*/
+{
+ PNDIS_CO_AF_BLOCK pAf;
+ PNDIS_AF_LIST AfList;
+ PNDIS_M_OPEN_BLOCK CallMgrOpen, ClientOpen;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PNDIS_PROTOCOL_BLOCK Protocol;
+ KIRQL OldIrql;
+ NTSTATUS Status;
+
+ *NdisAfHandle = NULL;
+ ClientOpen = (PNDIS_M_OPEN_BLOCK)((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacBindingHandle;
+ Miniport = ClientOpen->MiniportHandle;
+ Protocol = ClientOpen->ProtocolHandle;
+
+ CoReferencePackage();
+
+ do
+ {
+ //
+ // Make sure the binding is not closing down
+ //
+ if (ClientOpen->Flags & fMINIPORT_OPEN_CLOSING)
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // Make sure that the miniport is a CoNdis miniport and
+ // protocol is also a NDIS 4.1 or later protocol.
+ //
+ if ((Miniport->DriverHandle->MiniportCharacteristics.MajorNdisVersion < 4) ||
+ ((Miniport->DriverHandle->MiniportCharacteristics.MajorNdisVersion == 4) &&
+ (Miniport->DriverHandle->MiniportCharacteristics.MinorNdisVersion < 1)) ||
+ (Miniport->DriverHandle->MiniportCharacteristics.CoCreateVcHandler == NULL))
+ {
+ //
+ // Not a NDIS 4.1 or later miniport
+ //
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ if ((Protocol->ProtocolCharacteristics.MajorNdisVersion < 4) ||
+ ((Protocol->ProtocolCharacteristics.MajorNdisVersion == 4) &&
+ (Protocol->ProtocolCharacteristics.MinorNdisVersion < 1)))
+ {
+ //
+ // Not a NDIS 4.1 or later protocol
+ //
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // Make sure that the client characteristics are 4.1 or later
+ //
+ if ((ClCharacteristics->MajorVersion != 4) ||
+ (ClCharacteristics->MinorVersion != 1) ||
+ (SizeOfClCharacteristics < sizeof(NDIS_CLIENT_CHARACTERISTICS)))
+ {
+ //
+ // Not a NDIS 4.1 or later protocol
+ //
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ //
+ // Search the miniport block for a registered call-manager for this address family
+ //
+ for (AfList = Miniport->CallMgrAfList;
+ AfList != NULL;
+ AfList = AfList->NextOpen)
+ {
+ if (AfList->AddressFamily == AddressFamily->AddressFamily)
+ {
+ CallMgrOpen = AfList->Open;
+ break;
+ }
+ }
+
+ //
+ // If we found a matching call manager, make sure that the callmgr
+ // is not currently closing.
+ //
+ if ((AfList == NULL) ||
+ ((AfList != NULL) && (AfList->Open->Flags & fMINIPORT_OPEN_CLOSING)) ||
+ (Miniport->Flags & (fMINIPORT_CLOSING | fMINIPORT_HALTING)))
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ //
+ // NOTE: We can possibly wait a little while here and retry
+ // before actually failing this call if (AfList == NULL).
+ //
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // Allocate memory for the AF block.
+ //
+ pAf = ALLOC_FROM_POOL(sizeof(NDIS_CO_AF_BLOCK), NDIS_TAG_CO);
+ if (pAf == NULL)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ pAf->References = 1;
+ pAf->Flags = 0;
+ pAf->Miniport = Miniport;
+
+ pAf->ClientOpen = ClientOpen;
+ pAf->CallMgrOpen = CallMgrOpen = AfList->Open;
+ pAf->ClientContext = ClientAfContext;
+
+ //
+ // Reference the call-manager's file object - we do not want to let it
+ // duck from under the client.
+ //
+ //
+ // Reference the client and the call-manager opens
+ //
+ ClientOpen->References++;
+ if (CallMgrOpen != NULL)
+ {
+ ObReferenceObject(CallMgrOpen->FileObject);
+ CallMgrOpen->References++;
+ }
+ else
+ {
+ ObReferenceObject(Miniport->DeviceObject);
+ Miniport->Ref.ReferenceCount ++;
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ INITIALIZE_SPIN_LOCK(&pAf->Lock);
+
+ //
+ // Cache in call-manager entry points
+ //
+ pAf->CallMgrEntries = &AfList->CmChars;
+
+ //
+ // And also Cache in client entry points
+ //
+ CopyMemory(&pAf->ClientEntries,
+ ClCharacteristics,
+ sizeof(NDIS_CLIENT_CHARACTERISTICS));
+
+
+ //
+ // Cache some handlers in the open-block
+ //
+ ClientOpen->CoCreateVcHandler = ClCharacteristics->ClCreateVcHandler;
+ ClientOpen->CoDeleteVcHandler = ClCharacteristics->ClDeleteVcHandler;
+
+ //
+ // Now call the CallMgr's OpenAfHandler
+ //
+ Status = (*AfList->CmChars.CmOpenAfHandler)((CallMgrOpen != NULL) ?
+ CallMgrOpen->ProtocolBindingContext :
+ Miniport->MiniportAdapterContext,
+ AddressFamily,
+ pAf,
+ &pAf->CallMgrContext);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisCmOpenAddressFamilyComplete(Status,
+ pAf,
+ pAf->CallMgrContext);
+ Status = NDIS_STATUS_PENDING;
+ }
+
+ } while (FALSE);
+
+ if (!NT_SUCCESS(Status))
+ {
+ CoDereferencePackage();
+ }
+
+ return Status;
+}
+
+
+VOID
+NdisCmOpenAddressFamilyComplete(
+ IN NDIS_STATUS Status,
+ IN NDIS_HANDLE NdisAfHandle,
+ IN NDIS_HANDLE CallMgrAfContext
+ )
+/*++
+
+Routine Description:
+
+ Completion routine for the OpenAddressFamily call. The call manager had pended this
+ call earlier (or will pend). If the call succeeded there is a valid CallMgrContext
+ supplied here as well
+
+Arguments:
+ Status - Completion status
+ NdisAfHandle - Pointer to the AfBlock
+ CallMgrAfContext - Call manager's context used in other calls into the call manager.
+
+Return Value:
+ NONE. The client's completion handler is called.
+
+--*/
+{
+ PNDIS_CO_AF_BLOCK pAf;
+ PNDIS_M_OPEN_BLOCK ClientOpen;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ KIRQL OldIrql;
+
+ ASSERT (Status != NDIS_STATUS_PENDING);
+
+ pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
+ ClientOpen = pAf->ClientOpen;
+ Miniport = pAf->Miniport;
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ if (pAf->CallMgrOpen != NULL)
+ {
+ ObDereferenceObject(pAf->CallMgrOpen->FileObject);
+ }
+ else
+ {
+ ObDereferenceObject(Miniport->DeviceObject);
+ }
+ }
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ pAf->CallMgrContext = CallMgrAfContext;
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // OpenAfHandler failed
+ //
+ if (pAf->CallMgrOpen != NULL)
+ {
+ pAf->CallMgrOpen->References--;
+ if (pAf->CallMgrOpen->References == 0)
+ {
+ ndisMFinishClose(Miniport, pAf->CallMgrOpen);
+ }
+ }
+ else
+ {
+ ndisDereferenceMiniport(Miniport);
+ }
+
+ ClientOpen->References--;
+ if (ClientOpen->References == 0)
+ {
+ ndisMFinishClose(Miniport, ClientOpen);
+ }
+ FREE_POOL(pAf);
+
+ CoDereferencePackage();
+ }
+ else
+ {
+ //
+ // queue this CallMgr open onto the miniport open
+ //
+ pAf->NextAf = ClientOpen->NextAf;
+ ClientOpen->NextAf = pAf;
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ //
+ // Finally call the client's completion handler
+ //
+ (*pAf->ClientEntries.ClOpenAfCompleteHandler)(Status,
+ pAf->ClientContext,
+ (Status == NDIS_STATUS_SUCCESS) ? pAf : NULL);
+}
+
+
+NDIS_STATUS
+NdisClCloseAddressFamily(
+ IN NDIS_HANDLE NdisAfHandle
+ )
+/*++
+
+Routine Description:
+
+ This call closes the Af object which essentially tears down the client-callmanager
+ 'binding'. Causes all open Vcs to be closed and saps to be de-registered "by the call
+ manager".
+
+Arguments:
+
+ NdisAfHandle - Pointer to the Af.
+
+Return Value:
+
+ Status from Call Manager.
+
+--*/
+{
+ PNDIS_CO_AF_BLOCK pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ KIRQL OldIrql;
+
+ //
+ // Mark the address family as closing and call the call-manager to process.
+ //
+ ACQUIRE_SPIN_LOCK(&pAf->Lock, &OldIrql);
+ if (pAf->Flags & AF_CLOSING)
+ {
+ Status = NDIS_STATUS_FAILURE;
+ }
+ pAf->Flags |= AF_CLOSING;
+ RELEASE_SPIN_LOCK(&pAf->Lock, OldIrql);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ Status = (*pAf->CallMgrEntries->CmCloseAfHandler)(pAf->CallMgrContext);
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisCmCloseAddressFamilyComplete(Status, pAf);
+ Status = NDIS_STATUS_PENDING;
+ }
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ CoDereferencePackage();
+ }
+
+ return Status;
+}
+
+
+VOID
+NdisCmCloseAddressFamilyComplete(
+ IN NDIS_STATUS Status,
+ IN NDIS_HANDLE NdisAfHandle
+ )
+/*++
+
+Routine Description:
+
+ Completion routine for the CloseAddressFamily call. The call manager had pended this
+ call earlier (or will pend). If the call succeeded there is a valid CallMgrContext
+ supplied here as well
+
+Arguments:
+ Status - Completion status
+ NdisAfHandle - Pointer to the AfBlock
+
+Return Value:
+ NONE. The client's completion handler is called.
+
+--*/
+{
+ PNDIS_CO_AF_BLOCK pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ KIRQL OldIrql;
+
+ Miniport = pAf->Miniport;
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Dereference the file object for the call-manager
+ //
+ if (pAf->CallMgrOpen != NULL)
+ {
+ ObDereferenceObject(pAf->CallMgrOpen->FileObject);
+ }
+ else
+ {
+ ObDereferenceObject(Miniport->DeviceObject);
+ }
+
+ Miniport = pAf->Miniport;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ if (pAf->CallMgrOpen != NULL)
+ {
+ pAf->CallMgrOpen->References--;
+ if (pAf->CallMgrOpen->References == 0)
+ {
+ ndisMFinishClose(Miniport, pAf->CallMgrOpen);
+ }
+ }
+ else
+ {
+ ndisDereferenceMiniport(Miniport);
+ }
+
+ pAf->ClientOpen->References--;
+ if (pAf->ClientOpen->References == 0)
+ {
+ ndisMFinishClose(Miniport, pAf->ClientOpen);
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ CoDereferencePackage();
+ }
+
+ //
+ // Complete the call to the client
+ //
+ (*pAf->ClientEntries.ClCloseAfCompleteHandler)(Status,
+ pAf->ClientContext);
+
+ //
+ // Finally dereference the AF Block, if the call-manager successfully closed it.
+ //
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ ndisDereferenceAf(pAf);
+ }
+}
+
+
+BOOLEAN
+ndisReferenceAf(
+ IN PNDIS_CO_AF_BLOCK pAf
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ KIRQL OldIrql;
+ BOOLEAN rc = FALSE;
+
+ ACQUIRE_SPIN_LOCK(&pAf->Lock, &OldIrql);
+
+ if ((pAf->Flags & AF_CLOSING) == 0)
+ {
+ pAf->References ++;
+ rc = TRUE;
+ }
+
+ RELEASE_SPIN_LOCK(&pAf->Lock, OldIrql);
+
+ return rc;
+}
+
+
+VOID
+ndisDereferenceAf(
+ IN PNDIS_CO_AF_BLOCK pAf
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ KIRQL OldIrql;
+ BOOLEAN Done = FALSE;
+
+ ACQUIRE_SPIN_LOCK(&pAf->Lock, &OldIrql);
+
+ ASSERT (pAf->References > 0);
+ pAf->References --;
+ if (pAf->References == 0)
+ {
+ ASSERT (pAf->Flags & AF_CLOSING);
+ Done = TRUE;
+ }
+
+ RELEASE_SPIN_LOCK(&pAf->Lock, OldIrql);
+
+ if (Done)
+ FREE_POOL(pAf);
+}
+
+
+NDIS_STATUS
+NdisClRegisterSap(
+ IN NDIS_HANDLE NdisAfHandle,
+ IN NDIS_HANDLE ProtocolSapContext,
+ IN PCO_SAP Sap,
+ OUT PNDIS_HANDLE NdisSapHandle
+ )
+/*++
+
+Routine Description:
+ This is a call from a NDIS 4.1 or later protocol to register its SAP
+ with the call manager.
+
+Arguments:
+ NdisBindingHandle - Pointer to the protocol's NDIS_OPEN_BLOCK.
+ PCO_ADDRESS_FAMILY - The address family being registered.
+ ClientAfContext - Protocol context associated with this handle.
+ NdisAfHandle - Handle returned by NDIS for this address family.
+
+Return Value:
+ NDIS_STATUS_SUCCESS if the address family open is successfully.
+ NDIS_STATUS_PENDING if the call-manager pends this call. The caller will get
+ NDIS_STATUS_FAILURE if the caller is not a NDIS 4.1 prototcol or this address
+ family is not registered for this miniport.
+
+--*/
+{
+ NDIS_STATUS Status;
+ PNDIS_CO_AF_BLOCK pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
+ PNDIS_CO_SAP_BLOCK pSap;
+
+ *NdisSapHandle = NULL;
+ do
+ {
+ //
+ // Reference the Af for this SAP
+ //
+ if (!ndisReferenceAf(pAf))
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ pSap = (PNDIS_CO_SAP_BLOCK)ALLOC_FROM_POOL(sizeof(NDIS_CO_SAP_BLOCK), NDIS_TAG_CO);
+ if (pSap == NULL)
+ {
+ *NdisSapHandle = NULL;
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ pSap->Flags = 0;
+ pSap->References = 1;
+ INITIALIZE_SPIN_LOCK(&pSap->Lock);
+ pSap->AfBlock = pAf;
+ pSap->Sap = Sap;
+ pSap->ClientContext = ProtocolSapContext;
+ Status = (*pAf->CallMgrEntries->CmRegisterSapHandler)(pAf->CallMgrContext,
+ Sap,
+ pSap,
+ &pSap->CallMgrContext);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisCmRegisterSapComplete(Status, pSap, pSap->CallMgrContext);
+ Status = NDIS_STATUS_PENDING;
+ }
+
+ } while (FALSE);
+
+ return Status;
+}
+
+
+VOID
+NdisCmRegisterSapComplete(
+ IN NDIS_STATUS Status,
+ IN NDIS_HANDLE NdisSapHandle,
+ IN NDIS_HANDLE CallMgrSapContext
+ )
+/*++
+
+Routine Description:
+ Completion routine for the registerSap call. The call manager had pended this
+ call earlier (or will pend). If the call succeeded there is a valid CallMgrContext
+ supplied here as well
+
+Arguments:
+ Status - Completion status
+ NdisAfHandle - Pointer to the AfBlock
+ CallMgrAfContext - Call manager's context used in other calls into the call manager.
+
+Return Value:
+ NONE. The client's completion handler is called.
+
+--*/
+{
+ PNDIS_CO_SAP_BLOCK pSap = (PNDIS_CO_SAP_BLOCK)NdisSapHandle;
+ PNDIS_CO_AF_BLOCK pAf;
+
+ ASSERT (Status != NDIS_STATUS_PENDING);
+
+ pAf = pSap->AfBlock;
+ pSap->CallMgrContext = CallMgrSapContext;
+
+ //
+ // Call the clients completion handler
+ //
+ (*pAf->ClientEntries.ClRegisterSapCompleteHandler)(Status,
+ pSap->ClientContext,
+ pSap->Sap,
+ pSap);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ ndisDereferenceAf(pSap->AfBlock);
+ FREE_POOL(pSap);
+ }
+}
+
+
+NDIS_STATUS
+NdisClDeregisterSap(
+ IN NDIS_HANDLE NdisSapHandle
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_CO_SAP_BLOCK pSap = (PNDIS_CO_SAP_BLOCK)NdisSapHandle;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+ BOOLEAN fAlreadyClosing;
+
+ ACQUIRE_SPIN_LOCK(&pSap->Lock, &OldIrql);
+
+ fAlreadyClosing = FALSE;
+ if (pSap->Flags & SAP_CLOSING)
+ {
+ fAlreadyClosing = TRUE;
+ }
+ pSap->Flags |= SAP_CLOSING;
+
+ RELEASE_SPIN_LOCK(&pSap->Lock, OldIrql);
+
+ if (fAlreadyClosing)
+ {
+ return NDIS_STATUS_FAILURE;
+ }
+
+ //
+ // Notify the call-manager that this sap is being de-registered
+ //
+ Status = (*pSap->AfBlock->CallMgrEntries->CmDeregisterSapHandler)(pSap->CallMgrContext);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisCmDeregisterSapComplete(Status, pSap);
+ Status = NDIS_STATUS_PENDING;
+ }
+
+ return Status;
+}
+
+
+VOID
+NdisCmDeregisterSapComplete(
+ IN NDIS_STATUS Status,
+ IN NDIS_HANDLE NdisSapHandle
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_CO_SAP_BLOCK pSap = (PNDIS_CO_SAP_BLOCK)NdisSapHandle;
+
+ ASSERT (Status != NDIS_STATUS_PENDING);
+
+ //
+ // Complete the call to the client and deref the sap
+ //
+ (*pSap->AfBlock->ClientEntries.ClDeregisterSapCompleteHandler)(Status,
+ pSap->ClientContext);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ ndisDereferenceAf(pSap->AfBlock);
+ ndisDereferenceSap(pSap);
+ }
+}
+
+
+BOOLEAN
+ndisReferenceSap(
+ IN PNDIS_CO_SAP_BLOCK pSap
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ KIRQL OldIrql;
+ BOOLEAN rc = FALSE;
+
+ ACQUIRE_SPIN_LOCK(&pSap->Lock, &OldIrql);
+
+ if ((pSap->Flags & SAP_CLOSING) == 0)
+ {
+ pSap->References ++;
+ rc = TRUE;
+ }
+
+ RELEASE_SPIN_LOCK(&pSap->Lock, OldIrql);
+
+ return rc;
+}
+
+
+VOID
+ndisDereferenceSap(
+ IN PNDIS_CO_SAP_BLOCK pSap
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ KIRQL OldIrql;
+ BOOLEAN Done = FALSE;
+
+ ACQUIRE_SPIN_LOCK(&pSap->Lock, &OldIrql);
+
+ ASSERT (pSap->References > 0);
+ pSap->References --;
+ if (pSap->References == 0)
+ {
+ ASSERT (pSap->Flags & SAP_CLOSING);
+ Done = TRUE;
+ }
+
+ RELEASE_SPIN_LOCK(&pSap->Lock, OldIrql);
+
+ if (Done)
+ FREE_POOL(pSap);
+}
+
+
+NDIS_STATUS
+NdisCoCreateVc(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE NdisAfHandle OPTIONAL,
+ IN NDIS_HANDLE ProtocolVcContext,
+ IN OUT PNDIS_HANDLE NdisVcHandle
+ )
+/*++
+
+Routine Description:
+ This is a call from either the call-manager or from the client to create a vc.
+ The vc would then be owned by call-manager (signalling vc) or the client.
+ This is a synchronous call to all parties and simply creates an end-point over
+ which either incoming calls can be dispatched or out-going calls can be made.
+
+Arguments:
+ NdisBindingHandle - Pointer to the caller's NDIS_OPEN_BLOCK.
+ NdisAfHandle - Pointer to the AF Block. Not specified for call-manager's private vcs.
+ A miniport resident call-manager must never create call-manager vcs i.e.
+ the NdisAfHandle must always be present
+ NdisVcHandle - Where the handle to this Vc will be returned.
+
+Return Value:
+ NDIS_STATUS_SUCCESS if all the components succeed.
+ ErrorCode to signify why the call failed.
+
+--*/
+{
+ PNDIS_M_OPEN_BLOCK Open;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PNDIS_CO_VC_BLOCK Vc;
+ PNDIS_CO_AF_BLOCK pAf;
+ NDIS_STATUS Status;
+
+ Open = (PNDIS_M_OPEN_BLOCK)(((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->MacBindingHandle);
+ Miniport = Open->MiniportHandle;
+ *NdisVcHandle = NULL;
+
+ //
+ // Allocate the memory for NDIS_VC_BLOCK
+ //
+ Vc = ALLOC_FROM_POOL(sizeof(NDIS_CO_VC_BLOCK), NDIS_TAG_CO);
+ if (Vc == NULL)
+ return NDIS_STATUS_RESOURCES;
+
+ //
+ // Initialize the VC block
+ //
+ NdisZeroMemory(Vc, sizeof(NDIS_CO_VC_BLOCK));
+ INITIALIZE_SPIN_LOCK(&Vc->Lock);
+ InitializeListHead(&Vc->CallMgrLinkage);
+ InitializeListHead(&Vc->ClientLinkage);
+
+ //
+ // Cache some miniport handlers
+ //
+ Vc->Miniport = Miniport;
+ Vc->WCoSendPacketsHandler = Miniport->DriverHandle->MiniportCharacteristics.CoSendPacketsHandler;
+ Vc->WCoDeleteVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoDeleteVcHandler;
+ Vc->WCoActivateVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoActivateVcHandler;
+ Vc->WCoDeactivateVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoDeactivateVcHandler;
+
+ //
+ // We have only one reference for vc on creation.
+ //
+ pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
+ Vc->AfBlock = pAf;
+ Vc->References = 1;
+
+ //
+ // First call the miniport to get its context
+ //
+ Status = (*Open->MiniportCoCreateVcHandler)(Miniport->MiniportAdapterContext,
+ Vc,
+ &Vc->MiniportContext);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ FREE_POOL(Vc);
+ return Status;
+ }
+
+ if (ARGUMENT_PRESENT(NdisAfHandle))
+ {
+ Vc->ClientOpen = pAf->ClientOpen;
+ Vc->CallMgrOpen = pAf->CallMgrOpen;
+
+ Vc->CoSendCompleteHandler =
+ pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoSendCompleteHandler;
+ Vc->CoReceivePacketHandler =
+ pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler;
+ Vc->ClModifyCallQoSCompleteHandler = pAf->ClientEntries.ClModifyCallQoSCompleteHandler;
+ Vc->ClIncomingCallQoSChangeHandler = pAf->ClientEntries.ClIncomingCallQoSChangeHandler;
+ Vc->ClCallConnectedHandler = pAf->ClientEntries.ClCallConnectedHandler;
+
+ Vc->CmActivateVcCompleteHandler = pAf->CallMgrEntries->CmActivateVcCompleteHandler;
+ Vc->CmDeactivateVcCompleteHandler = pAf->CallMgrEntries->CmDeactivateVcCompleteHandler;
+ Vc->CmModifyCallQoSHandler = pAf->CallMgrEntries->CmModifyCallQoSHandler;
+
+ //
+ // Determine who the caller is and initialize the other.
+ //
+ if (Open == pAf->ClientOpen)
+ {
+ Vc->ClientContext = ProtocolVcContext;
+
+ if (pAf->CallMgrOpen == NULL)
+ {
+ Vc->CallMgrContext = Vc->MiniportContext;
+ }
+ else
+ {
+ //
+ // Call-up to the call-manager now to get its context
+ //
+ Status = (*pAf->CallMgrOpen->CoCreateVcHandler)(pAf->CallMgrContext,
+ Vc,
+ &Vc->CallMgrContext);
+ }
+ }
+ else
+ {
+ ASSERT (pAf->CallMgrOpen == Open);
+
+ Vc->CallMgrContext = ProtocolVcContext;
+
+ //
+ // Call-up to the client now to get its context
+ //
+ Status = (*pAf->ClientOpen->CoCreateVcHandler)(pAf->ClientContext,
+ Vc,
+ &Vc->ClientContext);
+ }
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (Open == pAf->ClientOpen)
+ {
+ //
+ // Link this in the open_block
+ //
+ ExInterlockedInsertHeadList(&Open->InactiveVcHead,
+ &Vc->ClientLinkage,
+ &Open->SpinLock.SpinLock);
+ if (pAf->CallMgrOpen != NULL)
+ {
+ Vc->DeleteVcContext = Vc->CallMgrContext;
+ Vc->CoDeleteVcHandler = pAf->CallMgrOpen->CoDeleteVcHandler;
+ ExInterlockedInsertHeadList(&pAf->CallMgrOpen->InactiveVcHead,
+ &Vc->CallMgrLinkage,
+ &pAf->CallMgrOpen->SpinLock.SpinLock);
+ }
+ else
+ {
+ Vc->DeleteVcContext = NULL;
+ Vc->CoDeleteVcHandler = NULL;
+ }
+ }
+ else
+ {
+ //
+ // Link this in the open_block
+ //
+ Vc->DeleteVcContext = Vc->ClientContext;
+ Vc->CoDeleteVcHandler = pAf->ClientOpen->CoDeleteVcHandler;
+ ExInterlockedInsertHeadList(&Open->InactiveVcHead,
+ &Vc->CallMgrLinkage,
+ &Open->SpinLock.SpinLock);
+ ExInterlockedInsertHeadList(&pAf->ClientOpen->InactiveVcHead,
+ &Vc->ClientLinkage,
+ &pAf->ClientOpen->SpinLock.SpinLock);
+ }
+ }
+ else
+ {
+ Status = (*Vc->WCoDeleteVcHandler)(Vc->MiniportContext);
+
+ FREE_POOL(Vc);
+ Vc = NULL;
+ }
+ }
+ else
+ {
+ //
+ // This is a call-manager only VC and so the call-manager is the client and there
+ // is no call-manager associated with it. This VC cannot be used to CoMakeCall or
+ // CmDispatchIncomingCall. Set the client values to the call-manager
+ //
+ // Vc->CoDeleteVcContexr = NULL;
+ // Vc->CoDeleteVcHandler = NULL;
+ Vc->ClientOpen = Open;
+ Vc->ClientContext = ProtocolVcContext;
+ Vc->CoSendCompleteHandler =
+ Open->ProtocolHandle->ProtocolCharacteristics.CoSendCompleteHandler;
+ Vc->CoReceivePacketHandler =
+ Open->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler;
+
+ //
+ // Do set the following call-manager entries since this VC will need to be
+ // activated. Also set the call-managers context for the same reasons.
+ //
+ Vc->CmActivateVcCompleteHandler = Open->CmActivateVcCompleteHandler;
+ Vc->CmDeactivateVcCompleteHandler = Open->CmDeactivateVcCompleteHandler;
+ Vc->CallMgrContext = ProtocolVcContext;
+
+ //
+ // Link this in the open_block
+ //
+ ExInterlockedInsertHeadList(&Open->InactiveVcHead,
+ &Vc->ClientLinkage,
+ &Open->SpinLock.SpinLock);
+ }
+
+ *NdisVcHandle = Vc;
+ return Status;
+}
+
+
+NDIS_STATUS
+NdisCoDeleteVc(
+ IN PNDIS_HANDLE NdisVcHandle
+ )
+/*++
+
+Routine Description:
+
+ Synchronous call from either the call-manager or the client to delete a VC. Only inactive
+ VCs can be deleted. Active Vcs or partially active Vcs cannot be.
+
+Arguments:
+
+ NdisVcHandle The Vc to delete
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS If all goes well
+ NDIS_STATUS_NOT_ACCEPTED If Vc is active
+ NDIS_STATUS_CLOSING If Vc de-activation is pending
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+
+ ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
+
+ if (Vc->Flags & (VC_ACTIVE | VC_ACTIVATE_PENDING))
+ {
+ Status = NDIS_STATUS_NOT_ACCEPTED;
+ }
+ else if (Vc->Flags & VC_DEACTIVATE_PENDING)
+ {
+ Status = NDIS_STATUS_CLOSING;
+ }
+ else
+ {
+ Vc->Flags |= VC_CLOSING;
+
+ //
+ // Call the miniport to delete it first
+ //
+ Status = (*Vc->WCoDeleteVcHandler)(Vc->MiniportContext);
+ ASSERT (Status == NDIS_STATUS_SUCCESS);
+
+ //
+ // Next the non-creator, if any
+ //
+ if (Vc->CoDeleteVcHandler != NULL)
+ {
+ Status = (*Vc->CoDeleteVcHandler)(Vc->DeleteVcContext);
+ ASSERT (Status == NDIS_STATUS_SUCCESS);
+ }
+
+ //
+ // Now de-link the vc from the client and call-manager
+ //
+ ACQUIRE_SPIN_LOCK_DPC(&Vc->ClientOpen->SpinLock.SpinLock);
+ RemoveEntryList(&Vc->ClientLinkage);
+ RELEASE_SPIN_LOCK_DPC(&Vc->ClientOpen->SpinLock.SpinLock);
+
+ if (Vc->CallMgrOpen != NULL)
+ {
+ ACQUIRE_SPIN_LOCK_DPC(&Vc->CallMgrOpen->SpinLock.SpinLock);
+ RemoveEntryList(&Vc->CallMgrLinkage);
+ RELEASE_SPIN_LOCK_DPC(&Vc->CallMgrOpen->SpinLock.SpinLock);
+ }
+
+ Status = NDIS_STATUS_SUCCESS;
+ }
+
+ RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ ndisDereferenceVc(Vc);
+ }
+
+ return Status;
+}
+
+
+NDIS_STATUS
+NdisMCmCreateVc(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE NdisAfHandle,
+ IN NDIS_HANDLE MiniportVcContext,
+ OUT PNDIS_HANDLE NdisVcHandle
+ )
+/*++
+
+Routine Description:
+
+ This is a call by the miniport (with a resident CM) to create a Vc for an incoming call.
+
+Arguments:
+ MiniportAdapterHandle - Miniport's adapter context
+ NdisAfHandle - Pointer to the AF Block.
+ MiniportVcContext - Miniport's context to associate with this vc.
+ NdisVcHandle - Where the handle to this Vc will be returned.
+
+Return Value:
+ NDIS_STATUS_SUCCESS if all the components succeed.
+ ErrorCode to signify why the call failed.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_CO_VC_BLOCK Vc;
+ PNDIS_CO_AF_BLOCK pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
+ NDIS_STATUS Status;
+
+ *NdisVcHandle = NULL;
+
+ //
+ // Allocate the memory for NDIS_VC_BLOCK
+ //
+ Vc = ALLOC_FROM_POOL(sizeof(NDIS_CO_VC_BLOCK), NDIS_TAG_CO);
+ if (Vc == NULL)
+ return NDIS_STATUS_RESOURCES;
+
+ //
+ // Initialize the VC block
+ //
+ NdisZeroMemory(Vc, sizeof(NDIS_CO_VC_BLOCK));
+ INITIALIZE_SPIN_LOCK(&Vc->Lock);
+ InitializeListHead(&Vc->CallMgrLinkage);
+ InitializeListHead(&Vc->ClientLinkage);
+
+ //
+ // Cache some miniport handlers
+ //
+ Vc->Miniport = Miniport;
+ Vc->WCoSendPacketsHandler = Miniport->DriverHandle->MiniportCharacteristics.CoSendPacketsHandler;
+ Vc->WCoDeleteVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoDeleteVcHandler;
+ Vc->WCoActivateVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoActivateVcHandler;
+ Vc->WCoDeactivateVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoDeactivateVcHandler;
+ Vc->MiniportContext = MiniportVcContext;
+
+ //
+ // We have only one reference for vc on creation.
+ //
+ pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
+ Vc->AfBlock = pAf;
+ Vc->References = 1;
+
+ ASSERT (ARGUMENT_PRESENT(NdisAfHandle));
+
+ Vc->ClientOpen = pAf->ClientOpen;
+ Vc->CallMgrOpen = NULL;
+
+ Vc->CoSendCompleteHandler =
+ pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoSendCompleteHandler;
+ Vc->CoReceivePacketHandler =
+ pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler;
+ Vc->ClModifyCallQoSCompleteHandler = pAf->ClientEntries.ClModifyCallQoSCompleteHandler;
+ Vc->ClIncomingCallQoSChangeHandler = pAf->ClientEntries.ClIncomingCallQoSChangeHandler;
+ Vc->ClCallConnectedHandler = pAf->ClientEntries.ClCallConnectedHandler;
+
+ Vc->CmActivateVcCompleteHandler = pAf->CallMgrEntries->CmActivateVcCompleteHandler;
+ Vc->CmDeactivateVcCompleteHandler = pAf->CallMgrEntries->CmDeactivateVcCompleteHandler;
+ Vc->CmModifyCallQoSHandler = pAf->CallMgrEntries->CmModifyCallQoSHandler;
+
+ Vc->CallMgrContext = MiniportVcContext;
+
+ //
+ // Call-up to the client now to get its context
+ //
+ Status = (*pAf->ClientOpen->CoCreateVcHandler)(pAf->ClientContext,
+ Vc,
+ &Vc->ClientContext);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Link this in the open_block
+ //
+ Vc->DeleteVcContext = Vc->ClientContext;
+ Vc->CoDeleteVcHandler = pAf->ClientOpen->CoDeleteVcHandler;
+ ExInterlockedInsertHeadList(&pAf->ClientOpen->InactiveVcHead,
+ &Vc->ClientLinkage,
+ &pAf->ClientOpen->SpinLock.SpinLock);
+ }
+ else
+ {
+ Status = (*Vc->WCoDeleteVcHandler)(Vc->MiniportContext);
+
+ FREE_POOL(Vc);
+ Vc = NULL;
+ }
+
+ *NdisVcHandle = Vc;
+ return Status;
+}
+
+
+NDIS_STATUS
+NdisMCmDeleteVc(
+ IN PNDIS_HANDLE NdisVcHandle
+ )
+/*++
+
+Routine Description:
+
+ This is a called by the miniport (with a resident CM) to delete a Vc created by it. Identical to
+ NdisMCoDeleteVc but a seperate api for completeness.
+
+Arguments:
+
+ NdisVcHandle The Vc to delete
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS If all goes well
+ NDIS_STATUS_NOT_ACCEPTED If Vc is active
+ NDIS_STATUS_CLOSING If Vc de-activation is pending
+
+--*/
+{
+ return(NdisMCmDeleteVc(NdisVcHandle));
+}
+
+
+NDIS_STATUS
+NdisCmActivateVc(
+ IN PNDIS_HANDLE NdisVcHandle,
+ IN OUT PCO_CALL_PARAMETERS CallParameters
+ )
+/*++
+
+Routine Description:
+
+ Called by the call-manager to set the Vc parameters on the Vc. The wrapper
+ saved the media id (e.g. Vpi/Vci for atm) in the Vc so that a p-mode protocol can
+ get this info as well on receives.
+
+Arguments:
+
+ NdisVcHandle The Vc to set parameters on.
+ MediaParameters The parameters to set.
+
+Return Value:
+
+ NDIS_STATUS_PENDING If the miniport pends the call.
+ NDIS_STATUS_CLOSING If Vc de-activation is pending
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+
+ ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
+
+ //
+ // Make sure the Vc does not have an activation/de-activation pending
+ // Not that it is ok for the Vc to be already active - then it is a re-activation.
+ //
+ if (Vc->Flags & VC_ACTIVATE_PENDING)
+ {
+ Status = NDIS_STATUS_NOT_ACCEPTED;
+ }
+ else if (Vc->Flags & VC_DEACTIVATE_PENDING)
+ {
+ Status = NDIS_STATUS_CLOSING;
+ }
+ else
+ {
+ Vc->Flags |= VC_ACTIVATE_PENDING;
+
+ //
+ // Save the media id for the Vc
+ //
+ Status = NDIS_STATUS_SUCCESS;
+ Vc->pVcId = &CallParameters->MediaParameters->MediaSpecific;
+ }
+
+ RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Now call down to the miniport to activate it
+ //
+ Status = (*Vc->WCoActivateVcHandler)(Vc->MiniportContext, CallParameters);
+ }
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisMCoActivateVcComplete(Status, Vc, CallParameters);
+ Status = NDIS_STATUS_PENDING;
+ }
+
+ return Status;
+}
+
+
+NDIS_STATUS
+NdisMCmActivateVc(
+ IN PNDIS_HANDLE NdisVcHandle,
+ IN PCO_CALL_PARAMETERS CallParameters
+ )
+/*++
+
+Routine Description:
+
+ Called by the miniport resident call-manager to set the Vc parameters on the Vc. This is a
+ synchronous call.
+
+Arguments:
+
+ NdisVcHandle The Vc to set parameters on.
+ MediaParameters The parameters to set.
+
+Return Value:
+
+ NDIS_STATUS_CLOSING If Vc de-activation is pending
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+
+ ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
+
+ //
+ // Make sure the Vc does not have an activation/de-activation pending
+ // Not that it is ok for the Vc to be already active - then it is a re-activation.
+ //
+ if (Vc->Flags & VC_ACTIVATE_PENDING)
+ {
+ Status = NDIS_STATUS_NOT_ACCEPTED;
+ }
+ else if (Vc->Flags & VC_DEACTIVATE_PENDING)
+ {
+ Status = NDIS_STATUS_CLOSING;
+ }
+ else
+ {
+ Vc->Flags |= VC_ACTIVE;
+ Status = NDIS_STATUS_SUCCESS;
+ Vc->pVcId = &CallParameters->MediaParameters->MediaSpecific;
+ }
+
+ RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
+
+ return Status;
+}
+
+
+VOID
+NdisMCoActivateVcComplete(
+ IN NDIS_STATUS Status,
+ IN PNDIS_HANDLE NdisVcHandle,
+ IN PCO_CALL_PARAMETERS CallParameters
+ )
+/*++
+
+Routine Description:
+
+ Called by the mini-port to complete a pending activation call.
+
+Arguments:
+
+ Status Status of activation.
+ NdisVcHandle The Vc in question.
+
+Return Value:
+
+ NONE
+ The call-manager's completion routine is called.
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ KIRQL OldIrql;
+
+ ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
+
+ ASSERT (Vc->Flags & VC_ACTIVATE_PENDING);
+
+ Vc->Flags &= ~VC_ACTIVATE_PENDING;
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ Vc->Flags |= VC_ACTIVE;
+ }
+
+ RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
+
+ //
+ // Complete the call to the call-manager
+ //
+ (*Vc->CmActivateVcCompleteHandler)(Status, Vc->CallMgrContext, CallParameters);
+}
+
+
+NDIS_STATUS
+NdisCmDeactivateVc(
+ IN PNDIS_HANDLE NdisVcHandle
+ )
+/*++
+
+Routine Description:
+
+ Called by the call-manager to de-activate a Vc.
+
+Arguments:
+
+ NdisVcHandle The Vc to de-activate the Vc.
+
+Return Value:
+
+ NDIS_STATUS_PENDING If the miniport pends the call.
+ NDIS_STATUS_SUCCESS If all goes well
+ NDIS_STATUS_CLOSING If Vc de-activation is pending
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+
+ ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
+
+ if ((Vc->Flags & (VC_ACTIVE | VC_ACTIVATE_PENDING)) == 0)
+ {
+ Status = NDIS_STATUS_NOT_ACCEPTED;
+ }
+ else if (Vc->Flags & VC_DEACTIVATE_PENDING)
+ {
+ Status = NDIS_STATUS_CLOSING;
+ }
+ else
+ {
+ Vc->Flags |= VC_DEACTIVATE_PENDING;
+ }
+
+ RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
+
+ //
+ // Now call down to the miniport to de-activate it
+ //
+ Status = (*Vc->WCoDeactivateVcHandler)(Vc->MiniportContext);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisMCoDeactivateVcComplete(Status, Vc);
+ Status = NDIS_STATUS_PENDING;
+ }
+
+ return Status;
+}
+
+
+NDIS_STATUS
+NdisMCmDeactivateVc(
+ IN PNDIS_HANDLE NdisVcHandle
+ )
+/*++
+
+Routine Description:
+
+ Called by the miniport resident call-manager to de-activate the Vc. This is a
+ synchronous call.
+
+Arguments:
+
+ NdisVcHandle The Vc to set parameters on.
+
+Return Value:
+
+ NDIS_STATUS_CLOSING If Vc de-activation is pending
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+
+ ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
+
+ if ((Vc->Flags & (VC_ACTIVE | VC_ACTIVATE_PENDING)) == 0)
+ {
+ Status = NDIS_STATUS_NOT_ACCEPTED;
+ }
+ else if (Vc->Flags & VC_DEACTIVATE_PENDING)
+ {
+ Status = NDIS_STATUS_CLOSING;
+ }
+ else
+ {
+ Status = NDIS_STATUS_SUCCESS;
+ Vc->Flags &= ~VC_ACTIVE;
+ }
+
+ RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
+
+ return Status;
+}
+
+
+VOID
+NdisMCoDeactivateVcComplete(
+ IN NDIS_STATUS Status,
+ IN PNDIS_HANDLE NdisVcHandle
+ )
+/*++
+
+Routine Description:
+
+ Called by the mini-port to complete a pending de-activation of a Vc.
+
+Arguments:
+
+ NdisVcHandle The Vc in question.
+
+Return Value:
+
+ NONE
+ The call-manager's completion routine is called.
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ KIRQL OldIrql;
+
+ ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
+
+ ASSERT (Vc->Flags & VC_DEACTIVATE_PENDING);
+
+ Vc->Flags &= ~VC_DEACTIVATE_PENDING;
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ Vc->Flags &= ~VC_ACTIVE;
+ }
+
+ RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
+
+ //
+ // Complete the call to the call-manager
+ //
+ (*Vc->CmDeactivateVcCompleteHandler)(Status, Vc->CallMgrContext);
+}
+
+
+NDIS_STATUS
+NdisClMakeCall(
+ IN NDIS_HANDLE NdisVcHandle,
+ IN OUT PCO_CALL_PARAMETERS CallParameters,
+ IN NDIS_HANDLE ProtocolPartyContext OPTIONAL,
+ OUT PNDIS_HANDLE NdisPartyHandle OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ PNDIS_CO_AF_BLOCK pAf;
+ PNDIS_CO_PARTY_BLOCK pParty = NULL;
+ PVOID CallMgrPartyContext = NULL;
+ NDIS_STATUS Status;
+
+ do
+ {
+ pAf = Vc->AfBlock;
+ ASSERT (pAf != NULL);
+ if (!ndisReferenceAf(pAf))
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ if (ARGUMENT_PRESENT(NdisPartyHandle))
+ {
+ *NdisPartyHandle = NULL;
+ pParty = (PNDIS_CO_PARTY_BLOCK)ALLOC_FROM_POOL(sizeof(NDIS_CO_PARTY_BLOCK),
+ NDIS_TAG_CO);
+ if (pParty == NULL)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+ pParty->Vc = Vc;
+ pParty->ClientContext = ProtocolPartyContext;
+ pParty->ClIncomingDropPartyHandler =
+ pAf->ClientEntries.ClIncomingDropPartyHandler;
+ pParty->ClDropPartyCompleteHandler =
+ pAf->ClientEntries.ClDropPartyCompleteHandler;
+ }
+
+ //
+ // Pass the request off to the call manager
+ //
+ Status = (*pAf->CallMgrEntries->CmMakeCallHandler)(Vc->CallMgrContext,
+ CallParameters,
+ pParty,
+ &CallMgrPartyContext);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisCmMakeCallComplete(Status,
+ Vc,
+ pParty,
+ CallMgrPartyContext,
+ CallParameters);
+ Status = NDIS_STATUS_PENDING;
+ }
+ } while (FALSE);
+
+ if (!NT_SUCCESS(Status))
+ {
+ //
+ // These are resource failures and not a failure from call-manager
+ //
+ if (pParty != NULL)
+ {
+ FREE_POOL(pParty);
+ }
+ }
+
+ return Status;
+}
+
+
+VOID
+NdisCmMakeCallComplete(
+ IN NDIS_STATUS Status,
+ IN NDIS_HANDLE NdisVcHandle,
+ IN NDIS_HANDLE NdisPartyHandle OPTIONAL,
+ IN NDIS_HANDLE CallMgrPartyContext OPTIONAL,
+ IN PCO_CALL_PARAMETERS CallParameters
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_CO_AF_BLOCK pAf;
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
+ KIRQL OldIrql;
+
+ pAf = Vc->AfBlock;
+
+ ASSERT (Status != NDIS_STATUS_PENDING);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Call completed successfully. Complete it to the client.
+ //
+
+ //
+ // Reference the Vc for the client. This is dereferenced when
+ // the client calls NdisClCloseCall()
+ //
+ ndisReferenceVc(Vc);
+
+
+ if (ARGUMENT_PRESENT(NdisPartyHandle))
+ {
+ pParty->CallMgrContext = CallMgrPartyContext;
+ ndisReferenceVc(Vc);
+ }
+
+ ACQUIRE_SPIN_LOCK(&pAf->ClientOpen->SpinLock.SpinLock, &OldIrql);
+ RemoveEntryList(&Vc->ClientLinkage);
+ InsertHeadList(&pAf->ClientOpen->ActiveVcHead,
+ &Vc->ClientLinkage);
+ RELEASE_SPIN_LOCK(&pAf->ClientOpen->SpinLock.SpinLock, OldIrql);
+ }
+ else
+ {
+ ndisDereferenceAf(pAf);
+ }
+
+ (*pAf->ClientEntries.ClMakeCallCompleteHandler)(Status,
+ Vc->ClientContext,
+ pParty,
+ CallParameters);
+}
+
+
+NDIS_STATUS
+NdisCmDispatchIncomingCall(
+ IN NDIS_HANDLE NdisSapHandle,
+ IN NDIS_HANDLE NdisVcHandle,
+ IN OUT PCO_CALL_PARAMETERS CallParameters
+ )
+/*++
+
+Routine Description:
+
+ Call from the call-manager to dispatch an incoming vc to the client who registered the Sap.
+ The client is identified by the NdisSapHandle.
+
+Arguments:
+
+ NdisBindingHandle - Identifies the miniport on which the Vc is created
+ NdisSapHandle - Identifies the client
+ CallParameters - Self explanatory
+ NdisVcHandle - Pointer to the NDIS_CO_VC_BLOCK created via NdisCmCreateVc
+
+Return Value:
+
+ Return value from the client or an processing error.
+
+--*/
+{
+ PNDIS_CO_SAP_BLOCK Sap;
+ PNDIS_CO_VC_BLOCK Vc;
+ PNDIS_CO_AF_BLOCK pAf;
+ NDIS_STATUS Status;
+
+ Sap = (PNDIS_CO_SAP_BLOCK)NdisSapHandle;
+ Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ pAf = Sap->AfBlock;
+
+ ASSERT(pAf == Vc->AfBlock);
+
+ //
+ // Make sure the SAP's not closing
+ //
+ if (!ndisReferenceSap(Sap))
+ {
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Make sure the AF is not closing
+ //
+ if (!ndisReferenceAf(pAf))
+ {
+ ndisDereferenceSap(Sap);
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Notify the client of this call
+ //
+ Status = (*pAf->ClientEntries.ClIncomingCallHandler)(Sap->ClientContext,
+ Vc->ClientContext,
+ CallParameters);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisClIncomingCallComplete(Status, Vc, CallParameters);
+ Status = NDIS_STATUS_PENDING;
+ }
+
+ ndisDereferenceSap(Sap);
+
+ return Status;
+}
+
+
+VOID
+NdisClIncomingCallComplete(
+ IN NDIS_STATUS Status,
+ IN NDIS_HANDLE NdisVcHandle,
+ IN PCO_CALL_PARAMETERS CallParameters
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ KIRQL OldIrql;
+
+ ASSERT (Status != NDIS_STATUS_PENDING);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ ACQUIRE_SPIN_LOCK(&Vc->ClientOpen->SpinLock.SpinLock, &OldIrql);
+ //
+ // Reference the Vc. This is dereferenced when NdisClCloseCall is called.
+ //
+ Vc->References ++;
+ RemoveEntryList(&Vc->ClientLinkage);
+ InsertHeadList(&Vc->ClientOpen->ActiveVcHead,
+ &Vc->ClientLinkage);
+
+ RELEASE_SPIN_LOCK(&Vc->ClientOpen->SpinLock.SpinLock, OldIrql);
+ }
+
+ //
+ // Call the call-manager handler to notify that client is done with this.
+ //
+ (*Vc->AfBlock->CallMgrEntries->CmIncomingCallCompleteHandler)(
+ Status,
+ Vc->CallMgrContext,
+ CallParameters);
+}
+
+
+VOID
+NdisCmDispatchCallConnected(
+ IN NDIS_HANDLE NdisVcHandle
+ )
+/*++
+
+Routine Description:
+
+ Called by the call-manager to complete the final hand-shake on an incoming call.
+
+Arguments:
+
+ NdisVcHandle - Pointer to the vc block
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+
+ (*Vc->ClCallConnectedHandler)(Vc->ClientContext);
+}
+
+
+NDIS_STATUS
+NdisClModifyCallQoS(
+ IN NDIS_HANDLE NdisVcHandle,
+ IN PCO_CALL_PARAMETERS CallParameters
+ )
+/*++
+
+Routine Description:
+
+ Initiated by the client to modify the QoS associated with the call.
+
+Arguments:
+
+ NdisVcHandle - Pointer to the vc block
+ CallParameters - New call QoS
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ NDIS_STATUS Status;
+
+ //
+ // Ask the call-manager to take care of this
+ //
+ Status = (*Vc->CmModifyCallQoSHandler)(Vc->CallMgrContext,
+ CallParameters);
+ return Status;
+}
+
+VOID
+NdisCmModifyCallQoSComplete(
+ IN NDIS_STATUS Status,
+ IN NDIS_HANDLE NdisVcHandle,
+ IN PCO_CALL_PARAMETERS CallParameters
+ )
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+
+ //
+ // Simply notify the client
+ //
+ (*Vc->ClModifyCallQoSCompleteHandler)(Status,
+ Vc->ClientContext,
+ CallParameters);
+}
+
+
+VOID
+NdisCmDispatchIncomingCallQoSChange(
+ IN NDIS_HANDLE NdisVcHandle,
+ IN PCO_CALL_PARAMETERS CallParameters
+ )
+/*++
+
+Routine Description:
+
+ Called by the call-manager to indicate a remote requested change in the call-qos. This is
+ simply an indication. A client must respond by either accepting it (do nothing) or reject
+ it (by either modifying the call qos or by tearing down the call).
+
+Arguments:
+
+ NdisVcHandle - Pointer to the vc block
+ CallParameters - New call qos
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+
+ //
+ // Simply notify the client
+ //
+ (*Vc->ClIncomingCallQoSChangeHandler)(Vc->ClientContext,
+ CallParameters);
+}
+
+
+NDIS_STATUS
+NdisClCloseCall(
+ IN NDIS_HANDLE NdisVcHandle,
+ IN NDIS_HANDLE NdisPartyHandle OPTIONAL,
+ IN PVOID Buffer OPTIONAL,
+ IN UINT Size OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+ Called by the client to close down a connection established via either NdisClMakeCall
+ or accepting an incoming call via NdisClIncomingCallComplete. The optional buffer can
+ be specified by the client to send a disconnect message. Upto the call-manager to do
+ something reasonable with it.
+
+Arguments:
+
+ NdisVcHandle - Pointer to the vc block
+ Buffer - Optional disconnect message
+ Size - Size of the disconnect message
+
+Return Value:
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
+ NDIS_STATUS Status;
+
+ //
+ // Simply notify the call-manager
+ //
+ Status = (*Vc->AfBlock->CallMgrEntries->CmCloseCallHandler)(Vc->CallMgrContext,
+ (pParty != NULL) ?
+ pParty->CallMgrContext :
+ NULL,
+ Buffer,
+ Size);
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisCmCloseCallComplete(Status, Vc, pParty);
+ Status = NDIS_STATUS_PENDING;
+ }
+
+ return Status;
+}
+
+
+VOID
+NdisCmCloseCallComplete(
+ IN NDIS_STATUS Status,
+ IN NDIS_HANDLE NdisVcHandle,
+ IN NDIS_HANDLE NdisPartyHandle OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+
+
+Arguments:
+
+ NdisVcHandle - Pointer to the vc block
+
+Return Value:
+
+ Nothing. Client handler called
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
+
+ //
+ // Notify the client and dereference the Vc
+ //
+ (*Vc->AfBlock->ClientEntries.ClCloseCallCompleteHandler)(Status,
+ Vc->ClientContext,
+ (pParty != NULL) ?
+ pParty->CallMgrContext :
+ NULL);
+
+ ndisDereferenceAf(Vc->AfBlock);
+ ndisDereferenceVc(Vc);
+ if (pParty != NULL)
+ {
+ ASSERT (Vc == pParty->Vc);
+ ndisDereferenceVc(pParty->Vc);
+ FREE_POOL(pParty);
+ }
+}
+
+
+VOID
+NdisCmDispatchIncomingCloseCall(
+ IN NDIS_STATUS CloseStatus,
+ IN NDIS_HANDLE NdisVcHandle,
+ IN PVOID Buffer,
+ IN UINT Size
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+
+ //
+ // Notify the client
+ //
+ (*Vc->AfBlock->ClientEntries.ClIncomingCloseCallHandler)(
+ CloseStatus,
+ Vc->ClientContext,
+ Buffer,
+ Size);
+}
+
+
+NDIS_STATUS
+NdisClAddParty(
+ IN NDIS_HANDLE NdisVcHandle,
+ IN NDIS_HANDLE ProtocolPartyContext,
+ IN OUT PCO_CALL_PARAMETERS CallParameters,
+ OUT PNDIS_HANDLE NdisPartyHandle
+ )
+/*++
+
+Routine Description:
+
+ Call from the client to the call-manager to add a party to a point-to-multi-point call.
+
+Arguments:
+
+ NdisVcHandle - The handle client obtained via NdisClMakeCall()
+ ProtocolPartyContext - Protocol's context for this leaf
+ Flags - Call flags
+ CallParameters - Call parameters
+ NdisPartyHandle - Place holder for the handle to identify the leaf
+
+Return Value:
+
+ NDIS_STATUS_PENDING The call has pended and will complete via CoAddPartyCompleteHandler.
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ PNDIS_CO_PARTY_BLOCK pParty;
+ NDIS_STATUS Status;
+
+ do
+ {
+ *NdisPartyHandle = NULL;
+ if (!ndisReferenceVc(Vc))
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ pParty = ALLOC_FROM_POOL(sizeof(NDIS_CO_PARTY_BLOCK), NDIS_TAG_CO);
+ if (pParty == NULL)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ pParty->ClientContext = ProtocolPartyContext;
+ pParty->Vc = Vc;
+ pParty->ClIncomingDropPartyHandler =
+ Vc->AfBlock->ClientEntries.ClIncomingDropPartyHandler;
+ pParty->ClDropPartyCompleteHandler =
+ Vc->AfBlock->ClientEntries.ClDropPartyCompleteHandler;
+
+ //
+ // Simply call the call-manager to do its stuff.
+ //
+ Status = (*Vc->AfBlock->CallMgrEntries->CmAddPartyHandler)(
+ Vc->CallMgrContext,
+ CallParameters,
+ pParty,
+ &pParty->CallMgrContext);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisCmAddPartyComplete(Status,
+ pParty,
+ pParty->CallMgrContext,
+ CallParameters);
+ Status = NDIS_STATUS_PENDING;
+ }
+ } while (FALSE);
+
+ return Status;
+}
+
+
+VOID
+NdisCmAddPartyComplete(
+ IN NDIS_STATUS Status,
+ IN NDIS_HANDLE NdisPartyHandle,
+ IN NDIS_HANDLE CallMgrPartyContext OPTIONAL,
+ IN PCO_CALL_PARAMETERS CallParameters
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
+
+ ASSERT (Status != NDIS_STATUS_PENDING);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ pParty->CallMgrContext = CallMgrPartyContext;
+ }
+
+ //
+ // Complete the call to the client
+ //
+ (*pParty->Vc->AfBlock->ClientEntries.ClAddPartyCompleteHandler)(
+ Status,
+ pParty->ClientContext,
+ pParty,
+ CallParameters);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ ndisDereferenceVc(pParty->Vc);
+ FREE_POOL(pParty);
+ }
+}
+
+
+NDIS_STATUS
+NdisClDropParty(
+ IN NDIS_HANDLE NdisPartyHandle,
+ IN PVOID Buffer OPTIONAL,
+ IN UINT Size OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
+ NDIS_STATUS Status;
+
+ //
+ // Pass it along to the call-manager to handle this
+ //
+ Status = (*pParty->Vc->AfBlock->CallMgrEntries->CmDropPartyHandler)(
+ pParty->CallMgrContext,
+ Buffer,
+ Size);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisCmDropPartyComplete(Status, pParty);
+ Status = NDIS_STATUS_PENDING;
+ }
+
+ return Status;
+}
+
+
+VOID
+NdisCmDropPartyComplete(
+ IN NDIS_STATUS Status,
+ IN NDIS_HANDLE NdisPartyHandle
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
+
+ ASSERT (Status != NDIS_STATUS_PENDING);
+
+ //
+ // Complete the call to the client
+ //
+ (*pParty->ClDropPartyCompleteHandler)(Status,
+ pParty->ClientContext);
+ ndisDereferenceVc(pParty->Vc);
+ FREE_POOL(pParty);
+}
+
+
+VOID
+NdisCmDispatchIncomingDropParty(
+ IN NDIS_STATUS DropStatus,
+ IN NDIS_HANDLE NdisPartyHandle,
+ IN PVOID Buffer,
+ IN UINT Size
+ )
+/*++
+
+Routine Description:
+
+ Called by the call-manager to notify the client that this leaf of the multi-party
+ call is terminated. The client cannot use the NdisPartyHandle after completing this
+ call - synchronously or by calling NdisClIncomingDropPartyComplete.
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
+
+ //
+ // Notify the client
+ //
+ (*pParty->ClIncomingDropPartyHandler)(DropStatus,
+ pParty->ClientContext,
+ Buffer,
+ Size);
+}
+
+
+BOOLEAN
+ndisReferenceVc(
+ IN PNDIS_CO_VC_BLOCK Vc
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ KIRQL OldIrql;
+ BOOLEAN rc = FALSE;
+
+ ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
+
+ if ((Vc->Flags & VC_CLOSING) == 0)
+ {
+ Vc->References ++;
+ rc = TRUE;
+ }
+
+ RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
+
+ return rc;
+}
+
+
+VOID
+ndisDereferenceVc(
+ IN PNDIS_CO_VC_BLOCK Vc
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ KIRQL OldIrql;
+ BOOLEAN Done = FALSE;
+
+ ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
+
+ ASSERT (Vc->References > 0);
+ Vc->References --;
+ if (Vc->References == 0)
+ {
+ ASSERT (Vc->Flags & VC_CLOSING);
+ Done = TRUE;
+ }
+
+ RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
+
+ if (Done)
+ FREE_POOL(Vc);
+}
+
+
+VOID
+ndisMCoFreeResources(
+ PNDIS_M_OPEN_BLOCK Open
+ )
+/*++
+
+Routine Description:
+
+ Cleans-up address family list for call-managers etc.
+
+ CALLED WITH MINIPORT LOCK HELD.
+
+Arguments:
+
+ Open - Pointer to the Open block for miniports
+
+Return Value:
+
+ None
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PNDIS_AF_LIST *pAfList, pTmp;
+
+ Miniport = Open->MiniportHandle;
+
+ for (pAfList = &Miniport->CallMgrAfList;
+ (pTmp = *pAfList) != NULL;
+ NOTHING)
+ {
+ if (pTmp->Open == Open)
+ {
+ *pAfList = pTmp->NextOpen;
+ FREE_POOL(pTmp);
+ }
+ else
+ {
+ pAfList = &pTmp->NextOpen;
+ }
+ }
+
+ ASSERT (IsListEmpty(&Open->ActiveVcHead));
+ ASSERT (IsListEmpty(&Open->InactiveVcHead));
+}
+
+
+NDIS_STATUS
+NdisCoRequest(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE NdisAfHandle OPTIONAL,
+ IN NDIS_HANDLE NdisVcHandle OPTIONAL,
+ IN NDIS_HANDLE NdisPartyHandle OPTIONAL,
+ IN PNDIS_REQUEST NdisRequest
+ )
+/*++
+
+Routine Description:
+
+ This api is used for two separate paths.
+ 1. A symmetric call between the client and the call-manager. This mechanism is a
+ two-way mechanism for the call-manager and client to communicate with each other in an
+ asynchronous manner.
+ 2. A request down to the miniport.
+
+Arguments:
+
+ NdisBindingHandle - Specifies the binding and identifies the caller as call-manager/client
+ NdisAfHandle - Pointer to the AF Block and identifies the target. If absent, the
+ request is targeted to the miniport.
+ NdisVcHandle - Pointer to optional VC block. If present the request relates to the
+ VC
+ NdisPartyHandle - Pointer to the optional Party Block. If present the request relates
+ to the party.
+ NdisRequest - The request itself
+
+Return Value:
+ NDIS_STATUS_PENDING if the target pends the call.
+ NDIS_STATUS_FAILURE if the binding or af is closing.
+ Anything else return code from the other end.
+
+--*/
+{
+ PNDIS_M_OPEN_BLOCK Open;
+ PNDIS_CO_AF_BLOCK pAf;
+ NDIS_HANDLE VcContext;
+ PNDIS_COREQ_RESERVED ReqRsvd;
+ NDIS_STATUS Status;
+
+ ReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(NdisRequest);
+ Open = (PNDIS_M_OPEN_BLOCK)(((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacBindingHandle);
+
+ do
+ {
+ if (ARGUMENT_PRESENT(NdisAfHandle))
+ {
+ CO_REQUEST_HANDLER CoRequestHandler;
+ NDIS_HANDLE AfContext, PartyContext;
+
+ pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
+ //
+ // Attempt to reference the AF
+ //
+ if (!ndisReferenceAf(pAf))
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ VcContext = NULL;
+ PartyContext = NULL;
+ NdisZeroMemory(ReqRsvd, sizeof(NDIS_COREQ_RESERVED));
+
+ //
+ // Figure out who we are and call the peer
+ //
+ if (pAf->ClientOpen == Open)
+ {
+ //
+ // This is the client, so call the call-manager's CoRequestHandler
+ //
+ CoRequestHandler =
+ pAf->CallMgrOpen->ProtocolHandle->ProtocolCharacteristics.CoRequestHandler;
+ AfContext = pAf->CallMgrContext;
+ ReqRsvd->AfContext = pAf->ClientContext;
+ ReqRsvd->CoRequestCompleteHandler = Open->CoRequestCompleteHandler;
+ if (ARGUMENT_PRESENT(NdisVcHandle))
+ {
+ VcContext = ((PNDIS_CO_VC_BLOCK)NdisVcHandle)->CallMgrContext;
+ }
+ if (ARGUMENT_PRESENT(NdisPartyHandle))
+ {
+ PartyContext = ((PNDIS_CO_PARTY_BLOCK)NdisPartyHandle)->CallMgrContext;
+ }
+ }
+ else
+ {
+ ASSERT (pAf->CallMgrOpen == Open);
+ //
+ // This is the call-manager, so call the client's CoRequestHandler
+ //
+ CoRequestHandler =
+ pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoRequestHandler;
+ AfContext = pAf->ClientContext;
+ ReqRsvd->AfContext = pAf->CallMgrContext;
+ ReqRsvd->CoRequestCompleteHandler = Open->CoRequestCompleteHandler;
+ if (ARGUMENT_PRESENT(NdisVcHandle))
+ {
+ ReqRsvd->VcContext = pAf->CallMgrContext;
+ VcContext = ((PNDIS_CO_VC_BLOCK)NdisVcHandle)->ClientContext;
+ }
+ if (ARGUMENT_PRESENT(NdisPartyHandle))
+ {
+ ReqRsvd->PartyContext = ((PNDIS_CO_PARTY_BLOCK)NdisPartyHandle)->CallMgrContext;
+ PartyContext = ((PNDIS_CO_PARTY_BLOCK)NdisPartyHandle)->ClientContext;
+ }
+ }
+
+ //
+ // Now call the handler
+ //
+ Status = (*CoRequestHandler)(AfContext, VcContext, PartyContext, NdisRequest);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisCoRequestComplete(Status,
+ NdisAfHandle,
+ NdisVcHandle,
+ NdisPartyHandle,
+ NdisRequest);
+
+ Status = NDIS_STATUS_PENDING;
+ }
+ }
+ else
+ {
+ KIRQL OldIrql;
+ PNDIS_MINIPORT_BLOCK Miniport;
+
+ Miniport = Open->MiniportHandle;
+
+ //
+ // Start off by referencing the open.
+ //
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ if (Open->Flags & fMINIPORT_OPEN_CLOSING)
+ {
+ Status = NDIS_STATUS_CLOSING;
+ }
+ else if (Miniport->Flags & (fMINIPORT_RESET_IN_PROGRESS | fMINIPORT_RESET_REQUESTED))
+ {
+ Status = NDIS_STATUS_RESET_IN_PROGRESS;
+ }
+ else
+ {
+ Open->References ++;
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ ReqRsvd->Open = Open;
+ ReqRsvd->CoRequestCompleteHandler = Open->CoRequestCompleteHandler;
+ ReqRsvd->VcContext = NULL;
+ ReqRsvd->Flags = COREQ_DOWNLEVEL;
+ ReqRsvd->RealRequest = NdisRequest;
+ if (ARGUMENT_PRESENT(NdisVcHandle))
+ {
+ ReqRsvd->VcContext = ((PNDIS_CO_VC_BLOCK)NdisVcHandle)->ClientContext;
+ }
+
+ //
+ // Call the miniport's CoRequest Handler
+ //
+ Status = (*Open->MiniportCoRequestHandler)(Open->MiniportAdapterContext,
+ (NdisVcHandle != NULL) ?
+ ((PNDIS_CO_VC_BLOCK)NdisVcHandle)->MiniportContext :
+ NULL,
+ NdisRequest);
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisMCoRequestComplete(Status,
+ Open->MiniportHandle,
+ NdisRequest);
+ }
+ }
+
+ }
+ } while (FALSE);
+
+ return Status;
+}
+
+
+VOID
+NdisCoRequestComplete(
+ IN NDIS_STATUS Status,
+ IN NDIS_HANDLE NdisAfHandle,
+ IN NDIS_HANDLE NdisVcHandle OPTIONAL,
+ IN NDIS_HANDLE NdisPartyHandle OPTIONAL,
+ IN PNDIS_REQUEST NdisRequest
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_COREQ_RESERVED ReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(NdisRequest);
+
+ //
+ // Simply call the request completion handler and deref the Af block
+ //
+ (*ReqRsvd->CoRequestCompleteHandler)(Status,
+ ReqRsvd->AfContext,
+ ReqRsvd->VcContext,
+ ReqRsvd->PartyContext,
+ NdisRequest);
+ ndisDereferenceAf((PNDIS_CO_AF_BLOCK)NdisAfHandle);
+}
+
+
+VOID
+NdisMCoRequestComplete(
+ IN NDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_COREQ_RESERVED ReqRsvd;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ ReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(NdisRequest);
+ Miniport = (PNDIS_MINIPORT_BLOCK)NdisBindingHandle;
+ Open = ReqRsvd->Open;
+
+ if ((NdisRequest->RequestType == NdisRequestQueryInformation) &&
+ (NdisRequest->DATA.QUERY_INFORMATION.Oid == OID_GEN_CURRENT_PACKET_FILTER) &&
+ (NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength != 0))
+ {
+ if (Open->Flags & fMINIPORT_OPEN_PMODE)
+ {
+ *(PULONG)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer) |=
+ NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL;
+ }
+ }
+
+ if (Open != NULL)
+ {
+ PNDIS_REQUEST RealRequest;
+ KIRQL OldIrql;
+
+ RealRequest = NdisRequest;
+ if (ReqRsvd->RealRequest != NULL)
+ {
+ RealRequest = ReqRsvd->RealRequest;
+ RealRequest->DATA.QUERY_INFORMATION.BytesWritten = NdisRequest->DATA.QUERY_INFORMATION.BytesWritten;
+ RealRequest->DATA.QUERY_INFORMATION.BytesNeeded = NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded;
+ }
+
+ RealRequest = (ReqRsvd->RealRequest == NULL) ? NdisRequest : ReqRsvd->RealRequest;
+ ASSERT ((ReqRsvd->Flags & (COREQ_GLOBAL_REQ | COREQ_QUERY_OIDS)) == 0);
+
+ if (ReqRsvd->Flags == COREQ_DOWNLEVEL)
+ {
+ ASSERT(RealRequest != NdisRequest);
+
+ //
+ // Complete the request to the protocol and deref the open
+ //
+ (*ReqRsvd->RequestCompleteHandler)(ReqRsvd->Open->ProtocolBindingContext,
+ RealRequest,
+ Status);
+ FREE_POOL(NdisRequest);
+ }
+ else
+ {
+ ASSERT(RealRequest == NdisRequest);
+
+ //
+ // Complete the request to the protocol and deref the open
+ //
+ (*ReqRsvd->CoRequestCompleteHandler)(Status,
+ ReqRsvd->Open->ProtocolBindingContext,
+ ReqRsvd->VcContext,
+ NULL,
+ NdisRequest);
+ }
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ Open->References --;
+ if (Open->References == 0)
+ {
+ ndisMFinishClose(Miniport, Open);
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+ }
+ else if (ReqRsvd->Flags == COREQ_GLOBAL_REQ)
+ {
+ PIRP Irp;
+ PNDIS_QUERY_GLOBAL_REQUEST GlobalRequest;
+
+ GlobalRequest = CONTAINING_RECORD(NdisRequest,
+ NDIS_QUERY_GLOBAL_REQUEST,
+ Request);
+
+ ASSERT(ReqRsvd->RealRequest == NULL);
+ Irp = GlobalRequest->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;
+ }
+
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ FREE_POOL (GlobalRequest);
+ }
+ else if (ReqRsvd->Flags == COREQ_QUERY_OIDS)
+ {
+ PNDIS_QUERY_OPEN_REQUEST OpenReq;
+
+ ASSERT(ReqRsvd->RealRequest == NULL);
+ OpenReq = CONTAINING_RECORD(NdisRequest,
+ NDIS_QUERY_OPEN_REQUEST,
+ Request);
+ OpenReq->NdisStatus = Status;
+ SET_EVENT(&OpenReq->Event);
+ }
+ else if (ReqRsvd->Flags == COREQ_QUERY_STATS)
+ {
+ PNDIS_QUERY_ALL_REQUEST AllReq;
+
+ ASSERT(ReqRsvd->RealRequest == NULL);
+ AllReq = CONTAINING_RECORD(NdisRequest,
+ NDIS_QUERY_ALL_REQUEST,
+ Request);
+ AllReq->NdisStatus = Status;
+ SET_EVENT(&AllReq->Event);
+ }
+ else if (ReqRsvd->Flags == COREQ_QUERY_SET)
+ {
+ PNDIS_QS_REQUEST QSReq;
+
+ ASSERT(ReqRsvd->RealRequest == NULL);
+ QSReq = CONTAINING_RECORD(NdisRequest,
+ NDIS_QS_REQUEST,
+ Request);
+ QSReq->NdisStatus = Status;
+ SET_EVENT(&QSReq->Event);
+ }
+ else
+ {
+ ASSERT(0);
+ }
+}
+
+
+VOID
+NdisMCoIndicateReceivePacket(
+ IN NDIS_HANDLE NdisVcHandle,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by the Miniport to indicate a set of packets to
+ a particular VC.
+
+Arguments:
+
+ NdisVcHandle - The handle suppplied by Ndis when the VC on which
+ data is received was first reserved.
+
+ PacketArray - Array of packets.
+
+ NumberOfPackets - Number of packets being indicated.
+
+Return Value:
+
+ None.
+--*/
+{
+ UINT i, Ref, NumPmodeOpens;
+ PPNDIS_PACKET pPktArray;
+ NDIS_STATUS Status;
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ PNDIS_MINIPORT_BLOCK Miniport;
+
+ Miniport = Vc->Miniport;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
+
+ //
+ // NOTE that checking Vc Flags for Closing should not be needed since the CallMgr
+ // holds onto the protocol's CloseCall request until the ref count goes to zero -
+ // which means the miniport has to have completed its RELEASE_VC, which will
+ // inturn mandate that we will NOT get any further indications from it.
+ // The miniport must not complete a RELEASE_VC until it is no longer indicating data.
+ //
+ for (i = 0, pPktArray = PacketArray;
+ i < NumberOfPackets;
+ i++, pPktArray++)
+ {
+ PNDIS_PACKET Packet;
+ NDIS_STATUS SavedStatus;
+
+ Packet = *pPktArray;
+ ASSERT(Packet != NULL);
+
+ //
+ // Set context in the packet so that NdisReturnPacket can do the right thing
+ //
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount = 0;
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->Miniport = Miniport;
+
+ //
+ // Ensure that we force re-calculation.
+ //
+ Packet->Private.ValidCounts = FALSE;
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ //
+ // Indicate the packet to the binding.
+ //
+ Ref = (*Vc->CoReceivePacketHandler)(Vc->ClientOpen->ProtocolBindingContext,
+ Vc->ClientContext,
+ Packet);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ if (Ref > 0)
+ {
+ ASSERT(NDIS_GET_PACKET_STATUS(Packet) != NDIS_STATUS_RESOURCES);
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount += Ref;
+ if (PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount != 0)
+ {
+ NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_PENDING);
+ }
+ }
+
+ //
+ // If there are promiscuous opens on this miniport, indicate it to them as well.
+ // The client context will identify the VC.
+ //
+ if (Miniport->PmodeOpens > 0)
+ {
+ PNDIS_M_OPEN_BLOCK pPmodeOpen;
+
+ NumPmodeOpens = Miniport->PmodeOpens;
+ for (pPmodeOpen = Miniport->OpenQueue;
+ (NumPmodeOpens > 0);
+ pPmodeOpen = pPmodeOpen->MiniportNextOpen)
+ {
+ if (pPmodeOpen->Flags & fMINIPORT_OPEN_PMODE)
+ {
+ pPmodeOpen->ReceivedAPacket = TRUE;
+ SavedStatus = NDIS_GET_PACKET_STATUS(Packet);
+ NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_RESOURCES);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ //
+ // For Pmode opens, we pass the VcId to the indication routine
+ // since the protocol does not really own the VC.
+ //
+ Ref = (*pPmodeOpen->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler)(
+ pPmodeOpen->ProtocolBindingContext,
+ Vc->pVcId,
+ Packet);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ ASSERT(Ref == 0);
+ NDIS_SET_PACKET_STATUS(Packet, SavedStatus);
+
+ NumPmodeOpens --;
+ }
+ }
+ }
+ }
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ //
+ // It should be impossible to assert here
+ // since the pVc will not lose all of its reference counts
+ // until the Miniport completes the RELEASE_VC which is should not
+ // do UNTIL there are no outstanding indications.
+ //
+ ASSERT(Vc->References);
+
+}
+
+
+VOID
+NdisMCoReceiveComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by the Miniport to indicate that the receive
+ process is complete to all bindings. Only those bindings which
+ have received packets will be notified. The Miniport lock is held
+ when this is called.
+
+Arguments:
+
+ MiniportAdapterHandle - The handle supplied by Ndis at initialization
+ time through miniport initialize.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ //
+ // check all of the bindings on this adapter
+ //
+ for (Open = Miniport->OpenQueue;
+ Open != NULL;
+ NOTHING)
+ {
+ if (((Open->Flags & fMINIPORT_OPEN_CLOSING) == 0) &&
+ Open->ReceivedAPacket)
+ {
+ //
+ // Indicate the binding.
+ //
+
+ Open->ReceivedAPacket = FALSE;
+
+ Open->References++;
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (*Open->ReceiveCompleteHandler)(Open->ProtocolBindingContext);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ //
+ // possibly the client closed the adapter in the time interval where
+ // the spin lock is released.
+ //
+ if ((--Open->References) == 0)
+ {
+ //
+ // This binding is shutting down. We have to kill it.
+ //
+ ndisMFinishClose(Miniport, Open);
+
+ //
+ // we have to start over in the loop through all of the
+ // Opens since the finishClose could have remove one or more
+ // opens from the list
+ //
+ Open = Miniport->OpenQueue;
+ }
+ else if (Open->Flags & fMINIPORT_OPEN_CLOSING)
+ {
+ //
+ // This Open has been dequeued from the miniport so start over
+ // at the beginning of the list
+ //
+ Open = Miniport->OpenQueue;
+ }
+ }
+ else
+ {
+ Open = Open->MiniportNextOpen;
+ }
+ }
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+}
+
+
+VOID
+NdisCoSendPackets(
+ IN NDIS_HANDLE NdisVcHandle,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PNDIS_PACKET Packet;
+ ULONG PacketCount;
+ NDIS_STATUS s;
+ ULONG NumPmodeOpens;
+
+ //
+ // If there are promiscuous opens on this miniport, this must be indicated to them.
+ // Do this before it is send down to the miniport to preserve packet ordering.
+ //
+ Miniport = Vc->Miniport;
+ if (Miniport->PmodeOpens > 0)
+ {
+ PNDIS_M_OPEN_BLOCK pPmodeOpen;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ NumPmodeOpens = Miniport->PmodeOpens;
+ for (pPmodeOpen = Miniport->OpenQueue;
+ (NumPmodeOpens > 0);
+ pPmodeOpen = pPmodeOpen->MiniportNextOpen)
+ {
+ if (pPmodeOpen->Flags & fMINIPORT_OPEN_PMODE)
+ {
+ ULONG Ref;
+
+ pPmodeOpen->ReceivedAPacket = TRUE;
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ PacketCount = NumberOfPackets;
+ Packet = *PacketArray;
+ while (PacketCount--)
+ {
+ //
+ // For Pmode opens, we pass the VcId to the indication routine
+ // since the protocol does not really own the VC. On lookback
+ // the packet cannot be held.
+ //
+ s = NDIS_GET_PACKET_STATUS(Packet);
+ NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_RESOURCES);
+ Ref = (*pPmodeOpen->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler)(
+ pPmodeOpen->ProtocolBindingContext,
+ Vc->pVcId,
+ Packet);
+
+ ASSERT (Ref == 0);
+ NDIS_SET_PACKET_STATUS(Packet, s);
+
+ Packet++;
+ }
+ NumPmodeOpens--;
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ }
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ }
+
+ //
+ // Simply call down to the miniport. The miniport must complete the sends for
+ // all cases. The send either succeeds/pends or fails. The miniport cannot
+ // ask the wrapper to queue it.
+ //
+ (*Vc->WCoSendPacketsHandler)(Vc->MiniportContext,
+ PacketArray,
+ NumberOfPackets);
+
+ PacketCount = NumberOfPackets;
+ Packet = *PacketArray;
+ while (PacketCount--)
+ {
+ NDIS_STATUS s;
+ s = NDIS_GET_PACKET_STATUS(Packet);
+ if (s != NDIS_STATUS_PENDING)
+ {
+ (Vc->CoSendCompleteHandler)(s,
+ Vc->ClientContext,
+ Packet);
+ }
+ }
+}
+
+
+VOID
+NdisMCoSendComplete(
+ IN NDIS_STATUS Status,
+ IN NDIS_HANDLE NdisVcHandle,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+ This function is called by the miniport when a send has completed. This
+ routine simply calls the protocol to pass along the indication.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+ NdisVcHandle - the handle supplied to the adapter on the OID_RESERVE_VC
+ PacketArray - a ptr to an array of NDIS_PACKETS
+ NumberOfPackets - the number of packets in PacketArray
+ Status - the send status that applies to all packets in the array
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PNDIS_M_OPEN_BLOCK Open;
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+
+ //
+ // There should not be any reason to grab the spin lock and increment the
+ // ref count on Open since the open cannot close until the Vc closes and
+ // the Vc cannot close in the middle of an indication because the miniport
+ // will not complete a RELEASE_VC until is it no longer indicating
+ //
+ //
+ // Indicate to Protocol;
+ //
+
+ Open = Vc->ClientOpen;
+ Miniport = Vc->Miniport;
+
+ (Vc->CoSendCompleteHandler)(Status,
+ Vc->ClientContext,
+ Packet);
+
+ //
+ // Technically this Vc should not close since there is a send outstanding
+ // on it, and the client should not close a Vc with an outstanding send.
+ //
+ ASSERT(Vc->References);
+ ASSERT(Open->References);
+}
+
+
+VOID
+NdisMCoIndicateStatus(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE NdisVcHandle,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN ULONG StatusBufferSize
+ )
+/*++
+
+Routine Description:
+
+ This routine handles passing CoStatus to the protocol. The miniport calls
+ this routine when it has status on a VC or a general status for all Vcs - in
+ this case the NdisVcHandle is null.
+
+Arguments:
+
+ MiniportAdapterHandle - pointer to the mini-port block;
+ NdisVcHandle - a pointer to the Vc block
+ GeneralStatus - the completion status of the request.
+ StatusBuffer - a buffer containing medium and status specific info
+ StatusBufferSize - the size of the buffer.
+
+Return Value:
+
+ none
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ if (Vc != NULL)
+ {
+ Open = Vc->ClientOpen;
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.CoStatusHandler)(
+ Open->ProtocolBindingContext,
+ Vc->ClientContext,
+ GeneralStatus,
+ StatusBuffer,
+ StatusBufferSize);
+ }
+ else
+ {
+ //
+ // this must be a general status for all clients of this miniport
+ // since the Vc handle is null, so indicate this to all protocols.
+ //
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ for (Open = Miniport->OpenQueue;
+ Open != NULL;
+ NOTHING)
+ {
+ if ((Open->Flags & fMINIPORT_OPEN_CLOSING) == 0)
+ {
+ Open->References++;
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.CoStatusHandler)(
+ Open->ProtocolBindingContext,
+ NULL,
+ GeneralStatus,
+ StatusBuffer,
+ StatusBufferSize);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ //
+ // possibly the client closed the adapter in the time interval where
+ // the spin lock is released.
+ //
+ if ((--Open->References) == 0)
+ {
+ //
+ // This binding is shutting down. We have to kill it.
+ //
+ ndisMFinishClose(Miniport, Open);
+
+ //
+ // we have to start over in the loop through all of the
+ // Opens since the finishClose could have remove one or more
+ // opens from the list - this may result in status being indicated
+ // twice to a particular protocol....
+ //
+ Open = Miniport->OpenQueue;
+ continue;
+
+ }
+ else if (Open->Flags & fMINIPORT_OPEN_CLOSING)
+ {
+ //
+ // This Open has been dequeued from the miniport so start over
+ // at the beginning of the list
+ //
+ Open = Miniport->OpenQueue;
+ continue;
+ }
+ }
+ Open = Open->MiniportNextOpen;
+ }
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ }
+}
+
+
+NDIS_STATUS
+ndisMRejectSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+ This routine handles any error cases where a protocol binds to an Atm
+ miniport and tries to use the normal NdisSend() call.
+
+Arguments:
+
+ NdisBindingHandle - Handle returned by NdisOpenAdapter.
+
+ Packet - the Ndis packet to send
+
+
+Return Value:
+
+ NDIS_STATUS - always fails
+
+--*/
+{
+ return(NDIS_STATUS_NOT_SUPPORTED);
+}
+
+
+VOID
+ndisMRejectSendPackets(
+ IN PNDIS_OPEN_BLOCK OpenBlock,
+ IN PPNDIS_PACKET Packet,
+ IN UINT NumberOfPackets
+ )
+/*++
+
+Routine Description:
+
+ This routine handles any error cases where a protocol binds to an Atm
+ miniport and tries to use the normal NdisSend() call.
+
+Arguments:
+
+ OpenBlock - Pointer to the NdisOpenBlock
+
+ Packet - Pointer to the array of packets to send
+
+ NumberOfPackets - self-explanatory
+
+
+Return Value:
+
+ None - SendCompleteHandler is called for the protocol calling this.
+
+--*/
+{
+ PNDIS_M_OPEN_BLOCK MiniportOpen = (PNDIS_M_OPEN_BLOCK)(OpenBlock->MacBindingHandle);
+ UINT i;
+
+ for (i = 0; i < NumberOfPackets; i++)
+ {
+ (*MiniportOpen->SendCompleteHandler)(MiniportOpen->ProtocolBindingContext,
+ Packet[i],
+ NDIS_STATUS_NOT_SUPPORTED);
+ }
+}
+
+
+NDIS_STATUS
+ndisMWrappedRequest(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+/*++
+
+Routine Description:
+
+ This routine handles wrapping an NdisRequest to NdisCoRequest since a NDIS 4.1
+ miniport does not support QueryInformation and SetInformation handlers.
+
+Arguments:
+
+ NdisBindingHandle - Points to the NDIS_OPEN_BLOCK
+
+ NdisRequest - The request
+
+
+Return Value:
+
+ NDIS_STATUS_PENDING If the request pends or an appropriate code if it succeeds/fails
+
+--*/
+{
+ PNDIS_M_OPEN_BLOCK Open;
+ KIRQL OldIrql;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PNDIS_COREQ_RESERVED ReqRsvd;
+ PNDIS_REQUEST NewReq;
+ NDIS_STATUS Status;
+ PULONG Filter;
+
+
+ Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+ Miniport = Open->MiniportHandle;
+
+ //
+ // Start off by allocating a request. We do this since the original request is not
+ // big enough to accomodate the ReqRsvd block
+ //
+ NewReq = ALLOC_FROM_POOL(sizeof(NDIS_REQUEST), NDIS_TAG_CO);
+ if (NewReq == NULL)
+ {
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ //
+ // Copy the original request to the new structure
+ //
+ NewReq->RequestType = NdisRequest->RequestType;
+ NewReq->DATA.SET_INFORMATION.Oid = NdisRequest->DATA.SET_INFORMATION.Oid;
+ NewReq->DATA.SET_INFORMATION.InformationBuffer = NdisRequest->DATA.SET_INFORMATION.InformationBuffer;
+ NewReq->DATA.SET_INFORMATION.InformationBufferLength = NdisRequest->DATA.SET_INFORMATION.InformationBufferLength;
+
+ ReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(NewReq);
+ ReqRsvd->RealRequest = NdisRequest;
+
+ //
+ // Start off by referencing the open.
+ //
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ if (Open->Flags & fMINIPORT_OPEN_CLOSING)
+ {
+ Status = NDIS_STATUS_CLOSING;
+ }
+ else if (Miniport->Flags & (fMINIPORT_RESET_IN_PROGRESS | fMINIPORT_RESET_REQUESTED))
+ {
+ Status = NDIS_STATUS_RESET_IN_PROGRESS;
+ }
+ else
+ {
+ Open->References ++;
+ Status = NDIS_STATUS_SUCCESS;
+
+ Filter = (PULONG)(NdisRequest->DATA.SET_INFORMATION.InformationBuffer);
+
+ //
+ // If this was a request to turn p-mode/l-only on/off then mark things appropriately
+ //
+ if ((NdisRequest->RequestType == NdisRequestSetInformation) &&
+ (NdisRequest->DATA.SET_INFORMATION.Oid == OID_GEN_CURRENT_PACKET_FILTER))
+ {
+ if (*Filter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL))
+ {
+ if ((Open->Flags & fMINIPORT_OPEN_PMODE) == 0)
+ {
+ Open->Flags |= fMINIPORT_OPEN_PMODE;
+ Miniport->PmodeOpens ++;
+ }
+ *Filter &= ~(NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL);
+ }
+ else
+ {
+ if (Open->Flags & fMINIPORT_OPEN_PMODE)
+ {
+ Open->Flags &= ~fMINIPORT_OPEN_PMODE;
+ Miniport->PmodeOpens --;
+ }
+ }
+ }
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ ReqRsvd->Open = Open;
+ ReqRsvd->RequestCompleteHandler = Open->ProtocolHandle->ProtocolCharacteristics.RequestCompleteHandler;
+ ReqRsvd->VcContext = NULL;
+ ReqRsvd->Flags = COREQ_DOWNLEVEL;
+
+ if ((NdisRequest->RequestType == NdisRequestSetInformation) &&
+ (NdisRequest->DATA.SET_INFORMATION.Oid == OID_GEN_CURRENT_PACKET_FILTER) &&
+ (*Filter == 0))
+ {
+ NewReq->DATA.SET_INFORMATION.BytesRead = 4;
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ //
+ // Call the miniport's CoRequest Handler
+ //
+ Status = (*Open->MiniportCoRequestHandler)(Open->MiniportAdapterContext,
+ NULL,
+ NewReq);
+ }
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisMCoRequestComplete(Status,
+ Open->MiniportHandle,
+ NewReq);
+ Status = NDIS_STATUS_PENDING;
+ }
+ }
+
+ return Status;
+}
+
+
diff --git a/private/ntos/ndis/ndis40/ndisdbg.h b/private/ntos/ndis/ndis40/ndisdbg.h
new file mode 100644
index 000000000..eadfefcc3
--- /dev/null
+++ b/private/ntos/ndis/ndis40/ndisdbg.h
@@ -0,0 +1,270 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ ndisdbg.h
+
+Abstract:
+
+ NDIS wrapper definitions
+
+Author:
+
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Jul-14 Kyle Brandon Added debug supported for conditional breaks.
+--*/
+#ifndef __DEBUG_H
+#define __DEBUG_H
+
+//
+// Define module numbers.
+//
+#define MODULE_NDIS 0x00010000
+#define MODULE_DATA 0x00020000
+#define MODULE_INIT 0x00030000
+#define MODULE_INITPNP 0x00040000
+#define MODULE_COMMON 0x00050000
+#define MODULE_CONFIG 0x00060000
+#define MODULE_CONFIGM 0x00070000
+#define MODULE_BUS 0x00080000
+#define MODULE_TIMER 0x00090000
+#define MODULE_TIMERM 0x000A0000
+#define MODULE_MINIPORT 0x000B0000
+#define MODULE_REQUESTM 0x000C0000
+#define MODULE_MINISUB 0x000D0000
+#define MODULE_MAC 0x000E0000
+#define MODULE_PROTOCOL 0x000F0000
+#define MODULE_EFILTER 0x00100000
+#define MODULE_TFILTER 0x00110000
+#define MODULE_FFILTER 0x00120000
+#define MODULE_AFILTER 0x00130000
+#define MODULE_DEBUG 0x00140000
+#define MODULE_MININT 0x00150000
+#define MODULE_SENDM 0x00160000
+#define MODULE_NDIS_CO 0x00170000
+
+
+#define DBG_LEVEL_INFO 0x00000000
+#define DBG_LEVEL_LOG 0x00000800
+#define DBG_LEVEL_WARN 0x00001000
+#define DBG_LEVEL_ERR 0x00002000
+#define DBG_LEVEL_FATAL 0x00003000
+
+#define DBG_COMP_INIT 0x00000001
+#define DBG_COMP_CONFIG 0x00000002
+#define DBG_COMP_SEND 0x00000004
+#define DBG_COMP_RECV 0x00000008
+#define DBG_COMP_MEMORY 0x00000010
+#define DBG_COMP_FILTER 0x00000020
+#define DBG_COMP_PROTOCOL 0x00000040
+#define DBG_COMP_REQUEST 0x00000080
+#define DBG_COMP_UNLOAD 0x00000100
+#define DBG_COMP_WORK_ITEM 0x00000200
+#define DBG_COMP_OPEN 0x00000400
+#define DBG_COMP_LOCKS 0x00000800
+#define DBG_COMP_ALL 0xFFFFFFFF
+
+#if DBG
+
+#if defined(MEMPRINT)
+#include "memprint.h" // DavidTr's memprint program at ntos\srv
+#endif // MEMPRINT
+
+extern ULONG ndisDebugSystems;
+extern LONG ndisDebugLevel;
+extern ULONG ndisDebugInformationOffset;
+
+#ifdef NDIS_NT
+#define MINIPORT_AT_DPC_LEVEL (CURRENT_IRQL == DISPATCH_LEVEL)
+#else
+#define MINIPORT_AT_DPC_LEVEL 1
+#endif
+
+#define DBGPRINT(Component, Level, Fmt) \
+ { \
+ if ((Level >= ndisDebugLevel) && \
+ ((ndisDebugSystems & Component) == Component)) \
+ { \
+ DbgPrint("***NDIS*** (%x, %d) ", \
+ MODULE_NUMBER >> 16, __LINE__); \
+ DbgPrint Fmt; \
+ } \
+ }
+
+#define DBGBREAK(Component, Level) \
+{ \
+ if ((Level >= ndisDebugLevel) && (ndisDebugSystems & Component)) \
+ { \
+ DbgPrint("***NDIS*** DbgBreak @ %x, %d\n", MODULE_NUMBER, __LINE__); \
+ DbgBreakPoint(); \
+ } \
+}
+
+#define IF_DBG(Component, Level) if ((Level >= ndisDebugLevel) && (ndisDebugSystems & Component))
+
+extern UINT AfilterDebugFlag;
+
+#ifdef NDIS_NT
+#define DbgIsNonPaged(_Address) (MmIsNonPagedSystemAddressValid((PVOID)(_Address)))
+#else
+#define DbgIsNonPaged(_Address) TRUE
+#endif
+
+#define DbgIsPacket(_Packet) \
+ ( ((_Packet)->Private.Pool->PacketLength) > sizeof(_Packet) )
+
+#define DbgIsNull(_Ptr) ( ((PVOID)(_Ptr)) == NULL )
+
+//
+// The following structures are used to hold debugging information
+//
+//
+#if _DBG
+VOID
+ndisMInitializeDebugInformation(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+VOID
+NDISM_LOG_RECV_PACKET(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PVOID Context1,
+ IN PVOID Context2,
+ IN ULONG Ident
+ );
+
+VOID
+NDISM_LOG_PACKET(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PVOID Context1,
+ IN PVOID Context2,
+ IN ULONG Ident
+ );
+
+typedef struct _PACKET_LOG_ENTRY
+{
+ PNDIS_MINIPORT_BLOCK Miniport;
+ PVOID Context1;
+ PVOID Context2;
+ ULONG Ident;
+} PACKET_LOG_ENTRY, *PPACKET_LOG_ENTRY;
+
+typedef struct _SPIN_LOCK_LOG_ENTRY
+{
+ ULONG Ident; // Module & line number.
+ ULONG Function; // Acquire or release.
+ ULONG SpinLock; // Pointer to the spinlock.
+ ULONG filler2;
+} SPIN_LOCK_LOG_ENTRY, *PSPIN_LOCK_LOG_ENTRY;
+
+typedef struct _LOCAL_LOCK_LOG_ENTRY
+{
+ ULONG Ident;
+ ULONG Function;
+ ULONG Status;
+ ULONG filler1;
+} LOCAL_LOCK_LOG_ENTRY, *PLOCAL_LOCK_LOG_ENTRY;
+
+#define LOG_SIZE 1024
+
+typedef struct _PACKET_LOG
+{
+ UINT CurrentEntry;
+ PPACKET_LOG_ENTRY Head;
+ KSPIN_LOCK Lock;
+ PPACKET_LOG_ENTRY Buffer;
+} PACKET_LOG, *PPACKET_LOG;
+
+typedef struct _SPIN_LOCK_LOG
+{
+ UINT CurrentEntry;
+ PSPIN_LOCK_LOG_ENTRY Head;
+ KSPIN_LOCK Lock;
+ PSPIN_LOCK_LOG_ENTRY Buffer;
+} SPIN_LOCK_LOG, *PSPIN_LOCK_LOG;
+
+typedef struct _LOCAL_LOCK_LOG
+{
+ UINT CurrentEntry;
+ PLOCAL_LOCK_LOG_ENTRY Head;
+ KSPIN_LOCK Lock;
+ PLOCAL_LOCK_LOG_ENTRY Buffer;
+} LOCAL_LOCK_LOG, *PLOCAL_LOCK_LOG;
+
+
+typedef struct _NDIS_MOJO
+{
+ PSPIN_LOCK_LOG SpinLockLog;
+ PLOCAL_LOCK_LOG LocalLockLog;
+ PPACKET_LOG SendPacketLog;
+ PPACKET_LOG RecvPacketLog;
+} NDIS_MOJO, *PNDIS_MOJO;
+
+#define NUMBER_OF_LOGS 4
+
+//
+// Macros for referencing the logs.
+//
+#define SPIN_LOCK_LOG(_M) ((PNDIS_MOJO)(_M)->Reserved)->SpinLockLog
+
+#define SL_CURRENT_ENTRY(_M) SPIN_LOCK_LOG((_M))->CurrentEntry
+#define SL_HEAD(_M) SPIN_LOCK_LOG((_M))->Head
+#define SL_LOCK(_M) SPIN_LOCK_LOG((_M))->Lock
+#define SL_LOG(_M) SPIN_LOCK_LOG((_M))->Buffer
+
+#define LOCAL_LOCK_LOG(_M) ((PNDIS_MOJO)(_M)->Reserved)->LocalLockLog
+
+#define LL_CURRENT_ENTRY(_M) LOCAL_LOCK_LOG((_M))->CurrentEntry
+#define LL_HEAD(_M) LOCAL_LOCK_LOG((_M))->Head
+#define LL_LOCK(_M) LOCAL_LOCK_LOG((_M))->Lock
+#define LL_LOG(_M) LOCAL_LOCK_LOG((_M))->Buffer
+
+#define SEND_PACKET_LOG(_M) ((PNDIS_MOJO)(_M)->Reserved)->SendPacketLog
+
+#define SPL_CURRENT_ENTRY(_M) SEND_PACKET_LOG((_M))->CurrentEntry
+#define SPL_HEAD(_M) SEND_PACKET_LOG((_M))->Head
+#define SPL_LOCK(_M) SEND_PACKET_LOG((_M))->Lock
+#define SPL_LOG(_M) SEND_PACKET_LOG((_M))->Buffer
+
+#define RECV_PACKET_LOG(_M) ((PNDIS_MOJO)(_M)->Reserved)->RecvPacketLog
+
+#define RPL_CURRENT_ENTRY(_M) RECV_PACKET_LOG((_M))->CurrentEntry
+#define RPL_HEAD(_M) RECV_PACKET_LOG((_M))->Head
+#define RPL_LOCK(_M) RECV_PACKET_LOG((_M))->Lock
+#define RPL_LOG(_M) RECV_PACKET_LOG((_M))->Buffer
+
+#else
+
+#define ndisMInitializeDebugInformation(_Miniport)
+#define NDISM_LOG_RECV_PACKET(Miniport, Context1, Context2, Ident)
+#define NDISM_LOG_PACKET(Miniport, Context1, Context2, Ident)
+
+#endif // _DBG
+
+#else
+
+#define ndisMInitializeDebugInformation(_Miniport)
+#define NDISM_LOG_RECV_PACKET(Miniport, Context1, Context2, Ident)
+#define NDISM_LOG_PACKET(Miniport, Context1, Context2, Ident)
+
+#define MINIPORT_AT_DPC_LEVEL 1
+#define DBGPRINT(Component, Level, Fmt)
+#define DBGBREAK(Component, Level)
+
+#define DbgIsNonPaged(_Address) TRUE
+#define DbgIsPacket(_Packet) TRUE
+#define DbgIsNull(_Ptr) FALSE
+
+#define IF_DBG(Component, Level) if (FALSE)
+
+#endif
+
+#endif // __DEBUG_H
diff --git a/private/ntos/ndis/ndis40/ndisnt.h b/private/ntos/ndis/ndis40/ndisnt.h
new file mode 100644
index 000000000..978aa33e9
--- /dev/null
+++ b/private/ntos/ndis/ndis40/ndisnt.h
@@ -0,0 +1,325 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ ndisnt.h
+
+Abstract:
+
+ Windows NT Specific macros
+
+Author:
+
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Nov-95 Jameel Hyder Split up from a monolithic file
+--*/
+
+#define Increment(a,b) InterlockedIncrement(a)
+#define Decrement(a,b) InterlockedDecrement(a)
+
+#define CURRENT_THREAD ((LONG)PsGetCurrentThread())
+
+#define CopyMemory(Destination,Source,Length) RtlCopyMemory(Destination,Source,Length)
+#define MoveMemory(Destination,Source,Length) RtlMoveMemory(Destination,Source,Length)
+#define ZeroMemory(Destination,Length) RtlZeroMemory(Destination,Length)
+
+#define INITIALIZE_SPIN_LOCK(_L_) KeInitializeSpinLock(_L_)
+#define ACQUIRE_SPIN_LOCK(_SpinLock, _pOldIrql) ExAcquireSpinLock(_SpinLock, _pOldIrql)
+#define RELEASE_SPIN_LOCK(_SpinLock, _OldIrql) ExReleaseSpinLock(_SpinLock, _OldIrql)
+
+#define ACQUIRE_SPIN_LOCK_DPC(_SpinLock) \
+ { \
+ ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); \
+ ExAcquireSpinLockAtDpcLevel(_SpinLock); \
+ }
+
+#define RELEASE_SPIN_LOCK_DPC(_SpinLock) \
+ { \
+ ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); \
+ ExReleaseSpinLockFromDpcLevel(_SpinLock); \
+ }
+
+
+#define NDIS_ACQUIRE_SPIN_LOCK(_SpinLock, _pOldIrql) ExAcquireSpinLock(&(_SpinLock)->SpinLock, _pOldIrql)
+#define NDIS_RELEASE_SPIN_LOCK(_SpinLock, _OldIrql) ExReleaseSpinLock(&(_SpinLock)->SpinLock, _OldIrql)
+
+
+#define NDIS_ACQUIRE_SPIN_LOCK_DPC(_SpinLock) \
+ { \
+ ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); \
+ ExAcquireSpinLockAtDpcLevel(&(_SpinLock)->SpinLock); \
+ }
+
+#define NDIS_RELEASE_SPIN_LOCK_DPC(_SpinLock) \
+ { \
+ ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); \
+ ExReleaseSpinLockFromDpcLevel(&(_SpinLock)->SpinLock); \
+ }
+
+//
+// Debug versions for the miniport locks.
+//
+#if DBG && _DBG
+
+//
+// LOG macro for use at unknown IRQL.
+//
+#define DBG_LOG_LOCK(_M, _SpinLock, _Ident) \
+{ \
+ KIRQL _OldIrql; \
+ IF_DBG(DBG_COMP_LOCKS, DBG_LEVEL_LOG) \
+ { \
+ ACQUIRE_SPIN_LOCK(&SL_LOCK(_M), &_OldIrql); \
+ SL_HEAD(_M) = &SL_LOG(_M)[SL_CURRENT_ENTRY(_M)]; \
+ SL_HEAD(_M)->Ident = (ULONG)(MODULE_NUMBER | __LINE__); \
+ SL_HEAD(_M)->Function = (ULONG)(_Ident); \
+ SL_HEAD(_M)->SpinLock = (ULONG)_SpinLock; \
+ if (SL_CURRENT_ENTRY(_M)-- == 0) \
+ SL_CURRENT_ENTRY(_M) = (LOG_SIZE - 1); \
+ RELEASE_SPIN_LOCK(&SL_LOCK(_M), _OldIrql); \
+ } \
+}
+
+//
+// LOG macro for use at DPC level.
+//
+#define DBG_LOG_LOCK_DPC(_M, _SpinLock, _Ident) \
+{ \
+ IF_DBG(DBG_COMP_LOCKS, DBG_LEVEL_LOG) \
+ { \
+ ACQUIRE_SPIN_LOCK_DPC(&SL_LOCK(_M)); \
+ SL_HEAD(_M) = &SL_LOG(_M)[SL_CURRENT_ENTRY(_M)]; \
+ SL_HEAD(_M)->Ident = (ULONG)(MODULE_NUMBER | __LINE__); \
+ SL_HEAD(_M)->Function = (ULONG)(_Ident); \
+ SL_HEAD(_M)->SpinLock = (ULONG)_SpinLock; \
+ if (SL_CURRENT_ENTRY(_M)-- == 0) \
+ SL_CURRENT_ENTRY(_M) = (LOG_SIZE - 1); \
+ RELEASE_SPIN_LOCK_DPC(&SL_LOCK(_M)); \
+ } \
+}
+
+
+
+// Miniport Lock macros
+//
+// Debug versions of these macros will log where
+// and by whom they were called.
+//
+#define DBG_LOG_LOCAL_LOCK(_M, _L, _Ident) \
+{ \
+ IF_DBG(DBG_COMP_LOCKS, DBG_LEVEL_LOG) \
+ { \
+ KIRQL lockOldIrql; \
+ ACQUIRE_SPIN_LOCK(&LL_LOCK(_M), &lockOldIrql); \
+ LL_HEAD(_M) = &LL_LOG(_M)[LL_CURRENT_ENTRY(_M)]; \
+ LL_HEAD(_M)->Ident = (ULONG)(MODULE_NUMBER | __LINE__); \
+ LL_HEAD(_M)->Function = (ULONG)(_Ident); \
+ LL_HEAD(_M)->Status = (_L) ? 's' : 'f'; \
+ if (LL_CURRENT_ENTRY(_M)-- == 0) \
+ LL_CURRENT_ENTRY(_M) = (LOG_SIZE - 1); \
+ RELEASE_SPIN_LOCK(&LL_LOCK(_M), lockOldIrql); \
+ } \
+}
+
+#else
+
+#define DBG_LOG_LOCK(_M, _SpinLock, _Ident)
+#define DBG_LOG_LOCK_DPC(_M, _SpinLock, _Ident)
+#define DBG_LOG_LOCAL_LOCK(_M, _L, _Ident)
+
+#endif
+
+#define NDIS_ACQUIRE_COMMON_SPIN_LOCK(_M, _pS, _pIrql, _pT) \
+{ \
+ LONG _original; \
+ \
+ DBG_LOG_LOCK((_M), (_pS), 'a'); \
+ \
+ ExAcquireSpinLock(&(_pS)->SpinLock, _pIrql); \
+ _original = InterlockedExchange((_pT), CURRENT_THREAD); \
+ ASSERT(0 == _original); \
+}
+
+#define NDIS_RELEASE_COMMON_SPIN_LOCK(_M, _pS, _Irql, _pT) \
+{ \
+ DBG_LOG_LOCK((_M), (_pS), 'r'); \
+ \
+ InterlockedExchange((_pT), 0); \
+ ExReleaseSpinLock(&(_pS)->SpinLock, _Irql); \
+}
+
+#define NDIS_ACQUIRE_COMMON_SPIN_LOCK_DPC(_M, _pS, _pT) \
+{ \
+ LONG _original; \
+ ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); \
+ \
+ DBG_LOG_LOCK_DPC((_M), (_pS), 'a'); \
+ \
+ ExAcquireSpinLockAtDpcLevel(&(_pS)->SpinLock); \
+ _original = InterlockedExchange((_pT), CURRENT_THREAD); \
+ ASSERT(0 == _original); \
+}
+
+#define NDIS_RELEASE_COMMON_SPIN_LOCK_DPC(_M, _pS, _pT) \
+{ \
+ ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); \
+ \
+ DBG_LOG_LOCK_DPC((_M), (_pS), 'r'); \
+ \
+ InterlockedExchange((_pT), 0); \
+ ExReleaseSpinLockFromDpcLevel(&(_pS)->SpinLock); \
+}
+
+
+#define NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(_M, _pIrql) \
+ NDIS_ACQUIRE_COMMON_SPIN_LOCK((_M), &(_M)->Lock, (_pIrql), &(_M)->MiniportThread)
+
+#define NDIS_ACQUIRE_SEND_SPIN_LOCK(_M, _pIrql) \
+ NDIS_ACQUIRE_COMMON_SPIN_LOCK((_M), &(_M)->SendLock, (_pIrql), &(_M)->SendThread)
+
+#define NDIS_RELEASE_MINIPORT_SPIN_LOCK(_M, _Irql) \
+ NDIS_RELEASE_COMMON_SPIN_LOCK((_M), &(_M)->Lock, (_Irql), &(_M)->MiniportThread)
+
+#define NDIS_RELEASE_SEND_SPIN_LOCK(_M, _Irql) \
+ NDIS_RELEASE_COMMON_SPIN_LOCK((_M), &(_M)->SendLock, (_Irql), &(_M)->SendThread)
+
+#define NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(_M) \
+ NDIS_ACQUIRE_COMMON_SPIN_LOCK_DPC((_M), &(_M)->Lock, &(_M)->MiniportThread)
+
+#define NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(_M) \
+ NDIS_ACQUIRE_COMMON_SPIN_LOCK_DPC((_M), &(_M)->SendLock, &(_M)->SendThread)
+
+#define NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(_M) \
+ NDIS_RELEASE_COMMON_SPIN_LOCK_DPC(_M, &(_M)->Lock, &(_M)->MiniportThread)
+
+#define NDIS_RELEASE_SEND_SPIN_LOCK_DPC(_M) \
+ NDIS_RELEASE_COMMON_SPIN_LOCK_DPC(_M, &(_M)->SendLock, &(_M)->SendThread)
+
+#define LOCK_MINIPORT(_M, _L) \
+{ \
+ if ((_M)->LockAcquired) \
+ { \
+ (_L) = FALSE; \
+ } \
+ else \
+ { \
+ (_M)->LockAcquired = TRUE; \
+ (_L) = TRUE; \
+ } \
+ \
+ DBG_LOG_LOCAL_LOCK((_M), (_L), 'l'); \
+}
+
+
+#define UNLOCK_MINIPORT(_M, _L) \
+{ \
+ if (_L) \
+ { \
+ (_M)->LockAcquired = FALSE; \
+ } \
+ \
+ DBG_LOG_LOCAL_LOCK((_M), (_L), 'u'); \
+}
+
+
+#define BLOCK_LOCK_MINIPORT(_M, _L) \
+ { \
+ KIRQL OldIrql; \
+ \
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(_M, &OldIrql); \
+ LOCK_MINIPORT(_M, _L); \
+ while (!_L) { \
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(_M, OldIrql); \
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(_M, &OldIrql); \
+ LOCK_MINIPORT(_M, _L); \
+ } \
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(_M, OldIrql); \
+ }
+
+#define BLOCK_LOCK_MINIPORT_DPC(_M, _L) \
+ { \
+ KIRQL OldIrql; \
+ \
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(_M); \
+ LOCK_MINIPORT(_M, _L); \
+ while (!_L) { \
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(_M); \
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(_M); \
+ LOCK_MINIPORT(_M, _L); \
+ } \
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(_M); \
+ }
+
+//
+// Some macros for platform independence
+//
+
+#if TRACK_MEMORY
+
+#define ALLOC_FROM_POOL(_Size_, _Tag_) AllocateM(_Size_, \
+ MODULE_NUMBER | __LINE__, \
+ _Tag_)
+#define FREE_POOL(_P_) FreeM(_P_)
+
+#else
+
+#define ALLOC_FROM_POOL(_Size_, _Tag_) ExAllocatePoolWithTag(NonPagedPool, \
+ _Size_, \
+ _Tag_)
+#define FREE_POOL(_P_) ExFreePool(_P_)
+
+#endif
+
+#define INITIALIZE_WORK_ITEM(_W, _R, _C) ExInitializeWorkItem(_W, _R, _C)
+#define QUEUE_WORK_ITEM(_W, _Q) ExQueueWorkItem(_W, _Q)
+
+#define CURRENT_IRQL KeGetCurrentIrql()
+#define RAISE_IRQL_TO_DISPATCH(_pIrql_) KeRaiseIrql(DISPATCH_LEVEL, _pIrql_)
+#define LOWER_IRQL(_Irql_) KeLowerIrql(_Irql_)
+
+#define INITIALIZE_TIMER(_Timer_) KeInitializeTimer(_Timer_)
+#define INITIALIZE_TIMER_EX(_Timer_,_Type_) KeInitializeTimerEx(_Timer_, _Type_)
+#define CANCEL_TIMER(_Timer_) KeCancelTimer(_Timer_)
+#define SET_TIMER(_Timer_, _Time_, _Dpc_) KeSetTimer(_Timer_, _Time_, _Dpc_)
+#define SET_PERIODIC_TIMER(_Timer_, _DueTime_, _PeriodicTime_, _Dpc_) \
+ KeSetTimerEx(_Timer_, _DueTime_, _PeriodicTime_, _Dpc_)
+
+#define INITIALIZE_EVENT(_pEvent_) KeInitializeEvent(_pEvent_, NotificationEvent, FALSE)
+#define SET_EVENT(_pEvent_) KeSetEvent(_pEvent_, 0, FALSE)
+#define RESET_EVENT(_pEvent_) KeResetEvent(_pEvent_)
+
+#define INITIALIZE_MUTEX(_M_) KeInitializeMutex(_M_, 0xFFFF)
+#define RELEASE_MUTEX(_M_) KeReleaseMutex(_M_, FALSE)
+
+#define WAIT_FOR_OBJECT(_O_, _TO_) KeWaitForSingleObject(_O_, \
+ Executive, \
+ KernelMode, \
+ TRUE, \
+ _TO_) \
+
+#define QUEUE_DPC(_pDpc_) KeInsertQueueDpc(_pDpc_, NULL, NULL)
+#define INITIALIZE_DPC(_pDpc_, _R_, _C_) KeInitializeDpc(_pDpc_, _R_, _C_)
+#define SET_DPC_IMPORTANCE(_pDpc_) KeSetImportanceDpc(_pDpc_, LowImportance)
+#define SET_PROCESSOR_DPC(_pDpc_, _R_) if (!ndisSkipProcessorAffinity) \
+ KeSetTargetProcessorDpc(_pDpc_, _R_)
+#define SYNC_WITH_ISR(_O_, _F_, _C_) KeSynchronizeExecution(_O_, \
+ (PKSYNCHRONIZE_ROUTINE)(_F_), \
+ _C_)
+
+#define MDL_ADDRESS(_MDL_) MmGetSystemAddressForMdl(_MDL_)
+#define MDL_SIZE(_MDL_) MmGetMdlByteCount(_MDL_)
+#define MDL_OFFSET(_MDL_) MmGetMdlByteOffset(_MDL_)
+#define MDL_VA(_MDL_) MmGetMdlVirtualAddress(_MDL_)
+
+#define NDIS_EQUAL_UNICODE_STRING(s1, s2) (((s1)->Length == (s2)->Length) && \
+ RtlEqualMemory((s1)->Buffer, (s2)->Buffer, (s1)->Length))
+#define CHAR_TO_INT(_s, _b, _p) RtlCharToInteger(_s, _b, _p)
+
diff --git a/private/ntos/ndis/ndis40/ndistags.h b/private/ntos/ndis/ndis40/ndistags.h
new file mode 100644
index 000000000..55b1a8cec
--- /dev/null
+++ b/private/ntos/ndis/ndis40/ndistags.h
@@ -0,0 +1,53 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ ndistags.h
+
+Abstract:
+
+ List of pool tags used by the NDIS Wraper.
+
+Author:
+
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Mar-96 Jameel Hyder Initial version
+--*/
+
+#ifndef _NDISTAGS_
+#define _NDISTAGS_
+
+#define NDIS_TAG_DEFAULT ' DN'
+#define NDIS_TAG_WORK_ITEM 'iwDN'
+#define NDIS_TAG_NAME_BUF 'naDN'
+#define NDIS_TAG_CO 'ocDN'
+#define NDIS_TAG_DMA 'bdDN'
+#define NDIS_TAG_ALLOC_MEM 'maDN'
+#define NDIS_TAG_SLOT_INFO 'isDN'
+#define NDIS_TAG_PKT_POOL 'ppDN'
+#define NDIS_TAG_RSRC_LIST 'lrDN'
+#define NDIS_TAG_LOOP_PKT 'plDN'
+#define NDIS_TAG_Q_REQ 'qrDN'
+#define NDIS_TAG_PROT_BLK 'bpDN'
+#define NDIS_TAG_OPEN_BLK 'boDN'
+#define NDIS_TAG_DFRD_TMR 'tdDN'
+#define NDIS_TAG_LA_BUF 'blDN'
+#define NDIS_TAG_MAC_BLOCK 'bMDN'
+#define NDIS_TAG_MAP_REG 'rmDN'
+#define NDIS_TAG_MINI_BLOCK 'bmDN'
+#define NDIS_TAG_DBG ' dDN'
+#define NDIS_TAG_DBG_S 'sdDN'
+#define NDIS_TAG_DBG_L 'ldDN'
+#define NDIS_TAG_DBG_P 'pdDN'
+#define NDIS_TAG_DBG_LOG 'lDDN'
+#define NDIS_TAG_FILTER 'fpDN'
+#define NDIS_TAG_STRING 'tsDN'
+#endif // _NDISTAGS_
diff --git a/private/ntos/ndis/ndis40/pragma.h b/private/ntos/ndis/ndis40/pragma.h
new file mode 100644
index 000000000..ec73aeebb
--- /dev/null
+++ b/private/ntos/ndis/ndis40/pragma.h
@@ -0,0 +1,733 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ pragma.h
+
+Abstract:
+
+ Pragma definitions for pageable/init/section-pageable NDIS Wrapper routines.
+
+Author:
+
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Feb-96 Jameel Hyder Moved from individual source files
+--*/
+
+#ifndef _PRAGMA_
+#define _PRAGMA_
+
+#ifdef ALLOC_PRAGMA
+#ifdef NDIS_NT
+
+#pragma alloc_text(INIT, DriverEntry)
+#pragma alloc_text(INIT, ndisReadRegistry)
+#pragma alloc_text(INIT, ndisAddMediaTypeToArray)
+#pragma alloc_text(INIT, ndisReadParameters)
+
+#pragma alloc_text(PAGENPNP, ndisDispatchRequest)
+#pragma alloc_text(PAGENPNP, ndisHandlePnPRequest)
+#pragma alloc_text(PAGENPNP, ndisHandleLoadDriver)
+#pragma alloc_text(PAGENPNP, ndisHandleUnloadDriver)
+#pragma alloc_text(PAGENPNP, ndisHandleTranslateName)
+#pragma alloc_text(PAGENPNP, ndisHandleProtocolNotification)
+#pragma alloc_text(PAGENPNP, ndisReferenceAdapterOrMiniportByName)
+#pragma alloc_text(PAGENPNP, ndisHandleLegacyTransport)
+#pragma alloc_text(PAGENPNP, ndisInitializeBindings)
+#pragma alloc_text(PAGENPNP, NdisCompleteBindAdapter)
+#pragma alloc_text(PAGENPNP, ndisQueuedProtocolNotification)
+#pragma alloc_text(PAGENPNP, NdisCompleteUnbindAdapter)
+#pragma alloc_text(PAGENPNP, NdisRegisterTdiCallBack)
+#pragma alloc_text(PAGENPNP, ndisInitializePackage)
+#pragma alloc_text(PAGENPNP, NdisOpenFile)
+#pragma alloc_text(PAGENPNP, NdisCloseFile)
+#pragma alloc_text(PAGENPNP, NdisQueryMapRegisterCount)
+#pragma alloc_text(PAGENPNP, ndisUnloadMiniport)
+#pragma alloc_text(PAGENPNP, ndisTranslateMiniportName)
+#pragma alloc_text(PAGENPNP, ndisUnloadMac)
+#pragma alloc_text(PAGENPNP, ndisTranslateMacName)
+#pragma alloc_text(PAGENPNP, ndisCreateIrpHandler)
+#pragma alloc_text(PAGENPNP, ndisDeviceControlIrpHandler)
+#pragma alloc_text(PAGENPNP, ndisSuccessIrpHandler)
+
+#pragma alloc_text(PAGENDSI, ndisInitializeAllAdapterInstances)
+#pragma alloc_text(PAGENDSI, ndisInitializeAdapter)
+#pragma alloc_text(PAGENDSI, ndisMInitializeAdapter)
+#pragma alloc_text(PAGENDSI, ndisQueuedBindNotification)
+#pragma alloc_text(PAGENDSI, NdisIMInitializeDeviceInstance)
+#pragma alloc_text(PAGENDSI, NdisIMDeInitializeDeviceInstance)
+#pragma alloc_text(PAGENDSI, ndisValidatePcmciaDriver)
+#pragma alloc_text(PAGENDSI, ndisCheckIfPcmciaCardPresent)
+#pragma alloc_text(PAGENDSI, ndisFixBusInformation)
+#pragma alloc_text(PAGENDSI, ndisAddBusInformation)
+#pragma alloc_text(PAGENDSI, ndisSearchGlobalDb)
+#pragma alloc_text(PAGENDSI, ndisAddGlobalDb)
+#pragma alloc_text(PAGENDSI, ndisDeleteGlobalDb)
+#pragma alloc_text(PAGENDSI, ndisCheckProtocolBinding)
+#pragma alloc_text(PAGENDSI, ndisProtocolAlreadyBound)
+#pragma alloc_text(PAGENDSI, ndisUpdateDriverInstance)
+#pragma alloc_text(PAGENDSI, NdisOpenConfiguration)
+#pragma alloc_text(PAGENDSI, NdisOpenGlobalConfiguration)
+#pragma alloc_text(PAGENDSI, NdisOpenConfigurationKeyByName)
+#pragma alloc_text(PAGENDSI, NdisOpenConfigurationKeyByIndex)
+#pragma alloc_text(PAGENDSI, NdisReadConfiguration)
+#pragma alloc_text(PAGENDSI, NdisWriteConfiguration)
+#pragma alloc_text(PAGENDSI, NdisCloseConfiguration)
+#pragma alloc_text(PAGENDSI, NdisReadBindingInformation)
+#pragma alloc_text(PAGENDSI, NdisReadNetworkAddress)
+#pragma alloc_text(PAGENDSI, NdisConvertStringToAtmAddress)
+#pragma alloc_text(PAGENDSI, ndisSaveLinkage)
+#pragma alloc_text(PAGENDSI, ndisSaveParameters)
+#pragma alloc_text(PAGENDSI, ndisCheckRoute)
+#pragma alloc_text(PAGENDSI, ndisCheckPortUsage)
+#pragma alloc_text(PAGENDSI, ndisStartMapping)
+#pragma alloc_text(PAGENDSI, ndisEndMapping)
+#pragma alloc_text(PAGENDSI, NdisImmediateReadPortUchar)
+#pragma alloc_text(PAGENDSI, NdisImmediateReadPortUshort)
+#pragma alloc_text(PAGENDSI, NdisImmediateReadPortUlong)
+#pragma alloc_text(PAGENDSI, NdisImmediateWritePortUchar)
+#pragma alloc_text(PAGENDSI, NdisImmediateWritePortUshort)
+#pragma alloc_text(PAGENDSI, NdisImmediateWritePortUlong)
+#pragma alloc_text(PAGENDSI, ndisCheckMemoryUsage)
+#pragma alloc_text(PAGENDSI, NdisImmediateReadSharedMemory)
+#pragma alloc_text(PAGENDSI, NdisImmediateWriteSharedMemory)
+#pragma alloc_text(PAGENDSI, NdisInitializeWrapper)
+#pragma alloc_text(PAGENDSI, NdisRegisterAdapterShutdownHandler)
+#pragma alloc_text(PAGENDSI, NdisRegisterMac)
+#pragma alloc_text(PAGENDSI, NdisRegisterAdapter)
+#pragma alloc_text(PAGENDSI, NdisMapIoSpace)
+#pragma alloc_text(PAGENDSI, NdisPciAssignResources)
+#pragma alloc_text(PAGENDSI, NdisAllocateDmaChannel)
+#pragma alloc_text(PAGENDSI, NdisMAllocateMapRegisters)
+#pragma alloc_text(PAGENDSI, NdisMSetAttributes)
+#pragma alloc_text(PAGENDSI, NdisMSetAttributesEx)
+#pragma alloc_text(PAGENDSI, NdisReadEisaSlotInformationEx)
+#pragma alloc_text(PAGENDSI, NdisReadEisaSlotInformation)
+#pragma alloc_text(PAGENDSI, NdisReadMcaPosInformation)
+#pragma alloc_text(PAGENDSI, NdisImmediateReadPciSlotInformation)
+#pragma alloc_text(PAGENDSI, NdisImmediateWritePciSlotInformation)
+#pragma alloc_text(PAGENDSI, NdisOverrideBusNumber)
+#pragma alloc_text(PAGENDSI, NdisInitializeInterrupt)
+
+#pragma alloc_text(PAGENDSM, NdisMRegisterMiniport)
+#pragma alloc_text(PAGENDSM, NdisIMRegisterLayeredMiniport)
+#pragma alloc_text(PAGENDSM, NdisMDeregisterIoPortRange)
+#pragma alloc_text(PAGENDSM, NdisMRegisterIoPortRange)
+#pragma alloc_text(PAGENDSM, NdisMMapIoSpace)
+#pragma alloc_text(PAGENDSM, NdisMUnmapIoSpace)
+#pragma alloc_text(PAGENDSM, NdisMRegisterDmaChannel)
+#pragma alloc_text(PAGENDSM, NdisMDeregisterDmaChannel)
+#pragma alloc_text(PAGENDSM, NdisMAllocateSharedMemory)
+#pragma alloc_text(PAGENDSM, NdisMFreeSharedMemory)
+#pragma alloc_text(PAGENDSM, NdisMReadDmaCounter)
+#pragma alloc_text(PAGENDSM, NdisMFreeMapRegisters)
+#pragma alloc_text(PAGENDSM, NdisMRegisterAdapterShutdownHandler)
+#pragma alloc_text(PAGENDSM, NdisMDeregisterAdapterShutdownHandler)
+#pragma alloc_text(PAGENDSM, NdisMPciAssignResources)
+#pragma alloc_text(PAGENDSM, NdisMInitializeTimer)
+#pragma alloc_text(PAGENDSM, NdisMCancelTimer)
+#pragma alloc_text(PAGENDSM, NdisMDeregisterInterrupt)
+#pragma alloc_text(PAGENDSM, NdisMRegisterInterrupt)
+#pragma alloc_text(PAGENDSM, NdisMSynchronizeWithInterrupt)
+#pragma alloc_text(PAGENDSM, ndisMIsr)
+#pragma alloc_text(PAGENDSM, ndisMDpc)
+#pragma alloc_text(PAGENDSM, ndisMWakeUpDpc)
+#pragma alloc_text(PAGENDSM, ndisMDpcTimer)
+#pragma alloc_text(PAGENDSM, ndisMTimerDpc)
+#pragma alloc_text(PAGENDSM, ndisMDeferredTimerDpc)
+#pragma alloc_text(PAGENDSM, ndisMDeQueueWorkItem)
+#pragma alloc_text(PAGENDSM, ndisMDeQueueWorkItemFullDuplex)
+#pragma alloc_text(PAGENDSM, ndisMQueueWorkItem)
+#pragma alloc_text(PAGENDSM, ndisMQueueWorkItemFullDuplex)
+#pragma alloc_text(PAGENDSM, ndisMQueueNewWorkItem)
+#pragma alloc_text(PAGENDSM, ndisMQueueNewWorkItemFullDuplex)
+#pragma alloc_text(PAGENDSM, ndisMProcessDeferredFullDuplex)
+#pragma alloc_text(PAGENDSM, ndisMProcessDeferred)
+#if _SEND_PRIORITY
+#pragma alloc_text(PAGENDSM, ndisMProcessDeferredFullDuplexPrioritySends)
+#pragma alloc_text(PAGENDSM, ndisMProcessDeferredPrioritySends)
+#endif
+#pragma alloc_text(PAGENDSM, ndisMProcessResetRequested)
+#pragma alloc_text(PAGENDSM, NdisMIndicateStatus)
+#pragma alloc_text(PAGENDSM, NdisMIndicateStatusComplete)
+#pragma alloc_text(PAGENDSM, NdisMWanIndicateReceive)
+#pragma alloc_text(PAGENDSM, NdisMWanIndicateReceiveComplete)
+#pragma alloc_text(PAGENDSM, NdisQueryReceiveInformation)
+#pragma alloc_text(PAGENDSM, NdisReturnPackets)
+#pragma alloc_text(PAGENDSM, ndisMIndicatePacket)
+#pragma alloc_text(PAGENDSM, ndisMLazyReturnPackets)
+#pragma alloc_text(PAGENDSM, NdisMTransferDataComplete)
+#pragma alloc_text(PAGENDSM, ndisMTransferDataSync)
+#pragma alloc_text(PAGENDSM, ndisMTransferData)
+#pragma alloc_text(PAGENDSM, ndisMDummyTransferData)
+#pragma alloc_text(PAGENDSM, ndisMAbortPacketsAndRequests)
+#pragma alloc_text(PAGENDSM, ndisMResetCompleteCommonStep2)
+#pragma alloc_text(PAGENDSM, ndisMResetCompleteCommonStep1)
+#pragma alloc_text(PAGENDSM, ndisMProcessResetRequested)
+#pragma alloc_text(PAGENDSM, ndisMResetCompleteFullDuplex)
+#pragma alloc_text(PAGENDSM, NdisMResetComplete)
+#pragma alloc_text(PAGENDSM, ndisMResetFullDuplex)
+#pragma alloc_text(PAGENDSM, ndisMReset)
+#pragma alloc_text(PAGENDSM, ndisMResetSend)
+#pragma alloc_text(PAGENDSM, ndisMResetSendPackets)
+#pragma alloc_text(PAGENDSM, ndisMFinishClose)
+#pragma alloc_text(PAGENDSM, ndisMKillOpen)
+#pragma alloc_text(PAGENDSM, ndisDeQueueOpenOnMiniport)
+#pragma alloc_text(PAGENDSM, ndisDequeueMiniportOnDriver)
+#pragma alloc_text(PAGENDSM, ndisQueueMiniportOnDriver)
+#pragma alloc_text(PAGENDSM, ndisDereferenceMiniport)
+#pragma alloc_text(PAGENDSM, ndisDereferenceDriver)
+#pragma alloc_text(PAGENDSM, ndisMHaltMiniport)
+#pragma alloc_text(PAGENDSM, ndisMUnload)
+#pragma alloc_text(PAGENDSM, ndisMShutdown)
+#pragma alloc_text(PAGENDSM, ndisMRequest)
+#pragma alloc_text(PAGENDSI, ndisMUndoBogusFilters)
+#pragma alloc_text(PAGENDSI, ndisMDoMiniportOp)
+#pragma alloc_text(PAGENDSM, ndisMRequestQueryInformationPost)
+#pragma alloc_text(PAGENDSM, ndisMSyncQueryInformationComplete)
+#pragma alloc_text(PAGENDSM, NdisMQueryInformationComplete)
+#pragma alloc_text(PAGENDSM, ndisMRequestSetInformationPost)
+#pragma alloc_text(PAGENDSM, ndisMSyncSetInformationComplete)
+#pragma alloc_text(PAGENDSM, NdisMSetInformationComplete)
+#pragma alloc_text(PAGENDSM, ndisMAbortQueryStatisticsRequest)
+#pragma alloc_text(PAGENDSM, ndisMSetPacketFilter)
+#pragma alloc_text(PAGENDSM, ndisMSetCurrentLookahead)
+#pragma alloc_text(PAGENDSM, ndisMSetMulticastList)
+#pragma alloc_text(PAGENDSM, ndisMSetFunctionalAddress)
+#pragma alloc_text(PAGENDSM, ndisMSetGroupAddress)
+#pragma alloc_text(PAGENDSM, ndisMSetFddiMulticastList)
+#pragma alloc_text(PAGENDSM, ndisMSetInformation)
+#pragma alloc_text(PAGENDSM, ndisMQueryCurrentPacketFilter)
+#pragma alloc_text(PAGENDSM, ndisMQueryMediaSupported)
+#pragma alloc_text(PAGENDSM, ndisMQueryEthernetMulticastList)
+#pragma alloc_text(PAGENDSM, ndisMQueryLongMulticastList)
+#pragma alloc_text(PAGENDSM, ndisMQueryShortMulticastList)
+#pragma alloc_text(PAGENDSM, ndisMQueryMaximumFrameSize)
+#pragma alloc_text(PAGENDSM, ndisMQueryMaximumTotalSize)
+#pragma alloc_text(PAGENDSM, ndisMQueryNetworkAddress)
+#pragma alloc_text(PAGENDSM, ndisMQueryInformation)
+#pragma alloc_text(PAGENDSM, ndisMDoRequests)
+#pragma alloc_text(PAGENDSM, ndisMAllocateRequest)
+#pragma alloc_text(PAGENDSM, ndisMQueueRequest)
+#pragma alloc_text(PAGENDSM, ndisMRestoreFilterSettings)
+#pragma alloc_text(PAGENDSM, ndisMFilterOutStatisticsOids)
+#pragma alloc_text(PAGENDSM, ndisMQueryOidList)
+#pragma alloc_text(PAGENDSM, ndisMChangeFddiAddresses)
+#pragma alloc_text(PAGENDSM, ndisMChangeFunctionalAddress)
+#pragma alloc_text(PAGENDSM, ndisMChangeGroupAddress)
+#pragma alloc_text(PAGENDSM, ndisMCloseAction)
+#pragma alloc_text(PAGENDSM, ndisMChangeClass)
+#pragma alloc_text(PAGENDSM, ndisMChangeEthAddresses)
+#pragma alloc_text(PAGENDSM, ndisMCopyFromPacketToBuffer)
+#pragma alloc_text(PAGENDSM, ndisMIndicateLoopback)
+#pragma alloc_text(PAGENDSM, ndisMIsLoopbackPacket)
+#pragma alloc_text(PAGENDSM, ndisMStartSendPacketsFullDuplex)
+#pragma alloc_text(PAGENDSM, ndisMStartSendsFullDuplex)
+#pragma alloc_text(PAGENDSM, ndisMStartSendPackets)
+#pragma alloc_text(PAGENDSM, ndisMStartSends)
+#pragma alloc_text(PAGENDSM, ndisMSyncSend)
+#pragma alloc_text(PAGENDSM, ndisMWanSend)
+#pragma alloc_text(PAGENDSM, NdisMSendComplete)
+#pragma alloc_text(PAGENDSM, ndisMSendCompleteFullDuplex)
+#pragma alloc_text(PAGENDSM, NdisMWanSendComplete)
+#pragma alloc_text(PAGENDSM, ndisMSendResourcesAvailableFullDuplex)
+#pragma alloc_text(PAGENDSM, NdisMSendResourcesAvailable)
+#pragma alloc_text(PAGENDSM, ndisMSendFullDuplex)
+#pragma alloc_text(PAGENDSM, ndisMSend)
+#pragma alloc_text(PAGENDSM, NdisMStartBufferPhysicalMapping)
+#pragma alloc_text(PAGENDSM, NdisMCompleteBufferPhysicalMapping)
+
+#pragma alloc_text(PAGENDSP, ndisMOpenAdapter)
+#pragma alloc_text(PAGENDSP, ndisMSendFullDuplexToSendPackets)
+#pragma alloc_text(PAGENDSP, ndisMSendPacketsFullDuplex)
+#pragma alloc_text(PAGENDSP, ndisMSendToSendPackets)
+#pragma alloc_text(PAGENDSP, ndisMSendPackets)
+#pragma alloc_text(PAGENDSP, ndisMSendPacketsFullDuplexToSend)
+#pragma alloc_text(PAGENDSP, ndisMSendPacketsToSend)
+#pragma alloc_text(PAGENDSP, NdisRegisterProtocol)
+#pragma alloc_text(PAGENDSP, NdisDeregisterProtocol)
+#pragma alloc_text(PAGENDSP, NdisOpenAdapter)
+#pragma alloc_text(PAGENDSP, NdisCloseAdapter)
+#pragma alloc_text(PAGENDSP, NdisSetProtocolFilter)
+#pragma alloc_text(PAGENDSP, NdisGetDriverHandle)
+#pragma alloc_text(PAGENDSP, ndisDereferenceProtocol)
+#pragma alloc_text(PAGENDSP, NdisOpenProtocolConfiguration)
+#pragma alloc_text(PAGENDSP, ndisQueueOpenOnProtocol)
+#pragma alloc_text(PAGENDSP, ndisDeQueueOpenOnProtocol)
+#pragma alloc_text(PAGENDSP, NdisWriteEventLogEntry)
+
+#pragma alloc_text(PAGENDSW, NdisDeregisterMac)
+#pragma alloc_text(PAGENDSW, ndisDpc)
+#pragma alloc_text(PAGENDSW, ndisIsr)
+#pragma alloc_text(PAGENDSW, ndisDereferenceMac)
+#pragma alloc_text(PAGENDSW, ndisDereferenceAdapter)
+#pragma alloc_text(PAGENDSW, ndisKillAdapter)
+#pragma alloc_text(PAGENDSW, ndisQueueOpenOnAdapter)
+#pragma alloc_text(PAGENDSW, ndisDeQueueOpenOnAdapter)
+#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, NdisCompleteOpenAdapter)
+#pragma alloc_text(PAGENDSW, ndisQueuedCompleteOpenAdapter)
+#pragma alloc_text(PAGENDSW, NdisCompleteCloseAdapter)
+#pragma alloc_text(PAGENDSW, ndisQueuedCompleteCloseAdapter)
+#pragma alloc_text(PAGENDSW, ndisMacReceiveCompleteHandler)
+#pragma alloc_text(PAGENDSW, ndisMacReceiveHandler)
+#pragma alloc_text(PAGENDSW, ndisGetOpenBlockFromProtocolBindingContext)
+#pragma alloc_text(PAGENDSW, ndisShutdown)
+#pragma alloc_text(PAGENDSW, ndisUnload)
+
+#pragma alloc_text(PAGENDSE, ethRemoveBindingFromLists)
+#pragma alloc_text(PAGENDSE, ethRemoveAndFreeBinding)
+#pragma alloc_text(PAGENDSE, EthCreateFilter)
+#pragma alloc_text(PAGENDSE, EthDeleteFilter)
+#pragma alloc_text(PAGENDSE, EthNoteFilterOpenAdapter)
+#pragma alloc_text(PAGENDSE, EthDeleteFilterOpenAdapter)
+#pragma alloc_text(PAGENDSE, ethUndoChangeFilterAddresses)
+#pragma alloc_text(PAGENDSE, EthChangeFilterAddresses)
+#pragma alloc_text(PAGENDSE, ethUpdateDirectedBindingList)
+#pragma alloc_text(PAGENDSE, ethUpdateBroadcastBindingList)
+#pragma alloc_text(PAGENDSE, ethUpdateSpecificBindingLists)
+#pragma alloc_text(PAGENDSE, ethUndoFilterAdjust)
+#pragma alloc_text(PAGENDSE, EthFilterAdjust)
+#pragma alloc_text(PAGENDSE, EthNumberOfOpenFilterAddresses)
+#pragma alloc_text(PAGENDSE, EthQueryOpenFilterAddresses)
+#pragma alloc_text(PAGENDSE, EthQueryGlobalFilterAddresses)
+#pragma alloc_text(PAGENDSE, EthFilterIndicateReceiveComplete)
+#pragma alloc_text(PAGENDSE, EthFilterDprIndicateReceiveComplete)
+#pragma alloc_text(PAGENDSE, EthFilterDprIndicateReceiveCompleteFullMac)
+#pragma alloc_text(PAGENDSE, EthFilterIndicateReceive)
+#pragma alloc_text(PAGENDSE, EthFilterDprIndicateReceive)
+#pragma alloc_text(PAGENDSE, EthFilterDprIndicateReceiveFullMac)
+#pragma alloc_text(PAGENDSE, EthFilterDprIndicateReceivePacket)
+#pragma alloc_text(PAGENDSE, EthFindMulticast)
+#pragma alloc_text(PAGENDSE, EthShouldAddressLoopBack)
+
+#pragma alloc_text(PAGENDST, trRemoveBindingFromLists)
+#pragma alloc_text(PAGENDST, trRemoveAndFreeBinding)
+#pragma alloc_text(PAGENDST, TrCreateFilter)
+#pragma alloc_text(PAGENDST, TrDeleteFilter)
+#pragma alloc_text(PAGENDST, TrNoteFilterOpenAdapter)
+#pragma alloc_text(PAGENDST, TrDeleteFilterOpenAdapter)
+#pragma alloc_text(PAGENDST, trUndoChangeFunctionalAddress)
+#pragma alloc_text(PAGENDST, TrChangeFunctionalAddress)
+#pragma alloc_text(PAGENDST, trUndoChangeGroupAddress)
+#pragma alloc_text(PAGENDST, trCompleteChangeGroupAddress)
+#pragma alloc_text(PAGENDST, TrChangeGroupAddress)
+#pragma alloc_text(PAGENDST, trUpdateDirectedBindingList)
+#pragma alloc_text(PAGENDST, trUpdateBroadcastBindingList)
+#pragma alloc_text(PAGENDST, trUpdateSpecificBindingLists)
+#pragma alloc_text(PAGENDST, trUndoFilterAdjust)
+#pragma alloc_text(PAGENDST, TrFilterAdjust)
+#pragma alloc_text(PAGENDST, TrFilterIndicateReceive)
+#pragma alloc_text(PAGENDST, TrFilterDprIndicateReceive)
+#pragma alloc_text(PAGENDST, TrFilterDprIndicateReceiveFullMac)
+#pragma alloc_text(PAGENDST, TrFilterDprIndicateReceivePacket)
+#pragma alloc_text(PAGENDST, TrFilterIndicateReceiveComplete)
+#pragma alloc_text(PAGENDST, TrFilterDprIndicateReceiveComplete)
+#pragma alloc_text(PAGENDST, TrFilterDprIndicateReceiveCompleteFullMac)
+#pragma alloc_text(PAGENDST, TrShouldAddressLoopBack)
+
+#pragma alloc_text(PAGENDSF, fddiRemoveBindingFromLists)
+#pragma alloc_text(PAGENDSF, fddiRemoveAndFreeBinding)
+#pragma alloc_text(PAGENDSF, FddiCreateFilter)
+#pragma alloc_text(PAGENDSF, FddiDeleteFilter)
+#pragma alloc_text(PAGENDSF, FddiNoteFilterOpenAdapter)
+#pragma alloc_text(PAGENDSF, FddiDeleteFilterOpenAdapter)
+#pragma alloc_text(PAGENDSF, fddiUndoChangeFilterLongAddresses)
+#pragma alloc_text(PAGENDSF, FddiChangeFilterLongAddresses)
+#pragma alloc_text(PAGENDSF, fddiUndoChangeFilterShortAddresses)
+#pragma alloc_text(PAGENDSF, FddiChangeFilterShortAddresses)
+#pragma alloc_text(PAGENDSF, fddiUpdateDirectedBindingList)
+#pragma alloc_text(PAGENDSF, fddiUpdateBroadcastBindingList)
+#pragma alloc_text(PAGENDSF, fddiUpdateSpecificBindingLists)
+#pragma alloc_text(PAGENDSF, fddiUndoFilterAdjust)
+#pragma alloc_text(PAGENDSF, FddiFilterAdjust)
+#pragma alloc_text(PAGENDSF, FddiNumberOfOpenFilterLongAddresses)
+#pragma alloc_text(PAGENDSF, FddiNumberOfOpenFilterShortAddresses)
+#pragma alloc_text(PAGENDSF, FddiQueryOpenFilterLongAddresses)
+#pragma alloc_text(PAGENDSF, FddiQueryOpenFilterShortAddresses)
+#pragma alloc_text(PAGENDSF, FddiQueryGlobalFilterLongAddresses)
+#pragma alloc_text(PAGENDSF, FddiQueryGlobalFilterShortAddresses)
+#pragma alloc_text(PAGENDSF, FddiFilterIndicateReceive)
+#pragma alloc_text(PAGENDSF, FddiFilterDprIndicateReceive)
+#pragma alloc_text(PAGENDSF, FddiFilterDprIndicateReceiveFullMac)
+#pragma alloc_text(PAGENDSF, FddiFilterDprIndicateReceivePacket)
+#pragma alloc_text(PAGENDSF, FddiFilterIndicateReceiveComplete)
+#pragma alloc_text(PAGENDSF, FddiFilterDprIndicateReceiveComplete)
+#pragma alloc_text(PAGENDSF, FddiFilterDprIndicateReceiveCompleteFullMac)
+#pragma alloc_text(PAGENDSF, FddiFindMulticastLongAddress)
+#pragma alloc_text(PAGENDSF, FddiFindMulticastShortAddress)
+#pragma alloc_text(PAGENDSF, FddiShouldAddressLoopBack)
+
+#pragma alloc_text(PAGENDSA, ArcAllocateBuffers)
+#pragma alloc_text(PAGENDSA, ArcAllocatePackets)
+#pragma alloc_text(PAGENDSA, ArcDiscardPacketBuffers)
+#pragma alloc_text(PAGENDSA, ArcFreeNdisPacket)
+#pragma alloc_text(PAGENDSA, ArcDestroyPacket)
+#pragma alloc_text(PAGENDSA, ArcConvertToNdisPacket)
+#pragma alloc_text(PAGENDSA, ArcFilterDprIndicateReceive)
+#pragma alloc_text(PAGENDSA, ArcCreateFilter)
+#pragma alloc_text(PAGENDSA, ArcDeleteFilter)
+#pragma alloc_text(PAGENDSA, ArcNoteFilterOpenAdapter)
+#pragma alloc_text(PAGENDSA, ArcDeleteFilterOpenAdapter)
+#pragma alloc_text(PAGENDSA, ArcFilterAdjust)
+#pragma alloc_text(PAGENDSA, ArcFilterDoIndication)
+#pragma alloc_text(PAGENDSA, ArcFilterDprIndicateReceiveComplete)
+#pragma alloc_text(PAGENDSA, ArcConvertOidListToEthernet)
+#pragma alloc_text(PAGENDSA, ndisMArcCopyFromBufferToPacket)
+#pragma alloc_text(PAGENDSA, ndisMArcnetSend)
+#pragma alloc_text(PAGENDSA, ndisMArcTransferData)
+#pragma alloc_text(PAGENDSA, ndisMArcIndicateEthEncapsulatedReceive)
+#pragma alloc_text(PAGENDSA, ndisMBuildArcnetHeader)
+#pragma alloc_text(PAGENDSA, ndisMFreeArcnetHeader)
+#pragma alloc_text(PAGENDSA, ndisMArcnetSendLoopback)
+
+#pragma alloc_text(PAGENDCO, NdisCmRegisterAddressFamily)
+#pragma alloc_text(PAGENDCO, NdisClOpenAddressFamily)
+#pragma alloc_text(PAGENDCO, NdisCmOpenAddressFamilyComplete)
+#pragma alloc_text(PAGENDCO, NdisClCloseAddressFamily)
+#pragma alloc_text(PAGENDCO, NdisCmCloseAddressFamilyComplete)
+#pragma alloc_text(PAGENDCO, NdisClRegisterSap)
+#pragma alloc_text(PAGENDCO, NdisCmRegisterSapComplete)
+#pragma alloc_text(PAGENDCO, NdisClDeregisterSap)
+#pragma alloc_text(PAGENDCO, NdisCmDeregisterSapComplete)
+#pragma alloc_text(PAGENDCO, NdisClMakeCall)
+#pragma alloc_text(PAGENDCO, NdisCmMakeCallComplete)
+#pragma alloc_text(PAGENDCO, NdisCmDispatchIncomingCall)
+#pragma alloc_text(PAGENDCO, NdisClIncomingCallComplete)
+#pragma alloc_text(PAGENDCO, NdisCmDispatchCallConnected)
+#pragma alloc_text(PAGENDCO, NdisClModifyCallQoS)
+#pragma alloc_text(PAGENDCO, NdisCmModifyCallQoSComplete)
+#pragma alloc_text(PAGENDCO, NdisCmDispatchIncomingCallQoSChange)
+#pragma alloc_text(PAGENDCO, NdisClCloseCall)
+#pragma alloc_text(PAGENDCO, NdisCmCloseCallComplete)
+#pragma alloc_text(PAGENDCO, NdisCmDispatchIncomingCloseCall)
+#pragma alloc_text(PAGENDCO, NdisClAddParty)
+#pragma alloc_text(PAGENDCO, NdisCmAddPartyComplete)
+#pragma alloc_text(PAGENDCO, NdisClDropParty)
+#pragma alloc_text(PAGENDCO, NdisCmDropPartyComplete)
+#pragma alloc_text(PAGENDCO, NdisCmDispatchIncomingDropParty)
+#pragma alloc_text(PAGENDCO, NdisCoCreateVc)
+#pragma alloc_text(PAGENDCO, NdisCoDeleteVc)
+#pragma alloc_text(PAGENDCO, NdisCmActivateVc)
+#pragma alloc_text(PAGENDCO, NdisMCoActivateVcComplete)
+#pragma alloc_text(PAGENDCO, NdisCmDeactivateVc)
+#pragma alloc_text(PAGENDCO, NdisMCoDeactivateVcComplete)
+#pragma alloc_text(PAGENDCO, NdisCoRequest)
+#pragma alloc_text(PAGENDCO, NdisCoRequestComplete)
+#pragma alloc_text(PAGENDCO, NdisMCoIndicateReceivePacket)
+#pragma alloc_text(PAGENDCO, NdisMCoReceiveComplete)
+#pragma alloc_text(PAGENDCO, NdisCoSendPackets)
+#pragma alloc_text(PAGENDCO, NdisMCoSendComplete)
+#pragma alloc_text(PAGENDCO, NdisMCoIndicateStatus)
+#pragma alloc_text(PAGENDCO, NdisMCmRegisterAddressFamily)
+#pragma alloc_text(PAGENDCO, NdisMCmCreateVc)
+// #pragma alloc_text(PAGENDCO, NdisMCmDeleteVc)
+#pragma alloc_text(PAGENDCO, NdisMCmActivateVc)
+#pragma alloc_text(PAGENDCO, NdisMCmDeactivateVc)
+#pragma alloc_text(PAGENDCO, ndisMNotifyAfRegistration)
+#pragma alloc_text(PAGENDCO, ndisReferenceAf)
+#pragma alloc_text(PAGENDCO, ndisDereferenceAf)
+#pragma alloc_text(PAGENDCO, ndisReferenceSap)
+#pragma alloc_text(PAGENDCO, ndisDereferenceSap)
+#pragma alloc_text(PAGENDSM, ndisMCoFreeResources)
+#pragma alloc_text(PAGENDCO, ndisReferenceVc)
+#pragma alloc_text(PAGENDCO, ndisDereferenceVc)
+#pragma alloc_text(PAGENDCO, ndisMRejectSend)
+#pragma alloc_text(PAGENDCO, ndisMRejectSendPackets)
+#pragma alloc_text(PAGENDCO, ndisMCoDpc)
+#pragma alloc_text(PAGENDCO, ndisMCoDpcTimer)
+
+#else // NDIS_WIN
+
+#pragma NDIS_PAGEABLE_FUNCTION(NdisMInitializeTimer)
+#pragma NDIS_LOCKED_FUNCTION(NdisMCancelTimer)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisMDeregisterInterrupt)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisMRegisterInterrupt)
+#pragma NDIS_LOCKED_FUNCTION(NdisMSynchronizeWithInterrupt)
+#pragma NDIS_LOCKED_FUNCTION(ndisMIsr)
+#pragma NDIS_LOCKED_FUNCTION(ndisMDpc)
+#pragma NDIS_LOCKED_FUNCTION(ndisMWakeUpDpc)
+#pragma NDIS_LOCKED_FUNCTION(ndisMDpcTimer)
+#pragma NDIS_LOCKED_FUNCTION(ndisMTimerDpc)
+#pragma NDIS_LOCKED_FUNCTION(ndisMDeferredTimerDpc)
+#pragma NDIS_LOCKED_FUNCTION(ndisMDeQueueWorkItem)
+#pragma NDIS_LOCKED_FUNCTION(ndisMDeQueueWorkItemFullDuplex)
+#pragma NDIS_LOCKED_FUNCTION(ndisMQueueWorkItem)
+#pragma NDIS_LOCKED_FUNCTION(ndisMQueueWorkItemFullDuplex)
+#pragma NDIS_LOCKED_FUNCTION(ndisMQueueNewWorkItem)
+#pragma NDIS_LOCKED_FUNCTION(ndisMQueueNewWorkItemFullDuplex)
+#pragma NDIS_LOCKED_FUNCTION(ndisMProcessDeferredFullDuplex)
+#pragma NDIS_LOCKED_FUNCTION(ndisMProcessDeferred)
+#if _SEND_PRIORITY
+#pragma NDIS_LOCKED_FUNCTION(PAGENDSM, ndisMProcessDeferredFullDuplexPrioritySends)
+#pragma NDIS_LOCKED_FUNCTION(PAGENDSM, ndisMProcessDeferredPrioritySends)
+#endif
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMProcessResetRequested)
+#pragma NDIS_LOCKED_FUNCTION(NdisMIndicateStatus)
+#pragma NDIS_LOCKED_FUNCTION(NdisMIndicateStatusComplete)
+#pragma NDIS_LOCKED_FUNCTION(NdisMWanIndicateReceive)
+#pragma NDIS_LOCKED_FUNCTION(NdisMWanIndicateReceiveComplete)
+#pragma NDIS_LOCKED_FUNCTION(NdisQueryReceiveInformation)
+#pragma NDIS_LOCKED_FUNCTION(NdisReturnPackets)
+#pragma NDIS_LOCKED_FUNCTION(ndisMIndicatePacket)
+#pragma NDIS_LOCKED_FUNCTION(ndisMLazyReturnPackets)
+#pragma NDIS_LOCKED_FUNCTION(NdisMTransferDataComplete)
+#pragma NDIS_LOCKED_FUNCTION(ndisMTransferDataSync)
+#pragma NDIS_LOCKED_FUNCTION(ndisMTransferData)
+#pragma NDIS_LOCKED_FUNCTION(ndisMDummyTransferData)
+#pragma NDIS_LOCKED_FUNCTION(ndisMAbortPacketsAndRequests)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMResetCompleteCommonStep2)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMResetCompleteCommonStep1)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMProcessResetRequested)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMResetCompleteFullDuplex)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisMResetComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMResetFullDuplex)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMReset)
+#pragma NDIS_LOCKED_FUNCTION(ndisMResetSend)
+#pragma NDIS_LOCKED_FUNCTION(ndisMResetSendPackets)
+#pragma NDIS_LOCKED_FUNCTION(NdisIMSwitchToMiniport)
+#pragma NDIS_LOCKED_FUNCTION(NdisIMRevertBack)
+#pragma NDIS_LOCKED_FUNCTION(NdisIMQueueMiniportCallback)
+#pragma NDIS_LOCKED_FUNCTION(ndisIMQueueWorkItem)
+#pragma NDIS_LOCKED_FUNCTION(ndisIMQueueWorkItemFullDuplex)
+#pragma NDIS_LOCKED_FUNCTION(ndisIMQueueNewWorkItem)
+#pragma NDIS_LOCKED_FUNCTION(ndisIMQueueNewWorkItemFullDuplex)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMRequest)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMUndoBogusFilters)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMDoMiniportOp)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMRequestQueryInformationPost)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMSyncQueryInformationComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisMQueryInformationComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMRequestSetInformationPost)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMSyncSetInformationComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisMSetInformationComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMAbortQueryStatisticsRequest)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMSetPacketFilter)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMSetCurrentLookahead)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMSetMulticastList)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMSetFunctionalAddress)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMSetGroupAddress)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMSetFddiMulticastList)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMSetInformation)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMQueryCurrentPacketFilter)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMQueryMediaSupported)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMQueryEthernetMulticastList)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMQueryLongMulticastList)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMQueryShortMulticastList)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMQueryMaximumFrameSize)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMQueryMaximumTotalSize)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMQueryNetworkAddress)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMQueryInformation)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMDoRequests)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMAllocateRequest)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMQueueRequest)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMRestoreFilterSettings)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMFilterOutStatisticsOids)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMQueryOidList)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMChangeFddiAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMChangeFunctionalAddress)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMChangeGroupAddress)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMCloseAction)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMChangeClass)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMChangeEthAddresses)
+#pragma NDIS_LOCKED_FUNCTION(ndisMCopyFromPacketToBuffer)
+#pragma NDIS_LOCKED_FUNCTION(ndisMIndicateLoopback)
+#pragma NDIS_LOCKED_FUNCTION(ndisMIsLoopbackPacket)
+#pragma NDIS_LOCKED_FUNCTION(ndisMStartSendPacketsFullDuplex)
+#pragma NDIS_LOCKED_FUNCTION(ndisMStartSendsFullDuplex)
+#pragma NDIS_LOCKED_FUNCTION(ndisMStartSendPackets)
+#pragma NDIS_LOCKED_FUNCTION(ndisMStartSends)
+#pragma NDIS_LOCKED_FUNCTION(ndisMSyncSend)
+#pragma NDIS_LOCKED_FUNCTION(ndisMWanSend)
+#pragma NDIS_LOCKED_FUNCTION(NdisMSendComplete)
+#pragma NDIS_LOCKED_FUNCTION(ndisMSendCompleteFullDuplex)
+#pragma NDIS_LOCKED_FUNCTION(NdisMWanSendComplete)
+#pragma NDIS_LOCKED_FUNCTION(ndisMSendResourcesAvailableFullDuplex)
+#pragma NDIS_LOCKED_FUNCTION(NdisMSendResourcesAvailable)
+#pragma NDIS_LOCKED_FUNCTION(ndisMSendFullDuplexToSendPackets)
+#pragma NDIS_LOCKED_FUNCTION(ndisMSendPacketsFullDuplex)
+#pragma NDIS_LOCKED_FUNCTION(ndisMSendToSendPackets)
+#pragma NDIS_LOCKED_FUNCTION(ndisMSendPackets)
+#pragma NDIS_LOCKED_FUNCTION(ndisMSendPacketsFullDuplexToSend)
+#pragma NDIS_LOCKED_FUNCTION(ndisMSendFullDuplex)
+#pragma NDIS_LOCKED_FUNCTION(ndisMSendPacketsToSend)
+#pragma NDIS_LOCKED_FUNCTION(ndisMSend)
+
+#pragma NDIS_PAGEABLE_FUNCTION(ethRemoveBindingFromLists)
+#pragma NDIS_PAGEABLE_FUNCTION(ethRemoveAndFreeBinding)
+#pragma NDIS_PAGEABLE_FUNCTION(EthCreateFilter)
+#pragma NDIS_PAGEABLE_FUNCTION(EthDeleteFilter)
+#pragma NDIS_PAGEABLE_FUNCTION(EthNoteFilterOpenAdapter)
+#pragma NDIS_PAGEABLE_FUNCTION(EthDeleteFilterOpenAdapter)
+#pragma NDIS_PAGEABLE_FUNCTION(ethUndoChangeFilterAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(EthChangeFilterAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(ethUpdateDirectedBindingList)
+#pragma NDIS_PAGEABLE_FUNCTION(ethUpdateBroadcastBindingList)
+#pragma NDIS_PAGEABLE_FUNCTION(ethUpdateSpecificBindingLists)
+#pragma NDIS_PAGEABLE_FUNCTION(ethUndoFilterAdjust)
+#pragma NDIS_PAGEABLE_FUNCTION(EthFilterAdjust)
+#pragma NDIS_PAGEABLE_FUNCTION(EthNumberOfOpenFilterAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(EthQueryOpenFilterAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(EthQueryGlobalFilterAddresses)
+#pragma NDIS_LOCKED_FUNCTION(EthFilterIndicateReceiveComplete)
+#pragma NDIS_LOCKED_FUNCTION(EthFilterDprIndicateReceiveComplete)
+#pragma NDIS_LOCKED_FUNCTION(EthFilterDprIndicateReceiveCompleteFullMac)
+#pragma NDIS_LOCKED_FUNCTION(EthFilterIndicateReceive)
+#pragma NDIS_LOCKED_FUNCTION(EthFilterDprIndicateReceive)
+#pragma NDIS_LOCKED_FUNCTION(EthFilterDprIndicateReceiveFullMac)
+#pragma NDIS_LOCKED_FUNCTION(EthFilterDprIndicateReceivePacket)
+#pragma NDIS_LOCKED_FUNCTION(EthFindMulticast)
+#pragma NDIS_LOCKED_FUNCTION(EthShouldAddressLoopBack)
+
+#pragma NDIS_PAGEABLE_FUNCTION(trRemoveBindingFromLists)
+#pragma NDIS_PAGEABLE_FUNCTION(trRemoveAndFreeBinding)
+#pragma NDIS_PAGEABLE_FUNCTION(TrCreateFilter)
+#pragma NDIS_PAGEABLE_FUNCTION(TrDeleteFilter)
+#pragma NDIS_PAGEABLE_FUNCTION(TrNoteFilterOpenAdapter)
+#pragma NDIS_PAGEABLE_FUNCTION(TrDeleteFilterOpenAdapter)
+#pragma NDIS_PAGEABLE_FUNCTION(trUndoChangeFunctionalAddress)
+#pragma NDIS_PAGEABLE_FUNCTION(TrChangeFunctionalAddress)
+#pragma NDIS_PAGEABLE_FUNCTION(trUndoChangeGroupAddress)
+#pragma NDIS_PAGEABLE_FUNCTION(trCompleteChangeGroupAddress)
+#pragma NDIS_PAGEABLE_FUNCTION(TrChangeGroupAddress)
+#pragma NDIS_PAGEABLE_FUNCTION(trUpdateDirectedBindingList)
+#pragma NDIS_PAGEABLE_FUNCTION(trUpdateBroadcastBindingList)
+#pragma NDIS_PAGEABLE_FUNCTION(trUpdateSpecificBindingLists)
+#pragma NDIS_PAGEABLE_FUNCTION(trUndoFilterAdjust)
+#pragma NDIS_PAGEABLE_FUNCTION(TrFilterAdjust)
+#pragma NDIS_LOCKED_FUNCTION(TrFilterIndicateReceive)
+#pragma NDIS_LOCKED_FUNCTION(TrFilterDprIndicateReceive)
+#pragma NDIS_LOCKED_FUNCTION(TrFilterDprIndicateReceiveFullMac)
+#pragma NDIS_LOCKED_FUNCTION(TrFilterDprIndicateReceivePacket)
+#pragma NDIS_LOCKED_FUNCTION(TrFilterIndicateReceiveComplete)
+#pragma NDIS_LOCKED_FUNCTION(TrFilterDprIndicateReceiveComplete)
+#pragma NDIS_LOCKED_FUNCTION(TrFilterDprIndicateReceiveCompleteFullMac)
+#pragma NDIS_LOCKED_FUNCTION(TrShouldAddressLoopBack)
+
+#pragma NDIS_PAGEABLE_FUNCTION(fddiRemoveBindingFromLists)
+#pragma NDIS_PAGEABLE_FUNCTION(fddiRemoveAndFreeBinding)
+#pragma NDIS_PAGEABLE_FUNCTION(FddiCreateFilter)
+#pragma NDIS_PAGEABLE_FUNCTION(FddiDeleteFilter)
+#pragma NDIS_PAGEABLE_FUNCTION(FddiNoteFilterOpenAdapter)
+#pragma NDIS_PAGEABLE_FUNCTION(FddiDeleteFilterOpenAdapter)
+#pragma NDIS_PAGEABLE_FUNCTION(fddiUndoChangeFilterLongAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(FddiChangeFilterLongAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(fddiUndoChangeFilterShortAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(FddiChangeFilterShortAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(fddiUpdateDirectedBindingList)
+#pragma NDIS_PAGEABLE_FUNCTION(fddiUpdateBroadcastBindingList)
+#pragma NDIS_PAGEABLE_FUNCTION(fddiUpdateSpecificBindingLists)
+#pragma NDIS_PAGEABLE_FUNCTION(fddiUndoFilterAdjust)
+#pragma NDIS_PAGEABLE_FUNCTION(FddiFilterAdjust)
+#pragma NDIS_PAGEABLE_FUNCTION(FddiNumberOfOpenFilterLongAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(FddiNumberOfOpenFilterShortAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(FddiQueryOpenFilterLongAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(FddiQueryOpenFilterShortAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(FddiQueryGlobalFilterLongAddresses)
+#pragma NDIS_PAGEABLE_FUNCTION(FddiQueryGlobalFilterShortAddresses)
+#pragma NDIS_LOCKED_FUNCTION(FddiFilterIndicateReceive)
+#pragma NDIS_LOCKED_FUNCTION(FddiFilterDprIndicateReceive)
+#pragma NDIS_LOCKED_FUNCTION(FddiFilterDprIndicateReceiveFullMac)
+#pragma NDIS_LOCKED_FUNCTION(FddiFilterDprIndicateReceivePacket)
+#pragma NDIS_LOCKED_FUNCTION(FddiFilterIndicateReceiveComplete)
+#pragma NDIS_LOCKED_FUNCTION(FddiFilterDprIndicateReceiveComplete)
+#pragma NDIS_LOCKED_FUNCTION(FddiFilterDprIndicateReceiveCompleteFullMac)
+#pragma NDIS_LOCKED_FUNCTION(FddiFindMulticastLongAddress)
+#pragma NDIS_LOCKED_FUNCTION(FddiFindMulticastShortAddress)
+#pragma NDIS_LOCKED_FUNCTION(FddiShouldAddressLoopBack)
+
+#pragma NDIS_LOCKED_FUNCTION(ArcAllocateBuffers)
+#pragma NDIS_LOCKED_FUNCTION(ArcAllocatePackets)
+#pragma NDIS_LOCKED_FUNCTION(ArcDiscardPacketBuffers)
+#pragma NDIS_LOCKED_FUNCTION(ArcFreeNdisPacket)
+#pragma NDIS_LOCKED_FUNCTION(ArcDestroyPacket)
+#pragma NDIS_LOCKED_FUNCTION(ArcConvertToNdisPacket)
+#pragma NDIS_LOCKED_FUNCTION(ArcFilterDprIndicateReceive)
+#pragma NDIS_PAGEABLE_FUNCTION(ArcCreateFilter)
+#pragma NDIS_PAGEABLE_FUNCTION(ArcDeleteFilter)
+#pragma NDIS_PAGEABLE_FUNCTION(ArcNoteFilterOpenAdapter)
+#pragma NDIS_PAGEABLE_FUNCTION(ArcDeleteFilterOpenAdapter)
+#pragma NDIS_PAGEABLE_FUNCTION(ArcFilterAdjust)
+#pragma NDIS_LOCKED_FUNCTION(ArcFilterDoIndication)
+#pragma NDIS_LOCKED_FUNCTION(ArcFilterDprIndicateReceiveComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(ArcConvertOidListToEthernet)
+#pragma NDIS_LOCKED_FUNCTION(ndisMArcCopyFromBufferToPacket)
+#pragma NDIS_LOCKED_FUNCTION(ndisMArcnetSend)
+#pragma NDIS_LOCKED_FUNCTION(ndisMArcTransferData)
+#pragma NDIS_LOCKED_FUNCTION(ndisMArcIndicateEthEncapsulatedReceive)
+#pragma NDIS_LOCKED_FUNCTION(ndisMBuildArcnetHeader)
+#pragma NDIS_LOCKED_FUNCTION(ndisMFreeArcnetHeader)
+#pragma NDIS_LOCKED_FUNCTION(ndisMArcnetSendLoopback)
+
+
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmRegisterAddressFamily)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisClOpenAddressFamily)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmOpenAddressFamilyComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMNotifyAfRegistration)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisClCloseAddressFamily)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmCloseAddressFamilyComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisClRegisterSap)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmRegisterSapComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisClDeregisterSap)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmDeregisterSapComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisClMakeCall)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmMakeCallComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmDispatchIncomingCall)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisClIncomingCallComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmDispatchCallConnected)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisClModifyCallQoS)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmModifyCallQoSComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmDispatchIncomingCallQoSChange)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisClCloseCall)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmCloseCallComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmDispatchIncomingCloseCall)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisClAddParty)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmAddPartyComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisClDropParty)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmDropPartyComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmDispatchIncomingDropParty)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCoCreateVc)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCoDeleteVc)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmActivateVc)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisMCoActivateVcComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCmDeactivateVc)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisMCoDeactivateVcComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCoRequest)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisCoRequestComplete)
+#pragma NDIS_LOCKED_FUNCTION(NdisMCoIndicateReceivePacket)
+#pragma NDIS_LOCKED_FUNCTION(NdisMCoReceiveComplete)
+#pragma NDIS_LOCKED_FUNCTION(NdisCoSendPackets)
+#pragma NDIS_LOCKED_FUNCTION(NdisMCoSendComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisMCoIndicateStatus)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisMCmRegisterAddressFamily)
+#pragma NDIS_PAGEABLE_FUNCTION(NdisMCoRequestComplete)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisReferenceAf)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisDereferenceAf)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisReferenceSap)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisDereferenceSap)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisMCoFreeResources)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisReferenceVc)
+#pragma NDIS_PAGEABLE_FUNCTION(ndisDereferenceVc)
+#pragma NDIS_LOCKED_FUNCTION(ndisMRejectSend)
+#pragma NDIS_LOCKED_FUNCTION(ndisMRejectSendPackets)
+#pragma NDIS_LOCKED_FUNCTION(ndisMCoDpc)
+#pragma NDIS_LOCKED_FUNCTION(ndisMCoDpcTimer)
+#endif // NDIS_NT
+#endif // ALLOC_PRAGMA
+
+#endif // _PRAGMA_
diff --git a/private/ntos/ndis/ndis40/precomp.h b/private/ntos/ndis/ndis40/precomp.h
new file mode 100644
index 000000000..07c0aa762
--- /dev/null
+++ b/private/ntos/ndis/ndis40/precomp.h
@@ -0,0 +1,17 @@
+#include "ndisnt.h"
+#include "wrapper.h"
+#include "protos.h"
+#include "mac.h"
+#include "mini.h"
+#include "filter.h"
+
+#include <afilter.h>
+#include <efilter.h>
+#include <ffilter.h>
+#include <tfilter.h>
+
+#include "pragma.h"
+
+#include <tdikrnl.h>
+#include <ndisprv.h>
+
diff --git a/private/ntos/ndis/ndis40/protocol.c b/private/ntos/ndis/ndis40/protocol.c
new file mode 100644
index 000000000..f021a0ced
--- /dev/null
+++ b/private/ntos/ndis/ndis40/protocol.c
@@ -0,0 +1,1757 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ protocol.c
+
+Abstract:
+
+ NDIS wrapper functions used by protocol modules
+
+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
+ 01-Jun-1995 JameelH Re-organization/optimization
+
+--*/
+
+#define GLOBALS
+#include <precomp.h>
+#pragma hdrstop
+
+#include <stdarg.h>
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_PROTOCOL
+
+//
+// Requests used by protocol modules
+//
+//
+
+VOID
+NdisRegisterProtocol(
+ OUT PNDIS_STATUS pStatus,
+ 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 pProtocol;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+ USHORT size;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisRegisterProtocol\n"));
+
+ ProtocolReferencePackage();
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ BOOLEAN f = FALSE;
+ if (DbgIsNull(ProtocolCharacteristics->OpenAdapterCompleteHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterProtocol: OpenAdapterCompleteHandler Null\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(ProtocolCharacteristics->CloseAdapterCompleteHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterProtocol: CloseAdapterCompleteHandler Null\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(ProtocolCharacteristics->SendCompleteHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterProtocol: SendCompleteHandler Null\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(ProtocolCharacteristics->TransferDataCompleteHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterProtocol: TransferDataCompleteHandler Null\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(ProtocolCharacteristics->ResetCompleteHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterProtocol: ResetCompleteHandler Null\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(ProtocolCharacteristics->RequestCompleteHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterProtocol: RequestCompleteHandler Null\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(ProtocolCharacteristics->ReceiveHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterProtocol: ReceiveHandler Null\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(ProtocolCharacteristics->ReceiveCompleteHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterProtocol: ReceiveCompleteHandler Null\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(ProtocolCharacteristics->StatusHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterProtocol: StatusHandler Null\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(ProtocolCharacteristics->StatusCompleteHandler))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("RegisterProtocol: StatusCompleteHandler Null\n"));
+ f = TRUE;
+ }
+ if (f)
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+
+ do
+ {
+ //
+ // Check version numbers and CharacteristicsLength.
+ //
+ size = 0; // Used to indicate bad version below
+ if (ProtocolCharacteristics->MajorNdisVersion == 3)
+ {
+ if (ProtocolCharacteristics->MinorNdisVersion == 0)
+ {
+ size = sizeof(NDIS30_PROTOCOL_CHARACTERISTICS);
+ }
+ }
+ else if (ProtocolCharacteristics->MajorNdisVersion == 4)
+ {
+ if (ProtocolCharacteristics->MinorNdisVersion == 0)
+ {
+ size = sizeof(NDIS40_PROTOCOL_CHARACTERISTICS);
+ }
+ else if (ProtocolCharacteristics->MinorNdisVersion == 1)
+ {
+ size = sizeof(NDIS41_PROTOCOL_CHARACTERISTICS);
+ }
+ }
+
+ //
+ // Check that this is an NDIS 3.0/4.0/4.1 protocol.
+ //
+ if (size == 0)
+ {
+ Status = NDIS_STATUS_BAD_VERSION;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisRegisterProtocol\n"));
+ break;
+ }
+
+ //
+ // Check that CharacteristicsLength is enough.
+ //
+ if (CharacteristicsLength < size)
+ {
+ Status = NDIS_STATUS_BAD_CHARACTERISTICS;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisRegisterProtocol\n"));
+ break;
+ }
+
+ //
+ // Allocate memory for the NDIS protocol block.
+ //
+ pProtocol = (PNDIS_PROTOCOL_BLOCK)ALLOC_FROM_POOL(sizeof(NDIS_PROTOCOL_BLOCK) +
+ ProtocolCharacteristics->Name.Length + sizeof(WCHAR),
+ NDIS_TAG_PROT_BLK);
+ if (pProtocol == (PNDIS_PROTOCOL_BLOCK)NULL)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisRegisterProtocol\n"));
+ break;
+ }
+ ZeroMemory(pProtocol, sizeof(NDIS_PROTOCOL_BLOCK) + sizeof(WCHAR) + ProtocolCharacteristics->Name.Length);
+ pProtocol->Length = sizeof(NDIS_PROTOCOL_BLOCK);
+ INITIALIZE_MUTEX(&pProtocol->Mutex);
+
+ //
+ // Copy over the characteristics table.
+ //
+ CopyMemory(&pProtocol->ProtocolCharacteristics,
+ ProtocolCharacteristics,
+ size);
+
+ // Upcase the name in the characteristics table before saving it.
+ pProtocol->ProtocolCharacteristics.Name.Buffer = (PWCHAR)((PUCHAR)pProtocol +
+ sizeof(NDIS_PROTOCOL_BLOCK));
+ pProtocol->ProtocolCharacteristics.Name.Length = ProtocolCharacteristics->Name.Length;
+ pProtocol->ProtocolCharacteristics.Name.MaximumLength = ProtocolCharacteristics->Name.Length;
+ RtlCopyUnicodeString(&pProtocol->ProtocolCharacteristics.Name,
+ &ProtocolCharacteristics->Name);
+
+ //
+ // No opens for this protocol yet.
+ //
+ pProtocol->OpenQueue = (PNDIS_OPEN_BLOCK)NULL;
+
+ NdisInitializeRef(&pProtocol->Ref);
+ *NdisProtocolHandle = (NDIS_HANDLE)pProtocol;
+ Status = NDIS_STATUS_SUCCESS;
+
+ //
+ // Link the protocol into the list.
+ //
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+
+ if (ProtocolCharacteristics->Flags & NDIS_PROTOCOL_CALL_MANAGER)
+ {
+ //
+ // If this protocol is a call-manager, then it must bind to the
+ // adapters below ahead of others. So link it at the head of the list.
+ //
+ pProtocol->NextProtocol = ndisProtocolList;
+ ndisProtocolList = pProtocol;
+ }
+ else
+ {
+ PNDIS_PROTOCOL_BLOCK *pTemp;
+
+ for (pTemp = & ndisProtocolList;
+ *pTemp != NULL;
+ pTemp = &(*pTemp)->NextProtocol)
+ {
+ if (((*pTemp)->ProtocolCharacteristics.Flags & NDIS_PROTOCOL_CALL_MANAGER) == 0)
+ break;
+ }
+ pProtocol->NextProtocol = *pTemp;
+ *pTemp = pProtocol;
+ }
+
+ if ((pProtocol->ProtocolCharacteristics.BindAdapterHandler != NULL) &&
+ ((ndisMiniDriverList != NULL) || (ndisMacDriverList != NULL)) &&
+ ndisReferenceProtocol(pProtocol))
+ {
+ // Start a worker thread to notify the protocol of any existing drivers
+ INITIALIZE_WORK_ITEM(&pProtocol->WorkItem, ndisNotifyProtocols, pProtocol);
+ QUEUE_WORK_ITEM(&pProtocol->WorkItem, DelayedWorkQueue);
+ }
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisRegisterProtocol\n"));
+
+ } while (FALSE);
+
+ *pStatus = Status;
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ ProtocolDereferencePackage();
+ }
+}
+
+
+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 ProtP = (PNDIS_PROTOCOL_BLOCK)NdisProtocolHandle;
+ UINT i;
+ KEVENT DeregEvent;
+
+ //
+ // If the protocol is already closing, return.
+ //
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisDeregisterProtocol\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("Protocol: %wZ\n",&ProtP->ProtocolCharacteristics.Name));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(NdisProtocolHandle))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("DeregisterProtocol: Null Handle\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(NdisProtocolHandle))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("DeregisterProtocol: Handle not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ }
+ if (!NdisCloseRef(&ProtP->Ref))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisDeregisterProtocol\n"));
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ //
+ // Kill all the opens for this protocol.
+ //
+ INITIALIZE_EVENT(&DeregEvent);
+ ProtP->DeregEvent = &DeregEvent;
+ while (ProtP->OpenQueue != (PNDIS_OPEN_BLOCK)NULL)
+ {
+ //
+ // This removes it from the protocol's OpenQueue etc.
+ //
+
+ ndisKillOpenAndNotifyProtocol(ProtP->OpenQueue);
+ }
+
+ //
+ // Kill all the protocol filters for this protocol.
+ //
+ for (i = 0; i < NdisMediumMax; i++)
+ {
+ while (ProtP->ProtocolFilter[i] != NULL)
+ {
+ PNDIS_PROTOCOL_FILTER pF;
+
+ pF = ProtP->ProtocolFilter[i];
+ ProtP->ProtocolFilter[i] = pF->Next;
+ FREE_POOL(pF);
+ ndisDereferenceProtocol(ProtP);
+ }
+ }
+
+ ndisDereferenceProtocol(ProtP);
+
+ WAIT_FOR_OBJECT(&DeregEvent, NULL);
+ *Status = NDIS_STATUS_SUCCESS;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisDeregisterProtocol\n"));
+}
+
+
+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.
+ //
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisOpenAdapter\n"));
+
+ IF_DBG(DBG_COMP_CONFIG, DBG_LEVEL_ERR)
+ {
+ BOOLEAN f = FALSE;
+ if (DbgIsNull(NdisProtocolHandle))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("OpenAdapter: Null ProtocolHandle\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(NdisProtocolHandle))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("OpenAdapter: ProtocolHandle not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(ProtocolBindingContext))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("OpenAdapter: Null Context\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(ProtocolBindingContext))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("OpenAdapter: Context not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (f)
+ DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
+
+ }
+
+ NewOpenP = (PNDIS_OPEN_BLOCK)
+ ALLOC_FROM_POOL(sizeof(NDIS_OPEN_BLOCK) + AdapterName->MaximumLength,
+ NDIS_TAG_OPEN_BLK);
+ if (NewOpenP == (PNDIS_OPEN_BLOCK)NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisOpenAdapter\n"));
+ return;
+ }
+
+ ZeroMemory(NewOpenP, sizeof(NDIS_OPEN_BLOCK));
+ NewOpenP->AdapterName.Buffer = (PWCHAR)((PUCHAR)NewOpenP + sizeof(NDIS_OPEN_BLOCK));
+ NewOpenP->AdapterName.Length = AdapterName->Length;
+ NewOpenP->AdapterName.MaximumLength = AdapterName->MaximumLength;
+ RtlUpcaseUnicodeString(&NewOpenP->AdapterName,
+ AdapterName,
+ FALSE);
+
+ OpenEaLength = sizeof(FILE_FULL_EA_INFORMATION) +
+ sizeof(ndisInternalEaName) +
+ sizeof(ndisInternalEaValue);
+
+ OpenEa = ALLOC_FROM_POOL(OpenEaLength, NDIS_TAG_DEFAULT);
+
+ if (OpenEa == NULL)
+ {
+ FREE_POOL(NewOpenP);
+ *Status = NDIS_STATUS_RESOURCES;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisOpenAdapter\n"));
+ return;
+ }
+
+ OpenEa->NextEntryOffset = 0;
+ OpenEa->Flags = 0;
+ OpenEa->EaNameLength = sizeof(ndisInternalEaName);
+ OpenEa->EaValueLength = sizeof(ndisInternalEaValue);
+
+ CopyMemory(OpenEa->EaName,
+ ndisInternalEaName,
+ sizeof(ndisInternalEaName));
+
+ CopyMemory(&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);
+ FREE_POOL(OpenEa);
+
+ if (NtOpenStatus != STATUS_SUCCESS)
+ {
+ FREE_POOL(NewOpenP);
+
+ *Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==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);
+
+ //
+ // Get the adapter (or miniport) block from the device object.
+ //
+
+ 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;
+ PMINIPORT_PENDING_OPEN MiniportPendingOpen;
+ ULONG i;
+
+ UsingEncapsulation = FALSE;
+
+ //
+ // Is this the ndiswan miniport wrapper?
+ //
+ if ((Miniport->MacOptions & (NDIS_MAC_OPTION_RESERVED | NDIS_MAC_OPTION_NDISWAN)) ==
+ (NDIS_MAC_OPTION_RESERVED | NDIS_MAC_OPTION_NDISWAN))
+ {
+ //
+ // Yup. We want the binding to think that this is an
+ // ndiswan link.
+ //
+ for (i = 0; i < MediumArraySize; i++)
+ {
+ if (MediumArray[i] == NdisMediumWan)
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ //
+ // 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;
+ ObDereferenceObject( FileObject);
+ return;
+ }
+
+ UsingEncapsulation = TRUE;
+ }
+ else
+ {
+ *Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
+ ObDereferenceObject( FileObject);
+ return;
+ }
+ }
+
+ *SelectedMediumIndex = i;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ //
+ // 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)
+ {
+ NdisZeroMemory(MiniportPendingOpen, sizeof(MINIPORT_PENDING_OPEN));
+
+ //
+ // Save off the parameters for this open so we can
+ // do the actual NdisOpenAdapter() later on.
+ //
+ 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;
+
+ if (UsingEncapsulation)
+ {
+ MINIPORT_SET_FLAG(MiniportPendingOpen, fPENDING_OPEN_USING_ENCAPSULATION);
+ }
+
+ //
+ // Queue a work item to process the pending open adapter.
+ //
+ NDISM_QUEUE_NEW_WORK_ITEM(Miniport, NdisWorkItemPendingOpen, MiniportPendingOpen, NULL);
+
+ //
+ // Make sure ndisMProcessDeferred() completes the open.
+ //
+ *Status = NDIS_STATUS_PENDING;
+
+ //
+ // Lock the miniport. If the lock fails, then
+ // we must pend this open and try it later.
+ //
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // If we can grab the local lock then we can
+ // process this open now.
+ //
+ if (LocalLock)
+ {
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ //
+ // Unlock the miniport.
+ //
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ }
+ else
+ {
+ ObDereferenceObject( FileObject);
+ FREE_POOL( NewOpenP);
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ return;
+ }
+
+ //
+ // It is a mac
+ //
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("openadapter: adaptername=%s\n",TmpAdaptP->AdapterName.Buffer));
+ if (!ndisReferenceAdapter(TmpAdaptP))
+ {
+ //
+ // The adapter is closing.
+ //
+ ObDereferenceObject(FileObject);
+ FREE_POOL(NewOpenP);
+ *Status = NDIS_STATUS_CLOSING;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisOpenAdapter\n"));
+ return;
+ }
+
+ //
+ // Increment the protocol's reference count.
+ //
+ TmpProtP = (PNDIS_PROTOCOL_BLOCK)NdisProtocolHandle;
+ if (!ndisReferenceProtocol(TmpProtP))
+ {
+ //
+ // The protocol is closing.
+ //
+ ndisDereferenceAdapter(TmpAdaptP);
+ ObDereferenceObject(FileObject);
+ FREE_POOL(NewOpenP);
+ *Status = NDIS_STATUS_CLOSING;
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisOpenAdapter\n"));
+ return;
+ }
+
+
+ //
+ // Set up the elements of the open structure.
+ //
+ INITIALIZE_SPIN_LOCK(&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->ResetHandler = TmpAdaptP->MacHandle->MacCharacteristics.ResetHandler;
+ NewOpenP->RequestHandler = TmpAdaptP->MacHandle->MacCharacteristics.RequestHandler;
+
+ NewOpenP->SendCompleteHandler = TmpProtP->ProtocolCharacteristics.SendCompleteHandler;
+ NewOpenP->TransferDataCompleteHandler = TmpProtP->ProtocolCharacteristics.TransferDataCompleteHandler;
+ NewOpenP->SendPacketsHandler = ndisMSendPacketsToFullMac;
+
+ //
+ // 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;
+ NewOpenP->ReceivePacketHandler = NULL;
+
+ //
+ // Patch the open into the global list of macs
+ //
+ ACQUIRE_SPIN_LOCK(&ndisGlobalOpenListLock, &OldIrql);
+
+ NewOpenP->NextGlobalOpen = ndisGlobalOpenList;
+ ndisGlobalOpenList = NewOpenP;
+
+ RELEASE_SPIN_LOCK(&ndisGlobalOpenListLock, OldIrql);
+
+
+ //
+ // 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 = 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 *ppOpen;
+
+ //
+ // Something went wrong, clean up and exit.
+ //
+ ACQUIRE_SPIN_LOCK(&ndisGlobalOpenListLock, &OldIrql);
+
+ for (ppOpen = &ndisGlobalOpenList;
+ *ppOpen != NULL;
+ ppOpen = &(*ppOpen)->NextGlobalOpen)
+ {
+ if (*ppOpen == NewOpenP)
+ {
+ *ppOpen = NewOpenP->NextGlobalOpen;
+ break;
+ }
+ }
+
+ RELEASE_SPIN_LOCK(&ndisGlobalOpenListLock, OldIrql);
+
+ ObDereferenceObject(FileObject);
+ ndisDereferenceAdapter(TmpAdaptP);
+ ndisDereferenceProtocol(TmpProtP);
+ FREE_POOL(NewOpenP);
+ *Status = NDIS_STATUS_OPEN_FAILED;
+ }
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisOpenAdapter\n"));
+}
+
+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);
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>NdisCloseAdapter\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("Protocol %wZ is closing Adapter %wZ\n",
+ &(OpenP->ProtocolHandle)->ProtocolCharacteristics.Name,
+ &(OpenP->AdapterHandle)->AdapterName));
+
+ IF_DBG(DBG_COMP_CONFIG, DBG_LEVEL_ERR)
+ {
+ if (DbgIsNull(NdisBindingHandle))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("OpenAdapter: Null BindingHandle\n"));
+ DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
+ }
+ if (!DbgIsNonPaged(NdisBindingHandle))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("OpenAdapter: BindingHandle not in NonPaged Memory\n"));
+ DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
+ }
+ }
+
+ //
+ // Is this a miniport?
+ //
+ 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;
+ }
+
+ //
+ // This returns TRUE if it finished synchronously.
+ //
+ if (ndisKillOpen(OpenP))
+ {
+ *Status = NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ *Status = NDIS_STATUS_PENDING; // will complete later
+ }
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==NdisCloseAdapter\n"));
+#undef OpenP
+}
+
+
+VOID
+NdisSetProtocolFilter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN RECEIVE_HANDLER ReceiveHandler,
+ IN RECEIVE_PACKET_HANDLER ReceivePacketHandler,
+ IN NDIS_MEDIUM Medium,
+ IN UINT Offset,
+ IN UINT Size,
+ IN PUCHAR Pattern
+ )
+/*++
+
+Routine Description:
+
+ Sets a protocol filter.
+
+Arguments:
+
+ Status Returns the final status.
+ NdisProtocolHandle The handle returned by NdisRegisterProtocol.
+ ReceiveHandler This will be invoked instead of the default receivehandler
+ when the pattern match happens.
+ ReceivePacketHandler This will be invoked instead of the default receivepackethandler
+ when the pattern match happens.
+ Size Size of pattern
+ Pattern This must match
+
+Return Value:
+
+ None.
+
+Note:
+
+--*/
+{
+ PNDIS_PROTOCOL_BLOCK ProtP = ((PNDIS_OPEN_BLOCK)NdisBindingHandle)->ProtocolHandle;
+ PNDIS_PROTOCOL_FILTER PFilter;
+ KIRQL OldIrql;
+
+ PFilter = ALLOC_FROM_POOL(sizeof(NDIS_PROTOCOL_FILTER) + Size, NDIS_TAG_FILTER);
+ if (PFilter == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ PFilter->ReceiveHandler = ReceiveHandler;
+ PFilter->ReceivePacketHandler = ReceivePacketHandler;
+ PFilter->Size = Size;
+ PFilter->Offset = Offset;
+ CopyMemory((PUCHAR)PFilter + sizeof(NDIS_PROTOCOL_FILTER),
+ Pattern,
+ Size);
+
+ if ((Medium < NdisMediumMax) && ndisReferenceProtocol(ProtP))
+ {
+ NDIS_ACQUIRE_SPIN_LOCK(&ProtP->Ref.SpinLock, &OldIrql);
+ PFilter->Next = ProtP->ProtocolFilter[Medium];
+ ProtP->ProtocolFilter[Medium] = PFilter;
+ if ((PFilter->Offset + PFilter->Size) > (USHORT)(ProtP->MaxPatternSize))
+ ProtP->MaxPatternSize = PFilter->Size;
+ NDIS_RELEASE_SPIN_LOCK(&ProtP->Ref.SpinLock, OldIrql);
+ *Status = NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ *Status = NDIS_STATUS_CLOSING;
+ FREE_POOL(PFilter);
+ }
+}
+
+
+VOID
+NdisGetDriverHandle(
+ IN NDIS_HANDLE NdisBindingHandle,
+ OUT PNDIS_HANDLE NdisDriverHandle
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+ None.
+
+Note:
+
+--*/
+{
+ PNDIS_OPEN_BLOCK OpenBlock = (PNDIS_OPEN_BLOCK)NdisBindingHandle;
+
+ //
+ // Figure out if it is a miniport or a mac and return the ptr to the
+ // NDIS_M_DRIVER_BLOCK/NDIS_ADAPTER_BLOCK
+ //
+ if (OpenBlock->AdapterHandle->DeviceObject == NULL)
+ {
+ *NdisDriverHandle = ((PNDIS_M_OPEN_BLOCK)(OpenBlock->MacBindingHandle))->DriverHandle;
+ }
+ else
+ {
+ *NdisDriverHandle = OpenBlock->MacHandle;
+ }
+}
+
+
+VOID
+ndisDereferenceProtocol(
+ IN PNDIS_PROTOCOL_BLOCK ProtP
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+ None.
+
+Note:
+
+--*/
+{
+ if (NdisDereferenceRef(&(ProtP)->Ref))
+ {
+ KIRQL OldIrql;
+ PNDIS_PROTOCOL_BLOCK *ppProt;
+
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+
+ for (ppProt = &ndisProtocolList;
+ *ppProt != NULL;
+ ppProt = &(*ppProt)->NextProtocol)
+ {
+ if (*ppProt == ProtP)
+ {
+ *ppProt = ProtP->NextProtocol;
+ break;
+ }
+ }
+
+ ASSERT (*ppProt == ProtP->NextProtocol);
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ if (ProtP->DeregEvent != NULL)
+ SET_EVENT(ProtP->DeregEvent);
+ FREE_POOL(ProtP);
+
+ ProtocolDereferencePackage();
+ }
+}
+
+
+VOID
+ndisNotifyProtocols(
+ IN PNDIS_PROTOCOL_BLOCK pProt
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+ None.
+
+Note:
+
+--*/
+{
+ KIRQL OldIrql;
+ PNDIS_M_DRIVER_BLOCK MiniBlock, NextMiniBlock;
+ PNDIS_MAC_BLOCK MacBlock, NextMacBlock;
+
+ //
+ // Check again if reference is allowed i.e. if the protocol called NdisDeregisterProtocol
+ // before this thread had a chance to run.
+ //
+ if (!ndisReferenceProtocol(pProt))
+ {
+ return;
+ }
+
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+
+ // First walk the list of miniports
+ for (MiniBlock = ndisMiniDriverList;
+ MiniBlock != NULL;
+ MiniBlock = NextMiniBlock)
+ {
+ PNDIS_MINIPORT_BLOCK Miniport, NextMiniport;
+
+ NextMiniBlock = MiniBlock->NextDriver;
+ if (ndisReferenceDriver(MiniBlock))
+ {
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ NDIS_ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
+
+ for (Miniport = MiniBlock->MiniportQueue;
+ Miniport != NULL;
+ Miniport = NextMiniport)
+ {
+ NextMiniport = Miniport->NextMiniport;
+ if (ndisReferenceMiniport(Miniport))
+ {
+ NDIS_BIND_CONTEXT BindContext;
+ NDIS_STATUS BindStatus;
+
+ NDIS_RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
+
+ if (ndisCheckProtocolBinding(pProt,
+ &Miniport->MiniportName,
+ &Miniport->BaseName,
+ &BindContext.ProtocolSection))
+ {
+ ASSERT(CURRENT_IRQL < DISPATCH_LEVEL);
+ INITIALIZE_EVENT(&BindContext.Event);
+
+ WAIT_FOR_OBJECT(&pProt->Mutex, NULL);
+
+ if (!pProt->Ref.Closing)
+ {
+ (*pProt->ProtocolCharacteristics.BindAdapterHandler)(&BindStatus,
+ &BindContext,
+ &Miniport->MiniportName,
+ &BindContext.ProtocolSection,
+ NULL);
+ if (BindStatus == NDIS_STATUS_PENDING)
+ {
+ WAIT_FOR_OBJECT(&BindContext.Event, NULL);
+ }
+ }
+
+ RELEASE_MUTEX(&pProt->Mutex);
+
+ FREE_POOL(BindContext.ProtocolSection.Buffer);
+ }
+
+ NDIS_ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
+ NextMiniport = Miniport->NextMiniport;
+ ndisDereferenceMiniport(Miniport);
+ }
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
+
+ NextMiniBlock = MiniBlock->NextDriver;
+ ndisDereferenceDriver(MiniBlock);
+
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+ }
+ }
+
+ // And now the list of macs
+ for (MacBlock = ndisMacDriverList;
+ MacBlock != NULL;
+ MacBlock = NextMacBlock)
+ {
+ PNDIS_ADAPTER_BLOCK Adapter, NextAdapter;
+
+ NextMacBlock = MacBlock->NextMac;
+ if (ndisReferenceMac(MacBlock))
+ {
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ NDIS_ACQUIRE_SPIN_LOCK(&MacBlock->Ref.SpinLock, &OldIrql);
+
+ for (Adapter = MacBlock->AdapterQueue;
+ Adapter != NULL;
+ Adapter = NextAdapter)
+ {
+ NextAdapter = Adapter->NextAdapter;
+ if (ndisReferenceAdapter(Adapter))
+ {
+ NDIS_BIND_CONTEXT BindContext;
+ NDIS_STATUS BindStatus;
+
+ NDIS_RELEASE_SPIN_LOCK(&MacBlock->Ref.SpinLock, OldIrql);
+
+ if (ndisCheckProtocolBinding(pProt,
+ &Adapter->AdapterName,
+ &Adapter->BaseName,
+ &BindContext.ProtocolSection))
+ {
+ ASSERT(CURRENT_IRQL < DISPATCH_LEVEL);
+ INITIALIZE_EVENT(&BindContext.Event);
+ WAIT_FOR_OBJECT(&pProt->Mutex, NULL);
+
+ if (!pProt->Ref.Closing)
+ {
+ (*pProt->ProtocolCharacteristics.BindAdapterHandler)(&BindStatus,
+ &BindContext,
+ &Adapter->AdapterName,
+ &BindContext.ProtocolSection,
+ NULL);
+ if (BindStatus == NDIS_STATUS_PENDING)
+ {
+ WAIT_FOR_OBJECT(&BindContext.Event, NULL);
+ }
+ }
+
+ RELEASE_MUTEX(&pProt->Mutex);
+
+ FREE_POOL(BindContext.ProtocolSection.Buffer);
+ }
+
+ NDIS_ACQUIRE_SPIN_LOCK(&MacBlock->Ref.SpinLock, &OldIrql);
+ NextAdapter = Adapter->NextAdapter;
+ ndisDereferenceAdapter(Adapter);
+ }
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&MacBlock->Ref.SpinLock, OldIrql);
+
+ NextMacBlock = MacBlock->NextMac;
+ ndisDereferenceMac(MacBlock);
+
+ ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
+ }
+ }
+
+ RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
+
+ //
+ // Dereference twice - one for reference by caller and one for reference at the beginning
+ // of this routine.
+ //
+ ndisDereferenceProtocol(pProt);
+ ndisDereferenceProtocol(pProt);
+}
+
+
+VOID
+NdisOpenProtocolConfiguration(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING ProtocolSection
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+ None.
+
+Note:
+
+--*/
+{
+ PNDIS_CONFIGURATION_HANDLE HandleToReturn;
+ PNDIS_WRAPPER_CONFIGURATION_HANDLE ConfigHandle;
+#define PQueryTable ConfigHandle->ParametersQueryTable
+
+ //
+ // Allocate the space for configuration handle
+ //
+
+ *Status = NdisAllocateMemory((PVOID*)&HandleToReturn,
+ sizeof(NDIS_CONFIGURATION_HANDLE) + sizeof(NDIS_WRAPPER_CONFIGURATION_HANDLE),
+ 0,
+ HighestAcceptableMax);
+
+ if (*Status != NDIS_STATUS_SUCCESS)
+ {
+ *ConfigurationHandle = (NDIS_HANDLE)NULL;
+ return;
+ }
+
+ ZeroMemory(HandleToReturn, sizeof(NDIS_CONFIGURATION_HANDLE) + sizeof(NDIS_WRAPPER_CONFIGURATION_HANDLE));
+
+ ConfigHandle = (PNDIS_WRAPPER_CONFIGURATION_HANDLE)((PUCHAR)HandleToReturn + sizeof(NDIS_CONFIGURATION_HANDLE));
+
+ HandleToReturn->KeyQueryTable = ConfigHandle->ParametersQueryTable;
+ HandleToReturn->ParameterList = NULL;
+
+ //
+ // 1.
+ // Call ndisSaveParameter for a parameter, which will allocate storage for it.
+ //
+ PQueryTable[0].QueryRoutine = ndisSaveParameters;
+ PQueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ PQueryTable[0].DefaultType = REG_NONE;
+ //
+ // PQueryTable[0].Name and PQueryTable[0].EntryContext
+ // are filled in inside ReadConfiguration, in preparation
+ // for the callback.
+ //
+ // PQueryTable[0].Name = KeywordBuffer;
+ // PQueryTable[0].EntryContext = ParameterValue;
+
+ //
+ // 2.
+ // Stop
+ //
+
+ PQueryTable[1].QueryRoutine = NULL;
+ PQueryTable[1].Flags = 0;
+ PQueryTable[1].Name = NULL;
+
+ //
+ // NOTE: Some fields in ParametersQueryTable[3] are used to store information for later retrieval.
+ //
+ PQueryTable[3].QueryRoutine = NULL;
+ PQueryTable[3].Name = ProtocolSection->Buffer;
+ PQueryTable[3].EntryContext = NULL;
+ PQueryTable[3].DefaultData = NULL;
+
+ *ConfigurationHandle = (NDIS_HANDLE)HandleToReturn;
+ *Status = NDIS_STATUS_SUCCESS;
+}
+
+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.
+
+--*/
+{
+ KIRQL OldIrql;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>ndisQueueOpenOnProtocol\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("Protocol: %wZ\n",&ProtP->ProtocolCharacteristics.Name));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ BOOLEAN f = FALSE;
+ if (DbgIsNull(OpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisQueueOpenOnProtocol: Null Open Block\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(OpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisQueueOpenOnProtocol: Open Block not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(ProtP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisQueueOpenOnProtocol: Null Protocol Block\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(ProtP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisQueueOpenOnProtocol: Protocol Block not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (f)
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+ NDIS_ACQUIRE_SPIN_LOCK(&ProtP->Ref.SpinLock, &OldIrql);
+
+ //
+ // Make sure the protocol is not closing.
+ //
+
+ if (ProtP->Ref.Closing)
+ {
+ NDIS_RELEASE_SPIN_LOCK(&ProtP->Ref.SpinLock, OldIrql);
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==ndisQueueOpenOnProtocol\n"));
+ return FALSE;
+ }
+
+
+ //
+ // Attach this open at the head of the queue.
+ //
+
+ OpenP->ProtocolNextOpen = ProtP->OpenQueue;
+ ProtP->OpenQueue = OpenP;
+
+
+ NDIS_RELEASE_SPIN_LOCK(&ProtP->Ref.SpinLock, OldIrql);
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==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.
+
+--*/
+{
+ KIRQL OldIrql;
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("==>ndisDeQueueOpenOnProtocol\n"));
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("Protocol: %wZ\n",&ProtP->ProtocolCharacteristics.Name));
+
+ IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
+ {
+ BOOLEAN f = FALSE;
+ if (DbgIsNull(OpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisDeQueueOpenOnProtocol: Null Open Block\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(OpenP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisDeQueueOpenOnProtocol: Open Block not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (DbgIsNull(ProtP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisDeQueueOpenOnProtocol: Null Protocol Block\n"));
+ f = TRUE;
+ }
+ if (!DbgIsNonPaged(ProtP))
+ {
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
+ ("ndisDeQueueOpenOnProtocol: Protocol Block not in NonPaged Memory\n"));
+ f = TRUE;
+ }
+ if (f)
+ DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
+ }
+
+ NDIS_ACQUIRE_SPIN_LOCK(&ProtP->Ref.SpinLock, &OldIrql);
+
+ //
+ // 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;
+ }
+
+ NDIS_RELEASE_SPIN_LOCK(&ProtP->Ref.SpinLock, OldIrql);
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("<==ndisDeQueueOpenOnProtocol\n"));
+}
+
+
+#define MAX_EVENT_LOG_DATA_SIZE ((ERROR_LOG_MAXIMUM_SIZE - sizeof(IO_ERROR_LOG_PACKET) + sizeof(ULONG)) & ~3)
+
+NDIS_STATUS
+NdisWriteEventLogEntry(
+ IN PVOID LogHandle,
+ IN ULONG EventCode,
+ IN ULONG UniqueEventValue,
+ IN USHORT NumStrings,
+ IN PVOID StringsList OPTIONAL,
+ IN ULONG DataSize,
+ IN PVOID Data OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+ This function allocates an I/O error log record, fills it in and writes it
+ to the I/O error log on behalf of a NDIS Protocol.
+
+
+Arguments:
+
+ LogHandle - Pointer to the driver object logging this event.
+
+ EventCode - Identifies the error message.
+
+ UniqueEventValue - Identifies this instance of a given error message.
+
+ NumStrings - Number of unicode strings in strings list.
+
+ DataSize - Number of bytes of data.
+
+ Strings - Array of pointers to unicode strings (PWCHAR).
+
+ Data - Binary dump data for this message, each piece being
+ aligned on word boundaries.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS - The error was successfully logged.
+ NDIS_STATUS_BUFFER_TOO_SHORT - The error data was too large to be logged.
+ NDIS_STATUS_RESOURCES - Unable to allocate memory.
+
+Notes:
+
+ This code is paged and may not be called at raised IRQL.
+
+--*/
+{
+ PIO_ERROR_LOG_PACKET ErrorLogEntry;
+ ULONG PaddedDataSize;
+ ULONG PacketSize;
+ ULONG TotalStringsSize = 0;
+ USHORT i;
+ PWCHAR *Strings;
+ PWCHAR Tmp;
+
+ Strings = (PWCHAR *)StringsList;
+
+ //
+ // Sum up the length of the strings
+ //
+ for (i = 0; i < NumStrings; i++)
+ {
+ PWCHAR currentString;
+ ULONG stringSize;
+
+ stringSize = sizeof(UNICODE_NULL);
+ currentString = Strings[i];
+
+ while (*currentString++ != UNICODE_NULL)
+ {
+ stringSize += sizeof(WCHAR);
+ }
+
+ TotalStringsSize += stringSize;
+ }
+
+ if (DataSize % sizeof(ULONG))
+ {
+ PaddedDataSize = DataSize + (sizeof(ULONG) - (DataSize % sizeof(ULONG)));
+ }
+ else
+ {
+ PaddedDataSize = DataSize;
+ }
+
+ PacketSize = TotalStringsSize + PaddedDataSize;
+
+ if (PacketSize > MAX_EVENT_LOG_DATA_SIZE)
+ {
+ return (NDIS_STATUS_BUFFER_TOO_SHORT); // Too much error data
+ }
+
+ //
+ // Now add in the size of the log packet, but subtract 4 from the data
+ // since the packet struct contains a ULONG for data.
+ //
+ if (PacketSize > sizeof(ULONG))
+ {
+ PacketSize += sizeof(IO_ERROR_LOG_PACKET) - sizeof(ULONG);
+ }
+ else
+ {
+ PacketSize += sizeof(IO_ERROR_LOG_PACKET);
+ }
+
+ ASSERT(PacketSize <= ERROR_LOG_MAXIMUM_SIZE);
+
+ ErrorLogEntry = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry((PDRIVER_OBJECT)LogHandle,
+ (UCHAR) PacketSize);
+
+ if (ErrorLogEntry == NULL)
+ {
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ //
+ // Fill in the necessary log packet fields.
+ //
+ ErrorLogEntry->UniqueErrorValue = UniqueEventValue;
+ ErrorLogEntry->ErrorCode = EventCode;
+ ErrorLogEntry->NumberOfStrings = NumStrings;
+ ErrorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET) +
+ PaddedDataSize - sizeof(ULONG);
+ ErrorLogEntry->DumpDataSize = (USHORT) PaddedDataSize;
+
+ //
+ // Copy the Dump Data to the packet
+ //
+ if (DataSize > 0)
+ {
+ RtlMoveMemory((PVOID) ErrorLogEntry->DumpData,
+ Data,
+ DataSize);
+ }
+
+ //
+ // Copy the strings to the packet.
+ //
+ Tmp = (PWCHAR)((PUCHAR)ErrorLogEntry + ErrorLogEntry->StringOffset + PaddedDataSize);
+
+ for (i = 0; i < NumStrings; i++)
+ {
+ PWCHAR wchPtr = Strings[i];
+
+ while( (*Tmp++ = *wchPtr++) != UNICODE_NULL)
+ NOTHING;
+ }
+
+ IoWriteErrorLogEntry(ErrorLogEntry);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
diff --git a/private/ntos/ndis/ndis40/protos.h b/private/ntos/ndis/ndis40/protos.h
new file mode 100644
index 000000000..dd8f0623c
--- /dev/null
+++ b/private/ntos/ndis/ndis40/protos.h
@@ -0,0 +1,1991 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ protos.h
+
+Abstract:
+
+ NDIS wrapper function prototypes
+
+Author:
+
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Jun-95 Jameel Hyder Split up from a monolithic file
+--*/
+
+NTSTATUS
+ndisDispatchRequest(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ );
+
+NTSTATUS
+ndisHandlePnPRequest(
+ IN PIRP pIrp
+ );
+
+NTSTATUS
+ndisHandleLoadDriver(
+ IN PUNICODE_STRING pDevice
+ );
+
+NTSTATUS
+ndisHandleUnloadDriver(
+ IN PUNICODE_STRING pDevice
+ );
+
+NTSTATUS
+ndisHandleTranslateName(
+ IN PUNICODE_STRING pDevice,
+ IN PUCHAR Buffer,
+ IN UINT BufferLength,
+ OUT PUINT AmountCopied
+
+ );
+
+NTSTATUS
+ndisHandleLegacyTransport(
+ IN PUNICODE_STRING pDevice
+ );
+
+NTSTATUS
+ndisHandleProtocolNotification(
+ IN PUNICODE_STRING pDevice
+ );
+
+VOID
+ndisReferenceAdapterOrMiniportByName(
+ IN PUNICODE_STRING pDevice,
+ OUT PNDIS_MINIPORT_BLOCK * pMiniport,
+ OUT PNDIS_ADAPTER_BLOCK * pAdapter
+ );
+
+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
+ndisMCoDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+VOID
+ndisMCoDpcTimer(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+VOID
+ndisMCoTimerDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+VOID
+ndisMWakeUpDpc(
+ IN PKDPC Dpc,
+ IN PVOID Context,
+ IN PVOID SystemContext1,
+ IN PVOID SystemContext2
+ );
+
+VOID
+ndisMDeferredTimerDpc(
+ IN PKDPC Dpc,
+ IN PVOID Context,
+ IN PVOID SystemContext1,
+ IN 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
+ndisMResetFullDuplex(
+ IN NDIS_HANDLE NdisBindingHandle
+ );
+
+NDIS_STATUS
+ndisMReset(
+ IN NDIS_HANDLE NdisBindingHandle
+ );
+
+NDIS_STATUS
+ndisMRequest(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+#if _SEND_PRIORITY
+
+VOID
+FASTCALL
+ndisMProcessDeferredFullDuplexPrioritySends(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+VOID
+FASTCALL
+ndisMProcessDeferredPrioritySends(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+#endif
+
+VOID
+FASTCALL
+ndisMProcessDeferredFullDuplex(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+VOID
+FASTCALL
+ndisMProcessDeferred(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+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
+ndisMTransferDataSync(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+NDIS_STATUS
+ndisMDummyTransferData(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+VOID
+ndisMLazyReturnPackets(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+VOID
+ndisMIndicatePacket(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ );
+
+//
+// general reference/dereference functions
+//
+
+BOOLEAN
+NdisReferenceRef(
+ IN PREFERENCE RefP
+ );
+
+
+BOOLEAN
+NdisDereferenceRef(
+ IN PREFERENCE RefP
+ );
+
+
+VOID
+NdisInitializeRef(
+ IN PREFERENCE RefP
+ );
+
+
+BOOLEAN
+NdisCloseRef(
+ IN PREFERENCE RefP
+ );
+
+
+/*++
+BOOLEAN
+ndisReferenceProtocol(
+ IN PNDIS_PROTOCOL_BLOCK ProtP
+ );
+--*/
+
+#define ndisReferenceProtocol(ProtP) NdisReferenceRef(&(ProtP)->Ref)
+
+
+VOID
+ndisDereferenceProtocol(
+ IN PNDIS_PROTOCOL_BLOCK ProtP
+ );
+
+
+VOID
+ndisDeQueueOpenOnProtocol(
+ IN PNDIS_OPEN_BLOCK OpenP,
+ IN PNDIS_PROTOCOL_BLOCK ProtP
+ );
+
+
+BOOLEAN
+NdisFinishOpen(
+ IN PNDIS_OPEN_BLOCK OpenP
+ );
+
+
+VOID
+ndisKillOpenAndNotifyProtocol(
+ IN PNDIS_OPEN_BLOCK OldOpenP
+ );
+
+
+BOOLEAN
+ndisKillOpen(
+ IN PNDIS_OPEN_BLOCK OldOpenP
+ );
+
+/*++
+BOOLEAN
+ndisReferenceMac(
+ IN PNDIS_MAC_BLOCK MacP
+ );
+--*/
+#define ndisReferenceMac(MacP) NdisReferenceRef(&(MacP)->Ref)
+
+VOID
+ndisDereferenceMac(
+ IN PNDIS_MAC_BLOCK MacP
+ );
+
+BOOLEAN
+ndisQueueAdapterOnMac(
+ IN PNDIS_ADAPTER_BLOCK AdaptP,
+ IN PNDIS_MAC_BLOCK MacP
+ );
+
+VOID
+ndisDeQueueAdapterOnMac(
+ IN PNDIS_ADAPTER_BLOCK AdaptP,
+ IN PNDIS_MAC_BLOCK MacP
+ );
+
+/*++
+BOOLEAN
+ndisReferenceAdapter(
+ IN PNDIS_ADAPTER_BLOCK AdaptP
+ );
+--*/
+#define ndisReferenceAdapter(AdaptP) NdisReferenceRef(&(AdaptP)->Ref)
+
+
+BOOLEAN
+ndisQueueOpenOnAdapter(
+ IN PNDIS_OPEN_BLOCK OpenP,
+ IN PNDIS_ADAPTER_BLOCK AdaptP
+ );
+
+VOID
+ndisKillAdapter(
+ IN PNDIS_ADAPTER_BLOCK OldAdaptP
+ );
+
+VOID
+ndisDereferenceAdapter(
+ IN PNDIS_ADAPTER_BLOCK AdaptP
+ );
+
+VOID
+ndisDeQueueOpenOnAdapter(
+ IN PNDIS_OPEN_BLOCK OpenP,
+ IN PNDIS_ADAPTER_BLOCK AdaptP
+ );
+
+BOOLEAN
+ndisCheckPortUsage(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG PortNumber,
+ IN ULONG Length,
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+BOOLEAN
+ndisCheckMemoryUsage(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG Address,
+ IN ULONG Length,
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+NTSTATUS
+ndisStartMapping(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG InitialAddress,
+ IN ULONG Length,
+ OUT PVOID * InitialMapping,
+ OUT PBOOLEAN Mapped
+ );
+
+NTSTATUS
+ndisEndMapping(
+ IN PVOID InitialMapping,
+ IN ULONG Length,
+ IN BOOLEAN Mapped
+ );
+
+NDIS_STATUS
+ndisInitializeAdapter(
+ IN PNDIS_M_DRIVER_BLOCK pMiniBlock,
+ IN PUNICODE_STRING RegServiceName // Relative to Services key
+ );
+
+NDIS_STATUS
+ndisCheckIfPcmciaCardPresent(
+ IN PNDIS_M_DRIVER_BLOCK pMiniBlock
+ );
+
+NDIS_STATUS
+ndisFixBusInformation(
+ IN PNDIS_CONFIGURATION_HANDLE ConfigHandle,
+ IN PBUS_SLOT_DB pDb
+ );
+
+VOID
+ndisAddBusInformation(
+ IN PNDIS_CONFIGURATION_HANDLE ConfigHandle,
+ IN PBUS_SLOT_DB pDb
+ );
+
+BOOLEAN
+ndisSearchGlobalDb(
+ IN NDIS_INTERFACE_TYPE BusType,
+ IN ULONG BusId,
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber
+ );
+
+BOOLEAN
+ndisAddGlobalDb(
+ IN NDIS_INTERFACE_TYPE BusType,
+ IN ULONG BusId,
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber
+ );
+
+BOOLEAN
+ndisDeleteGlobalDb(
+ IN NDIS_INTERFACE_TYPE BusType,
+ IN ULONG BusId,
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber
+ );
+
+NTSTATUS
+ndisValidatePcmciaDriver(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+VOID
+ndisQueuedBindNotification(
+ IN PQUEUED_PROTOCOL_NOTIFICATION pQPN
+ );
+
+NDIS_STATUS
+NdisIMInitializeDeviceInstance(
+ IN NDIS_HANDLE DriverHandle,
+ IN PNDIS_STRING DeviceInstance
+ );
+
+NDIS_STATUS
+NdisIMRegisterLayeredMiniport(
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN PNDIS_MINIPORT_CHARACTERISTICS MiniportCharacteristics,
+ IN UINT CharacteristicsLength,
+ OUT PNDIS_HANDLE DriverHandle
+ );
+
+NDIS_STATUS
+ndisMInitializeAdapter(
+ IN PNDIS_M_DRIVER_BLOCK pMiniDriver,
+ IN PNDIS_WRAPPER_CONFIGURATION_HANDLE pConfigurationHandle,
+ IN PUNICODE_STRING pExportName,
+ IN PBUS_SLOT_DB pDb
+ );
+
+VOID
+ndisInitializeBindings(
+ IN PUNICODE_STRING ExportName,
+ IN PUNICODE_STRING ServiceName,
+ IN BOOLEAN Synchronous
+ );
+
+VOID
+ndisQueuedProtocolNotification(
+ IN PNDIS_BIND_CONTEXT pContext
+ );
+
+NDIS_STATUS
+ndisUpdateDriverInstance(
+ IN PUNICODE_STRING BaseString,
+ IN PUNICODE_STRING BindString,
+ IN PUNICODE_STRING ExportString,
+ IN PUNICODE_STRING RouteString
+ );
+
+BOOLEAN
+ndisCheckProtocolBinding(
+ IN PNDIS_PROTOCOL_BLOCK Protocol,
+ IN PUNICODE_STRING DeviceName,
+ IN PUNICODE_STRING BaseName,
+ OUT PUNICODE_STRING ProtocolSection
+ );
+
+BOOLEAN
+ndisProtocolAlreadyBound(
+ IN PNDIS_PROTOCOL_BLOCK Protocol,
+ IN PUNICODE_STRING AdapterName
+ );
+
+NDIS_STATUS
+ndisUnloadMiniport(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+NDIS_STATUS
+ndisTranslateMiniportName(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PUCHAR Buffer,
+ IN UINT BufferLength,
+ OUT PUINT AmountCopied
+ );
+
+NDIS_STATUS
+ndisUnloadMac(
+ IN PNDIS_ADAPTER_BLOCK Mac
+ );
+
+NDIS_STATUS
+ndisTranslateMacName(
+ IN PNDIS_ADAPTER_BLOCK Mac,
+ IN PUCHAR Buffer,
+ IN UINT BufferLength,
+ OUT PUINT AmountCopied
+ );
+
+VOID
+ndisNotifyProtocols(
+ IN PNDIS_PROTOCOL_BLOCK pProt
+ );
+
+NDIS_STATUS
+ndisInitializeAllAdapterInstances(
+ IN PNDIS_MAC_BLOCK MacBlock,
+ IN PNDIS_STRING DeviceInstance OPTIONAL
+ );
+
+/*++
+BOOLEAN
+ndisReferenceDriver(
+ IN PNDIS_M_DRIVER_BLOCK DriverP
+ );
+--*/
+#define ndisReferenceDriver(DriverP) NdisReferenceRef(&(DriverP)->Ref)
+
+
+VOID
+ndisDereferenceDriver(
+ IN PNDIS_M_DRIVER_BLOCK DriverP
+ );
+
+BOOLEAN
+ndisQueueMiniportOnDriver(
+ IN PNDIS_MINIPORT_BLOCK MiniportP,
+ IN PNDIS_M_DRIVER_BLOCK DriverP
+ );
+
+VOID
+ndisDequeueMiniportOnDriver(
+ IN PNDIS_MINIPORT_BLOCK MiniportP,
+ IN PNDIS_M_DRIVER_BLOCK DriverP
+ );
+
+/*++
+BOOLEAN
+ndisReferenceMiniport(
+ IN PNDIS_MINIPORT_BLOCK MiniportP
+ );
+--*/
+#define ndisReferenceMiniport(MiniportP) NdisReferenceRef(&(MiniportP)->Ref)
+
+VOID
+ndisDereferenceMiniport(
+ IN PNDIS_MINIPORT_BLOCK MiniportP
+ );
+
+VOID
+ndisDeQueueOpenOnMiniport(
+ IN PNDIS_M_OPEN_BLOCK OpenP,
+ IN PNDIS_MINIPORT_BLOCK MiniportP
+ );
+
+VOID
+ndisInitializePackage(
+ IN PPKG_REF pPkg,
+ IN PVOID RoutineName
+ );
+
+VOID
+ndisReferencePackage(
+ IN PPKG_REF pPkg
+ );
+
+VOID
+ndisDereferencePackage(
+ IN PPKG_REF pPkg
+ );
+
+#define ProtocolInitializePackage() ndisInitializePackage(&ProtocolPkg, NdisRegisterProtocol)
+#define MiniportInitializePackage() ndisInitializePackage(&MiniportPkg, ndisMReset)
+#define InitInitializePackage() ndisInitializePackage(&InitPkg, NdisReadConfiguration)
+#define PnPInitializePackage() ndisInitializePackage(&PnPPkg, ndisDispatchRequest)
+#define MacInitializePackage() ndisInitializePackage(&MacPkg, ndisIsr)
+#define CoInitializePackage() ndisInitializePackage(&CoPkg, NdisCmRegisterAddressFamily)
+#define EthInitializePackage() ndisInitializePackage(&EthPkg, EthCreateFilter)
+#define FddiInitializePackage() ndisInitializePackage(&FddiPkg, FddiCreateFilter)
+#define TrInitializePackage() ndisInitializePackage(&TrPkg, TrCreateFilter)
+#define ArcInitializePackage() ndisInitializePackage(&ArcPkg, ArcCreateFilter)
+
+#define ProtocolReferencePackage() ndisReferencePackage(&ProtocolPkg)
+#define MiniportReferencePackage() ndisReferencePackage(&MiniportPkg)
+#define InitReferencePackage() ndisReferencePackage(&InitPkg)
+#define PnPReferencePackage() ndisReferencePackage(&PnPPkg)
+#define MacReferencePackage() ndisReferencePackage(&MacPkg)
+#define CoReferencePackage() ndisReferencePackage(&CoPkg)
+#define EthReferencePackage() ndisReferencePackage(&EthPkg)
+#define FddiReferencePackage() ndisReferencePackage(&FddiPkg)
+#define TrReferencePackage() ndisReferencePackage(&TrPkg)
+#define ArcReferencePackage() ndisReferencePackage(&ArcPkg)
+
+#define ProtocolDereferencePackage() ndisDereferencePackage(&ProtocolPkg)
+#define MiniportDereferencePackage() ndisDereferencePackage(&MiniportPkg)
+#define InitDereferencePackage() ndisDereferencePackage(&InitPkg)
+#define PnPDereferencePackage() ndisDereferencePackage(&PnPPkg)
+#define MacDereferencePackage() ndisDereferencePackage(&MacPkg)
+#define CoDereferencePackage() ndisDereferencePackage(&CoPkg)
+#define EthDereferencePackage() ndisDereferencePackage(&EthPkg)
+#define FddiDereferencePackage() ndisDereferencePackage(&FddiPkg)
+#define TrDereferencePackage() ndisDereferencePackage(&TrPkg)
+#define ArcDereferencePackage() ndisDereferencePackage(&ArcPkg)
+
+//
+// IRP handlers established on behalf of NDIS devices by
+// the wrapper.
+//
+
+NTSTATUS
+ndisCreateIrpHandler(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+ndisDeviceControlIrpHandler(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+ndisCloseIrpHandler(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+ndisSuccessIrpHandler(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN 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
+ );
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+VOID
+ndisReadRegistry(
+ VOID
+ );
+
+NTSTATUS
+ndisReadParameters(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+ndisAddMediaTypeToArray(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+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
+ndisGetOpenBlockFromProtocolBindingContext(
+ IN NDIS_HANDLE ProtocolBindingContext
+ );
+
+NTSTATUS
+ndisShutdown(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN 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
+ );
+
+//
+// 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
+ndisMProcessResetRequested(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ OUT PBOOLEAN pAddressingReset
+ );
+
+
+#undef NdisMResetComplete
+
+EXPORT
+VOID
+NdisMResetComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_STATUS Status,
+ IN BOOLEAN AddressingReset
+ );
+
+VOID
+ndisMResetCompleteFullDuplex(
+ IN NDIS_HANDLE Miniport,
+ IN NDIS_STATUS Status,
+ IN BOOLEAN AddressingReset
+ );
+
+VOID
+ndisMResetCompleteCommonStep1(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_STATUS Status,
+ IN BOOLEAN AddressingReset
+ );
+
+VOID
+ndisMResetCompleteCommonStep2(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+
+
+NDIS_STATUS
+ndisMWanSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE NdisLinkHandle,
+ IN PVOID Packet
+ );
+
+VOID
+NdisMWanSendComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ );
+
+extern
+NTSTATUS
+ndisSaveParameters(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+extern
+NTSTATUS
+ndisSaveLinkage(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+extern
+NTSTATUS
+ndisCheckRoute(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+VOID
+ndisMHaltMiniport(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+NDIS_STATUS
+ndisMAllocateRequest(
+ OUT PNDIS_REQUEST * pRequest,
+ IN NDIS_REQUEST_TYPE RequestType,
+ IN NDIS_OID Oid,
+ IN PVOID Buffer,
+ IN ULONG BufferLength
+ );
+
+NDIS_STATUS
+ndisMFilterOutStatisticsOids(
+ PNDIS_MINIPORT_BLOCK Miniport,
+ PNDIS_REQUEST Request
+ );
+
+// VOID
+// ndisMFreeInternalRequest(
+// PVOID PRequest
+// )
+#define ndisMFreeInternalRequest(_pRequest) FREE_POOL(_pRequest)
+
+//
+// Some Wan functions that crept in because
+// the send/receive paths for WAN drivers is different
+//
+
+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
+ );
+
+VOID
+ndisMTimerDpc(
+ IN PKDPC Dpc,
+ IN PVOID Context,
+ IN PVOID SystemContext1,
+ IN PVOID SystemContext2
+ );
+
+VOID
+ndisMAbortPacketsAndRequests(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+VOID
+ndisMAbortQueryStatisticsRequest(
+ IN PNDIS_REQUEST Request,
+ IN NDIS_STATUS Status
+ );
+
+BOOLEAN
+FASTCALL
+ndisMIndicateLoopback(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+BOOLEAN
+FASTCALL
+ndisMIsLoopbackPacket(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_PACKET Packet
+ );
+
+VOID
+ndisMDoRequests(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+VOID
+ndisMCopyFromPacketToBuffer(
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ IN UINT BytesToCopy,
+ OUT PCHAR Buffer,
+ OUT PUINT BytesCopied
+ );
+
+NTSTATUS
+ndisMShutdown(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+ndisMUnload(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+NTSTATUS
+ndisMQueryOidList(
+ IN PNDIS_USER_OPEN_CONTEXT OpenContext,
+ IN PIRP Irp
+ );
+
+NDIS_STATUS
+ndisSplitStatisticsOids(
+ IN PNDIS_USER_OPEN_CONTEXT OpenContext,
+ IN PNDIS_OID OidList,
+ IN ULONG NumOids
+ );
+
+BOOLEAN
+ndisValidOid(
+ IN PNDIS_USER_OPEN_CONTEXT OpenContext,
+ IN NDIS_OID Oid
+ );
+
+VOID
+ndisQueuedCompleteOpenAdapter(
+ IN PQUEUED_OPEN_CLOSE pQoC
+ );
+
+VOID
+ndisQueuedCompleteCloseAdapter(
+ IN PQUEUED_OPEN_CLOSE pQoC
+ );
+
+VOID
+ndisMFinishClose(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_M_OPEN_BLOCK Open
+ );
+
+BOOLEAN
+ndisMKillOpen(
+ IN PNDIS_OPEN_BLOCK OldOpenP
+ );
+
+NTSTATUS
+ndisQueryOidList(
+ IN PNDIS_USER_OPEN_CONTEXT OpenContext,
+ IN PIRP Irp
+ );
+
+VOID
+ndisBugcheckHandler(
+ IN PNDIS_WRAPPER_CONTEXT WrapperContext,
+ IN ULONG Size
+ );
+
+
+VOID
+ndisMUndoBogusFilters(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+LONG
+ndisMDoMiniportOp(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN BOOLEAN Query,
+ IN ULONG Oid,
+ IN PVOID Buf,
+ IN LONG BufSize,
+ IN LONG ErrorCodesToReturn
+ );
+
+VOID
+ndisMOpenAdapter(
+ 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
+ );
+
+NDIS_STATUS
+ndisMFinishPendingOpen(
+ PMINIPORT_PENDING_OPEN MiniportPendingOpen
+ );
+
+VOID
+ndisMFinishQueuedPendingOpen(
+ IN PMINIPORT_PENDING_OPEN MiniportPendingOpen
+ );
+
+VOID
+ndisMResetCleanup(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN BOOLEAN Synchronous
+ );
+
+VOID
+ndisMSyncQueryInformationComplete(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+ndisMSyncSetInformationComplete(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+ndisMRequestQueryInformationPost(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+ndisMRequestSetInformationPost(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request,
+ IN NDIS_STATUS Status
+ );
+
+
+VOID
+ndisMQueueRequest(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request,
+ IN PNDIS_M_OPEN_BLOCK Open
+ );
+
+VOID
+ndisMRestoreFilterSettings(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_M_OPEN_BLOCK Open
+ );
+
+NDIS_STATUS
+ndisMSetPacketFilter(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+NDIS_STATUS
+ndisMSetCurrentLookahead(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+NDIS_STATUS
+ndisMSetMulticastList(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+//
+// EthFilterxxx
+//
+BOOLEAN
+EthFindMulticast(
+ IN UINT NumberOfAddresses,
+ IN CHAR AddressArray[][ETH_LENGTH_OF_ADDRESS],
+ IN CHAR MulticastAddress[ETH_LENGTH_OF_ADDRESS],
+ OUT PUINT ArrayIndex
+ );
+
+VOID
+ethUndoFilterAdjust(
+ IN PETH_FILTER Filter,
+ IN PETH_BINDING_INFO Binding
+ );
+
+VOID
+ethUndoChangeFilterAddresses(
+ IN PETH_FILTER Filter
+ );
+
+VOID
+ethRemoveBindingFromLists(
+ IN PETH_FILTER Filter,
+ IN PETH_BINDING_INFO Binding
+ );
+
+VOID
+ethRemoveAndFreeBinding(
+ IN PETH_FILTER Filter,
+ IN PETH_BINDING_INFO Binding,
+ IN BOOLEAN fCallCloseAction
+ );
+
+VOID
+ethUpdateDirectedBindingList(
+ IN OUT PETH_FILTER Filter,
+ IN PETH_BINDING_INFO Binding,
+ IN BOOLEAN fAddBindingToList
+ );
+
+VOID
+ethUpdateBroadcastBindingList(
+ IN OUT PETH_FILTER Filter,
+ IN PETH_BINDING_INFO Binding,
+ IN BOOLEAN fAddToList
+ );
+
+VOID
+ethUpdateSpecificBindingLists(
+ IN OUT PETH_FILTER Filter,
+ IN PETH_BINDING_INFO Binding
+ );
+
+VOID
+EthFilterDprIndicateReceiveFullMac(
+ 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
+);
+
+VOID
+EthFilterDprIndicateReceiveCompleteFullMac(
+ IN PETH_FILTER Filter
+ );
+
+//
+// FddiFilterxxxx
+//
+
+VOID
+fddiRemoveBindingFromLists(
+ IN PFDDI_FILTER Filter,
+ IN PFDDI_BINDING_INFO Binding
+ );
+
+VOID
+fddiRemoveAndFreeBinding(
+ IN PFDDI_FILTER Filter,
+ IN PFDDI_BINDING_INFO Binding,
+ IN BOOLEAN fCallCloseAction
+ );
+
+BOOLEAN
+FddiFindMulticastLongAddress(
+ IN UINT NumberOfAddresses,
+ IN CHAR AddressArray[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN CHAR MulticastAddress[FDDI_LENGTH_OF_LONG_ADDRESS],
+ OUT PUINT ArrayIndex
+ );
+
+BOOLEAN
+FddiFindMulticastShortAddress(
+ IN UINT NumberOfAddresses,
+ IN CHAR AddressArray[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN CHAR MulticastAddress[FDDI_LENGTH_OF_SHORT_ADDRESS],
+ OUT PUINT ArrayIndex
+ );
+
+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
+ );
+
+VOID
+fddiUpdateSpecificBindingLists(
+ IN OUT PFDDI_FILTER Filter,
+ IN PFDDI_BINDING_INFO Binding
+ );
+
+VOID
+fddiUpdateDirectedBindingList(
+ IN OUT PFDDI_FILTER Filter,
+ IN PFDDI_BINDING_INFO Binding,
+ IN BOOLEAN fAddToList
+ );
+
+VOID
+fddiUpdateBroadcastBindingList(
+ IN OUT PFDDI_FILTER Filter,
+ IN PFDDI_BINDING_INFO Binding,
+ IN BOOLEAN fAddToList
+ );
+
+VOID
+fddiUndoFilterAdjust(
+ IN OUT PFDDI_FILTER Filter,
+ IN PFDDI_BINDING_INFO Binding
+ );
+
+VOID
+fddiUndoChangeFilterLongAddresses(
+ IN PFDDI_FILTER Filter
+ );
+
+VOID
+fddiUndoChangeFilterShortAddresses(
+ IN PFDDI_FILTER Filter
+ );
+
+VOID
+FddiFilterDprIndicateReceiveFullMac(
+ 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
+ );
+
+VOID
+FddiFilterDprIndicateReceiveCompleteFullMac(
+ IN PFDDI_FILTER Filter
+ );
+
+//
+// TrFilterxxx
+//
+VOID
+trRemoveBindingFromLists(
+ IN PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding
+ );
+
+VOID
+trRemoveAndFreeBinding(
+ IN PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding,
+ IN BOOLEAN fCallCloseAction
+ );
+
+VOID
+trUpdateDirectedBindingList(
+ IN OUT PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding,
+ IN BOOLEAN fAddBindingToList
+ );
+
+VOID
+trUpdateBroadcastBindingList(
+ IN OUT PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding,
+ IN BOOLEAN fAddBindingToList
+ );
+
+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
+ );
+
+VOID
+trUpdateSpecificBindingLists(
+ IN OUT PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding
+ );
+
+VOID
+trUndoFilterAdjust(
+ IN OUT PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding
+ );
+
+VOID
+trUndoChangeFunctionalAddress(
+ IN OUT PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding
+ );
+
+VOID
+trUndoChangeGroupAddress(
+ IN OUT PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding
+ );
+
+VOID
+trCompleteChangeGroupAddress(
+ IN OUT PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding
+ );
+
+VOID
+TrFilterDprIndicateReceiveFullMac(
+ IN PTR_FILTER Filter,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+VOID
+TrFilterDprIndicateReceiveCompleteFullMac(
+ IN PTR_FILTER Filter
+ );
+
+//
+// ArcFilterxxx
+//
+VOID
+ndisMArcCopyFromBufferToPacket(
+ IN PCHAR Buffer,
+ IN UINT BytesToCopy,
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ OUT PUINT BytesCopied
+ );
+
+
+BOOLEAN
+FASTCALL
+ndisMArcnetSendLoopback(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_PACKET Packet
+ );
+
+NDIS_STATUS
+ndisMArcnetSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+NDIS_STATUS
+ndisMBuildArcnetHeader(
+ PNDIS_MINIPORT_BLOCK Miniport,
+ PNDIS_M_OPEN_BLOCK Open,
+ PNDIS_PACKET Packet
+ );
+
+VOID
+ndisMFreeArcnetHeader(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_PACKET Packet
+ );
+
+VOID
+ArcDeleteFilter(
+ IN PARC_FILTER Filter
+ );
+
+
+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
+ );
+
+VOID
+ndisMArcIndicateEthEncapsulatedReceive(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PVOID HeaderBuffer,
+ IN PVOID DataBuffer,
+ IN UINT Length
+ );
+
+VOID
+arcUndoFilterAdjust(
+ IN PARC_FILTER Filter,
+ IN PARC_BINDING_INFO Binding
+ );
+
+NDIS_STATUS
+ArcConvertOidListToEthernet(
+ IN PNDIS_OID OidList,
+ IN PULONG NumberOfOids
+ );
+
+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
+ );
+
+NDIS_STATUS
+ndisMSetFunctionalAddress(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+NDIS_STATUS
+ndisMSetGroupAddress(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+NDIS_STATUS
+ndisMSetFddiMulticastList(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request,
+ IN BOOLEAN fShort
+ );
+
+NDIS_STATUS
+ndisMSetInformation(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+NDIS_STATUS
+ndisMQueryCurrentPacketFilter(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+NDIS_STATUS
+ndisMQueryMediaSupported(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+NDIS_STATUS
+ndisMQueryEthernetMulticastList(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+NDIS_STATUS
+ndisMQueryLongMulticastList(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+NDIS_STATUS
+ndisMQueryShortMulticastList(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+NDIS_STATUS
+ndisMQueryMaximumFrameSize(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+NDIS_STATUS
+ndisMQueryMaximumTotalSize(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+NDIS_STATUS
+ndisMQueryNetworkAddress(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+NDIS_STATUS
+ndisMQueryInformation(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ );
+
+//
+// WORK ITEM ROUTINES.
+//
+VOID
+FASTCALL
+ndisMDeQueueWorkItem(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ OUT PVOID * WorkItemContext1,
+ OUT PVOID * WorkItemContext2
+ );
+
+VOID
+FASTCALL
+ndisMDeQueueWorkItemFullDuplex(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ OUT PVOID WorkItemContext1,
+ OUT PVOID WorkItemContext2
+ );
+
+NDIS_STATUS
+FASTCALL
+ndisMQueueWorkItem(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ OUT PVOID WorkItemContext1,
+ OUT PVOID WorkItemContext2
+ );
+
+NDIS_STATUS
+FASTCALL
+ndisMQueueWorkItemFullDuplex(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ OUT PVOID WorkItemContext1,
+ OUT PVOID WorkItemContext2
+ );
+
+NDIS_STATUS
+FASTCALL
+ndisMQueueNewWorkItem(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ OUT PVOID WorkItemContext1,
+ OUT PVOID WorkItemContext2
+ );
+
+NDIS_STATUS
+FASTCALL
+ndisMQueueNewWorkItemFullDuplex(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ OUT PVOID WorkItemContext1,
+ OUT PVOID WorkItemContext2
+ );
+
+
+VOID
+FASTCALL
+ndisIMDeQueueWorkItem(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ OUT PVOID WorkItemContext1,
+ OUT PVOID WorkItemContext2
+ );
+
+VOID
+FASTCALL
+ndisIMDeQueueWorkItemFullDuplex(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ OUT PVOID WorkItemContext1,
+ OUT PVOID WorkItemContext2
+ );
+
+NDIS_STATUS
+FASTCALL
+ndisIMQueueWorkItem(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ OUT PVOID WorkItemContext1,
+ OUT PVOID WorkItemContext2
+ );
+
+NDIS_STATUS
+FASTCALL
+ndisIMQueueNewWorkItem(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ OUT PVOID WorkItemContext1,
+ OUT PVOID WorkItemContext2
+ );
+
+//
+// SEND HANDLERS
+//
+//
+
+NDIS_STATUS FASTCALL
+ndisMSyncSend(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_PACKET Packet
+ );
+
+#undef NdisMSendResourcesAvailable
+
+VOID
+NdisMSendResourcesAvailable(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ );
+
+VOID
+ndisMSendResourcesAvailableFullDuplex(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ );
+
+#undef NdisMSendComplete
+
+VOID
+NdisMSendComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+ndisMSendCompleteFullDuplex(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ );
+
+BOOLEAN
+FASTCALL
+ndisMStartSendPacketsFullDuplex(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+BOOLEAN
+FASTCALL
+ndisMStartSendsFullDuplex(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+BOOLEAN
+FASTCALL
+ndisMStartSendPackets(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+BOOLEAN
+FASTCALL
+ndisMStartSends(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+NDIS_STATUS
+ndisMSendFullDuplexToSendPackets(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+VOID
+ndisMSendPacketsFullDuplex(
+ IN PNDIS_OPEN_BLOCK NdisOpenBlock,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ );
+
+NDIS_STATUS
+ndisMSendToSendPackets(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+VOID
+ndisMSendPackets(
+ IN PNDIS_OPEN_BLOCK NdisOpenBlock,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ );
+
+VOID
+ndisMSendPacketsFullDuplexToSend(
+ IN PNDIS_OPEN_BLOCK NdisOpenBlock,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ );
+
+NDIS_STATUS
+ndisMSendFullDuplex(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+VOID
+ndisMSendPacketsToSend(
+ IN PNDIS_OPEN_BLOCK NdisOpenBlock,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ );
+
+NDIS_STATUS
+ndisMSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+VOID
+ndisMSendPacketsToFullMac(
+ IN PNDIS_OPEN_BLOCK NdisOpenBlock,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ );
+
+VOID
+ndisMResetSendPackets(
+ IN PNDIS_OPEN_BLOCK NdisOpenBlock,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ );
+
+NDIS_STATUS
+ndisMResetSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+NDIS_STATUS
+ndisMResetWanSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE NdisLinkHandle,
+ IN PVOID Packet
+ );
+
+
+NDIS_STATUS
+ndisMCoSendPackets(
+ IN NDIS_HANDLE NdisVcHandle,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ );
+
+NDIS_STATUS
+ndisMRejectSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+VOID
+ndisMRejectSendPackets(
+ IN PNDIS_OPEN_BLOCK OpenBlock,
+ IN PPNDIS_PACKET Packets,
+ IN UINT NumberOfPackets
+ );
+
+NDIS_STATUS
+ndisMWrappedRequest(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+#undef NdisMStartBufferPhysicalMapping
+#undef NdisMCompleteBufferPhysicalMapping
+
+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
+ );
+
+NDIS_STATUS
+ndisAddResource(
+ OUT PCM_RESOURCE_LIST *pResources,
+ IN PCM_PARTIAL_RESOURCE_DESCRIPTOR NewResource,
+ IN NDIS_INTERFACE_TYPE AdapterType,
+ IN ULONG BusNumber,
+ IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PNDIS_STRING AdapterName
+ );
+
+NDIS_STATUS
+ndisRemoveResource(
+ OUT PCM_RESOURCE_LIST *pResources,
+ IN PCM_PARTIAL_RESOURCE_DESCRIPTOR DeadResource,
+ IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PNDIS_STRING AdapterName
+ );
+
+VOID
+ndisMReleaseResources(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+
+//
+// Co-Ndis prototypes
+//
+VOID
+ndisMNotifyAfRegistration(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PCO_ADDRESS_FAMILY AddressFamily OPTIONAL
+ );
+
+BOOLEAN
+ndisReferenceAf(
+ IN PNDIS_CO_AF_BLOCK AfBlock
+ );
+
+VOID
+ndisDereferenceAf(
+ IN PNDIS_CO_AF_BLOCK AfBlock
+ );
+
+BOOLEAN
+ndisReferenceSap(
+ IN PNDIS_CO_SAP_BLOCK SapBlock
+ );
+
+VOID
+ndisDereferenceSap(
+ IN PNDIS_CO_SAP_BLOCK SapBlock
+ );
+
+BOOLEAN
+ndisReferenceVc(
+ IN PNDIS_CO_VC_BLOCK AfBlock
+ );
+
+VOID
+ndisDereferenceVc(
+ IN PNDIS_CO_VC_BLOCK AfBlock
+ );
+
+VOID
+ndisMCoFreeResources(
+ PNDIS_M_OPEN_BLOCK Open
+ );
+
+//
+// If we are on an x86 box and internal debugging is enabled
+// then we prototype the following.
+//
+#if _DBG && defined(_M_IX86) && defined(_NDIS_INTERNAL_DEBUG)
+
+EXPORT
+VOID
+NdisMSetWriteBreakPoint(
+ IN PVOID LinearAddress
+ );
+
+EXPORT
+VOID
+NdisMClearWriteBreakPoint(
+ IN PVOID LinearAddress
+ );
+
+#else
+
+#define NdisMSetWriteBreakPoint(LinearAddress)
+#define NdisMClearWriteBreakPoint(LinearAddress)
+
+#endif
+
+#if TRACK_MEMORY
+
+extern
+PVOID
+AllocateM(
+ IN UINT Size,
+ IN ULONG ModLine,
+ IN ULONG Tag
+ );
+
+extern
+VOID
+FreeM(
+ IN PVOID MemPtr
+ );
+
+#endif
diff --git a/private/ntos/ndis/ndis40/requestm.c b/private/ntos/ndis/ndis40/requestm.c
new file mode 100644
index 000000000..1a3a5578d
--- /dev/null
+++ b/private/ntos/ndis/ndis40/requestm.c
@@ -0,0 +1,3994 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ requestm.c
+
+Abstract:
+
+ NDIS miniport request routines.
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 05-Oct-93
+ Jameel Hyder (JameelH) Re-organization 01-Jun-95
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_REQUESTM
+
+//
+// This macro verifies the query information buffer length.
+//
+#define VERIFY_QUERY_PARAMETERS(_Request, _SizeNeeded, _Status) \
+{ \
+ if ((_Request)->DATA.QUERY_INFORMATION.InformationBufferLength < (_SizeNeeded)) \
+ { \
+ (_Request)->DATA.QUERY_INFORMATION.BytesNeeded = (_SizeNeeded); \
+ \
+ Status = NDIS_STATUS_INVALID_LENGTH; \
+ } \
+ else \
+ { \
+ Status = NDIS_STATUS_SUCCESS; \
+ } \
+}
+
+//
+// This macro verifies the set information buffer length.
+//
+#define VERIFY_SET_PARAMETERS(_Request, _SizeNeeded, _Status) \
+{ \
+ if ((_Request)->DATA.SET_INFORMATION.InformationBufferLength < (_SizeNeeded)) \
+ { \
+ (_Request)->DATA.SET_INFORMATION.BytesNeeded = (_SizeNeeded); \
+ \
+ Status = NDIS_STATUS_INVALID_LENGTH; \
+ } \
+ else \
+ { \
+ Status = NDIS_STATUS_SUCCESS; \
+ } \
+}
+
+VOID
+ndisMQueueRequest(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request,
+ IN PNDIS_M_OPEN_BLOCK Open
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_REQUEST *ppReq;
+
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Next = NULL;
+ if (Open != NULL)
+ {
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open = Open;
+ Open->References++;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("+ Open 0x%x Reference 0x%x\n", Open, Open->References));
+ }
+
+ for (ppReq = &Miniport->PendingRequest;
+ *ppReq != NULL;
+ NOTHING)
+ {
+ ppReq = &(PNDIS_RESERVED_FROM_PNDIS_REQUEST(*ppReq))->Next;
+ }
+ *ppReq = Request;
+}
+
+NDIS_STATUS
+ndisMAllocateRequest(
+ OUT PNDIS_REQUEST * pRequest,
+ IN NDIS_REQUEST_TYPE RequestType,
+ IN NDIS_OID Oid,
+ IN PVOID Buffer,
+ IN ULONG BufferLength
+ )
+/*++
+
+Routine Description:
+
+ This routine will allocate a request to be used as an internal request.
+
+Arguments:
+
+ Request - Will contain a pointer to the new request on exit.
+ RequestType - Type of ndis request.
+ Oid - Request identifier.
+ Buffer - Pointer to the buffer for the request.
+ BufferLength- Length of the buffer.
+ Context1 - This is the type of request.
+ Context2 - Information that will be needed when the internal request
+ completes.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if the request allocation succeeded.
+ NDIS_STATUS_FAILURE otherwise.
+
+--*/
+{
+ PNDIS_REQUEST Request;
+ ULONG SizeNeeded;
+ PVOID Data;
+
+ //
+ // Allocate the request structure.
+ //
+ SizeNeeded = sizeof(NDIS_REQUEST) + BufferLength;
+ Data = ALLOC_FROM_POOL(SizeNeeded, NDIS_TAG_Q_REQ);
+ if (NULL == Data)
+ {
+ *pRequest = NULL;
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ //
+ // Zero out the request.
+ //
+ ZeroMemory(Data, SizeNeeded);
+
+ //
+ // Get a pointer to the request.
+ //
+ Request = Data;
+
+ //
+ // Set the request type.
+ //
+ Request->RequestType = RequestType;
+
+ //
+ // Copy the buffer that was passed to us into
+ // the new buffer.
+ //
+ if ((BufferLength > 0) &&
+ (Buffer != NULL) &&
+ (RequestType != NdisRequestQueryInformation) &&
+ (RequestType != NdisRequestQueryStatistics))
+ {
+ MoveMemory(Request + 1, Buffer, BufferLength);
+ }
+
+ //
+ // Initialize depending upon request type.
+ //
+ switch (RequestType)
+ {
+ case NdisRequestQueryStatistics:
+ case NdisRequestQueryInformation:
+ Request->DATA.QUERY_INFORMATION.Oid = Oid;
+ if ((BufferLength > 0) && (Buffer != NULL))
+ {
+ Request->DATA.QUERY_INFORMATION.InformationBuffer = Request + 1;
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength = BufferLength;
+ }
+
+ break;
+
+ case NdisRequestSetInformation:
+ Request->DATA.SET_INFORMATION.Oid = Oid;
+ if ((BufferLength > 0) && (Buffer != NULL))
+ {
+ Request->DATA.SET_INFORMATION.InformationBuffer = Request + 1;
+ Request->DATA.SET_INFORMATION.InformationBufferLength = BufferLength;
+ }
+
+ break;
+
+ default:
+
+ break;
+ }
+
+ //
+ // Give it back to the caller.
+ //
+ *pRequest = Request;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+VOID
+ndisMRestoreFilterSettings(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_M_OPEN_BLOCK Open
+ )
+/*++
+
+Routine Description:
+
+ This routine will build request's to send down to the driver to
+ restore the filter settings. we have free run of the request queue
+ since we just reset it.
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_REQUEST Request;
+ NDIS_STATUS Status;
+ ULONG PacketFilter;
+ UINT NumberOfAddresses;
+ UINT FunctionalAddress;
+ UINT GroupAddress;
+ PSINGLE_LIST_ENTRY Link;
+
+ //
+ // Get the packet filter for the media type.
+ //
+ 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_TEST_FLAG(
+ Miniport,
+ fMINIPORT_ARCNET_BROADCAST_SET) ||
+ (PacketFilter & NDIS_PACKET_TYPE_MULTICAST))
+ {
+ PacketFilter &= ~NDIS_PACKET_TYPE_MULTICAST;
+ PacketFilter |= NDIS_PACKET_TYPE_BROADCAST;
+ }
+
+ break;
+ }
+
+ //
+ // Allocate a request to restore the packet filter.
+ //
+ Status = ndisMAllocateRequest(&Request,
+ NdisRequestSetInformation,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ &PacketFilter,
+ sizeof(PacketFilter));
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Should do something here!!
+ //
+ }
+
+ ndisMQueueRequest(Miniport, Request, Open);
+
+ //
+ // Now build media dependant requests.
+ //
+ switch (Miniport->MediaType)
+ {
+ case NdisMedium802_3:
+
+ ///
+ // For ethernet we need to restore the multicast address list.
+ ///
+
+ //
+ // Get a list of all the multicast address that need
+ // to be set.
+ //
+ EthQueryGlobalFilterAddresses(&Status,
+ Miniport->EthDB,
+ NDIS_M_MAX_MULTI_LIST * ETH_LENGTH_OF_ADDRESS,
+ &NumberOfAddresses,
+ (PVOID)Miniport->MulticastBuffer);
+
+ //
+ // Allocate a request to restore the multicast address list.
+ //
+ Status = ndisMAllocateRequest(&Request,
+ NdisRequestSetInformation,
+ OID_802_3_MULTICAST_LIST,
+ Miniport->MulticastBuffer,
+ NumberOfAddresses * ETH_LENGTH_OF_ADDRESS);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Should do something here!!
+ //
+ }
+
+ ndisMQueueRequest(Miniport, Request, Open);
+ break;
+
+ case NdisMedium802_5:
+
+ ///
+ // For token ring we need to restore the functional address
+ // and the group address.
+ ///
+
+ //
+ // Get the current functional address from the filter
+ // library.
+ //
+ FunctionalAddress = TR_QUERY_FILTER_ADDRESSES(Miniport->TrDB);
+ FunctionalAddress = BYTE_SWAP_ULONG(FunctionalAddress);
+
+ //
+ // Allocate a request to restore the functional address.
+ //
+ Status = ndisMAllocateRequest(&Request,
+ NdisRequestSetInformation,
+ OID_802_5_CURRENT_FUNCTIONAL,
+ &FunctionalAddress,
+ sizeof(FunctionalAddress));
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Should do something here!!
+ //
+ }
+
+ ndisMQueueRequest(Miniport, Request, Open);
+
+ //
+ // Get the current group address from the filter library.
+ //
+ GroupAddress = TR_QUERY_FILTER_GROUP(Miniport->TrDB);
+ GroupAddress = BYTE_SWAP_ULONG(GroupAddress);
+
+ //
+ // Allocate a request to restore the group address.
+ //
+ Status = ndisMAllocateRequest(&Request,
+ NdisRequestSetInformation,
+ OID_802_5_CURRENT_GROUP,
+ &GroupAddress,
+ sizeof(GroupAddress));
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Should do something here!!
+ //
+ }
+
+ ndisMQueueRequest(Miniport, Request, Open);
+
+ break;
+
+ case NdisMediumFddi:
+
+ ///
+ // For FDDI we need to restore the long multicast address
+ // list and the short multicast address list.
+ ///
+
+ //
+ // Get the number of multicast addresses and the list
+ // of multicast addresses to send to the miniport driver.
+ //
+ FddiQueryGlobalFilterLongAddresses(&Status,
+ Miniport->FddiDB,
+ NDIS_M_MAX_MULTI_LIST * FDDI_LENGTH_OF_LONG_ADDRESS,
+ &NumberOfAddresses,
+ (PVOID)Miniport->MulticastBuffer);
+
+ //
+ // Allocate a request to restore the long multicast address list.
+ //
+ Status = ndisMAllocateRequest(&Request,
+ NdisRequestSetInformation,
+ OID_FDDI_LONG_MULTICAST_LIST,
+ Miniport->MulticastBuffer,
+ NumberOfAddresses * FDDI_LENGTH_OF_LONG_ADDRESS);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Should do something here!!
+ //
+ }
+
+ ndisMQueueRequest(Miniport, Request, Open);
+
+ //
+ // Get the number of multicast addresses and the list
+ // of multicast addresses to send to the miniport driver.
+ //
+ FddiQueryGlobalFilterShortAddresses(&Status,
+ Miniport->FddiDB,
+ NDIS_M_MAX_MULTI_LIST * FDDI_LENGTH_OF_SHORT_ADDRESS,
+ &NumberOfAddresses,
+ (PVOID)Miniport->MulticastBuffer);
+
+ //
+ // Allocate a request to restore the short multicast address list.
+ //
+ Status = ndisMAllocateRequest(&Request,
+ NdisRequestSetInformation,
+ OID_FDDI_SHORT_MULTICAST_LIST,
+ Miniport->MulticastBuffer,
+ NumberOfAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Should do something here!!
+ //
+ }
+
+ ndisMQueueRequest(Miniport, Request, Open);
+
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ //
+ // Only the packet filter is restored for arcnet and
+ // that was done above.
+ //
+
+ break;
+ }
+
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+}
+
+
+NDIS_STATUS
+ndisMRequest(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_M_OPEN_BLOCK Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = Open->MiniportHandle;
+ PNDIS_REQUEST_RESERVED Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(NdisRequest);
+ BOOLEAN LocalLock;
+ KIRQL OldIrql;
+ NDIS_STATUS Status;
+ PSINGLE_LIST_ENTRY Link;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ //
+ // Get protocol-options
+ //
+ if ((NdisRequest->RequestType == NdisRequestSetInformation) &&
+ (NdisRequest->DATA.SET_INFORMATION.Oid == OID_GEN_PROTOCOL_OPTIONS) &&
+ (NdisRequest->DATA.SET_INFORMATION.InformationBuffer != NULL))
+ {
+ PULONG ProtocolOptions;
+
+ ProtocolOptions = (PULONG)(NdisRequest->DATA.SET_INFORMATION.InformationBuffer);
+ if (*ProtocolOptions & NDIS_PROT_OPTION_NO_RSVD_ON_RCVPKT)
+ {
+ *ProtocolOptions &= ~NDIS_PROT_OPTION_NO_RSVD_ON_RCVPKT;
+ Open->Flags |= fMINIPORT_OPEN_NO_PROT_RSVD;
+ Open->FakeOpen->NoProtRsvdOnRcvPkt = TRUE;
+ }
+ if ((*ProtocolOptions & NDIS_PROT_OPTION_NO_LOOPBACK) &&
+ (Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK))
+ {
+ *ProtocolOptions &= ~fMINIPORT_OPEN_NO_LOOPBACK;
+ Open->Flags |= NDIS_PROT_OPTION_NO_LOOPBACK;
+ }
+ }
+
+ //
+ // Is there a reset in progress?
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS))
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ return(NDIS_STATUS_RESET_IN_PROGRESS);
+ }
+
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Got request 0x%x\n", NdisRequest));
+
+ //
+ // Place the new request on the pending queue.
+ //
+ ndisMQueueRequest(
+ Miniport,
+ NdisRequest,
+ (PNDIS_M_OPEN_BLOCK)NdisBindingHandle);
+
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+
+ 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.
+ //
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ return(NDIS_STATUS_PENDING);
+}
+
+
+VOID
+ndisMUndoBogusFilters(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+)
+
+/*++
+
+Routine Description:
+
+ Deletes the bogus filter packages created in NdisCallDriverAddAdapter.
+
+Arguments:
+
+ Miniport - Pointer to the Miniport.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ EthDeleteFilter(Miniport->EthDB);
+ Miniport->EthDB = NULL;
+ TrDeleteFilter(Miniport->TrDB);
+ Miniport->TrDB = NULL;
+ FddiDeleteFilter(Miniport->FddiDB);
+ Miniport->FddiDB = NULL;
+ ArcDeleteFilter(Miniport->ArcDB);
+ Miniport->ArcDB = NULL;
+}
+
+LONG
+ndisMDoMiniportOp(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN BOOLEAN Query,
+ IN ULONG Oid,
+ IN PVOID Buf,
+ IN LONG BufSize,
+ IN LONG ErrorCodesToReturn
+ )
+
+{
+ KIRQL OldIrql;
+ NTSTATUS NtStatus;
+ NDIS_STATUS NdisStatus;
+ LONG ErrorCode = 0;
+ UINT BytesWritten;
+ UINT BytesNeeded;
+ BOOLEAN LocalLock;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+
+ RAISE_IRQL_TO_DISPATCH(&OldIrql);
+ BLOCK_LOCK_MINIPORT_DPC(Miniport, LocalLock);
+
+ //
+ // Save a pointer to the miniport block as the
+ // current request. This will tell us that this request
+ // needs to be completed by setting the event.
+ //
+ Miniport->MiniportRequest = (PNDIS_REQUEST)Miniport;
+
+ //
+ // Do the appropriate operation.
+ //
+ if (Query)
+ {
+ NdisStatus = (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ Oid,
+ Buf,
+ BufSize,
+ &BytesWritten,
+ &BytesNeeded);
+ }
+ else
+ {
+ NdisStatus = (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ Oid,
+ Buf,
+ BufSize,
+ &BytesWritten,
+ &BytesNeeded);
+ }
+
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS))
+ {
+ //
+ // Queue a dpc to fire.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemDpc, &Miniport->Dpc, NULL);
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ LOWER_IRQL(OldIrql);
+
+ if (NdisStatus == NDIS_STATUS_PENDING)
+ {
+ LARGE_INTEGER TimeoutValue;
+
+ TimeoutValue.QuadPart = Int32x32To64(1000, -10000); // Make it 1 second
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+ NtStatus = WAIT_FOR_OBJECT(&Miniport->RequestEvent, &TimeoutValue);
+
+ NdisStatus = Miniport->RequestStatus;
+
+ if ((NtStatus != STATUS_SUCCESS) ||
+ (NdisStatus != NDIS_STATUS_SUCCESS))
+ {
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler)(Miniport->MiniportAdapterContext);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ ErrorCode = (NtStatus != STATUS_SUCCESS) ? ErrorCodesToReturn : ErrorCodesToReturn + 1;
+ }
+
+ RESET_EVENT(&Miniport->RequestEvent);
+ }
+
+ return(ErrorCode);
+}
+
+NDIS_STATUS
+ndisMFilterOutStatisticsOids(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+ This routine will filter out any statistics OIDs.
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ ULONG c;
+ PNDIS_OID OidList;
+ ULONG TotalOids;
+ ULONG CurrentDestOid;
+
+ //
+ // Initialize some temp variables.
+ //
+ OidList = Request->DATA.QUERY_INFORMATION.InformationBuffer;
+ TotalOids = Request->DATA.QUERY_INFORMATION.BytesWritten / sizeof(NDIS_OID);
+
+ //
+ // Copy the information OIDs to the buffer that
+ // was passed with the original request.
+ //
+ for (c = 0, CurrentDestOid = 0;
+ c < TotalOids;
+ c++
+ )
+ {
+ //
+ // Is this a statistic Oid?
+ //
+ if ((OidList[c] & 0x00FF0000) != 0x00020000)
+ {
+ OidList[CurrentDestOid++] = OidList[c];
+ }
+ }
+
+ //
+ // If ARCnet then do the filtering.
+ //
+ if ((Miniport->MediaType == NdisMediumArcnet878_2) &&
+ MINIPORT_TEST_FLAG(
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open,
+ fMINIPORT_OPEN_USING_ETH_ENCAPSULATION)
+ )
+ {
+ ArcConvertOidListToEthernet(OidList, &CurrentDestOid);
+ }
+
+ //
+ // Save the amount of data that was kept.
+ //
+ Request->DATA.QUERY_INFORMATION.BytesWritten =
+ CurrentDestOid * sizeof(NDIS_OID);
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+
+VOID
+ndisMRequestQueryInformationPost(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ switch (Request->DATA.QUERY_INFORMATION.Oid)
+ {
+ case OID_GEN_SUPPORTED_LIST:
+
+ //
+ // Was this a query for the size of the list?
+ //
+ if ((NULL == Request->DATA.QUERY_INFORMATION.InformationBuffer) ||
+ (0 == Request->DATA.QUERY_INFORMATION.InformationBufferLength) ||
+ (Status != NDIS_STATUS_SUCCESS))
+ {
+ //
+ // If this is ARCnet running encapsulated ethernet then
+ // we need to add a couple of OIDs to be safe.
+ //
+ if ((Miniport->MediaType == NdisMediumArcnet878_2) &&
+ MINIPORT_TEST_FLAG(
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open,
+ fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
+ {
+ Request->DATA.QUERY_INFORMATION.BytesNeeded +=
+ (ARC_NUMBER_OF_EXTRA_OIDS * sizeof(NDIS_OID));
+ }
+
+ Request->DATA.QUERY_INFORMATION.BytesWritten = 0;
+ }
+ else
+ {
+ //
+ // Filter out the statistics oids.
+ //
+ ndisMFilterOutStatisticsOids(Miniport, Request);
+ }
+ break;
+ }
+}
+
+VOID
+ndisMSyncQueryInformationComplete(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ This routine will process a query information complete. This is only
+ called from the wrapper. The difference is that this routine will not
+ call ndisMProcessDeferred() after processing the completion of the query.
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_REQUEST Request;
+ PNDIS_M_OPEN_BLOCK Open;
+ PNDIS_REQUEST_RESERVED Reserved;
+
+ //
+ // Check for global statistics request
+ //
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_REQUEST_TIMEOUT);
+
+ //
+ // If the current request is a pointer to the miniport block
+ // then this is an initialization request that pended.
+ // We complete this by setting the request event.
+ //
+ if (Miniport->MiniportRequest == (PNDIS_REQUEST)Miniport)
+ {
+ Miniport->MiniportRequest = NULL;
+ Miniport->RequestStatus = Status;
+ SET_EVENT(&Miniport->RequestEvent);
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Exit query information complete\n"));
+ return;
+ }
+
+ //
+ // Remove the request.
+ //
+ Request = Miniport->MiniportRequest;
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request);
+ Miniport->MiniportRequest = NULL;
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Request 0x%x\n", Request));
+
+ //
+ // Separate processing for query statistics information complete.
+ //
+ 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;
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Enter Query Statistics Information Complete\n"));
+
+ 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;
+ SET_EVENT(&OpenRequest->Event);
+
+ 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;
+ }
+
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ FREE_POOL (GlobalRequest);
+
+ break;
+
+ case IOCTL_NDIS_QUERY_ALL_STATS:
+
+ //
+ // An "all" query.
+ //
+
+ AllRequest = (PNDIS_QUERY_ALL_REQUEST)GlobalRequest;
+
+ AllRequest->NdisStatus = Status;
+ SET_EVENT(&AllRequest->Event);
+
+ break;
+ }
+
+ break;
+ }
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Exit Query Statistics Information Complete\n"));
+
+ return;
+ }
+
+ //
+ // Do any necessary post-processing on the query.
+ //
+ ndisMRequestQueryInformationPost(Miniport, Request, Status);
+
+ //
+ // Was this an internal request?
+ //
+ if (Reserved->Open != NULL)
+ {
+ //
+ // Indicate to Protocol;
+ //
+ Open = Reserved->Open;
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Open 0x%x\n", Open));
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.RequestCompleteHandler)(
+ Open->ProtocolBindingContext,
+ Request,
+ Status);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("- Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ Open->References--;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("==0 Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ if (Open->References == 0)
+ {
+ ndisMFinishClose(Miniport,Open);
+ }
+ }
+ else
+ {
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Completing Internal Request\n"));
+
+ ndisMFreeInternalRequest(Request);
+ }
+}
+
+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;
+ PSINGLE_LIST_ENTRY Link;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ //
+ // If there is no request then we assume this is a complete that was
+ // aborted due to the heart-beat.
+ //
+ if (Miniport->MiniportRequest == NULL)
+ {
+ return;
+ }
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Enter query information complete\n"));
+
+ //
+ // Do the actual processing of the query information complete.
+ //
+ ndisMSyncQueryInformationComplete(Miniport, Status);
+
+ //
+ // Are there more requests pending?
+ //
+ if (Miniport->PendingRequest != NULL)
+ {
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+ }
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Exit query information complete\n"));
+}
+
+
+VOID
+ndisMRequestSetInformationPost(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request,
+ IN NDIS_STATUS Status
+)
+/*++
+
+Routine Description:
+
+ This routine will do any necessary post processing for ndis requests
+ of the set information type.
+
+Arguments:
+
+ Miniport - Pointer to the miniport block.
+
+ Request - Pointer to the request to process.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_REQUEST_RESERVED Reserved;
+ ULONG GroupAddress;
+
+ //
+ // Get the reserved information for the request.
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request);
+
+ switch (Request->DATA.SET_INFORMATION.Oid)
+ {
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ //
+ // The request was completed with something besides
+ // NDIS_STATUS_SUCCESS (and of course NDIS_STATUS_PENDING).
+ // Return the packete filter to the original state.
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request);
+
+ switch (Miniport->MediaType)
+ {
+ case NdisMedium802_3:
+ ethUndoFilterAdjust(Miniport->EthDB, Reserved->Open->FilterHandle);
+ break;
+
+ case NdisMedium802_5:
+ trUndoFilterAdjust(Miniport->TrDB, Reserved->Open->FilterHandle);
+ break;
+
+ case NdisMediumFddi:
+ fddiUndoFilterAdjust(Miniport->FddiDB, Reserved->Open->FilterHandle);
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ if (MINIPORT_TEST_FLAG(Reserved->Open,
+ fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
+ {
+ ethUndoFilterAdjust(Miniport->EthDB, Reserved->Open->FilterHandle);
+ }
+ else
+ {
+ arcUndoFilterAdjust(Miniport->ArcDB, Reserved->Open->FilterHandle);
+ }
+
+ break;
+ }
+ }
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ //
+ // If we succeeded then update the binding information.
+ //
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ NdisMoveMemory(&Reserved->Open->CurrentLookahead,
+ Request->DATA.SET_INFORMATION.InformationBuffer,
+ 4);
+
+ Miniport->CurrentLookahead = Reserved->Open->CurrentLookahead;
+
+ Request->DATA.SET_INFORMATION.BytesRead = 4;
+ }
+
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+
+ //
+ // We only need to do cleanup if it did not
+ // return NDIS_STATUS_SUCCESS.
+ //
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ ethUndoChangeFilterAddresses(Miniport->EthDB);
+ }
+ else
+ {
+ Request->DATA.SET_INFORMATION.BytesRead =
+ Request->DATA.SET_INFORMATION.InformationBufferLength;
+ }
+
+ break;
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ trUndoChangeFunctionalAddress(Miniport->TrDB, Reserved->Open->FilterHandle);
+ }
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ trUndoChangeGroupAddress(Miniport->TrDB, Reserved->Open->FilterHandle);
+ }
+
+ break;
+
+ case OID_FDDI_LONG_MULTICAST_LIST:
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ fddiUndoChangeFilterLongAddresses(Miniport->FddiDB);
+ }
+ else
+ {
+ Request->DATA.SET_INFORMATION.BytesRead =
+ Request->DATA.SET_INFORMATION.InformationBufferLength;
+ }
+ break;
+
+ case OID_FDDI_SHORT_MULTICAST_LIST:
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ fddiUndoChangeFilterShortAddresses(Miniport->FddiDB);
+ }
+ else
+ {
+ Request->DATA.SET_INFORMATION.BytesRead =
+ Request->DATA.SET_INFORMATION.InformationBufferLength;
+ }
+ break;
+ }
+}
+
+VOID
+ndisMSyncSetInformationComplete(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ This routine will process a set information complete. This is only
+ called from the wrapper. The difference is that this routine will not
+ call ndisMProcessDeferred() after processing the completion of the set.
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_REQUEST Request;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ //
+ // Clear the timeout flag.
+ //
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_REQUEST_TIMEOUT);
+
+ //
+ // Get a pointer to the request that we are completeing.
+ // And clear out the request in-progress pointer.
+ //
+ Request = Miniport->MiniportRequest;
+ Miniport->MiniportRequest = NULL;
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Completing Set Information Request 0x%x\n", Request));
+
+ //
+ // Get a pointer to the open that made the request.
+ // for internal requests this will be NULL.
+ //
+ Open = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open;
+
+ //
+ // Do we need to indicate this request to the protocol?
+ // We do if it's not an internal request.
+ //
+ if (Open != NULL)
+ {
+ //
+ // If the open is not closing then notify it of
+ // the request completion.
+ //
+ if (!MINIPORT_TEST_FLAG(Open, fMINIPORT_OPEN_CLOSING))
+ {
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Open 0x%x\n", Open));
+
+ //
+ // Do any necessary post processing for the request.
+ //
+ ndisMRequestSetInformationPost(Miniport, Request, Status);
+
+ //
+ // Indicate to Protocol;
+ //
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.RequestCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Request,
+ Status
+ );
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ }
+
+ //
+ // Dereference the open.
+ //
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("- Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ Open->References--;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("==0 Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ if (Open->References == 0)
+ {
+ ndisMFinishClose(Miniport,Open);
+ }
+ }
+ else
+ {
+ //
+ // Internal requests are only used for restoring filter settings
+ // in the set information path. this means that no post processing
+ // needs to be done.
+ //
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Completeing internal request\n"));
+
+ //
+ // BUGBUG
+ //
+ // What if one of these requests fails???? We should probably halt
+ // the driver sine this is a fatal error as far as the bindings
+ // are concerned.
+ //
+ ASSERT(NDIS_STATUS_SUCCESS == Status);
+
+ //
+ // Is this the last internal request?
+ //
+ if (NULL == Miniport->PendingRequest)
+ {
+ //
+ // Now clear out the reset in progress stuff.
+ //
+ ndisMResetCompleteCommonStep2(Miniport);
+ }
+
+ //
+ // Free the request.
+ //
+ ndisMFreeInternalRequest(Request);
+ }
+}
+
+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;
+ PSINGLE_LIST_ENTRY Link;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ //
+ // If we don't have a request to complete assume it was
+ // aborted via the reset handler.
+ //
+ if ((Miniport->MiniportRequest == NULL) ||
+ (Miniport->MiniportRequest == (PNDIS_REQUEST)Miniport))
+ {
+ return;
+ }
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Enter set information complete\n"));
+
+ //
+ // Process the actual set information complete.
+ //
+ ndisMSyncSetInformationComplete(Miniport, Status);
+
+ //
+ // Are there more requests pending?
+ //
+ if (Miniport->PendingRequest != NULL)
+ {
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+ }
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Exit set information complete\n"));
+}
+
+VOID
+ndisMAbortQueryStatisticsRequest(
+ IN PNDIS_REQUEST Request,
+ IN 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;
+ SET_EVENT(&OpenRequest->Event);
+ 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;
+ }
+
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ FREE_POOL (GlobalRequest);
+ break;
+
+ case IOCTL_NDIS_QUERY_ALL_STATS:
+
+ //
+ // An "all" query.
+ //
+ AllRequest = (PNDIS_QUERY_ALL_REQUEST)GlobalRequest;
+
+ AllRequest->NdisStatus = Status;
+ SET_EVENT(&AllRequest->Event);
+
+ break;
+ }
+
+ break;
+ }
+
+} // ndisMAbortQueryStatisticsRequest
+
+NDIS_STATUS
+ndisMSetPacketFilter(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+ This routine will process two types of set packet filter requests.
+ The first one is for when a reset happens. We simply take the
+ packet filter setting that is in the request and send it to the adapter.
+ The second is when a protocol sets the packet filter, for this we need
+ to update the filter library and then send it down to the adapter.
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ ULONG PacketFilter;
+ PNDIS_REQUEST_RESERVED Reserved;
+
+ //
+ // Verify the information buffer length that was sent in.
+ //
+ VERIFY_SET_PARAMETERS(Request, sizeof(PacketFilter), Status);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return(Status);
+ }
+
+ //
+ // Now call the filter package to set the
+ // packet filter.
+ //
+ MoveMemory((PVOID)&PacketFilter,
+ Request->DATA.SET_INFORMATION.InformationBuffer,
+ sizeof(ULONG));
+
+ //
+ // Get a pointer to the reserved information of the request.
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request);
+
+ //
+ // If this request is because of an open that is closing then we
+ // have already adjusted the filter settings and we just need to
+ // make sure that the adapter has the new settings.
+ //
+ if (MINIPORT_TEST_FLAG(Reserved->Open, fMINIPORT_OPEN_CLOSING))
+ {
+ //
+ // By setting the Status to NDIS_STATUS_PENDING we will call
+ // down to the miniport's SetInformationHandler below.
+ //
+ Status = NDIS_STATUS_PENDING;
+ }
+ else
+ {
+ switch (Miniport->MediaType)
+ {
+ case NdisMedium802_3:
+ Status = EthFilterAdjust(Miniport->EthDB,
+ Reserved->Open->FilterHandle,
+ Request,
+ PacketFilter,
+ TRUE);
+
+ //
+ // Do this here in anticipation that we
+ // need to call down to the miniport
+ // driver.
+ //
+ PacketFilter = ETH_QUERY_FILTER_CLASSES(Miniport->EthDB);
+
+ break;
+
+ case NdisMedium802_5:
+ Status = TrFilterAdjust(Miniport->TrDB,
+ Reserved->Open->FilterHandle,
+ Request,
+ PacketFilter,
+ TRUE);
+
+ //
+ // Do this here in anticipation that we
+ // need to call down to the miniport
+ // driver.
+ //
+ PacketFilter = TR_QUERY_FILTER_CLASSES(Miniport->TrDB);
+
+ break;
+
+ case NdisMediumFddi:
+ Status = FddiFilterAdjust(Miniport->FddiDB,
+ Reserved->Open->FilterHandle,
+ Request,
+ PacketFilter,
+ TRUE);
+
+ //
+ // Do this here in anticipation that we
+ // need to call down to the miniport
+ // driver.
+ //
+ PacketFilter = FDDI_QUERY_FILTER_CLASSES(Miniport->FddiDB);
+
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ if (MINIPORT_TEST_FLAG(Reserved->Open, fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
+ {
+ Status = EthFilterAdjust(Miniport->EthDB,
+ Reserved->Open->FilterHandle,
+ Request,
+ PacketFilter,
+ TRUE);
+ }
+ else
+ {
+ Status = ArcFilterAdjust(Miniport->ArcDB,
+ Reserved->Open->FilterHandle,
+ Request,
+ PacketFilter,
+ TRUE);
+ }
+
+ //
+ // Do this here in anticipation that we
+ // need to call down to the miniport
+ // driver.
+ //
+ PacketFilter = ARC_QUERY_FILTER_CLASSES(Miniport->ArcDB);
+ PacketFilter |= ETH_QUERY_FILTER_CLASSES(Miniport->EthDB);
+
+ if (MINIPORT_TEST_FLAG(Miniport,
+ fMINIPORT_ARCNET_BROADCAST_SET) ||
+ (PacketFilter & NDIS_PACKET_TYPE_MULTICAST))
+ {
+ PacketFilter &= ~NDIS_PACKET_TYPE_MULTICAST;
+ PacketFilter |= NDIS_PACKET_TYPE_BROADCAST;
+ }
+
+ break;
+ }
+ }
+
+ //
+ // If the filter library returns NDIS_STATUS_PENDING from
+ // the XxxFitlerAdjust() then we need to call down to the
+ // miniport driver. Other wise this will have succeeded.
+ //
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ //
+ // Save the current global packet filter in a buffer that will stick around.
+ // Remove the ALL_LOCAL bit since miniport does not understand this (and does
+ // not need to).
+ //
+ *(UNALIGNED ULONG *)(Miniport->MulticastBuffer) = PacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL;
+
+ //
+ // If the local-only bit is set and the miniport is doing it's own
+ // loop back then we need to make sure that we loop back non-self
+ // directed packets that are sent out on the pipe.
+ //
+ if ((PacketFilter & NDIS_PACKET_TYPE_ALL_LOCAL) &&
+ (Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) == 0)
+ {
+ MINIPORT_SET_SEND_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED);
+ }
+ else
+ {
+ MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED);
+ }
+
+ //
+ // Call the miniport driver.
+ //
+ Status = (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ Miniport->MulticastBuffer,
+ sizeof(PacketFilter),
+ &Request->DATA.SET_INFORMATION.BytesRead,
+ &Request->DATA.SET_INFORMATION.BytesNeeded);
+ }
+
+ //
+ // If we have success then set the Bytes read in the original request.
+ //
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead = 4;
+ }
+ else if (Status != NDIS_STATUS_PENDING)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+ }
+
+ return(Status);
+}
+
+NDIS_STATUS
+ndisMSetCurrentLookahead(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ UINT Lookahead;
+ ULONG CurrentMax;
+ PNDIS_M_OPEN_BLOCK CurrentOpen;
+ NDIS_STATUS Status;
+
+ //
+ // Verify length of the information buffer.
+ //
+ VERIFY_SET_PARAMETERS(Request, sizeof(Lookahead), Status);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return(Status);
+ }
+
+ //
+ // Put the lookahead that the binding requests into a
+ // buffer we can use...
+ //
+ MoveMemory(&Lookahead,
+ Request->DATA.SET_INFORMATION.InformationBuffer,
+ sizeof(Lookahead));
+
+ //
+ // Verify that the lookahead is within boundaries...
+ //
+ if (Lookahead > Miniport->MaximumLookahead)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ return(NDIS_STATUS_INVALID_LENGTH);
+ }
+
+ //
+ // Find the maximum lookahead between all opens that
+ // are bound to the miniport driver.
+ //
+ for (CurrentOpen = Miniport->OpenQueue, CurrentMax = 0;
+ CurrentOpen != NULL;
+ CurrentOpen = CurrentOpen->MiniportNextOpen)
+ {
+ if (CurrentOpen->CurrentLookahead > CurrentMax)
+ {
+ CurrentMax = CurrentOpen->CurrentLookahead;
+ }
+ }
+
+ //
+ // Figure in the new lookahead.
+ //
+ if (Lookahead > CurrentMax)
+ {
+ CurrentMax = Lookahead;
+ }
+
+ //
+ // Adjust the current max lookahead if needed.
+ //
+ if (CurrentMax == 0)
+ {
+ CurrentMax = Miniport->MaximumLookahead;
+ }
+
+ //
+ // Set the default status.
+ //
+ Status = NDIS_STATUS_SUCCESS;
+
+ //
+ // Do we need to call the miniport driver with the
+ // new max lookahead?
+ //
+ if (Miniport->CurrentLookahead != CurrentMax)
+ {
+ //
+ // Save the new lookahead value in a buffer
+ // that will stick around.
+ //
+ MoveMemory(Miniport->MulticastBuffer,
+ &CurrentMax,
+ sizeof(CurrentMax));
+
+ //
+ // Send it to the driver.
+ //
+ Status = (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ Miniport->MulticastBuffer,
+ sizeof(CurrentMax),
+ &Request->DATA.SET_INFORMATION.BytesRead,
+ &Request->DATA.SET_INFORMATION.BytesNeeded);
+ }
+
+ //
+ // If we succeeded then update the binding information.
+ //
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->CurrentLookahead = Lookahead;
+ Request->DATA.SET_INFORMATION.BytesRead = sizeof(Lookahead);
+ Miniport->CurrentLookahead = CurrentMax;
+ }
+ else if (Status != NDIS_STATUS_PENDING)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+ }
+
+ return(Status);
+}
+
+NDIS_STATUS
+ndisMSetMulticastList(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ UINT NumberOfAddresses;
+ NDIS_STATUS Status;
+ PNDIS_REQUEST_RESERVED Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request);
+
+ //
+ // If the media type is not Ethernet or Ethernet encapsulated ARCnet
+ // then bail.
+ //
+ if ((Miniport->MediaType != NdisMedium802_3) &&
+ !((Miniport->MediaType == NdisMediumArcnet878_2) &&
+ MINIPORT_TEST_FLAG(Reserved->Open,
+ fMINIPORT_OPEN_USING_ETH_ENCAPSULATION)))
+ {
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ return(NDIS_STATUS_NOT_SUPPORTED);
+ }
+
+ //
+ // Verify the information buffer length that was passed in.
+ //
+ if ((Request->DATA.SET_INFORMATION.InformationBufferLength % ETH_LENGTH_OF_ADDRESS) != 0)
+ {
+ //
+ // The data must be a multiple of the Ethernet
+ // address size.
+ //
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ return(NDIS_STATUS_INVALID_DATA);
+ }
+
+ //
+ // If this request is because of an open that is closing then we
+ // have already adjusted the settings and we just need to
+ // make sure that the adapter has the new settings.
+ //
+ if (MINIPORT_TEST_FLAG(Reserved->Open, fMINIPORT_OPEN_CLOSING))
+ {
+ //
+ // By setting the Status to NDIS_STATUS_PENDING we will call
+ // down to the miniport's SetInformationHandler below.
+ //
+ Status = NDIS_STATUS_PENDING;
+ }
+ else
+ {
+ //
+ // Call the filter library for a normal set operation.
+ //
+ Status = EthChangeFilterAddresses(
+ Miniport->EthDB,
+ Reserved->Open->FilterHandle,
+ Request,
+ Request->DATA.SET_INFORMATION.InformationBufferLength / ETH_LENGTH_OF_ADDRESS,
+ Request->DATA.SET_INFORMATION.InformationBuffer,
+ TRUE);
+ }
+
+ //
+ // If the filter library returned pending then we need to
+ // call the miniport driver.
+ //
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ //
+ // Get a list of all the multicast address that need
+ // to be set.
+ //
+ EthQueryGlobalFilterAddresses(
+ &Status,
+ Miniport->EthDB,
+ NDIS_M_MAX_MULTI_LIST * ETH_LENGTH_OF_ADDRESS,
+ &NumberOfAddresses,
+ (PVOID)Miniport->MulticastBuffer);
+
+ //
+ // Call the driver with the new multicast list.
+ //
+ Status = (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ OID_802_3_MULTICAST_LIST,
+ Miniport->MulticastBuffer,
+ NumberOfAddresses * ETH_LENGTH_OF_ADDRESS,
+ &Request->DATA.SET_INFORMATION.BytesRead,
+ &Request->DATA.SET_INFORMATION.BytesNeeded);
+ }
+
+ //
+ // If we succeeded then update the request.
+ //
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead =
+ Request->DATA.SET_INFORMATION.InformationBufferLength;
+ }
+ else if (Status != NDIS_STATUS_PENDING)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+ }
+
+ return(Status);
+}
+
+NDIS_STATUS
+ndisMSetFunctionalAddress(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ UINT FunctionalAddress;
+
+ //
+ // Verify the media type.
+ //
+ if (Miniport->MediaType != NdisMedium802_5)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ return(NDIS_STATUS_NOT_SUPPORTED);
+ }
+
+ //
+ // Verify the buffer length that was passed in.
+ //
+ VERIFY_SET_PARAMETERS(Request, sizeof(FunctionalAddress), Status);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return(Status);
+ }
+
+ //
+ // If this request is because of an open that is closing then we
+ // have already adjusted the settings and we just need to
+ // make sure that the adapter has the new settings.
+ //
+ if (MINIPORT_TEST_FLAG(
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open, fMINIPORT_OPEN_CLOSING))
+ {
+ //
+ // By setting the Status to NDIS_STATUS_PENDING we will call
+ // down to the miniport's SetInformationHandler below.
+ //
+ Status = NDIS_STATUS_PENDING;
+ }
+ else
+ {
+ //
+ // Call the filter library to set the functional address.
+ //
+ Status = TrChangeFunctionalAddress(
+ Miniport->TrDB,
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->FilterHandle,
+ Request,
+ (PUCHAR)(Request->DATA.SET_INFORMATION.InformationBuffer),
+ TRUE);
+ }
+
+ //
+ // If the filter library returned NDIS_STATUS_PENDING then we
+ // need to call down to the miniport driver.
+ //
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ //
+ // Get the new combined functional address from the filter library
+ // and save it in a buffer that will stick around.
+ //
+ FunctionalAddress = TR_QUERY_FILTER_ADDRESSES(Miniport->TrDB);
+ FunctionalAddress = BYTE_SWAP_ULONG(FunctionalAddress);
+ MoveMemory(Miniport->MulticastBuffer,
+ &FunctionalAddress,
+ sizeof(FunctionalAddress));
+
+ //
+ // Call the miniport driver.
+ //
+ Status = (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ OID_802_5_CURRENT_FUNCTIONAL,
+ Miniport->MulticastBuffer,
+ sizeof(FunctionalAddress),
+ &Request->DATA.SET_INFORMATION.BytesRead,
+ &Request->DATA.SET_INFORMATION.BytesNeeded);
+ }
+
+ //
+ // If we succeeded then update the request.
+ //
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead =
+ Request->DATA.SET_INFORMATION.InformationBufferLength;
+ }
+ else if (Status != NDIS_STATUS_PENDING)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+ }
+
+ return(Status);
+}
+
+NDIS_STATUS
+ndisMSetGroupAddress(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ UINT GroupAddress;
+
+ //
+ // Verify the media type.
+ //
+ if (Miniport->MediaType != NdisMedium802_5)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ return(NDIS_STATUS_NOT_SUPPORTED);
+ }
+
+ //
+ // Verify the information buffer length.
+ //
+ VERIFY_SET_PARAMETERS(Request, sizeof(GroupAddress), Status);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return(Status);
+ }
+
+ //
+ // If this request is because of an open that is closing then we
+ // have already adjusted the settings and we just need to
+ // make sure that the adapter has the new settings.
+ //
+ if (MINIPORT_TEST_FLAG(
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open, fMINIPORT_OPEN_CLOSING))
+ {
+ //
+ // By setting the Status to NDIS_STATUS_PENDING we will call
+ // down to the miniport's SetInformationHandler below.
+ //
+ Status = NDIS_STATUS_PENDING;
+ }
+ else
+ {
+ //
+ // Call the filter library to set the new group address.
+ //
+ Status = TrChangeGroupAddress(
+ Miniport->TrDB,
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->FilterHandle,
+ Request,
+ (PUCHAR)(Request->DATA.SET_INFORMATION.InformationBuffer),
+ TRUE);
+ }
+
+ //
+ // If the filter library returned NDIS_STATUS_PENDING then we
+ // need to call down to the miniport driver.
+ //
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ //
+ // Get the new group address from the filter library
+ // and save it in a buffer that will stick around.
+ //
+ GroupAddress = TR_QUERY_FILTER_GROUP(Miniport->TrDB);
+ GroupAddress = BYTE_SWAP_ULONG(GroupAddress);
+ MoveMemory(Miniport->MulticastBuffer,
+ &GroupAddress,
+ sizeof(GroupAddress));
+
+ //
+ // Call the miniport driver with the new group address.
+ //
+ Status = (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ OID_802_5_CURRENT_GROUP,
+ Miniport->MulticastBuffer,
+ sizeof(GroupAddress),
+ &Request->DATA.SET_INFORMATION.BytesRead,
+ &Request->DATA.SET_INFORMATION.BytesNeeded);
+ }
+
+ //
+ // If we succeeded then update the request.
+ //
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead =
+ Request->DATA.SET_INFORMATION.InformationBufferLength;
+ }
+ else if (Status != NDIS_STATUS_PENDING)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+ }
+
+ return(Status);
+}
+
+NDIS_STATUS
+ndisMSetFddiMulticastList(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request,
+ IN BOOLEAN fShort
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ UINT NumberOfAddresses, AddrLen;
+
+ AddrLen = FDDI_LENGTH_OF_LONG_ADDRESS;
+ if (fShort)
+ {
+ AddrLen = FDDI_LENGTH_OF_SHORT_ADDRESS;
+ }
+ //
+ // Verify the media type.
+ //
+ if (Miniport->MediaType != NdisMediumFddi)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ return(NDIS_STATUS_NOT_SUPPORTED);
+ }
+
+ //
+ // Verify the information buffer length.
+ //
+ if ((Request->DATA.SET_INFORMATION.InformationBufferLength % AddrLen) != 0)
+ {
+ //
+ // The data must be a multiple of the Ethernet
+ // address size.
+ //
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ return(NDIS_STATUS_INVALID_DATA);
+ }
+
+ //
+ // If this request is because of an open that is closing then we
+ // have already adjusted the settings and we just need to
+ // make sure that the adapter has the new settings.
+ //
+ if (MINIPORT_TEST_FLAG(
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open, fMINIPORT_OPEN_CLOSING))
+ {
+ //
+ // By setting the Status to NDIS_STATUS_PENDING we will call
+ // down to the miniport's SetInformationHandler below.
+ //
+ Status = NDIS_STATUS_PENDING;
+ }
+ else
+ {
+ //
+ // Now call the filter package to set up the addresses.
+ //
+ Status = fShort ?
+ FddiChangeFilterShortAddresses(
+ Miniport->FddiDB,
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->FilterHandle,
+ Request,
+ Request->DATA.SET_INFORMATION.InformationBufferLength / AddrLen,
+ Request->DATA.SET_INFORMATION.InformationBuffer,
+ TRUE) :
+ FddiChangeFilterLongAddresses(
+ Miniport->FddiDB,
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->FilterHandle,
+ Request,
+ Request->DATA.SET_INFORMATION.InformationBufferLength / AddrLen,
+ Request->DATA.SET_INFORMATION.InformationBuffer,
+ TRUE);
+ }
+
+ //
+ // If the filter library returned NDIS_STATUS_PENDING then we
+ // need to call down to the miniport driver.
+ //
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ //
+ // Get the number of multicast addresses and the list
+ // of multicast addresses to send to the miniport driver.
+ //
+ fShort ?
+ FddiQueryGlobalFilterShortAddresses(&Status,
+ Miniport->FddiDB,
+ NDIS_M_MAX_MULTI_LIST * AddrLen,
+ &NumberOfAddresses,
+ (PVOID)Miniport->MulticastBuffer) :
+ FddiQueryGlobalFilterLongAddresses( &Status,
+ Miniport->FddiDB,
+ NDIS_M_MAX_MULTI_LIST * AddrLen,
+ &NumberOfAddresses,
+ (PVOID)Miniport->MulticastBuffer);
+
+ //
+ // Call the miniport driver.
+ //
+ Status = (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ fShort ? OID_FDDI_SHORT_MULTICAST_LIST : OID_FDDI_LONG_MULTICAST_LIST,
+ Miniport->MulticastBuffer,
+ NumberOfAddresses * AddrLen,
+ &Request->DATA.SET_INFORMATION.BytesRead,
+ &Request->DATA.SET_INFORMATION.BytesNeeded);
+ }
+
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead =
+ Request->DATA.SET_INFORMATION.InformationBufferLength;
+ }
+ else if (Status != NDIS_STATUS_PENDING)
+ {
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+ }
+
+ return(Status);
+}
+
+NDIS_STATUS
+ndisMSetInformation(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+
+ //
+ // If there is no open associated with the request
+ // then it is an internal request and we just send it down
+ // to the adapter.
+ //
+ if (PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open == NULL)
+ {
+ Status = (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ Request->DATA.SET_INFORMATION.Oid,
+ Request->DATA.SET_INFORMATION.InformationBuffer,
+ Request->DATA.SET_INFORMATION.InformationBufferLength,
+ &Request->DATA.SET_INFORMATION.BytesRead,
+ &Request->DATA.SET_INFORMATION.BytesNeeded);
+
+ return(Status);
+ }
+
+ //
+ // Process the binding's request.
+ //
+ switch (Request->DATA.SET_INFORMATION.Oid)
+ {
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ //
+ // Set the packet filter.
+ //
+ Status = ndisMSetPacketFilter(Miniport, Request);
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ //
+ // Set the current look ahead for the miniport.
+ //
+ Status = ndisMSetCurrentLookahead(Miniport, Request);
+
+ break;
+
+ case OID_GEN_PROTOCOL_OPTIONS:
+
+ VERIFY_SET_PARAMETERS(Request, sizeof(ULONG), Status);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ //
+ // Copy the protocol options into the open block.
+ //
+ MoveMemory(&PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->ProtocolOptions,
+ Request->DATA.SET_INFORMATION.InformationBuffer,
+ sizeof(ULONG));
+
+ Request->DATA.SET_INFORMATION.BytesRead = sizeof(ULONG);
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+
+ //
+ // Set the ethernet multicast list.
+ //
+ Status = ndisMSetMulticastList(Miniport, Request);
+ break;
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+
+ //
+ // Set the token ring functional address.
+ //
+ Status = ndisMSetFunctionalAddress(Miniport, Request);
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+
+ //
+ // Set the token ring group address.
+ //
+ Status = ndisMSetGroupAddress(Miniport, Request);
+
+ break;
+
+ case OID_FDDI_LONG_MULTICAST_LIST:
+
+ //
+ // Set the FDDI long multicast list.
+ //
+ Status = ndisMSetFddiMulticastList(Miniport, Request, FALSE);
+
+ break;
+
+ case OID_FDDI_SHORT_MULTICAST_LIST:
+
+ //
+ // Set the FDDI short multicast list.
+ //
+ Status = ndisMSetFddiMulticastList(Miniport, Request, TRUE);
+
+ break;
+
+ default:
+ Status =
+ (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ Request->DATA.SET_INFORMATION.Oid,
+ Request->DATA.SET_INFORMATION.InformationBuffer,
+ Request->DATA.SET_INFORMATION.InformationBufferLength,
+ &Request->DATA.SET_INFORMATION.BytesRead,
+ &Request->DATA.SET_INFORMATION.BytesNeeded);
+ break;
+ }
+
+ return(Status);
+}
+
+NDIS_STATUS
+ndisMQueryCurrentPacketFilter(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ ULONG PacketFilter;
+ NDIS_HANDLE FilterHandle;
+ NDIS_STATUS Status;
+
+ //
+ // Verify the buffer that was passed to us.
+ //
+ VERIFY_QUERY_PARAMETERS(Request, sizeof(PacketFilter), Status);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return(Status);
+ }
+
+ //
+ // Get the filter handle from the open block.
+ //
+ FilterHandle = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->FilterHandle;
+
+ //
+ // Get the packet filter from the filter library.
+ //
+ switch (Miniport->MediaType)
+ {
+ case NdisMedium802_3:
+ PacketFilter = ETH_QUERY_PACKET_FILTER(Miniport->EthDB, FilterHandle);
+
+ break;
+
+ case NdisMedium802_5:
+ PacketFilter = TR_QUERY_PACKET_FILTER(Miniport->TrDB, FilterHandle);
+ break;
+
+ case NdisMediumFddi:
+ PacketFilter = FDDI_QUERY_PACKET_FILTER(Miniport->FddiDB, FilterHandle);
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ if (MINIPORT_TEST_FLAG(
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open,
+ fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
+ {
+ PacketFilter = ETH_QUERY_PACKET_FILTER(Miniport->EthDB, FilterHandle);
+ }
+ else
+ {
+ PacketFilter = ARC_QUERY_PACKET_FILTER(Miniport->ArcDB, FilterHandle);
+ }
+ break;
+ }
+
+ //
+ // Place the packet filter in the buffer that was passed in.
+ //
+ MoveMemory(Request->DATA.QUERY_INFORMATION.InformationBuffer,
+ &PacketFilter,
+ sizeof(PacketFilter));
+
+ Request->DATA.QUERY_INFORMATION.BytesWritten = sizeof(PacketFilter);
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+ndisMQueryMediaSupported(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ ULONG MediaType;
+ NDIS_STATUS Status;
+
+ //
+ // Verify the size of the buffer that was passed in by the binding.
+ //
+ VERIFY_QUERY_PARAMETERS(Request, sizeof(MediaType), Status);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return(Status);
+ }
+
+ //
+ // Default the media type to what the miniport knows it is.
+ //
+ MediaType = (ULONG)Miniport->MediaType;
+
+ //
+ // If we are doing ethernet encapsulation then lie.
+ //
+ if ((NdisMediumArcnet878_2 == Miniport->MediaType) &&
+ MINIPORT_TEST_FLAG(PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open,
+ fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
+ {
+ //
+ // Tell the binding that we are ethernet.
+ //
+ MediaType = (ULONG)NdisMedium802_3;
+ }
+
+ //
+ // Save it in the request.
+ //
+ MoveMemory(Request->DATA.QUERY_INFORMATION.InformationBuffer,
+ &MediaType,
+ sizeof(MediaType));
+
+ Request->DATA.QUERY_INFORMATION.BytesWritten = sizeof(MediaType);
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+NDIS_STATUS
+ndisMQueryEthernetMulticastList(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ UINT NumberOfAddresses;
+
+ //
+ // call the filter library to get the list of multicast
+ // addresses for this open
+ //
+ EthQueryOpenFilterAddresses(&Status,
+ Miniport->EthDB,
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->FilterHandle,
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &NumberOfAddresses,
+ Request->DATA.QUERY_INFORMATION.InformationBuffer);
+
+ //
+ // If the library returned NDIS_STATUS_FAILURE then the buffer
+ // was not big enough. So call back down to determine how
+ // much buffer space we need.
+ //
+ if (NDIS_STATUS_FAILURE == Status)
+ {
+ Request->DATA.QUERY_INFORMATION.BytesNeeded =
+ ETH_LENGTH_OF_ADDRESS *
+ EthNumberOfOpenFilterAddresses(
+ Miniport->EthDB,
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->FilterHandle);
+
+ Request->DATA.QUERY_INFORMATION.BytesWritten = 0;
+
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ }
+ else
+ {
+ Request->DATA.QUERY_INFORMATION.BytesNeeded = 0;
+ Request->DATA.QUERY_INFORMATION.BytesWritten =
+ NumberOfAddresses * ETH_LENGTH_OF_ADDRESS;
+ }
+
+ return(Status);
+}
+
+NDIS_STATUS
+ndisMQueryLongMulticastList(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ UINT NumberOfAddresses;
+
+ //
+ // Call the filter library to get the list of long
+ // multicast address for this open.
+ //
+ FddiQueryOpenFilterLongAddresses(
+ &Status,
+ Miniport->FddiDB,
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->FilterHandle,
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &NumberOfAddresses,
+ Request->DATA.QUERY_INFORMATION.InformationBuffer);
+
+
+ //
+ // If the library returned NDIS_STATUS_FAILURE then the buffer
+ // was not big enough. So call back down to determine how
+ // much buffer space we need.
+ //
+ if (NDIS_STATUS_FAILURE == Status)
+ {
+ Request->DATA.QUERY_INFORMATION.BytesNeeded =
+ FDDI_LENGTH_OF_LONG_ADDRESS *
+ FddiNumberOfOpenFilterLongAddresses(
+ Miniport->FddiDB,
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->FilterHandle);
+
+
+ Request->DATA.QUERY_INFORMATION.BytesWritten = 0;
+
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ }
+ else
+ {
+ Request->DATA.QUERY_INFORMATION.BytesNeeded = 0;
+ Request->DATA.QUERY_INFORMATION.BytesWritten =
+ NumberOfAddresses * FDDI_LENGTH_OF_LONG_ADDRESS;
+ }
+
+ return(Status);
+}
+
+NDIS_STATUS
+ndisMQueryShortMulticastList(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ UINT NumberOfAddresses;
+
+ //
+ // Call the filter library to get the list of long
+ // multicast address for this open.
+ //
+ FddiQueryOpenFilterShortAddresses(
+ &Status,
+ Miniport->FddiDB,
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->FilterHandle,
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &NumberOfAddresses,
+ Request->DATA.QUERY_INFORMATION.InformationBuffer);
+
+
+ //
+ // If the library returned NDIS_STATUS_FAILURE then the buffer
+ // was not big enough. So call back down to determine how
+ // much buffer space we need.
+ //
+ if (NDIS_STATUS_FAILURE == Status)
+ {
+ Request->DATA.QUERY_INFORMATION.BytesNeeded =
+ FDDI_LENGTH_OF_SHORT_ADDRESS *
+ FddiNumberOfOpenFilterShortAddresses(
+ Miniport->FddiDB,
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open->FilterHandle);
+
+ Request->DATA.QUERY_INFORMATION.BytesWritten = 0;
+
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ }
+ else
+ {
+ Request->DATA.QUERY_INFORMATION.BytesNeeded = 0;
+ Request->DATA.QUERY_INFORMATION.BytesWritten =
+ NumberOfAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS;
+ }
+
+ return(Status);
+}
+
+NDIS_STATUS
+ndisMQueryMaximumFrameSize(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ PULONG pulBuffer = Request->DATA.QUERY_INFORMATION.InformationBuffer;
+
+ VERIFY_QUERY_PARAMETERS(Request, sizeof(*pulBuffer), Status);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return(Status);
+ }
+
+ //
+ // Is this ARCnet using encapsulated ethernet?
+ //
+ if (Miniport->MediaType == NdisMediumArcnet878_2)
+ {
+ if (MINIPORT_TEST_FLAG(
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open,
+ fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
+ {
+ //
+ // 504 - 14 (ethernet header) == 490.
+ //
+ *pulBuffer = ARC_MAX_FRAME_SIZE - 14;
+ Request->DATA.QUERY_INFORMATION.BytesWritten = sizeof(*pulBuffer);
+
+ return(NDIS_STATUS_SUCCESS);
+ }
+ }
+
+ //
+ // Call the miniport for the information.
+ //
+ Status = (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ Request->DATA.QUERY_INFORMATION.Oid,
+ Request->DATA.QUERY_INFORMATION.InformationBuffer,
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &(Request->DATA.QUERY_INFORMATION.BytesWritten),
+ &(Request->DATA.QUERY_INFORMATION.BytesNeeded));
+
+ return(Status);
+}
+
+NDIS_STATUS
+ndisMQueryMaximumTotalSize(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ PULONG pulBuffer = Request->DATA.QUERY_INFORMATION.InformationBuffer;
+
+ VERIFY_QUERY_PARAMETERS(Request, sizeof(*pulBuffer), Status);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return(Status);
+ }
+
+ //
+ // Is this ARCnet using encapsulated ethernet?
+ //
+ if (Miniport->MediaType == NdisMediumArcnet878_2)
+ {
+ if (MINIPORT_TEST_FLAG(
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open,
+ fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
+ {
+ *pulBuffer = ARC_MAX_FRAME_SIZE;
+ Request->DATA.QUERY_INFORMATION.BytesWritten = sizeof(*pulBuffer);
+
+ return(NDIS_STATUS_SUCCESS);
+ }
+ }
+
+ //
+ // Call the miniport for the information.
+ //
+ Status = (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ Request->DATA.QUERY_INFORMATION.Oid,
+ Request->DATA.QUERY_INFORMATION.InformationBuffer,
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &(Request->DATA.QUERY_INFORMATION.BytesWritten),
+ &(Request->DATA.QUERY_INFORMATION.BytesNeeded));
+
+ return(Status);
+}
+
+NDIS_STATUS
+ndisMQueryNetworkAddress(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ UCHAR Address[ETH_LENGTH_OF_ADDRESS];
+
+ VERIFY_QUERY_PARAMETERS(Request, ETH_LENGTH_OF_ADDRESS, Status);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return(Status);
+ }
+
+ //
+ // Is this ARCnet using encapsulated ethernet?
+ //
+ if (Miniport->MediaType == NdisMediumArcnet878_2)
+ {
+ if (MINIPORT_TEST_FLAG(
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open,
+ fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
+ {
+ //
+ // Arcnet-to-ethernet conversion.
+ //
+ ZeroMemory(Address, ETH_LENGTH_OF_ADDRESS);
+
+ Address[5] = Miniport->ArcnetAddress;
+
+ MoveMemory(Request->DATA.QUERY_INFORMATION.InformationBuffer,
+ Address,
+ ETH_LENGTH_OF_ADDRESS);
+
+ Request->DATA.QUERY_INFORMATION.BytesWritten = ETH_LENGTH_OF_ADDRESS;
+
+ return(NDIS_STATUS_SUCCESS);
+ }
+ }
+
+ //
+ // Call the miniport for the information.
+ //
+ Status = (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ Request->DATA.QUERY_INFORMATION.Oid,
+ Request->DATA.QUERY_INFORMATION.InformationBuffer,
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &(Request->DATA.QUERY_INFORMATION.BytesWritten),
+ &(Request->DATA.QUERY_INFORMATION.BytesNeeded)
+ );
+
+ return(Status);
+}
+
+NDIS_STATUS
+ndisMQueryInformation(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ PVOID Buffer;
+ PULONG pulBuffer;
+ ULONG BufferLength;
+ PNDIS_M_OPEN_BLOCK Open;
+ ULONG Generic;
+
+ //
+ // Copy the request information into temporary storage.
+ //
+ Buffer = Request->DATA.QUERY_INFORMATION.InformationBuffer;
+ pulBuffer = Buffer;
+ BufferLength = Request->DATA.QUERY_INFORMATION.InformationBufferLength;
+
+ Open = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open;
+
+ //
+ // We intercept some calls.
+ //
+ switch (Request->DATA.QUERY_INFORMATION.Oid)
+ {
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ Status = ndisMQueryCurrentPacketFilter(Miniport, Request);
+
+ break;
+
+ case OID_GEN_MEDIA_IN_USE:
+ case OID_GEN_MEDIA_SUPPORTED:
+
+ Status = ndisMQueryMediaSupported(Miniport, Request);
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ VERIFY_QUERY_PARAMETERS(
+ Request,
+ sizeof(Open->CurrentLookahead),
+ Status);
+
+ //
+ // Save the lookahead in the binding's buffer.
+ //
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ *pulBuffer = Open->CurrentLookahead;
+ Request->DATA.QUERY_INFORMATION.BytesWritten =
+ sizeof(Open->CurrentLookahead);
+ }
+
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+
+ VERIFY_QUERY_PARAMETERS(
+ Request,
+ sizeof(Miniport->MaximumLookahead),
+ Status);
+
+ //
+ // Save the lookahead in the binding's buffer.
+ //
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ *pulBuffer = Miniport->MaximumLookahead;
+ Request->DATA.QUERY_INFORMATION.BytesWritten =
+ sizeof(Miniport->MaximumLookahead);
+ }
+
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+
+ Status = ndisMQueryEthernetMulticastList(Miniport, Request);
+
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+
+ VERIFY_QUERY_PARAMETERS(
+ Request,
+ sizeof(Miniport->MaximumLongAddresses),
+ Status);
+
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ *pulBuffer = Miniport->MaximumLongAddresses;
+ Request->DATA.QUERY_INFORMATION.BytesWritten =
+ sizeof(Miniport->MaximumLongAddresses);
+ }
+
+ break;
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+
+ VERIFY_QUERY_PARAMETERS(
+ Request,
+ sizeof(*pulBuffer),
+ Status);
+
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ Generic = TR_QUERY_FILTER_BINDING_ADDRESS(
+ Miniport->TrDB,
+ Open->FilterHandle
+ );
+
+ *pulBuffer = BYTE_SWAP_ULONG(Generic);
+ Request->DATA.QUERY_INFORMATION.BytesWritten =
+ sizeof(*pulBuffer);
+ }
+
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+
+ VERIFY_QUERY_PARAMETERS(
+ Request,
+ sizeof(*pulBuffer),
+ Status);
+
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ *pulBuffer = TR_QUERY_FILTER_GROUP(Miniport->TrDB);
+ *pulBuffer = BYTE_SWAP_ULONG(*pulBuffer);
+ Request->DATA.QUERY_INFORMATION.BytesWritten =
+ sizeof(*pulBuffer);
+ }
+
+ break;
+
+ case OID_FDDI_LONG_MULTICAST_LIST:
+
+ Status = ndisMQueryLongMulticastList(Miniport, Request);
+
+ break;
+
+ case OID_FDDI_LONG_MAX_LIST_SIZE:
+
+ VERIFY_QUERY_PARAMETERS(
+ Request,
+ sizeof(*pulBuffer),
+ Status);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ *pulBuffer = Miniport->MaximumLongAddresses;
+ Request->DATA.QUERY_INFORMATION.BytesWritten =
+ sizeof(*pulBuffer);
+ }
+
+ break;
+
+ case OID_FDDI_SHORT_MULTICAST_LIST:
+
+ Status = ndisMQueryShortMulticastList(Miniport, Request);
+
+ break;
+
+ case OID_FDDI_SHORT_MAX_LIST_SIZE:
+
+ VERIFY_QUERY_PARAMETERS(
+ Request,
+ sizeof(Miniport->MaximumShortAddresses),
+ Status);
+
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ *pulBuffer = Miniport->MaximumShortAddresses;
+ Request->DATA.QUERY_INFORMATION.BytesWritten =
+ sizeof(Miniport->MaximumShortAddresses);
+ }
+
+ break;
+
+ //
+ // Start interceptions for running an ethernet
+ // protocol on top of an arcnet mini-port.
+ //
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+
+ Status = ndisMQueryMaximumFrameSize(Miniport, Request);
+
+ break;
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+
+ Status = ndisMQueryMaximumTotalSize(Miniport, Request);
+
+ break;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+ case OID_802_3_CURRENT_ADDRESS:
+
+ Status = ndisMQueryNetworkAddress(Miniport, Request);
+
+ break;
+
+ default:
+
+ //
+ // We don't filter this request, just pass it down
+ // to the driver.
+ //
+ Status = (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler)(
+ Miniport->MiniportAdapterContext,
+ Request->DATA.QUERY_INFORMATION.Oid,
+ Request->DATA.QUERY_INFORMATION.InformationBuffer,
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &Request->DATA.QUERY_INFORMATION.BytesWritten,
+ &Request->DATA.QUERY_INFORMATION.BytesNeeded);
+
+ break;
+ }
+
+ return(Status);
+}
+
+
+VOID
+ndisMDoRequests(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Submits a request to the mini-port.
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+Return Value:
+
+ TRUE if we need to place the work item back on the queue to process later.
+ FALSE if we are done with the work item.
+
+--*/
+
+{
+ NDIS_STATUS Status;
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Enter do requests\n"));
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ //
+ // Do we have a request in progress?
+ //
+ while ((Miniport->MiniportRequest == NULL) && (Miniport->PendingRequest != NULL))
+ {
+ PNDIS_REQUEST_RESERVED Reserved;
+ PNDIS_REQUEST NdisRequest;
+ UINT MulticastAddresses;
+ ULONG PacketFilter;
+ BOOLEAN DoMove;
+ PVOID MoveSource;
+ UINT MoveBytes;
+ ULONG GenericULong;
+
+ //
+ // Set defaults.
+ //
+ DoMove = TRUE;
+ Status = NDIS_STATUS_SUCCESS;
+
+ //
+ // Remove first request
+ //
+ NdisRequest = Miniport->PendingRequest;
+ Miniport->PendingRequest = PNDIS_RESERVED_FROM_PNDIS_REQUEST(NdisRequest)->Next;
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Starting protocol request 0x%x\n", NdisRequest));
+
+ //
+ // Clear the timeout flag.
+ //
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_REQUEST_TIMEOUT);
+
+ //
+ // Put it on mini-port queue
+ //
+ Miniport->MiniportRequest = NdisRequest;
+
+ //
+ // Submit to mini-port
+ //
+ switch (NdisRequest->RequestType)
+ {
+ case NdisRequestQueryInformation:
+
+ //
+ // Process the query information.
+ //
+ Status = ndisMQueryInformation(Miniport, NdisRequest);
+
+ 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))
+ {
+ MoveMemory(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
+ MoveSource,
+ MoveBytes);
+ }
+ }
+ }
+ else
+ {
+ NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = MoveBytes;
+ }
+ }
+ break;
+
+ case NdisRequestSetInformation:
+
+ //
+ // Process the set infromation.
+ //
+ Status = ndisMSetInformation(Miniport, NdisRequest);
+
+ break;
+ }
+
+ //
+ // Did the request pend? If so then there is nothing more to do.
+ //
+ if ((Status == NDIS_STATUS_PENDING) &&
+ (Miniport->MiniportRequest != NULL))
+ {
+ //
+ // Still outstanding
+ //
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Request pending, exit do requests\n"));
+
+ break;
+ }
+
+ //
+ // Complete request
+ //
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ switch (NdisRequest->RequestType)
+ {
+ case NdisRequestQueryStatistics:
+ case NdisRequestQueryInformation:
+
+ ndisMSyncQueryInformationComplete(Miniport, Status);
+ break;
+
+ case NdisRequestSetInformation:
+
+ ndisMSyncSetInformationComplete(Miniport, Status);
+ break;
+ }
+ }
+ }
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Exit do requests\n"));
+}
+
+//
+// IRP handlers established on behalf of NDIS devices by
+// the wrapper.
+//
+
+NTSTATUS
+ndisMQueryOidList(
+ IN PNDIS_USER_OPEN_CONTEXT OpenContext,
+ IN 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;
+ PNDIS_REQUEST_RESERVED Reserved;
+ BOOLEAN LocalLock;
+ PNDIS_MINIPORT_BLOCK Miniport = OpenContext->MiniportBlock;
+ KIRQL OldIrql;
+ PSINGLE_LIST_ENTRY Link;
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Enter query oid list\n"));
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ do
+ {
+ //
+ // First query the OID list with no buffer, to find out
+ // how big it should be.
+ //
+
+ INITIALIZE_EVENT(&OpenRequest.Event);
+
+ 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);
+ ndisMQueueRequest(Miniport, &OpenRequest.Request, NULL);
+
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+
+ if (LocalLock)
+ {
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+ WAIT_FOR_OBJECT(&OpenRequest.Event, NULL);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisStatus = OpenRequest.NdisStatus;
+
+ if ((NdisStatus != NDIS_STATUS_INVALID_LENGTH) &&
+ (NdisStatus != NDIS_STATUS_BUFFER_TOO_SHORT))
+ {
+ break;
+ }
+
+ //
+ // Now we know how much is needed, allocate temp storage...
+ //
+ TmpBufferLength = OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded;
+ TmpBuffer = ALLOC_FROM_POOL(TmpBufferLength, NDIS_TAG_DEFAULT);
+
+ if (TmpBuffer == NULL)
+ {
+ NdisStatus = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ //
+ // ...and query the real list.
+ //
+
+ RESET_EVENT(&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);
+ ndisMQueueRequest(Miniport, &OpenRequest.Request, NULL);
+
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+
+ if (LocalLock)
+ {
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ WAIT_FOR_OBJECT(&OpenRequest.Event, NULL);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisStatus = OpenRequest.NdisStatus;
+
+ ASSERT(NdisStatus == NDIS_STATUS_SUCCESS);
+
+ NdisStatus = ndisSplitStatisticsOids(OpenContext,
+ TmpBuffer,
+ TmpBufferLength/sizeof(NDIS_OID));
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("Exit query oid list\n"));
+
+ FREE_POOL(TmpBuffer);
+ } while (FALSE);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ return(NdisStatus);
+}
+
+
+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;
+
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_INFO,
+ ("ndisMCloseAction()\n"));
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("- Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ Open->References--;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("==0 Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ if (Open->References == 0)
+ {
+ ndisMFinishClose(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.
+
+
+--*/
+
+{
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_INFO,
+ ("ndisMChangeFunctionalAddress()\n"));
+
+ return(NDIS_STATUS_PENDING);
+}
+
+
+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.
+
+
+--*/
+
+{
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_INFO,
+ ("ndisMChangeGroupAddress()\n"));
+
+ return(NDIS_STATUS_PENDING);
+}
+
+
+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.
+
+
+--*/
+
+{
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_INFO,
+ ("ndisMChangeFddiAddresses()\n"));
+
+ return(NDIS_STATUS_PENDING);
+}
+
+
+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);
+ PNDIS_MINIPORT_BLOCK Miniport = Open->MiniportHandle;
+
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_INFO,
+ ("Enter ChangeEthAddresses\n"));
+
+ if ((Miniport->MediaType == NdisMediumArcnet878_2) &&
+ MINIPORT_TEST_FLAG(Open, fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
+ {
+ if (NewAddressCount > 0)
+ {
+ //
+ // Turn on broadcast acceptance.
+ //
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_ARCNET_BROADCAST_SET);
+ }
+ else
+ {
+ //
+ // Unset the broadcast filter.
+ //
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_ARCNET_BROADCAST_SET);
+ }
+
+ //
+ // Need to return success here so that we don't call down to the
+ // ARCnet miniport with an invalid OID, i.e. an ethernet one....
+ //
+ return(NDIS_STATUS_SUCCESS);
+ }
+
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_INFO,
+ ("ndisMChangeEthAddresses()\n"));
+
+ return(NDIS_STATUS_PENDING);
+}
+
+
+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.
+
+
+--*/
+
+{
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_INFO,
+ ("ndisMChangeClass()\n"));
+
+ return(NDIS_STATUS_PENDING);
+}
+
diff --git a/private/ntos/ndis/ndis40/sendm.c b/private/ntos/ndis/ndis40/sendm.c
new file mode 100644
index 000000000..8e3dfc7c4
--- /dev/null
+++ b/private/ntos/ndis/ndis40/sendm.c
@@ -0,0 +1,3212 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ sendm.c
+
+Abstract:
+
+Author:
+
+ Kyle Brandon (KyleB)
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+#include "sendm.h"
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_SENDM
+
+VOID
+ndisMCopyFromPacketToBuffer(
+ 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));
+
+ MoveMemory(Buffer, VirtualAddress, AmountToMove);
+
+ Buffer = (PCHAR)Buffer + AmountToMove;
+ VirtualAddress = (PCHAR)VirtualAddress + AmountToMove;
+
+ LocalBytesCopied += AmountToMove;
+ CurrentLength -= AmountToMove;
+ }
+ }
+
+ *BytesCopied = LocalBytesCopied;
+}
+
+BOOLEAN
+FASTCALL
+ndisMIsLoopbackPacket(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+ This routine will determine if a packet needs to be looped back in
+ software. if the packet is any kind of loopback packet then it
+ will get placed on the loopback queue and a workitem will be queued
+ to process it later.
+
+Arguments:
+
+ Miniport- Pointer to the miniport block to send the packet on.
+ Packet - Packet to check for loopback.
+
+Return Value:
+
+ Returns TRUE if the packet is self-directed.
+
+--*/
+{
+ PNDIS_BUFFER FirstBuffer;
+ UINT Length;
+ UINT Offset;
+ PUCHAR BufferAddress;
+ BOOLEAN Loopback;
+ BOOLEAN SelfDirected;
+ PNDIS_PACKET pNewPacket;
+ PUCHAR Buffer;
+ NDIS_STATUS Status;
+ PNDIS_BUFFER pNdisBuffer;
+ UINT HdrLength;
+ BOOLEAN ArcEncap = TRUE;
+
+ //
+ // 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 = MDL_ADDRESS(FirstBuffer);
+
+ //
+ // 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.
+ //
+ switch (Miniport->MediaType)
+ {
+ case NdisMedium802_3:
+
+ if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED))
+ {
+ if (ETH_IS_MULTICAST(BufferAddress))
+ {
+ Loopback = FALSE;
+ SelfDirected = FALSE;
+ break;
+ }
+
+ //
+ // Packet is of type directed, now make sure that it
+ // is not self-directed.
+ //
+ ETH_COMPARE_NETWORK_ADDRESSES_EQ(
+ BufferAddress,
+ Miniport->EthDB->AdapterAddress,
+ &Loopback);
+
+ SelfDirected = FALSE;
+
+ break;
+ }
+
+ //
+ // Check for the miniports that don't do loopback.
+ //
+ EthShouldAddressLoopBackMacro(Miniport->EthDB,
+ BufferAddress,
+ &Loopback,
+ &SelfDirected);
+ break;
+
+ case NdisMedium802_5:
+
+ if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED))
+ {
+ BOOLEAN IsNotDirected;
+ TR_IS_NOT_DIRECTED(BufferAddress + 2, &IsNotDirected);
+ if (IsNotDirected)
+ {
+ Loopback = FALSE;
+ SelfDirected = FALSE;
+ break;
+ }
+
+ //
+ // Packet is of type directed, now make sure that it
+ // is not self-directed.
+ //
+ TR_COMPARE_NETWORK_ADDRESSES_EQ(
+ BufferAddress + 2,
+ Miniport->TrDB->AdapterAddress,
+ &Loopback);
+
+ SelfDirected = FALSE;
+
+ break;
+ }
+
+ TrShouldAddressLoopBackMacro(Miniport->TrDB,
+ BufferAddress +2,
+ BufferAddress +8,
+ &Loopback,
+ &SelfDirected);
+
+ break;
+
+ case NdisMediumFddi:
+
+ if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED))
+ {
+ BOOLEAN IsMulticast;
+
+ FDDI_IS_MULTICAST(
+ BufferAddress + 1,
+ (BufferAddress[0] & 0x40) ?
+ FDDI_LENGTH_OF_LONG_ADDRESS :
+ FDDI_LENGTH_OF_SHORT_ADDRESS,
+ &IsMulticast);
+ if (IsMulticast)
+ {
+ Loopback = FALSE;
+ SelfDirected = FALSE;
+ break;
+ }
+
+ //
+ // Packet is of type directed, now make sure that it
+ // is not self-directed.
+ //
+ FDDI_COMPARE_NETWORK_ADDRESSES_EQ(
+ BufferAddress + 1,
+ (BufferAddress[0] & 0x40) ?
+ Miniport->FddiDB->AdapterLongAddress :
+ Miniport->FddiDB->AdapterShortAddress,
+ (BufferAddress[0] & 0x40) ?
+ FDDI_LENGTH_OF_LONG_ADDRESS :
+ FDDI_LENGTH_OF_SHORT_ADDRESS,
+ &Loopback);
+
+ SelfDirected = FALSE;
+
+ break;
+ }
+
+ FddiShouldAddressLoopBackMacro(Miniport->FddiDB,
+ BufferAddress + 1, // Skip FC byte to dest address.
+ (BufferAddress[0] & 0x40) ?
+ FDDI_LENGTH_OF_LONG_ADDRESS :
+ FDDI_LENGTH_OF_SHORT_ADDRESS,
+ &Loopback,
+ &SelfDirected);
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ //
+ // We just handle arcnet packets (encapsulated or not) in
+ // a totally different manner...
+ //
+ SelfDirected = ndisMArcnetSendLoopback(Miniport, Packet);
+
+ //
+ // Mark the packet as having been looped back.
+ //
+ MINIPORT_SET_PACKET_FLAG(Packet, fPACKET_HAS_BEEN_LOOPED_BACK);
+
+ return(SelfDirected);
+
+ break;
+ }
+
+ //
+ // If it is not a loopback packet then get out of here.
+ //
+ if (!Loopback)
+ {
+ ASSERT(!SelfDirected);
+ return FALSE;
+ }
+
+ //
+ // Get the buffer length.
+ //
+ NdisQueryPacket(Packet, NULL, NULL, NULL, &Length);
+ Offset = 0;
+
+ //
+ // Allocate a buffer for the packet.
+ //
+ pNewPacket = (PNDIS_PACKET)ALLOC_FROM_POOL(Length +
+ sizeof(NDIS_PACKET) +
+ sizeof(NDIS_PACKET_OOB_DATA) +
+ sizeof(NDIS_PACKET_PRIVATE_EXTENSION) +
+ PROTOCOL_RESERVED_SIZE_IN_PACKET,
+ NDIS_TAG_LOOP_PKT);
+ if (pNewPacket != NULL)
+ {
+ //
+ // Get a pointer to the destination buffer.
+ //
+ Buffer = (PUCHAR)pNewPacket +
+ sizeof(NDIS_PACKET) +
+ sizeof(NDIS_PACKET_OOB_DATA) +
+ sizeof(NDIS_PACKET_PRIVATE_EXTENSION) +
+ PROTOCOL_RESERVED_SIZE_IN_PACKET;
+
+ ZeroMemory(pNewPacket,
+ sizeof(NDIS_PACKET) +
+ sizeof(NDIS_PACKET_OOB_DATA) +
+ sizeof(NDIS_PACKET_PRIVATE_EXTENSION) +
+ PROTOCOL_RESERVED_SIZE_IN_PACKET);
+
+ //
+ // Allocate an MDL for the packet.
+ //
+ NdisAllocateBuffer(&Status,
+ &pNdisBuffer,
+ NULL,
+ Buffer,
+ Length);
+ if (NDIS_STATUS_SUCCESS == Status)
+ {
+ //
+ // NdisChainBufferAtFront()
+ //
+ pNewPacket->Private.Head = pNdisBuffer;
+ pNewPacket->Private.Tail = pNdisBuffer;
+
+ pNewPacket->Private.NdisPacketOobOffset = (USHORT)sizeof(NDIS_PACKET) + PROTOCOL_RESERVED_SIZE_IN_PACKET;
+
+ ndisMCopyFromPacketToBuffer(Packet, // Packet to copy from.
+ Offset, // Offset from beginning of packet.
+ Length, // Number of bytes to copy.
+ Buffer, // The destination buffer.
+ &HdrLength);// The number of bytes copied.
+ }
+ else
+ {
+ //
+ // Clean up the memory allocated for the packet.
+ //
+ FREE_POOL(pNewPacket);
+ pNewPacket = NULL;
+ }
+ }
+
+ //
+ // Do we have a packet built ?
+ //
+ if (NULL != pNewPacket)
+ {
+ //
+ // Mark the packet as having been looped back.
+ //
+ MINIPORT_SET_PACKET_FLAG(Packet, fPACKET_HAS_BEEN_LOOPED_BACK);
+
+ NDISM_LOG_PACKET(Miniport, Packet, pNewPacket, 'pool');
+
+ //
+ // Place the packet on the loopback queue.
+ //
+ if (NULL == Miniport->LoopbackHead)
+ {
+ Miniport->LoopbackHead = pNewPacket;
+
+ //
+ // If this is the first one on the loopback queue then we need
+ // to make sure that we pick it up later.
+ //
+ NDISM_DEFER_PROCESS_DEFERRED(Miniport);
+ }
+ else
+ {
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LoopbackTail)->Next = pNewPacket;
+ }
+
+ Miniport->LoopbackTail = pNewPacket;
+
+ //
+ // Packet needs to have a workitem queued.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSendLoopback, NULL, NULL);
+ }
+
+ return(SelfDirected);
+}
+
+
+BOOLEAN
+FASTCALL
+ndisMIndicateLoopback(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+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.
+
+--*/
+
+{
+ UINT Length;
+ PUCHAR BufferAddress;
+ PNDIS_PACKET Packet, QueueHead;
+ PNDIS_PACKET_OOB_DATA pOob;
+ NDIS_STATUS Status;
+ BOOLEAN fReturnStatus = FALSE;
+
+ // We should not be here if the driver handles loopback
+ ASSERT(Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK);
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+
+ //
+ // Get a local copy of the loopback queue.
+ //
+ QueueHead = Miniport->LoopbackHead;
+ Miniport->LoopbackHead = NULL;
+ Miniport->LoopbackTail = NULL;
+
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+
+ //
+ // Loop through any loopback packets that are queue'd.
+ //
+
+ while (QueueHead != NULL)
+ {
+ //
+ // Grab the first loopback packet to indicate up.
+ //
+ Packet = QueueHead;
+ pOob = NDIS_OOB_DATA_FROM_PACKET(Packet);
+ pOob->Status = NDIS_STATUS_RESOURCES;
+ QueueHead = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next;
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'i');
+
+ //
+ // Setup the packet references and packet array.
+ //
+ Miniport->LoopbackPacket = Packet;
+ BufferAddress = (PUCHAR)Packet +
+ sizeof(NDIS_PACKET) +
+ sizeof(NDIS_PACKET_OOB_DATA) +
+ sizeof(NDIS_PACKET_PRIVATE_EXTENSION) +
+ PROTOCOL_RESERVED_SIZE_IN_PACKET;
+
+ //
+ // For ethernet/token-ring/fddi/encapsulated arc-net, we want to
+ // indicate the packet using the receivepacket way.
+ //
+ switch (Miniport->MediaType)
+ {
+ case NdisMedium802_3:
+ pOob->HeaderSize = 14;
+ EthFilterDprIndicateReceivePacket(Miniport, &Packet, 1);
+ break;
+
+ case NdisMedium802_5:
+ pOob->HeaderSize = 14;
+ if (BufferAddress[8] & 0x80)
+ {
+ pOob->HeaderSize += (BufferAddress[14] & 0x1F);
+ }
+ TrFilterDprIndicateReceivePacket(Miniport, &Packet, 1);
+ break;
+
+ case NdisMediumFddi:
+ pOob->HeaderSize = (*BufferAddress & 0x40) ?
+ 2 * FDDI_LENGTH_OF_LONG_ADDRESS + 1:
+ 2 * FDDI_LENGTH_OF_SHORT_ADDRESS + 1;
+
+ FddiFilterDprIndicateReceivePacket(Miniport, &Packet, 1);
+ break;
+ }
+
+ ASSERT(NDIS_GET_PACKET_STATUS(Packet) != NDIS_STATUS_PENDING);
+ NdisFreeBuffer(Packet->Private.Head);
+ FREE_POOL(Packet);
+ }
+
+ Miniport->LoopbackPacket = NULL;
+
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+
+ //
+ // If there are more loopback packets on the loopback
+ // queue then we need to let process deferred know not to
+ // dequeue the loopback workitem.
+ //
+ if (Miniport->LoopbackHead != NULL)
+ {
+ fReturnStatus = TRUE;
+ }
+
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+
+ return(fReturnStatus);
+}
+
+BOOLEAN
+FASTCALL
+ndisMStartSendPacketsFullDuplex(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+{
+ BOOLEAN fReturn = FALSE;
+#ifdef NDIS_NT
+ PNDIS_PACKET Packet;
+ PNDIS_PACKET PrevPacket;
+ NDIS_STATUS Status;
+ PNDIS_PACKET_RESERVED Reserved;
+ PNDIS_M_OPEN_BLOCK Open;
+ UINT Flags;
+ PPNDIS_PACKET pPktArray;
+
+ //
+ // Acquire the send lock.
+ //
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'rfed');
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMStartSendPacketsFullDuplex\n"));
+
+ MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
+
+ //
+ // Loop and process sends.
+ //
+ while ((Miniport->SendResourcesAvailable != 0) &&
+ (Miniport->FirstPendingPacket != NULL))
+ {
+ UINT Count;
+ UINT ResourcesCount;
+ UINT NumberOfPackets;
+
+ //
+ // Initialize the packet array.
+ //
+ pPktArray = Miniport->PacketArray;
+
+ //
+ // Place as many packets as we can in the packet array to send
+ // to the miniport.
+ //
+ for (NumberOfPackets = 0;
+ (NumberOfPackets < Miniport->MaximumSendPackets) &&
+ (Miniport->FirstPendingPacket != NULL); )
+ {
+ //
+ // Grab the packet off of the pending queue.
+ //
+ Packet = Miniport->FirstPendingPacket;
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+
+ //
+ // Remove from pending 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_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED)) &&
+ !MINIPORT_TEST_PACKET_FLAG(Packet, fPACKET_HAS_BEEN_LOOPED_BACK) &&
+ ndisMIsLoopbackPacket(Miniport, Packet))
+ {
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Packet 0x%x is self-directed.\n", Packet));
+
+ //
+ // Get a pointer to the open block.
+ // DO NOT USE "Reserved->Open" TO CALL INTO THE MACRO!!!!!
+ //
+ Open = Reserved->Open;
+
+ //
+ // Complete the packet back to the binding.
+ //
+ NDISM_COMPLETE_SEND_FULL_DUPLEX(
+ Miniport,
+ Open,
+ Packet,
+ PrevPacket,
+ NDIS_STATUS_SUCCESS);
+
+ //
+ // No, we don't want to increment the counter for the
+ // miniport's packet array.
+ //
+ }
+ else
+ {
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'inim');
+
+ //
+ // We have to re-initialize this.
+ //
+ *pPktArray = Packet;
+ NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_SUCCESS);
+
+ //
+ // Increment the counter for the packet array index.
+ //
+ NumberOfPackets++;
+ pPktArray++;
+ }
+ }
+
+ //
+ // Are there any packets to send?
+ //
+ if (NumberOfPackets != 0)
+ {
+ //
+ // Get a temp pointer to our packet array.
+ //
+ pPktArray = Miniport->PacketArray;
+ Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Open;
+
+ //
+ // Pass the packet array down to the miniport.
+ //
+ (Open->SendPacketsHandler)(
+ Miniport->MiniportAdapterContext,
+ Miniport->PacketArray,
+ NumberOfPackets);
+
+ //
+ // First check to see if the LastMiniportPacket is NULL.
+ // If it is then the miniport called NdisMSendComplete()
+ // in our send context and we don't need to do anything more.
+ //
+ if (NULL == Miniport->LastMiniportPacket)
+ {
+ //
+ // We may still have packets pending to be sent down....
+ //
+ continue;
+ }
+
+ //
+ // Process the packet completion.
+ //
+ for (Count = 0; Count < NumberOfPackets; Count++, pPktArray++)
+ {
+ BOOLEAN fFoundPacket = FALSE;
+
+ //
+ // Try and find the packet on our miniport's packet queue.
+ //
+ Packet = Miniport->FirstPacket;
+ PrevPacket = NULL;
+
+ ASSERT(Packet != NULL);
+
+ //
+ // We are only going to travers the packet queue from the
+ // FirstPacket to the LastMiniportPacket.
+ // Why you ask? Well we need to make sure that the miniport
+ // didn't complete the packet we are now trying to complete
+ // with a call to NdisMSendComplete().
+ //
+ while (Packet != PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastMiniportPacket)->Next)
+ {
+ if (Packet == *pPktArray)
+ {
+ fFoundPacket = TRUE;
+ break;
+ }
+
+ PrevPacket = Packet;
+ Packet = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next;
+ }
+
+ //
+ // If we didn't find the packet on our queue then we need to
+ // go on to the next one since it MUST have been completed
+ // via NdisMSendComplete....
+ //
+ if (!fFoundPacket)
+ {
+ continue;
+ }
+
+ Status = NDIS_GET_PACKET_STATUS(*pPktArray);
+
+ //
+ // Process the packet based on it's return status.
+ //
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'dnep');
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Complete is pending\n"));
+ }
+ else if (NDIS_STATUS_RESOURCES != Status)
+ {
+#if DBG
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'liaf');
+ }
+ else
+ {
+ NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'ccus');
+ }
+#endif
+
+ ADD_RESOURCE(Miniport, 'F');
+
+ //
+ // Remove from the finish queue.
+ //
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Completed packet 0x%x with status 0x%x\n",
+ *pPktArray,
+ Status));
+
+ //
+ // Fix up the packet queues.
+ //
+ if (Miniport->FirstPacket == *pPktArray)
+ {
+ Miniport->FirstPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Next;
+
+ if (Miniport->LastMiniportPacket == *pPktArray)
+ {
+ Miniport->LastMiniportPacket = NULL;
+ }
+ }
+ else
+ {
+ //
+ // If we just completed the last packet then
+ // we need to update our last packet pointer.
+ //
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Next;
+ if (*pPktArray == Miniport->LastPacket)
+ {
+ Miniport->LastPacket = PrevPacket;
+ }
+
+ //
+ // If we just complete the last miniport packet then
+ // the last miniport packet is the previous packet.
+ //
+ if (Miniport->LastMiniportPacket == *pPktArray)
+ {
+ Miniport->LastMiniportPacket = PrevPacket;
+ }
+ }
+
+ //
+ // We need to save a pointer to the open so that we
+ // can dereference it after the completion.
+ //
+ Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Open;
+
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)(
+ Open->ProtocolBindingContext,
+ *pPktArray,
+ Status);
+
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+ else
+ {
+ //
+ // Once we hit a return code of NDIS_STATUS_RESOURCES
+ // for a packet then we must break out and re-queue.
+ //
+ CLEAR_RESOURCE(Miniport, 'S');
+ MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
+
+ break;
+ }
+ }
+
+ //
+ // if there are any packets that returned NDIS_STATUS_RESOURCES
+ // then re-queue them.
+ //
+ if (Count != NumberOfPackets)
+ {
+ PNDIS_PACKET FinalPrevPacket = PrevPacket;
+
+ for (ResourcesCount = NumberOfPackets - 1, pPktArray = &Miniport->PacketArray[ResourcesCount];
+ ResourcesCount > Count;
+ ResourcesCount--, pPktArray--)
+ {
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Packet 0x%x returned resources\n", *pPktArray));
+
+ NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'oser');
+
+ //
+ // Float the pointers.
+ //
+ Miniport->LastMiniportPacket = *(pPktArray - 1);
+ Miniport->FirstPendingPacket = *pPktArray;
+ }
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Packet 0x%x returned resources\n", *pPktArray));
+
+ NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'oser');
+
+ //
+ // If this is the last packet on the miniport queue
+ // then NULL the last miniport packet out so we know there
+ // are no more.
+ //
+ if (Miniport->FirstPacket == *pPktArray)
+ {
+ Miniport->LastMiniportPacket = NULL;
+ Miniport->FirstPendingPacket = *pPktArray;
+ }
+ else
+ {
+ //
+ // There are other packets that are pending on
+ // the miniport queue.
+ //
+ Miniport->LastMiniportPacket = PrevPacket;
+ Miniport->FirstPendingPacket = *pPktArray;
+ }
+ }
+ }
+ }
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMStartSendPacketsFullDuplex\n"));
+
+ //
+ // If there are no more resources available but
+ // there are still packets to send then we need to
+ // keep the workitem queue'd.
+ //
+ if ((0 == Miniport->SendResourcesAvailable) &&
+ (Miniport->FirstPendingPacket != NULL))
+ {
+ fReturn = TRUE;
+ }
+ else
+ {
+ fReturn = FALSE;
+ }
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'RFED');
+
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+#endif
+ return(fReturn);
+}
+
+BOOLEAN
+FASTCALL
+ndisMStartSendsFullDuplex(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+/*++
+
+Routine Description:
+
+ This routine will process any pending sends for full-duplex miniports.
+
+
+ !!!!!!!NOTE!!!!!!!!
+ This routine MUST be called with the Miniport Lock NOT held!!!!
+
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ BOOLEAN fReturn = FALSE;
+#ifdef NDIS_NT
+ PNDIS_PACKET Packet;
+ PNDIS_PACKET PrevPacket;
+ NDIS_STATUS Status;
+ PNDIS_PACKET_RESERVED Reserved;
+ PNDIS_M_OPEN_BLOCK Open;
+ UINT Flags;
+ KIRQL OldIrql;
+
+ //
+ // Acquire the send lock.
+ //
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'rfed');
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMStartSendsFullDuplex\n"));
+
+ MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
+
+ //
+ // Loop and process sends.
+ //
+ while ((Miniport->SendResourcesAvailable != 0) &&
+ (Miniport->FirstPendingPacket != NULL))
+ {
+ //
+ // Grab the packet off of the pending queue.
+ //
+ Packet = Miniport->FirstPendingPacket;
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ Open = Reserved->Open;
+
+ //
+ // Remove from pending queue
+ //
+ Miniport->FirstPendingPacket = Reserved->Next;
+
+ //
+ // Put on finish queue
+ //
+ PrevPacket = Miniport->LastMiniportPacket;
+ Miniport->LastMiniportPacket = Packet;
+
+ //
+ // Send the packet
+ //
+ NDISM_SEND_PACKET(Miniport, Open, Packet, &Status);
+
+ //
+ // Process the completion status of the packet.
+ //
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnep');
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Complete is pending\n"));
+ }
+ else if (Status != NDIS_STATUS_RESOURCES)
+ {
+ NDISM_COMPLETE_SEND_FULL_DUPLEX(
+ Miniport,
+ Open,
+ Packet,
+ PrevPacket,
+ Status);
+ }
+ else
+ {
+ NDISM_COMPLETE_SEND_RESOURCES(Miniport, Packet, PrevPacket);
+ }
+ }
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMStartSendsFullDuplex\n"));
+
+ //
+ // If there are no more resources available but
+ // there are still packets to send then we need to
+ // keep the workitem queue'd.
+ //
+ if ((0 == Miniport->SendResourcesAvailable) &&
+ (Miniport->FirstPendingPacket != NULL))
+ {
+ fReturn = TRUE;
+ }
+ else
+ {
+ fReturn = FALSE;
+ }
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'RFED');
+
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+#endif
+ return(fReturn);
+}
+
+BOOLEAN
+FASTCALL
+ndisMStartSendPackets(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+{
+ PNDIS_PACKET Packet;
+ PNDIS_PACKET PrevPacket;
+ NDIS_STATUS Status;
+ PNDIS_PACKET_RESERVED Reserved;
+ PNDIS_M_OPEN_BLOCK Open;
+ UINT Flags;
+ BOOLEAN fReturn;
+ PPNDIS_PACKET pPktArray;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("==>ndisMStartSendPackets\n"));
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'rfed');
+
+ MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
+
+ //
+ // Loop and process sends.
+ //
+ while ((Miniport->SendResourcesAvailable != 0) &&
+ (Miniport->FirstPendingPacket != NULL))
+ {
+ UINT Count;
+ UINT ResourcesCount;
+ UINT NumberOfPackets;
+ PNDIS_PACKET FirstPrevPacket = NULL;
+
+ //
+ // Initialize the packet array.
+ //
+ pPktArray = Miniport->PacketArray;
+
+ //
+ // Place as many packets as we can in the packet array to send
+ // to the miniport.
+ //
+ for (NumberOfPackets = 0;
+ (NumberOfPackets < Miniport->MaximumSendPackets) &&
+ (Miniport->FirstPendingPacket != NULL); )
+ {
+ //
+ // Grab the packet off of the pending queue.
+ //
+ Packet = Miniport->FirstPendingPacket;
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+
+ //
+ // Remove from pending 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_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED)) &&
+ !MINIPORT_TEST_PACKET_FLAG(Packet, fPACKET_HAS_BEEN_LOOPED_BACK) &&
+ ndisMIsLoopbackPacket(Miniport, Packet))
+ {
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Packet 0x%x is self-directed.\n", Packet));
+
+ //
+ // Get a pointer to our open block.
+ // DO NOT USE "Reserved->Open" TO CALL INTO THE MACRO SINCE IT
+ // WILL NOT BE VALID FOR THE LIFE OF THE MACRO!!!!!
+ //
+ Open = Reserved->Open;
+
+ //
+ // Complete the packet back to the binding.
+ //
+ NDISM_COMPLETE_SEND(
+ Miniport,
+ Open,
+ Packet,
+ PrevPacket,
+ NDIS_STATUS_SUCCESS);
+
+ //
+ // No, we don't want to increment the counter for the
+ // miniport's packet array.
+ //
+ }
+ else
+ {
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'inim');
+
+ //
+ // We have to re-initialize this.
+ //
+ *pPktArray = Packet;
+ NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_SUCCESS);
+
+ //
+ // Increment the counter for the packet array index.
+ //
+ NumberOfPackets++;
+ pPktArray++;
+ }
+ }
+
+ //
+ // Are there any packets to send?
+ //
+ if (NumberOfPackets != 0)
+ {
+ //
+ // Get a temp pointer to our packet array.
+ //
+ pPktArray = Miniport->PacketArray;
+ Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Open;
+
+ //
+ // Pass the packet array down to the miniport.
+ //
+ (Open->SendPacketsHandler)(
+ Miniport->MiniportAdapterContext,
+ Miniport->PacketArray,
+ NumberOfPackets);
+
+ //
+ // First check to see if the LastMiniportPacket is NULL.
+ // If it is then the miniport called NdisMSendComplete()
+ // in our send context and we don't need to do anything more.
+ //
+ if (NULL == Miniport->LastMiniportPacket)
+ {
+ //
+ // We may still have packets pending to be sent down....
+ //
+ continue;
+ }
+
+ //
+ // Process the packet completion.
+ //
+ for (Count = 0; Count < NumberOfPackets; Count++, pPktArray++)
+ {
+ BOOLEAN fFoundPacket = FALSE;
+
+ //
+ // Try and find the packet on our miniport's packet queue.
+ //
+ Packet = Miniport->FirstPacket;
+ PrevPacket = NULL;
+
+ ASSERT(Packet != NULL);
+
+ //
+ // We are only going to travers the packet queue from the
+ // FirstPacket to the LastMiniportPacket.
+ // Why you ask? Well we need to make sure that the miniport
+ // didn't complete the packet we are now trying to complete
+ // with a call to NdisMSendComplete().
+ //
+ while (Packet != PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastMiniportPacket)->Next)
+ {
+ if (Packet == *pPktArray)
+ {
+ fFoundPacket = TRUE;
+ break;
+ }
+
+ PrevPacket = Packet;
+ Packet = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next;
+ }
+
+ //
+ // If we didn't find the packet on our queue then we need to
+ // go on to the next one since it MUST have been completed
+ // via NdisMSendComplete....
+ //
+ if (!fFoundPacket)
+ {
+ continue;
+ }
+
+ Status = NDIS_GET_PACKET_STATUS(*pPktArray);
+
+ //
+ // Process the packet based on it's return status.
+ //
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'dnep');
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Complete is pending\n"));
+ }
+ else if (Status != NDIS_STATUS_RESOURCES)
+ {
+#if DBG
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'liaf');
+ }
+ else
+ {
+ NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'ccus');
+ }
+#endif
+
+ ADD_RESOURCE(Miniport, 'F');
+
+ //
+ // Remove from the finish queue.
+ //
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Completed packet 0x%x with status 0x%x\n",
+ *pPktArray,
+ Status));
+
+ //
+ // Fix up the packet queues.
+ //
+ if (Miniport->FirstPacket == *pPktArray)
+ {
+ Miniport->FirstPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Next;
+
+ if (Miniport->LastMiniportPacket == *pPktArray)
+ {
+ Miniport->LastMiniportPacket = NULL;
+ }
+ }
+ else
+ {
+ //
+ // If we just completed the last packet then
+ // we need to update our last packet pointer.
+ //
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Next;
+ if (*pPktArray == Miniport->LastPacket)
+ {
+ Miniport->LastPacket = PrevPacket;
+ }
+
+ //
+ // If we just complete the last miniport packet then
+ // the last miniport packet is the previous packet.
+ //
+ if (Miniport->LastMiniportPacket == *pPktArray)
+ {
+ Miniport->LastMiniportPacket = PrevPacket;
+ }
+ }
+
+ //
+ // We need to save a pointer to the open so that we
+ // can dereference it after the completion.
+ //
+ Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Open;
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)(
+ Open->ProtocolBindingContext,
+ *pPktArray,
+ Status);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("- Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ Open->References--;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("==0 Open 0x%x Reference 0x%x\n",
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Open,
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Open->References));
+
+ if (Open->References == 0)
+ {
+ ndisMFinishClose(Miniport, Open);
+ }
+ }
+ else
+ {
+ //
+ // Once we hit a return code of NDIS_STATUS_RESOURCES
+ // for a packet then we must break out and re-queue.
+ //
+ CLEAR_RESOURCE(Miniport, 'S');
+ MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
+
+ break;
+ }
+ }
+
+ //
+ // if there are any packets that returned NDIS_STATUS_RESOURCES
+ // then re-queue them.
+ //
+ if (Count != NumberOfPackets)
+ {
+ PNDIS_PACKET FinalPrevPacket = PrevPacket;
+
+ for (ResourcesCount = NumberOfPackets - 1, pPktArray = &Miniport->PacketArray[ResourcesCount];
+ ResourcesCount > Count;
+ ResourcesCount--, pPktArray--)
+ {
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Packet 0x%x returned resources\n", *pPktArray));
+
+ NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'oser');
+
+ //
+ // Float the pointers.
+ //
+ Miniport->LastMiniportPacket = *(pPktArray - 1);
+ Miniport->FirstPendingPacket = *pPktArray;
+ }
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Packet 0x%x returned resources\n", *pPktArray));
+
+ NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'oser');
+
+ //
+ // If this is the last packet on the miniport queue
+ // then NULL the last miniport packet out so we know there
+ // are no more.
+ //
+ if (Miniport->FirstPacket == *pPktArray)
+ {
+ Miniport->LastMiniportPacket = NULL;
+ Miniport->FirstPendingPacket = *pPktArray;
+ }
+ else
+ {
+ //
+ // There are other packets that are pending on
+ // the miniport queue.
+ //
+ Miniport->LastMiniportPacket = PrevPacket;
+ Miniport->FirstPendingPacket = *pPktArray;
+ }
+ }
+ }
+ }
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'RFED');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMStartSendPackets\n"));
+
+ return(FALSE);
+}
+
+BOOLEAN
+FASTCALL
+ndisMStartSends(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Submits as many sends as possible to the mini-port.
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+Return Value:
+
+ If there are more packets to send but no resources to do it with
+ the this is TRUE to keep a workitem queue'd.
+
+--*/
+
+{
+ PNDIS_PACKET Packet;
+ PNDIS_PACKET PrevPacket;
+ NDIS_STATUS Status;
+ PNDIS_PACKET_RESERVED Reserved;
+ PNDIS_M_OPEN_BLOCK Open;
+ UINT Flags;
+ BOOLEAN fReturn;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("==>ndisMStartSends\n"));
+
+ MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'rfed');
+
+ //
+ // Loop and process sends.
+ //
+ while ((Miniport->SendResourcesAvailable != 0) &&
+ (Miniport->FirstPendingPacket != NULL))
+ {
+ //
+ // Grab the packet off of the pending queue.
+ //
+ Packet = Miniport->FirstPendingPacket;
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ Open = Reserved->Open;
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 's');
+
+ //
+ // Is this arcnet using ethernet encapsulation?
+ //
+ if (Miniport->MediaType == NdisMediumArcnet878_2)
+ {
+ //
+ // Build the header for arcnet.
+ //
+ Status = ndisMBuildArcnetHeader(Miniport, Open, Packet);
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ return(TRUE);
+ }
+ }
+
+ //
+ // Remove from pending queue
+ //
+ Miniport->FirstPendingPacket = Reserved->Next;
+
+ //
+ // Put on finish queue
+ //
+ PrevPacket = Miniport->LastMiniportPacket;
+ Miniport->LastMiniportPacket = Packet;
+
+ //
+ // Send the packet.
+ //
+ NDISM_SEND_PACKET(Miniport, Open, Packet, &Status);
+
+ //
+ // Process the packet pending completion status.
+ //
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnep');
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Complete is pending\n"));
+ }
+ else
+ {
+ //
+ // Clean-up arcnet's extra buffers.
+ //
+ if (Miniport->MediaType == NdisMediumArcnet878_2)
+ {
+ ndisMFreeArcnetHeader(Miniport, Packet);
+ }
+
+ //
+ // Handle the completion and resources cases.
+ //
+ if (Status != NDIS_STATUS_RESOURCES)
+ {
+ NDISM_COMPLETE_SEND(
+ Miniport,
+ Open,
+ Packet,
+ PrevPacket,
+ Status);
+ }
+ else
+ {
+ NDISM_COMPLETE_SEND_RESOURCES(Miniport, Packet, PrevPacket);
+ }
+ }
+
+ }
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMStartSends\n"));
+
+ //
+ // If there are no more resources available but
+ // there are still packets to send then we need to
+ // keep the workitem queue'd.
+ //
+ if ((0 == Miniport->SendResourcesAvailable) &&
+ (Miniport->FirstPendingPacket != NULL))
+ {
+ fReturn = TRUE;
+ }
+ else
+ {
+ fReturn = FALSE;
+ }
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'RFED');
+
+ return(fReturn);
+}
+
+NDIS_STATUS FASTCALL
+ndisMSyncSend(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN 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.
+
+--*/
+
+{
+ PNDIS_PACKET PrevPacket;
+ NDIS_STATUS Status;
+ PNDIS_PACKET_RESERVED Reserved;
+ PNDIS_M_OPEN_BLOCK Open;
+ UINT Flags;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Enter Sync send.\n"));
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'cnys');
+
+ //
+ // Get the Open block that the send is for from the packet.
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ Open = Reserved->Open;
+
+ //
+ // Remove from Queue
+ //
+ Miniport->FirstPendingPacket = Reserved->Next;
+
+ //
+ // Put on finish queue
+ //
+ PrevPacket = Miniport->LastMiniportPacket;
+ Miniport->LastMiniportPacket = Packet;
+ MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
+
+ //
+ // Send the packet.
+ //
+ NDISM_SEND_PACKET(Miniport, Open, Packet, &Status);
+
+ //
+ // Process the status of the send.
+ //
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnep');
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Complete sync send is pending\n"));
+
+ return(NDIS_STATUS_PENDING);
+ }
+
+ //
+ // If send complete was called from the miniport's send handler
+ // then our local PrevPacket pointer may no longer be valid....
+ //
+ if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED))
+ {
+ MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
+ MiniportFindPacket(Miniport, Packet, &PrevPacket);
+ }
+
+ Miniport->LastMiniportPacket = PrevPacket;
+
+ if (Status != NDIS_STATUS_RESOURCES)
+ {
+#if DBG
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'liaf');
+ }
+ else
+ {
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'ccus');
+ }
+#endif
+
+ ADD_RESOURCE(Miniport, 'F');
+
+ //
+ // Remove from finish queue
+ //
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Completed 0x%x\n", Status));
+
+ if (PrevPacket == NULL)
+ {
+ //
+ // Set up the next packet to send.
+ //
+ Miniport->FirstPacket = Reserved->Next;
+ }
+ else
+ {
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = Reserved->Next;
+
+ if (Packet == Miniport->LastPacket)
+ {
+ Miniport->LastPacket = PrevPacket;
+ }
+ }
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("- Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ Open->References--;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("==0 Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ if (Open->References == 0)
+ ndisMFinishClose(Miniport, Open);
+ }
+ else
+ {
+ //
+ // Status == NDIS_STATUS_RESOURCES!!!!
+ //
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Deferring send\n"));
+
+ //
+ // Put on pending queue
+ //
+ Miniport->FirstPendingPacket = Packet;
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'oser');
+
+ //
+ // Set flag
+ //
+ CLEAR_RESOURCE(Miniport, 'S');
+
+ Status = NDIS_STATUS_PENDING;
+ }
+
+ return(Status);
+}
+
+
+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;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+ 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.
+ //
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ return Status;
+}
+
+VOID
+ndisMSendCompleteFullDuplex(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ )
+{
+#ifdef NDIS_NT
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+ PNDIS_PACKET_RESERVED Reserved;
+ LONG Thread;
+ BOOLEAN fAcquireMiniportLock = FALSE;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMSendCompleteFullDuplex\n"));
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("packet 0x%x\n", Packet));
+
+ //
+ // Acquire the send lock, unless it has alrady been acquired earlier
+ // by this thread....
+ //
+ Thread = InterlockedExchangeAdd(&Miniport->SendThread, 0);
+ if (CURRENT_THREAD != Thread)
+ {
+ //
+ // We need to try and grab the lock...
+ //
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+
+ MINIPORT_SET_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
+
+ //
+ // 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;
+
+ 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.
+ //
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = Reserved->Next;
+ if (Packet == Miniport->LastPacket)
+ {
+ 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;
+
+ //
+ // Do we need to queue another workitem to process more sends?
+ //
+ if (Miniport->FirstPendingPacket != NULL)
+ {
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+ }
+
+
+#if DBG
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'pmoc');
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'liaf');
+ }
+ else
+ {
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'ccus');
+ }
+#endif
+
+ ADD_RESOURCE(Miniport, 'P');
+
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+
+ //
+ // If the current thread has the miniport lock then we need to
+ // release it....
+ //
+ if (CURRENT_THREAD == Miniport->MiniportThread)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ fAcquireMiniportLock = TRUE;
+ }
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)(
+ Open->ProtocolBindingContext,
+ Packet,
+ Status);
+
+ if (fAcquireMiniportLock)
+ {
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ }
+
+ //
+ // If the SendLock was acquired on entry then we need to make sure
+ // that it's acquired on exit...
+ //
+ if (CURRENT_THREAD == Thread)
+ {
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMSendCompleteFullDuplex\n"));
+#endif
+}
+
+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;
+ PSINGLE_LIST_ENTRY Link;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMSendComplete\n"));
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("packet 0x%x\n", Packet));
+
+ MINIPORT_SET_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
+
+ //
+ // 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;
+
+ 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.
+ //
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = Reserved->Next;
+ if (Packet == Miniport->LastPacket)
+ {
+ 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;
+
+ //
+ // If this is arcnet, then free the appended header.
+ //
+ if (Miniport->MediaType == NdisMediumArcnet878_2)
+ {
+ ndisMFreeArcnetHeader(Miniport, Packet);
+ }
+
+#if DBG
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'pmoc');
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'liaf');
+ }
+ else
+ {
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'ccus');
+ }
+#endif
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)(
+ Open->ProtocolBindingContext,
+ Packet,
+ Status);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ ADD_RESOURCE(Miniport, 'P');
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("- Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ Open->References--;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("==0 Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ if (Open->References == 0)
+ {
+ ndisMFinishClose(Miniport,Open);
+ }
+
+ //
+ // Do we need to queue another workitem to process more sends?
+ //
+ if (Miniport->FirstPendingPacket != NULL)
+ {
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+ }
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMSendComplete\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
+ //
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'C');
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Packet,
+ Status);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ Open = Open->MiniportNextOpen;
+ }
+}
+
+VOID
+ndisMSendResourcesAvailableFullDuplex(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ )
+{
+#ifdef NDIS_NT
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ LONG Thread;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ Thread = InterlockedExchangeAdd(&Miniport->SendThread, 0);
+ if (CURRENT_THREAD != Thread)
+ {
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMSendResourcesAvailableFullDuplex\n"));
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'aser');
+ ADD_RESOURCE(Miniport, 'V');
+
+ //
+ // Are there more sends to process?
+ //
+ if (Miniport->FirstPendingPacket != NULL)
+ {
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+ }
+
+ if (CURRENT_THREAD != Thread)
+ {
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMSendResourcesAvailableFullDuplex\n"));
+#endif
+}
+
+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);
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMSendResourcesAvailable\n"));
+
+ ADD_RESOURCE(Miniport, 'V');
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'aser');
+
+ //
+ // Are there more sends to process?
+ //
+ if (Miniport->FirstPendingPacket != NULL)
+ {
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+ }
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMSendResourcesAvailable\n"));
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////
+//
+// UPPER-EDGE SEND HANDLERS
+//
+///////////////////////////////////////////////////////////////////////////////////////
+
+
+NDIS_STATUS
+ndisMSendFullDuplexToSendPackets(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ )
+{
+ NDIS_STATUS Status = NDIS_STATUS_PENDING;
+#ifdef NDIS_NT
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ PNDIS_PACKET_RESERVED Reserved;
+ KIRQL OldIrql;
+ BOOLEAN fQueueWorkItem = FALSE;
+ BOOLEAN fDeferredSend = FALSE;
+ BOOLEAN LocalLock;
+ UINT Flags;
+
+ NDIS_ACQUIRE_SEND_SPIN_LOCK(Miniport, &OldIrql);
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnes');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMSendFullDuplexToSendPackets\n"));
+
+ //
+ // Initialize the packet info.
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+
+ //
+ // Place the packet on the packet queue.
+ //
+ if (Miniport->FirstPacket == NULL)
+ {
+ //
+ // Place the packet at the head of the queue.
+ //
+ Miniport->FirstPacket = Packet;
+ }
+ else
+ {
+ CHECK_FOR_DUPLICATE_PACKET(Miniport, Packet);
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = Packet;
+ }
+
+ Miniport->LastPacket = Packet;
+
+ //
+ // This packet has not been looped back yet!
+ //
+ MINIPORT_CLEAR_PACKET_FLAG(Packet, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT));
+
+ //
+ // Check to see if a sync send is possible.
+ //
+ if (Miniport->FirstPendingPacket == NULL)
+ {
+ Miniport->FirstPendingPacket = Packet;
+ }
+
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'DNES');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMSendFullDuplexToSendPackets\n"));
+
+ NDIS_RELEASE_SEND_SPIN_LOCK(Miniport, OldIrql);
+#endif
+ return(Status);
+}
+
+VOID
+ndisMSendPacketsFullDuplex(
+ IN PNDIS_OPEN_BLOCK NdisOpenBlock,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ )
+{
+#ifdef NDIS_NT
+ PNDIS_M_OPEN_BLOCK NdisBindingHandle = (PNDIS_M_OPEN_BLOCK)NdisOpenBlock->MacBindingHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = NdisBindingHandle->MiniportHandle;
+ PPNDIS_PACKET pPktArray;
+ PNDIS_PACKET_RESERVED Reserved;
+ BOOLEAN LocalLock;
+ KIRQL OldIrql;
+ UINT c;
+
+ NDIS_ACQUIRE_SEND_SPIN_LOCK(Miniport, &OldIrql);
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMSendPacketsFullDuplex\n"));
+
+ //
+ // Place the packets on the miniport queue.
+ //
+ for (c = 0, pPktArray = PacketArray;
+ c < NumberOfPackets;
+ c++, pPktArray++)
+ {
+ //
+ // Get the first packet....
+ //
+ NDIS_SET_PACKET_STATUS(*pPktArray, NDIS_STATUS_PENDING);
+
+ //
+ // Initialize the packet info.
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray);
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+
+ //
+ // Place the packet on the packet queue.
+ //
+ if (Miniport->FirstPacket == NULL)
+ {
+ //
+ // Place the packet at the head of the queue.
+ //
+ Miniport->FirstPacket = *pPktArray;
+ }
+ else
+ {
+ CHECK_FOR_DUPLICATE_PACKET(Miniport, *pPktArray);
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = *pPktArray;
+ }
+
+ Miniport->LastPacket = *pPktArray;
+
+ //
+ // This packet has not been looped back yet!
+ //
+ MINIPORT_CLEAR_PACKET_FLAG(*pPktArray, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT));
+
+ //
+ // Check to see if a sync send is possible.
+ //
+ if (Miniport->FirstPendingPacket == NULL)
+ {
+ Miniport->FirstPendingPacket = *pPktArray;
+ }
+ }
+
+ //
+ // Queue a workitem for the new sends.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMSendPacketsFullDuplex\n"));
+
+ NDIS_RELEASE_SEND_SPIN_LOCK(Miniport, OldIrql);
+
+#endif
+}
+
+
+NDIS_STATUS
+ndisMSendToSendPackets(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ PNDIS_PACKET_RESERVED Reserved;
+ BOOLEAN LocalLock;
+ NDIS_STATUS Status = NDIS_STATUS_PENDING;
+ KIRQL OldIrql;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnes');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMSendToSendPackets\n"));
+
+ //
+ // Increment the references on this open.
+ //
+ ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle, ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References));
+
+ //
+ // Initialize the packet info.
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+
+ //
+ // Place the packet on the packet queue.
+ //
+ if (Miniport->FirstPacket == NULL)
+ {
+ //
+ // Place the packet at the head of the queue.
+ //
+ Miniport->FirstPacket = Packet;
+ }
+ else
+ {
+ CHECK_FOR_DUPLICATE_PACKET(Miniport, Packet);
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = Packet;
+ }
+
+ Miniport->LastPacket = Packet;
+
+ //
+ // This packet has not been looped back yet!
+ //
+ MINIPORT_CLEAR_PACKET_FLAG(Packet, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT));
+
+ //
+ // Check to see if a sync send is possible.
+ //
+ if (Miniport->FirstPendingPacket == NULL)
+ {
+ Miniport->FirstPendingPacket = Packet;
+ }
+
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+
+ //
+ // Try to grab the local lock on the miniport block.
+ //
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // If we have the local lock and there is not
+ // a reset in progress then fire off the send.
+ //
+ if (LocalLock)
+ {
+ //
+ // Process deferred.
+ //
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMSendToSendPackets\n"));
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'DNES');
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ return(NDIS_STATUS_PENDING);
+}
+
+
+VOID
+ndisMSendPackets(
+ IN PNDIS_OPEN_BLOCK NdisOpenBlock,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ )
+{
+ PNDIS_M_OPEN_BLOCK NdisBindingHandle = (PNDIS_M_OPEN_BLOCK)NdisOpenBlock->MacBindingHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = NdisBindingHandle->MiniportHandle;
+ BOOLEAN LocalLock;
+ KIRQL OldIrql;
+ UINT c;
+ PNDIS_PACKET_RESERVED Reserved;
+ PPNDIS_PACKET pPktArray;;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMSendPackets\n"));
+
+ //
+ // Place the packets on the miniport queue.
+ //
+ for (c = 0, pPktArray = PacketArray;
+ c < NumberOfPackets;
+ c++, pPktArray++)
+ {
+ //
+ // Get the first packet....
+ //
+ NDIS_SET_PACKET_STATUS(*pPktArray, NDIS_STATUS_PENDING);
+
+ //
+ // Initialize the packet info.
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray);
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+
+ //
+ // Increment the references on this open.
+ //
+ ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle, ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References));
+
+ //
+ // Place the packet on the packet queue.
+ //
+ if (Miniport->FirstPacket == NULL)
+ {
+ //
+ // Place the packet at the head of the queue.
+ //
+ Miniport->FirstPacket = *pPktArray;
+ }
+ else
+ {
+ CHECK_FOR_DUPLICATE_PACKET(Miniport, *pPktArray);
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = *pPktArray;
+ }
+
+ Miniport->LastPacket = *pPktArray;
+
+ //
+ // This packet has not been looped back yet!
+ //
+ MINIPORT_CLEAR_PACKET_FLAG(*pPktArray, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT));
+
+ //
+ // Check to see if a sync send is possible.
+ //
+ if (Miniport->FirstPendingPacket == NULL)
+ {
+ Miniport->FirstPendingPacket = *pPktArray;
+ }
+ }
+
+ //
+ // Queue a workitem for the new sends.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+
+ //
+ // Try to grab the local lock on the miniport block.
+ //
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // If we have the local lock and there is not
+ // a reset in progress then fire off the send.
+ //
+ if (LocalLock)
+ {
+ //
+ // Process deferred.
+ //
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMSendPackets\n"));
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+}
+
+VOID
+ndisMSendPacketsFullDuplexToSend(
+ IN PNDIS_OPEN_BLOCK NdisOpenBlock,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ )
+{
+#ifdef NDIS_NT
+ PNDIS_M_OPEN_BLOCK NdisBindingHandle = (PNDIS_M_OPEN_BLOCK)NdisOpenBlock->MacBindingHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = NdisBindingHandle->MiniportHandle;
+ PNDIS_PACKET_RESERVED Reserved;
+ PPNDIS_PACKET pPktArray;
+ BOOLEAN LocalLock;
+ KIRQL OldIrql;
+ UINT c;
+
+ NDIS_ACQUIRE_SEND_SPIN_LOCK(Miniport, &OldIrql);
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'kpes');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMSendPacketsFullDuplexToSend\n"));
+
+ //
+ // Place the packets on the miniport queue.
+ //
+ for (c = 0, pPktArray = PacketArray;
+ c < NumberOfPackets;
+ c++, pPktArray++)
+ {
+ //
+ // Initialize the packet info.
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray);
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+
+ //
+ // Place the packet on the packet queue.
+ //
+ if (Miniport->FirstPacket == NULL)
+ {
+ //
+ // Place the packet at the head of the queue.
+ //
+ Miniport->FirstPacket = *pPktArray;
+ }
+ else
+ {
+ CHECK_FOR_DUPLICATE_PACKET(Miniport, *pPktArray);
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = *pPktArray;
+ }
+
+ Miniport->LastPacket = *pPktArray;
+
+ //
+ // This packet has not been looped back yet.
+ //
+ MINIPORT_CLEAR_PACKET_FLAG(*pPktArray, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT));
+
+ //
+ // Check to see if a sync send is possible.
+ //
+ if (Miniport->FirstPendingPacket == NULL)
+ {
+ Miniport->FirstPendingPacket = *pPktArray;
+ }
+ }
+
+ //
+ // Queue a workitem for the new sends.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMSendPacketsFullDuplexToSend\n"));
+
+ NDIS_RELEASE_SEND_SPIN_LOCK(Miniport, OldIrql);
+#endif
+}
+
+NDIS_STATUS
+ndisMSendFullDuplex(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_PENDING;
+#ifdef NDIS_NT
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ PNDIS_PACKET_RESERVED Reserved;
+ KIRQL OldIrql;
+ BOOLEAN fQueueWorkItem = FALSE;
+ BOOLEAN fDeferredSend = FALSE;
+ BOOLEAN LocalLock;
+ UINT Flags;
+
+ NDIS_ACQUIRE_SEND_SPIN_LOCK(Miniport, &OldIrql);
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnes');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMSendFullDuplex\n"));
+
+ //
+ // Initialize the packet info.
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+
+ //
+ // Place the packet on the packet queue.
+ //
+ if (Miniport->FirstPacket == NULL)
+ {
+ //
+ // Place the packet at the head of the queue.
+ //
+ Miniport->FirstPacket = Packet;
+ }
+ else
+ {
+ CHECK_FOR_DUPLICATE_PACKET(Miniport, Packet);
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = Packet;
+ }
+
+ Miniport->LastPacket = Packet;
+
+ //
+ // This packet has not been looped back yet and it does not
+ // contain any media specific information.
+ //
+ MINIPORT_CLEAR_PACKET_FLAG(Packet, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT));
+
+ if (NULL == Miniport->FirstPendingPacket)
+ {
+ Miniport->FirstPendingPacket = Packet;
+ }
+
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'DNES');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMSendFullDuplex\n"));
+
+ NDIS_RELEASE_SEND_SPIN_LOCK(Miniport, OldIrql);
+#endif
+ return(Status);
+}
+
+VOID
+ndisMSendPacketsToSend(
+ IN PNDIS_OPEN_BLOCK NdisOpenBlock,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ )
+/*++
+
+Routine Description:
+
+ This routine will take a packet array and "thunk" it down for a
+ driver that does not support a send packet handler.
+ This involves queueing the packet array onto the miniport's packet queue
+ and sending them one at a time.
+
+Arguments:
+
+ NdisBindingHandle - Pointer to the NDIS_OPEN_BLOCK.
+ PacketArray - Array of PNDIS_PACKET structures that are
+ to be sent to the miniport as NDIS_PACKETs.
+ NumberOfPackets - Number of elements in the PacketArray.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_M_OPEN_BLOCK NdisBindingHandle = (PNDIS_M_OPEN_BLOCK)NdisOpenBlock->MacBindingHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = NdisBindingHandle->MiniportHandle;
+ PNDIS_PACKET Packet;
+ PNDIS_PACKET_RESERVED Reserved;
+ PPNDIS_PACKET pPktArray;
+ BOOLEAN LocalLock;
+ KIRQL OldIrql;
+ UINT c;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'kpes');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMSendPacketsToSend\n"));
+
+ //
+ // Try to grab the local lock on the miniport block.
+ //
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Place the packets on the miniport queue.
+ //
+ for (c = 0, pPktArray = PacketArray;
+ c < NumberOfPackets;
+ c++, pPktArray++)
+ {
+ //
+ // Initialize the packet info.
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray);
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+
+ //
+ // Increment the references on this open.
+ //
+ ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle, ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References));
+
+ //
+ // Place the packet on the packet queue.
+ //
+ if (Miniport->FirstPacket == NULL)
+ {
+ //
+ // Place the packet at the head of the queue.
+ //
+ Miniport->FirstPacket = *pPktArray;
+ }
+ else
+ {
+ CHECK_FOR_DUPLICATE_PACKET(Miniport, *pPktArray);
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = *pPktArray;
+ }
+
+ Miniport->LastPacket = *pPktArray;
+
+ //
+ // This packet has not been looped back yet.
+ //
+ MINIPORT_CLEAR_PACKET_FLAG(*pPktArray, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT));
+
+ //
+ // Check to see if a sync send is possible.
+ //
+ if (Miniport->FirstPendingPacket == NULL)
+ {
+ Miniport->FirstPendingPacket = *pPktArray;
+ }
+ }
+
+ //
+ // Queue a workitem for the new sends.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+
+ //
+ // If we have the local lock and there is not
+ // a reset in progress then fire off the send.
+ //
+ if (LocalLock)
+ {
+ //
+ // Process deferred.
+ //
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMSendPacketsToSend\n"));
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+}
+
+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;
+ BOOLEAN LocalLock;
+ BOOLEAN SyncSend = FALSE;
+ NDIS_STATUS Status = NDIS_STATUS_PENDING;
+ KIRQL OldIrql;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnes');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMSend\n"));
+
+ //
+ // Try to grab the local lock on the miniport block.
+ //
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Increment the references on this open.
+ //
+ ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle, ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References));
+
+ //
+ // Initialize the packet info.
+ //
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+
+ //
+ // Place the packet on the packet queue.
+ //
+ if (Miniport->FirstPacket == NULL)
+ {
+ //
+ // Place the packet at the head of the queue.
+ //
+ Miniport->FirstPacket = Packet;
+ }
+ else
+ {
+ CHECK_FOR_DUPLICATE_PACKET(Miniport, Packet);
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = Packet;
+ }
+
+ Miniport->LastPacket = Packet;
+
+ //
+ // Mark the packet as not having been looped back yet.
+ //
+ MINIPORT_CLEAR_PACKET_FLAG(Packet, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT));
+
+ if (NULL == Miniport->FirstPendingPacket)
+ {
+ Miniport->FirstPendingPacket = Packet;
+
+ SyncSend = TRUE;
+ }
+
+ //
+ // If we have the local lock and there is not
+ // a reset in progress then fire off the send.
+ //
+ if (LocalLock)
+ {
+ //
+ // Can we do a sync send?
+ //
+ if (SyncSend && (Miniport->WorkQueue[NdisWorkItemHalt].Next == NULL))
+ {
+ //
+ // TODO: Make the call to sync send inline!!!
+ //
+ // Synchronous send.
+ //
+ Status = ndisMSyncSend(Miniport, Packet);
+ }
+ else
+ {
+ //
+ // Process deferred.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+ }
+ else
+ {
+ //
+ // We can't get the local lock so queue a workitem
+ // to process the send later.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMSend\n"));
+
+ NDISM_LOG_PACKET(Miniport, Packet, (PVOID)Status, 'DNES');
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ return(Status);
+}
+
+
+VOID
+ndisMSendPacketsToFullMac(
+ IN PNDIS_OPEN_BLOCK NdisOpenBlock,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ UINT c;
+ UINT Flags;
+ PPNDIS_PACKET pPktArray;
+ NDIS_STATUS Status;
+
+ //
+ // Send the packets to the mac one at a time.
+ //
+ for (c = 0, pPktArray = PacketArray;
+ c < NumberOfPackets;
+ c++, pPktArray++)
+ {
+ //
+ // Send the packet to the mac driver.
+ //
+ Status = NdisOpenBlock->SendHandler(
+ NdisOpenBlock->MacBindingHandle,
+ *pPktArray);
+
+ //
+ // If the packet is not pending then complete it back to the protocol.
+ //
+ if (NDIS_STATUS_PENDING != Status)
+ {
+ //
+ // Call the protocol's complete handler....
+ //
+ (NdisOpenBlock->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)(
+ NdisOpenBlock->ProtocolBindingContext,
+ *pPktArray,
+ Status);
+ }
+ }
+}
+
+
+NDIS_STATUS
+ndisMResetWanSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE NdisLinkHandle,
+ IN PVOID Packet
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMResetWanSend\n"));
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnes');
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, ' PIR');
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'DNES');
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("ndisMResetWanSend: Reset in progress or Reset Requested\n"));
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMResetWanSend\n"));
+
+ return(NDIS_STATUS_RESET_IN_PROGRESS);
+}
+
+NDIS_STATUS
+ndisMResetSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMResetSend\n"));
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnes');
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, ' PIR');
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'DNES');
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("ndisMResetSend: Reset in progress or Reset Requested\n"));
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMResetSend\n"));
+
+ return(NDIS_STATUS_RESET_IN_PROGRESS);
+}
+
+VOID
+ndisMResetSendPackets(
+ IN PNDIS_OPEN_BLOCK NdisOpenBlock,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PNDIS_M_OPEN_BLOCK NdisBindingHandle = (PNDIS_M_OPEN_BLOCK)NdisOpenBlock->MacBindingHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = NdisBindingHandle->MiniportHandle;
+ UINT c;
+
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("==>ndisMResetSendPackets\n"));
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'kpes');
+
+ for (c = 0; c < NumberOfPackets; c++)
+ {
+ NDISM_LOG_PACKET(Miniport, PacketArray[c], NULL, ' PIR');
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("ndisMResetSendPackets: Reset in progress or Reset Requested\n"));
+
+ //
+ // For send packets we need to call the completion handler....
+ //
+ (NdisBindingHandle->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)(
+ NdisBindingHandle->ProtocolBindingContext,
+ PacketArray[c],
+ NDIS_STATUS_RESET_IN_PROGRESS);
+ }
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES');
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("<==ndisMResetSendPackets\n"));
+
+}
+
+
diff --git a/private/ntos/ndis/ndis40/sendm.h b/private/ntos/ndis/ndis40/sendm.h
new file mode 100644
index 000000000..b201fdb56
--- /dev/null
+++ b/private/ntos/ndis/ndis40/sendm.h
@@ -0,0 +1,334 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ D:\nt\private\ntos\ndis\wrapper\sendm.h
+
+Abstract:
+
+Author:
+
+ Kyle Brandon (KyleB)
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#ifndef __SENDM_H
+#define __SENDM_H
+
+#if DBG
+
+extern UCHAR ndisMSendRescBuffer[512];
+extern ULONG ndisMSendRescIndex;
+
+#define REMOVE_RESOURCE(W, C) \
+{ \
+ W->SendResourcesAvailable--; \
+ ndisMSendRescBuffer[ndisMSendRescIndex++] = (UCHAR)C; \
+ ndisMSendRescBuffer[ndisMSendRescIndex++] = (UCHAR)'R'; \
+ ndisMSendRescBuffer[ndisMSendRescIndex++] = (UCHAR)W->SendResourcesAvailable;\
+ ndisMSendRescBuffer[ndisMSendRescIndex] = (UCHAR)'X'; \
+ if (ndisMSendRescIndex >= 500) \
+ { \
+ ndisMSendRescIndex = 0; \
+ } \
+}
+
+#define ADD_RESOURCE(W, C) \
+{ \
+ W->SendResourcesAvailable=0xffffff; \
+ ndisMSendRescBuffer[ndisMSendRescIndex++] = (UCHAR)C; \
+ ndisMSendRescBuffer[ndisMSendRescIndex++] = (UCHAR)'A'; \
+ ndisMSendRescBuffer[ndisMSendRescIndex++] = (UCHAR)W->SendResourcesAvailable;\
+ ndisMSendRescBuffer[ndisMSendRescIndex] = (UCHAR)'X'; \
+ if (ndisMSendRescIndex >= 500) \
+ { \
+ ndisMSendRescIndex = 0; \
+ } \
+}
+
+#define CLEAR_RESOURCE(W, C) \
+{ \
+ W->SendResourcesAvailable = 0; \
+ ndisMSendRescBuffer[ndisMSendRescIndex++] = (UCHAR)C; \
+ ndisMSendRescBuffer[ndisMSendRescIndex++] = (UCHAR)'C'; \
+ ndisMSendRescBuffer[ndisMSendRescIndex++] = (UCHAR)W->SendResourcesAvailable;\
+ if (ndisMSendRescIndex >= 500) \
+ { \
+ ndisMSendRescIndex = 0; \
+ } \
+}
+
+#define CHECK_FOR_DUPLICATE_PACKET(_M, _P) \
+{ \
+ PNDIS_PACKET pTmpPacket; \
+ \
+ IF_DBG(DBG_COMP_SEND, DBG_LEVEL_FATAL) \
+ { \
+ for (pTmpPacket = (_M)->FirstPacket; \
+ pTmpPacket != NULL; \
+ pTmpPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(pTmpPacket)->Next) \
+ { \
+ if (_P == pTmpPacket) \
+ { \
+ DBGBREAK(DBG_COMP_SEND, DBG_LEVEL_FATAL); \
+ } \
+ } \
+ } \
+}
+
+#else
+
+#define REMOVE_RESOURCE(W, C) W->SendResourcesAvailable--
+#define ADD_RESOURCE(W, C) W->SendResourcesAvailable = 0x00ffffff
+#define CLEAR_RESOURCE(W, C) W->SendResourcesAvailable = 0
+
+#define CHECK_FOR_DUPLICATE_PACKET(_M, _P)
+
+#endif
+
+
+//
+// Macros used for getting to OOB data and packet extension.
+//
+#define PNDIS_PACKET_OOB_DATA_FROM_PNDIS_PACKET(p) (PNDIS_PACKET_OOB_DATA)((PUCHAR)Packet + Packet->Private.NdisPacketOobOffset)
+#define PNDIS_PACKET_PRIVATE_EXTENSION_FROM_PNDIS_PACKET(p) (PNDIS_PACKET_PRIVATE_EXTENSION)((PUCHAR)Packet + Packet->Private.NdisPacketOobOffset + sizeof(NDIS_PACKET_OOB_DATA))
+
+/*++
+
+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); \
+}
+
+#define NDISM_COMPLETE_SEND_COMMON(_M, _O, _P, _PrevP, _S) \
+{ \
+ if ((_S) != NDIS_STATUS_SUCCESS) \
+ { \
+ NDISM_LOG_PACKET((_M), (_P), NULL, 'liaf'); \
+ } \
+ else \
+ { \
+ NDISM_LOG_PACKET((_M), (_P), NULL, 'ccus'); \
+ } \
+ \
+ ADD_RESOURCE((_M), 'F'); \
+ \
+ /* \
+ Remove from finish queue \
+ */ \
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, \
+ ("Completed 0x%x\n", (_S))); \
+ \
+ /* \
+ If send complete was called from the miniport's send handler \
+ then our local PrevPacket pointer may no longer be valid. \
+ */ \
+ if (MINIPORT_TEST_SEND_FLAG((_M), fMINIPORT_SEND_COMPLETE_CALLED)) \
+ { \
+ MINIPORT_CLEAR_SEND_FLAG((_M), fMINIPORT_SEND_COMPLETE_CALLED); \
+ MiniportFindPacket((_M), (_P), &(_PrevP)); \
+ } \
+ \
+ /* \
+ Set up the next packet to send. \
+ */ \
+ (_M)->LastMiniportPacket = (_PrevP); \
+ if ((_PrevP) == NULL) \
+ { \
+ /* \
+ Place the packet at the head of the queue. \
+ */ \
+ (_M)->FirstPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(_P)->Next; \
+ } \
+ else \
+ { \
+ PNDIS_RESERVED_FROM_PNDIS_PACKET((_PrevP))->Next = \
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(_P)->Next; \
+ \
+ /* \
+ If we just unlinked the last packet then we need to update \
+ our last packet pointer. \
+ */ \
+ if ((_P) == (_M)->LastPacket) \
+ { \
+ (_M)->LastPacket = (_PrevP); \
+ } \
+ } \
+}
+
+#define NDISM_COMPLETE_SEND_FULL_DUPLEX(_M, _O, _P, _PrevP, _S) \
+{ \
+ /* \
+ The full-duplex completion will take care of everything but the \
+ open references. \
+ */ \
+ NDISM_COMPLETE_SEND_COMMON((_M), (_O), (_P), (_PrevP), (_S)); \
+ \
+ /* \
+ Indicate the completion to the protocol. \
+ */ \
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC((_M)); \
+ \
+ ((_O)->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)( \
+ (_O)->ProtocolBindingContext, \
+ (_P), \
+ (_S)); \
+ \
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC((_M)); \
+}
+
+#define NDISM_COMPLETE_SEND(_M, _O, _P, _PrevP, _S) \
+{ \
+ /* \
+ The full-duplex completion will take care of everything but the \
+ open references. \
+ */ \
+ NDISM_COMPLETE_SEND_COMMON((_M), (_O), (_P), (_PrevP), (_S)); \
+ \
+ /* \
+ Indicate the completion to the protocol. \
+ */ \
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC((_M)); \
+ \
+ ((_O)->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)( \
+ (_O)->ProtocolBindingContext, \
+ (_P), \
+ (_S)); \
+ \
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC((_M)); \
+ \
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO, \
+ ("- Open 0x%x Reference 0x%x\n", (_O), (_O)->References)); \
+ \
+ (_O)->References--; \
+ \
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO, \
+ ("==0 Open 0x%x Reference 0x%x\n", (_O), (_O)->References)); \
+ \
+ if ((_O)->References == 0) \
+ { \
+ ndisMFinishClose((_M), (_O)); \
+ } \
+}
+
+#define NDISM_COMPLETE_SEND_RESOURCES(_M, _P, _PrevP) \
+{ \
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, \
+ ("Deferring send\n")); \
+ \
+ NDISM_LOG_PACKET((_M), (_P), NULL, 'oser'); \
+ \
+ /* \
+ If send complete was called from the miniport's send handler \
+ then our local PrevPacket pointer may no longer be valid. \
+ */ \
+ if (MINIPORT_TEST_SEND_FLAG((_M), fMINIPORT_SEND_COMPLETE_CALLED)) \
+ { \
+ MINIPORT_CLEAR_SEND_FLAG((_M), fMINIPORT_SEND_COMPLETE_CALLED); \
+ MiniportFindPacket((_M), (_P), &(_PrevP)); \
+ } \
+ \
+ /* \
+ Remove from finish queue \
+ */ \
+ (_M)->LastMiniportPacket = (_PrevP); \
+ \
+ /* \
+ Put on pending queue \
+ */ \
+ (_M)->FirstPendingPacket = (_P); \
+ \
+ /* \
+ Mark the miniport as out of send resources. \
+ */ \
+ CLEAR_RESOURCE((_M), 'S'); \
+}
+
+#define NDISM_SEND_PACKET(_M, _O, _P, _pS) \
+{ \
+ UINT _Flags; \
+ \
+ /* \
+ Indicate the packet loopback if necessary. \
+ */ \
+ if ((((_M)->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) || \
+ MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED)) && \
+ !MINIPORT_TEST_PACKET_FLAG((_P), fPACKET_HAS_BEEN_LOOPED_BACK) && \
+ ndisMIsLoopbackPacket((_M), (_P))) \
+ { \
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, \
+ ("Packet is self-directed.\n")); \
+ \
+ /* \
+ Self-directed loopback always succeeds. \
+ */ \
+ *(_pS) = NDIS_STATUS_SUCCESS; \
+ } \
+ else \
+ { \
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, \
+ ("Sending packet 0x%x\n", Packet)); \
+ \
+ REMOVE_RESOURCE((_M), 'S'); \
+ \
+ NdisQuerySendFlags((_P), &_Flags); \
+ \
+ NDISM_LOG_PACKET((_M), (_P), NULL, 'inim'); \
+ \
+ /* \
+ Call down to the driver. \
+ */ \
+ *(_pS) = ((_O)->SendHandler)((_O)->MiniportAdapterContext, (_P), _Flags); \
+ } \
+}
+
+#endif // __SENDM_H
diff --git a/private/ntos/ndis/ndis40/sources.inc b/private/ntos/ndis/ndis40/sources.inc
new file mode 100644
index 000000000..a7812d04e
--- /dev/null
+++ b/private/ntos/ndis/ndis40/sources.inc
@@ -0,0 +1,77 @@
+!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
+
+TARGETNAME=ndis
+TARGETTYPE=EXPORT_DRIVER
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+INCLUDES=..;..\..\..\inc;..\..\..\..\inc;..\..\inc
+C_DEFINES= $(C_DEFINES) -DNDIS_WRAPPER -D_NTDRIVER_ -D_NTIFS_
+C_DEFINES= $(C_DEFINES) -DNDIS41_MINIPORT -D_SEND_PRIORITY=1
+C_DEFINES= $(C_DEFINES) -DNDIS41
+#C_DEFINES= $(C_DEFINES) -D_DBG=1
+
+NTPROFILEINPUT=yes
+
+
+SOURCES= \
+ ..\ndis.rc \
+ ..\ndis.c \
+ ..\data.c \
+ ..\init.c \
+ ..\initpnp.c \
+ ..\common.c \
+ ..\config.c \
+ ..\configm.c \
+ ..\bus.c \
+ ..\timer.c \
+ ..\timerm.c \
+ ..\miniport.c \
+ ..\minint.c \
+ ..\ndis_co.c \
+ ..\requestm.c \
+ ..\sendm.c \
+ ..\minisub.c \
+ ..\mac.c \
+ ..\protocol.c \
+ ..\efilter.c \
+ ..\ffilter.c \
+ ..\tfilter.c \
+ ..\afilter.c \
+ ..\debug.c
+
+PRECOMPILED_INCLUDE=..\precomp.h
+PRECOMPILED_PCH=precomp.pch
+PRECOMPILED_OBJ=precomp.obj
+
+DLLDEF=obj\*\ndis.def
+
+SOURCES_USED=..\sources.inc
+
+
+ \ No newline at end of file
diff --git a/private/ntos/ndis/ndis40/tfilter.c b/private/ntos/ndis/ndis40/tfilter.c
new file mode 100644
index 000000000..bb0754b3a
--- /dev/null
+++ b/private/ntos/ndis/ndis40/tfilter.c
@@ -0,0 +1,2813 @@
+/*++
+
+Copyright (c) 1990-1995 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
+ Jameel Hyder (JameelH) Re-organization 01-Jun-95
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_TFILTER
+
+//
+// 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
+
+
+//
+// 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:
+//
+// None
+//
+//--*/
+#define TR_FILTER_FREE_OPEN(Filter, LocalOpen)\
+{\
+ SET_BIT_IN_MASK(((LocalOpen)->FilterIndex), &((Filter)->FreeBindingMask)); \
+ FreePhys((LocalOpen), sizeof(TR_BINDING_INFO));\
+}
+
+#define TR_CHECK_FOR_INVALID_BROADCAST_INDICATION(_F) \
+IF_DBG(DBG_COMP_FILTER, DBG_LEVEL_WARN) \
+{ \
+ if (!((_F)->CombinedPacketFilter & NDIS_PACKET_TYPE_BROADCAST)) \
+ { \
+ /* \
+ We should never receive broadcast packets \
+ to someone else unless in p-mode. \
+ */ \
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_ERR, \
+ ("Bad driver, indicating broadcast packets when not set to.\n"));\
+ DBGBREAK(DBG_COMP_FILTER, DBG_LEVEL_ERR); \
+ } \
+}
+
+
+#define TR_CHECK_FOR_INVALID_DIRECTED_INDICATION(_F, _A) \
+IF_DBG(DBG_COMP_FILTER, DBG_LEVEL_WARN) \
+{ \
+ /* \
+ The result of comparing an element of the address \
+ array and the functional 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( \
+ (_F)->AdapterAddress, \
+ (_A), \
+ &Result); \
+ if (Result != 0) \
+ { \
+ /* \
+ We should never receive directed packets \
+ to someone else unless in p-mode. \
+ */ \
+ DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_ERR, \
+ ("Bad driver, indicating packets to another station when not in promiscuous mode.\n"));\
+ DBGBREAK(DBG_COMP_FILTER, DBG_LEVEL_ERR); \
+ } \
+}
+
+
+VOID
+trRemoveBindingFromLists(
+ IN PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding
+ )
+/*++
+
+ This routine will remove a binding from all of the list in a
+ filter database. These lists include the list of bindings,
+ the directed filter list and the broadcast filter list.
+
+Arguments:
+
+ Filter - Pointer to the filter database to remove the binding from.
+ Binding - Pointer to the binding to remove.
+
+--*/
+{
+ PTR_BINDING_INFO *ppBI;
+
+ //
+ // Remove the binding from the filters list
+ // of all bindings.
+ //
+ for (ppBI = &Filter->OpenList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextOpen)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextOpen;
+ break;
+ }
+ }
+ ASSERT(*ppBI == Binding->NextOpen);
+
+ //
+ // Remove it from the directed binding list - conditionally
+ //
+ for (ppBI = &Filter->DirectedList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextDirected)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextDirected;
+ break;
+ }
+ }
+
+ //
+ // Remove it from the broadcast/functional/group binding list - conditionally
+ //
+ for (ppBI = &Filter->BFGList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextBFG)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextBFG;
+ break;
+ }
+ }
+
+ Binding->NextDirected = NULL;
+ Binding->NextBFG = NULL;
+ Binding->NextOpen = NULL;
+}
+
+VOID
+trRemoveAndFreeBinding(
+ IN PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding,
+ IN BOOLEAN fCallCloseAction
+ )
+/*++
+
+Routine Description:
+
+ This routine will remove a binding from the filter database and
+ indicate a receive complete if necessary. This was made a function
+ to remove code redundancey in following routines. Its not time
+ critical so it's cool.
+
+Arguments:
+
+ Filter - Pointer to the filter database to remove the binding from.
+ Binding - Pointer to the binding to remove.
+ fCallCloseAction - TRUE if we should call the filter's close
+ action routine. FALSE if not.
+
+--*/
+{
+ //
+ // Remove the binding.
+ //
+ trRemoveBindingFromLists(Filter, Binding);
+
+ //
+ // If we have received and packet indications then
+ // notify the binding of the indication completion.
+ //
+ if (Binding->ReceivedAPacket)
+ {
+ if (NULL != Filter->Miniport)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+ }
+ else
+ {
+ NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ }
+
+ FilterIndicateReceiveComplete(Binding->NdisBindingContext);
+
+ if (NULL != Filter->Miniport)
+ {
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+ }
+ else
+ {
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ }
+ }
+
+ //
+ // Do we need to call the close action?
+ //
+ if (fCallCloseAction)
+ {
+ //
+ // Call the macs action routine so that they know we
+ // are no longer referencing this open binding.
+ //
+ Filter->CloseAction(Binding->MacBindingHandle);
+ }
+
+ //
+ // Free the open.
+ //
+ TR_FILTER_FREE_OPEN(Filter, Binding);
+}
+
+
+
+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->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);
+
+ //
+ // Zero the memory
+ //
+ ZeroMemory(LocalOpen, sizeof(TR_BINDING_INFO));
+
+ //
+ // Get place for the open and insert it.
+ //
+ TR_FILTER_ALLOC_OPEN(Filter, &LocalIndex);
+
+ LocalOpen->NextOpen = Filter->OpenList;
+ Filter->OpenList = LocalOpen;
+
+ LocalOpen->References = 1;
+ LocalOpen->FilterIndex = (UCHAR)LocalIndex;
+ LocalOpen->MacBindingHandle = MacBindingHandle;
+ LocalOpen->NdisBindingContext = NdisBindingContext;
+
+ *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;
+
+ //
+ // Set the packet filter to NONE.
+ //
+ StatusToReturn = TrFilterAdjust(Filter,
+ NdisFilterHandle,
+ NdisRequest,
+ (UINT)0,
+ FALSE);
+ if ((NDIS_STATUS_SUCCESS == StatusToReturn) ||
+ (NDIS_STATUS_PENDING == StatusToReturn))
+ {
+ NDIS_STATUS StatusToReturn2;
+
+ //
+ // Clear the functional address.
+ //
+ 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;
+
+ //
+ // Clear the group address if no other bindings are using it.
+ //
+ 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 the binding and indicate a receive complete
+ // if necessary.
+ //
+ trRemoveAndFreeBinding(Filter, LocalOpen, FALSE);
+ }
+ 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);
+}
+
+VOID
+trUndoChangeFunctionalAddress(
+ IN PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding
+)
+{
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+ Binding->FunctionalAddress = Binding->OldFunctionalAddress;
+ Filter->CombinedFunctionalAddress = Filter->OldCombinedFunctionalAddress;
+}
+
+
+
+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;
+
+ //
+ // Pointer to the open.
+ //
+ PTR_BINDING_INFO LocalOpen = (PTR_BINDING_INFO)NdisFilterHandle;
+
+ //
+ // 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->OldFunctionalAddress = LocalOpen->FunctionalAddress;
+ LocalOpen->FunctionalAddress = FunctionalAddress;
+
+ //
+ // Contains the value of the combined functional address before
+ // it is adjusted.
+ //
+ Filter->OldCombinedFunctionalAddress = Filter->CombinedFunctionalAddress;
+
+ //
+ // 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 (Filter->OldCombinedFunctionalAddress != Filter->CombinedFunctionalAddress)
+ {
+ StatusOfAdjust = Filter->AddressChangeAction(
+ Filter->OldCombinedFunctionalAddress,
+ 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.
+ //
+ trUndoChangeFunctionalAddress(Filter, LocalOpen);
+ }
+ }
+ else
+ {
+ StatusOfAdjust = NDIS_STATUS_SUCCESS;
+ }
+
+ return(StatusOfAdjust);
+}
+
+VOID
+trUndoChangeGroupAddress(
+ IN PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding
+ )
+{
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+ Filter->GroupAddress = Filter->OldGroupAddress;
+ Filter->GroupReferences = Filter->OldGroupReferences;
+
+ Binding->UsingGroupAddress = Binding->OldUsingGroupAddress;
+}
+
+
+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;
+
+ //
+ // 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 = NDIS_STATUS_PENDING;
+
+ //
+ // Convert the 32 bits of the address to a longword.
+ //
+ RetrieveUlong(&GroupAddress, GroupAddressArray);
+
+ Filter->OldGroupAddress = Filter->GroupAddress;
+ Filter->OldGroupReferences = Filter->GroupReferences;
+ LocalOpen->OldUsingGroupAddress = LocalOpen->UsingGroupAddress;
+
+ //
+ // If the new group address is 0 then a binding is
+ // attempting to delete the current group address.
+ //
+ if (0 == GroupAddress)
+ {
+ //
+ // Is the binding using the group address?
+ //
+ if (LocalOpen->UsingGroupAddress)
+ {
+ //
+ // Remove the bindings reference.
+ //
+ Filter->GroupReferences--;
+ LocalOpen->UsingGroupAddress = FALSE;
+
+ //
+ // Are any other bindings using the group address?
+ //
+ if (Filter->GroupReferences != 0)
+ {
+ //
+ // Since other bindings are using the group address
+ // we cannot tell the driver to remove it.
+ //
+ return(NDIS_STATUS_SUCCESS);
+ }
+
+ //
+ // We are the only binding using the group address
+ // so we fall through and call the driver to delete it.
+ //
+ }
+ else
+ {
+ //
+ // This binding is not using the group address but
+ // it is trying to clear it.
+ //
+ if (Filter->GroupReferences != 0)
+ {
+ //
+ // There are other bindings using the group address
+ // so we cannot delete it.
+ //
+ return(NDIS_STATUS_GROUP_ADDRESS_IN_USE);
+ }
+ else
+ {
+ //
+ // There are no bindings using the group address.
+ //
+ return(NDIS_STATUS_SUCCESS);
+ }
+ }
+ }
+ else
+ {
+ //
+ // See if this address is already the current address.
+ //
+ if (GroupAddress == Filter->GroupAddress)
+ {
+ //
+ // If the current binding is already using the
+ // group address then do nothing.
+ //
+ if (LocalOpen->UsingGroupAddress)
+ {
+ return(NDIS_STATUS_SUCCESS);
+ }
+
+ //
+ // If there are already bindings that are using the group
+ // address then we just need to update the bindings
+ // information.
+ //
+ if (Filter->GroupReferences != 0)
+ {
+ //
+ // We can take care of everything here...
+ //
+ Filter->GroupReferences++;
+ LocalOpen->UsingGroupAddress = TRUE;
+
+ return(NDIS_STATUS_SUCCESS);
+ }
+ }
+ else
+ {
+ //
+ // If there are other bindings using the address then
+ // we can't change it.
+ //
+ if (Filter->GroupReferences > 1)
+ {
+ return(NDIS_STATUS_GROUP_ADDRESS_IN_USE);
+ }
+
+ //
+ // Is there only one binding using the address?
+ // If is it some other binding?
+ //
+ if ((Filter->GroupReferences == 1) &&
+ (!LocalOpen->UsingGroupAddress))
+ {
+ //
+ // Some other binding is using the group address.
+ //
+ return(NDIS_STATUS_GROUP_ADDRESS_IN_USE);
+ }
+
+ //
+ // Is this the only binding using the address.
+ //
+ if ((Filter->GroupReferences == 1) &&
+ (LocalOpen->UsingGroupAddress))
+ {
+ //
+ // Remove the reference.
+ //
+ Filter->GroupReferences = 0;
+ LocalOpen->UsingGroupAddress = FALSE;
+ }
+ }
+ }
+
+ //
+ // Set the new filter information for the open.
+ //
+ Filter->GroupAddress = GroupAddress;
+ StatusOfAdjust = Filter->GroupChangeAction(
+ Filter->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.
+ //
+ trUndoChangeGroupAddress(Filter, LocalOpen);
+ }
+ else if (GroupAddress == 0)
+ {
+ LocalOpen->UsingGroupAddress = FALSE;
+ Filter->GroupReferences = 0;
+ }
+ else
+ {
+ LocalOpen->UsingGroupAddress = TRUE;
+ Filter->GroupReferences = 1;
+ }
+
+ return(StatusOfAdjust);
+}
+
+
+VOID
+trUpdateDirectedBindingList(
+ IN OUT PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding,
+ IN BOOLEAN fAddBindingToList
+ )
+{
+ PTR_BINDING_INFO CurrentBinding;
+ BOOLEAN AlreadyOnList;
+
+ //
+ // Do we need to add it to the directed list?
+ //
+ if (fAddBindingToList)
+ {
+ //
+ // First we need to see if it is already on the
+ // directed list.
+ //
+ for (CurrentBinding = Filter->DirectedList, AlreadyOnList = FALSE;
+ CurrentBinding != NULL;
+ CurrentBinding = CurrentBinding->NextDirected
+ )
+ {
+ if (CurrentBinding == Binding)
+ {
+ AlreadyOnList = TRUE;
+ }
+ }
+
+ if (!AlreadyOnList)
+ {
+ Binding->NextDirected = Filter->DirectedList;
+ Filter->DirectedList = Binding;
+ }
+ }
+ else
+ {
+ PTR_BINDING_INFO *ppBI;
+
+ for (ppBI = &Filter->DirectedList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextDirected)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextDirected;
+ break;
+ }
+ }
+ Binding->NextDirected = NULL;
+ }
+}
+
+
+VOID
+trUpdateBroadcastBindingList(
+ IN OUT PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding,
+ IN BOOLEAN fAddToList
+ )
+{
+ PTR_BINDING_INFO CurrentBinding;
+ BOOLEAN AlreadyOnList;
+
+ //
+ // Do we need to add it to the directed list?
+ //
+ if (fAddToList)
+ {
+ //
+ // First we need to see if it is already on the
+ // directed list.
+ //
+ for (CurrentBinding = Filter->BFGList, AlreadyOnList = FALSE;
+ CurrentBinding != NULL;
+ CurrentBinding = CurrentBinding->NextBFG)
+ {
+ if (CurrentBinding == Binding)
+ {
+ AlreadyOnList = TRUE;
+ }
+ }
+
+ if (!AlreadyOnList)
+ {
+ Binding->NextBFG = Filter->BFGList;
+ Filter->BFGList = Binding;
+ }
+ }
+ else
+ {
+ PTR_BINDING_INFO *ppBI;
+
+ for (ppBI = &Filter->BFGList;
+ *ppBI != NULL;
+ ppBI = &(*ppBI)->NextBFG)
+ {
+ if (*ppBI == Binding)
+ {
+ *ppBI = Binding->NextBFG;
+ break;
+ }
+ }
+
+ Binding->NextBFG = NULL;
+ }
+}
+
+
+VOID
+trUpdateSpecificBindingLists(
+ IN OUT PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding
+)
+{
+ BOOLEAN fOnDirectedList = FALSE;
+ BOOLEAN fOnBFGList = FALSE;
+ BOOLEAN fAddToDirectedList = FALSE;
+ BOOLEAN fAddToBFGList = FALSE;
+
+ //
+ // If the old filter is promsicuous then it is currently on
+ // both lists.
+ //
+ if (Binding->OldPacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL))
+ {
+ fOnDirectedList = TRUE;
+ fOnBFGList = TRUE;
+ }
+ else
+ {
+ //
+ // If the binding had the directed bit set then it is on
+ // the directed list.
+ //
+ if (Binding->OldPacketFilters & NDIS_PACKET_TYPE_DIRECTED)
+ {
+ fOnDirectedList = TRUE;
+ }
+
+ //
+ // If the binding had the broadcast/functional/group bit set then it is on
+ // the broadcast/functional list.
+ //
+ if (Binding->OldPacketFilters & (NDIS_PACKET_TYPE_BROADCAST |
+ NDIS_PACKET_TYPE_GROUP |
+ NDIS_PACKET_TYPE_FUNCTIONAL|
+ NDIS_PACKET_TYPE_ALL_FUNCTIONAL))
+ {
+ fOnBFGList = TRUE;
+ }
+ }
+
+ //
+ // If the current filter has the promsicuous bit set then we
+ // need to add it to both lists.
+ //
+ if (Binding->PacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL))
+ {
+ fAddToDirectedList = TRUE;
+ fAddToBFGList = TRUE;
+ }
+ else
+ {
+ //
+ // Was the directed bit set?
+ //
+ if (Binding->PacketFilters & NDIS_PACKET_TYPE_DIRECTED)
+ {
+ fAddToDirectedList = TRUE;
+ }
+
+ //
+ // Was the broadcast bit set?
+ //
+ if (Binding->PacketFilters & (NDIS_PACKET_TYPE_BROADCAST |
+ NDIS_PACKET_TYPE_GROUP |
+ NDIS_PACKET_TYPE_FUNCTIONAL |
+ NDIS_PACKET_TYPE_ALL_FUNCTIONAL))
+ {
+ fAddToBFGList = TRUE;
+ }
+ }
+
+ //
+ // Determine if the binding should be added or removed from
+ // the directed list.
+ //
+ if (!fOnDirectedList && fAddToDirectedList)
+ {
+ //
+ // Add the binding to the directed list.
+ //
+ trUpdateDirectedBindingList(Filter, Binding, TRUE);
+ }
+ else if (fOnDirectedList && !fAddToDirectedList)
+ {
+ //
+ // Remove it from the directed list.
+ //
+ trUpdateDirectedBindingList(Filter, Binding, FALSE);
+ }
+
+ //
+ // Determine if the binding should be added or removed from
+ // the broadcast list.
+ //
+ if (!fOnBFGList && fAddToBFGList)
+ {
+ //
+ // Add the binding to the broadcast list.
+ //
+ trUpdateBroadcastBindingList(Filter, Binding, TRUE);
+ }
+ else if (fOnBFGList && !fAddToBFGList)
+ {
+ //
+ // Remove the binding from the broadcast list.
+ //
+ trUpdateBroadcastBindingList(Filter, Binding, FALSE);
+ }
+
+}
+
+VOID
+trUndoFilterAdjust(
+ IN PTR_FILTER Filter,
+ IN PTR_BINDING_INFO Binding
+)
+{
+ //
+ // The user returned a bad status. Put things back as
+ // they were.
+ //
+ Binding->PacketFilters = Binding->OldPacketFilters;
+ Filter->CombinedPacketFilter = Filter->OldCombinedPacketFilter;
+
+ //
+ // Remove the binding from the filter lists.
+ //
+ trUpdateSpecificBindingLists(Filter, Binding);
+}
+
+
+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.
+
+--*/
+
+{
+ //
+ // Pointer to the open
+ //
+ PTR_BINDING_INFO LocalOpen = (PTR_BINDING_INFO)NdisFilterHandle;
+
+ //
+ // 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->OldPacketFilters = LocalOpen->PacketFilters;
+ LocalOpen->PacketFilters = FilterClasses;
+ Filter->OldCombinedPacketFilter = Filter->CombinedPacketFilter;
+
+ //
+ // 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;
+ }
+
+ //
+ // Update the specific binding lists with the new information.
+ //
+ trUpdateSpecificBindingLists(Filter, LocalOpen);
+
+ //
+ // If the packet filter has changed then we need to call down to
+ // the change action handler.
+ //
+ if ((Filter->OldCombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL) !=
+ (Filter->CombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL))
+ {
+ StatusOfAdjust = Filter->FilterChangeAction(
+ Filter->OldCombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL,
+ Filter->CombinedPacketFilter & ~NDIS_PACKET_TYPE_ALL_LOCAL,
+ 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.
+ //
+ trUndoFilterAdjust(Filter, LocalOpen);
+ }
+ }
+ else
+ {
+ StatusOfAdjust = NDIS_STATUS_SUCCESS;
+ }
+
+ return(StatusOfAdjust);
+}
+
+
+
+VOID
+TrFilterDprIndicateReceiveFullMac(
+ 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;
+
+ //
+ // TRUE if the packet is a MAC frame packet.
+ //
+ BOOLEAN IsMacFrame;
+
+ //
+ // 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, NextOpen;
+
+ //
+ // 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))
+ {
+ UINT ResultOfAddressCheck;
+
+ TR_IS_NOT_DIRECTED(DestinationAddress, &ResultOfAddressCheck);
+
+ //
+ // Handle the directed packet case first
+ //
+ if (!ResultOfAddressCheck)
+ {
+ UINT IsNotOurs;
+
+ //
+ // If it is a directed packet, then check if the combined packet
+ // filter is PROMISCUOUS, if it is check if it is directed towards
+ // us
+ //
+ IsNotOurs = FALSE; // Assume it is
+ if (Filter->CombinedPacketFilter & (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_LOCAL |
+ NDIS_PACKET_TYPE_ALL_FUNCTIONAL))
+ {
+ TR_COMPARE_NETWORK_ADDRESSES_EQ(Filter->AdapterAddress,
+ DestinationAddress,
+ &IsNotOurs);
+ }
+
+ //
+ // Walk the directed list and indicate up the packets.
+ //
+ for (LocalOpen = Filter->DirectedList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextDirected;
+
+ //
+ // Ignore if not directed to us and if the binding is not promiscuous
+ //
+ if (((LocalOpen->PacketFilters & NDIS_PACKET_TYPE_PROMISCUOUS) == 0) &&
+ IsNotOurs)
+ {
+ continue;
+ }
+
+ LocalOpen->References++;
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ //
+ // Indicate the packet to the binding.
+ //
+ ProtocolFilterIndicateReceive(&StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize,
+ NdisMedium802_5);
+
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ --LocalOpen->References;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ trRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+
+ return;
+ }
+
+ TR_IS_SOURCE_ROUTING(SourceAddress, &IsSourceRouting);
+ IsMacFrame = TR_IS_MAC_FRAME(HeaderBuffer);
+
+ //
+ // 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)
+ {
+ TR_CHECK_FOR_INVALID_BROADCAST_INDICATION(Filter);
+
+ 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
+ {
+ // Runt Packet
+ AddressType = NDIS_PACKET_TYPE_PROMISCUOUS;
+ IsSourceRouting = FALSE;
+ }
+
+
+ //
+ // At this point we know that the packet is either:
+ // - Runt packet - indicated by AddressType = NDIS_PACKET_TYPE_PROMISCUOUS (OR)
+ // - Broadcast packet - indicated by AddressType = NDIS_PACKET_TYPE_BROADCAST (OR)
+ // - Functional packet - indicated by AddressType = NDIS_PACKET_TYPE_FUNCTIONAL
+ //
+ // Walk the broadcast/functional list and indicate up the packets.
+ //
+ // The packet is indicated if it meets the following criteria:
+ //
+ // if ((Binding is promiscuous) OR
+ // ((Packet is broadcast) AND (Binding is Broadcast)) OR
+ // ((Packet is functional) AND
+ // ((Binding is all-functional) OR
+ // ((Binding is functional) AND (binding using functional address)))) OR
+ // ((Packet is a group packet) AND (Intersection of filters uses group addresses)) OR
+ // ((Packet is a macframe) AND (Binding wants mac frames)) OR
+ // ((Packet is a source routing packet) AND (Binding wants source routing packetss)))
+ //
+ for (LocalOpen = Filter->BFGList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ UINT LocalFilter = LocalOpen->PacketFilters;
+ UINT IntersectionOfFilters = LocalFilter & AddressType;
+ UINT IndexOfAddress;
+
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextBFG;
+
+ if ((LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_BROADCAST) &&
+ (LocalFilter & NDIS_PACKET_TYPE_BROADCAST)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_FUNCTIONAL) &&
+ ((LocalFilter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) ||
+ ((LocalFilter & NDIS_PACKET_TYPE_FUNCTIONAL) &&
+ (FunctionalAddress & LocalOpen->FunctionalAddress)))) ||
+
+ ((IntersectionOfFilters & NDIS_PACKET_TYPE_GROUP) &&
+ (LocalOpen->UsingGroupAddress) &&
+ (FunctionalAddress == Filter->GroupAddress)) ||
+
+ ((LocalFilter & NDIS_PACKET_TYPE_SOURCE_ROUTING) &&
+ IsSourceRouting) ||
+
+ ((LocalFilter & NDIS_PACKET_TYPE_MAC_FRAME) &&
+ IsMacFrame))
+ {
+ LocalOpen->References++;
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ //
+ // Indicate the packet to the binding.
+ //
+ ProtocolFilterIndicateReceive(&StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize,
+ NdisMedium802_5);
+
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ if ((--(LocalOpen->References)) == 0)
+ {
+ //
+ // This binding is shutting down.
+ //
+ trRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+ }
+}
+
+
+
+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;
+
+ NDIS_ACQUIRE_SPIN_LOCK(Filter->Lock, &OldIrql);
+
+ TrFilterDprIndicateReceiveFullMac(Filter,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize);
+
+ NDIS_RELEASE_SPIN_LOCK(Filter->Lock, OldIrql);
+}
+
+
+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;
+
+ //
+ // TRUE if the packet is a MAC frame packet.
+ //
+ BOOLEAN IsMacFrame;
+
+ //
+ // 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, NextOpen;
+
+ //
+ // 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))
+ {
+ UINT ResultOfAddressCheck;
+
+ TR_IS_NOT_DIRECTED(DestinationAddress, &ResultOfAddressCheck);
+
+ //
+ // Handle the directed packet case first
+ //
+ if (!ResultOfAddressCheck)
+ {
+ UINT IsNotOurs;
+
+ //
+ // If it is a directed packet, then check if the combined packet
+ // filter is PROMISCUOUS, if it is check if it is directed towards
+ // us
+ //
+ IsNotOurs = FALSE; // Assume it is
+ if (Filter->CombinedPacketFilter & (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_LOCAL |
+ NDIS_PACKET_TYPE_ALL_FUNCTIONAL))
+ {
+ TR_COMPARE_NETWORK_ADDRESSES_EQ(Filter->AdapterAddress,
+ DestinationAddress,
+ &IsNotOurs);
+ }
+
+ //
+ // Walk the directed list and indicate up the packets.
+ //
+ for (LocalOpen = Filter->DirectedList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextDirected;
+
+ //
+ // Ignore if not directed to us and if the binding is not promiscuous
+ //
+ if (((LocalOpen->PacketFilters & NDIS_PACKET_TYPE_PROMISCUOUS) == 0) &&
+ IsNotOurs)
+ {
+ continue;
+ }
+
+ LocalOpen->References++;
+
+// NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ //
+ // Indicate the packet to the binding.
+ //
+ ProtocolFilterIndicateReceive(&StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize,
+ NdisMedium802_5);
+
+// NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ --LocalOpen->References;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ trRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+
+ return;
+ }
+
+ TR_IS_SOURCE_ROUTING(SourceAddress, &IsSourceRouting);
+ IsMacFrame = TR_IS_MAC_FRAME(HeaderBuffer);
+
+ //
+ // 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)
+ {
+ TR_CHECK_FOR_INVALID_BROADCAST_INDICATION(Filter);
+
+ 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
+ {
+ // Runt Packet
+ AddressType = NDIS_PACKET_TYPE_PROMISCUOUS;
+ IsSourceRouting = FALSE;
+ }
+
+
+ //
+ // At this point we know that the packet is either:
+ // - Runt packet - indicated by AddressType = NDIS_PACKET_TYPE_PROMISCUOUS (OR)
+ // - Broadcast packet - indicated by AddressType = NDIS_PACKET_TYPE_BROADCAST (OR)
+ // - Functional packet - indicated by AddressType = NDIS_PACKET_TYPE_FUNCTIONAL
+ //
+ // Walk the broadcast/functional list and indicate up the packets.
+ //
+ // The packet is indicated if it meets the following criteria:
+ //
+ // if ((Binding is promiscuous) OR
+ // ((Packet is broadcast) AND (Binding is Broadcast)) OR
+ // ((Packet is functional) AND
+ // ((Binding is all-functional) OR
+ // ((Binding is functional) AND (binding using functional address)))) OR
+ // ((Packet is a group packet) AND (Intersection of filters uses group addresses)) OR
+ // ((Packet is a macframe) AND (Binding wants mac frames)) OR
+ // ((Packet is a source routing packet) AND (Binding wants source routing packetss)))
+ //
+ for (LocalOpen = Filter->BFGList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ UINT LocalFilter = LocalOpen->PacketFilters;
+ UINT IntersectionOfFilters = LocalFilter & AddressType;
+ UINT IndexOfAddress;
+
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextBFG;
+
+ if ((LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_BROADCAST) &&
+ (LocalFilter & NDIS_PACKET_TYPE_BROADCAST)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_FUNCTIONAL) &&
+ ((LocalFilter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) ||
+ ((LocalFilter & NDIS_PACKET_TYPE_FUNCTIONAL) &&
+ (FunctionalAddress & LocalOpen->FunctionalAddress)))) ||
+
+ ((IntersectionOfFilters & NDIS_PACKET_TYPE_GROUP) &&
+ (LocalOpen->UsingGroupAddress) &&
+ (FunctionalAddress == Filter->GroupAddress)) ||
+
+ ((LocalFilter & NDIS_PACKET_TYPE_SOURCE_ROUTING) &&
+ IsSourceRouting) ||
+
+ ((LocalFilter & NDIS_PACKET_TYPE_MAC_FRAME) &&
+ IsMacFrame))
+ {
+ LocalOpen->References++;
+
+// NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ //
+ // Indicate the packet to the binding.
+ //
+ ProtocolFilterIndicateReceive(&StatusOfReceive,
+ LocalOpen->NdisBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize,
+ NdisMedium802_5);
+
+// NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ LocalOpen->ReceivedAPacket = TRUE;
+
+ if ((--(LocalOpen->References)) == 0)
+ {
+ //
+ // This binding is shutting down.
+ //
+ trRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+ }
+}
+
+
+VOID
+TrFilterDprIndicateReceivePacket(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+)
+
+/*++
+
+Routine Description:
+
+ This routine is called by the Miniport to indicate packets to
+ all bindings. The packets will be filtered so that only the
+ appropriate bindings will receive the individual packets.
+ This is the code path for ndis 4.0 miniport drivers.
+
+Arguments:
+
+ Miniport - The Miniport block.
+
+ PacketArray - An array of Packets indicated by the miniport.
+
+ NumberOfPackets - Self-explanatory.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // The Filter of interest
+ //
+ PTR_FILTER Filter = Miniport->TrDB;
+
+ //
+ // Current packet being processed
+ //
+ PPNDIS_PACKET pPktArray = PacketArray;
+
+ //
+ // Pointer to the buffer in the ndispacket
+ //
+ PNDIS_BUFFER Buffer;
+
+ //
+ // Pointer to the 1st segment of the buffer, points to dest address
+ //
+ PUCHAR Address;
+
+ //
+ // Total packet length
+ //
+ UINT i, LASize, PacketSize, NumIndicates = 0;
+
+ //
+ // The destination address in the lookahead buffer.
+ //
+ PCHAR DestinationAddress;
+
+ //
+ // The source address in the lookahead buffer.
+ //
+ PCHAR SourceAddress;
+
+ //
+ // Will hold the type of address that we know we've got.
+ //
+ UINT AddressType;
+
+ //
+ // TRUE if the packet is source routing packet.
+ //
+ BOOLEAN IsSourceRouting;
+
+ //
+ // TRUE if the packet is a MAC frame packet.
+ //
+ BOOLEAN IsMacFrame;
+
+ //
+ // 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 filter classes of the binding being indicated.
+ //
+ UINT BindingFilters;
+
+ //
+ // Decides whether we use the protocol's revpkt handler or fall
+ // back to old rcvindicate handler
+ //
+ BOOLEAN fFallBack, fPmode, FixRef;
+
+ //
+ // Will hold the open being indicated.
+ //
+ PTR_BINDING_INFO LocalOpen, NextOpen;
+ PNDIS_OPEN_BLOCK pOpenBlock; \
+
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
+
+ // Walk all the packets
+ for (i = 0; i < NumberOfPackets; i++, pPktArray++)
+ {
+ PNDIS_PACKET Packet = *pPktArray;
+ PNDIS_PACKET_OOB_DATA pOob;
+
+ ASSERT(Packet != NULL);
+
+ pOob = NDIS_OOB_DATA_FROM_PACKET(Packet);
+
+ NdisGetFirstBufferFromPacket(Packet,
+ &Buffer,
+ &Address,
+ &LASize,
+ &PacketSize);
+ ASSERT(Buffer != NULL);
+
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount = 0;
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->Miniport = Miniport;
+
+ //
+ // Set the status here that nobody is holding the packet. This will get
+ // overwritten by the real status from the protocol. Pay heed to what
+ // the miniport is saying.
+ //
+ if (pOob->Status != NDIS_STATUS_RESOURCES)
+ {
+ pOob->Status = NDIS_STATUS_SUCCESS;
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount --;
+ fFallBack = FALSE;
+ FixRef = TRUE;
+ }
+ else
+ {
+ fFallBack = TRUE;
+ FixRef = FALSE;
+ }
+
+ //
+ // Ensure that we force re-calculation.
+ //
+ Packet->Private.ValidCounts = FALSE;
+
+ //
+ // The destination address in the lookahead buffer.
+ //
+ DestinationAddress = (PCHAR)Address + 2;
+
+ //
+ // The source address in the lookahead buffer.
+ //
+ SourceAddress = (PCHAR)Address + 8;
+
+ // Determine if there is source routing info and compute hdr len
+#if DBG
+ {
+ UINT HdrSize;
+
+ HdrSize = 14;
+ if (Address[8] & 0x80)
+ {
+ HdrSize += (Address[14] & 0x1F);
+ }
+ ASSERT(HdrSize == pOob->HeaderSize);
+ }
+#endif
+ //
+ // A quick check for Runt packets. These are only indicated to Promiscuous bindings
+ //
+ if (PacketSize >= pOob->HeaderSize)
+ {
+ UINT ResultOfAddressCheck;
+
+ //
+ // If it is a directed packet, then check if the combined packet
+ // filter is PROMISCUOUS, if it is check if it is directed towards us
+ //
+ TR_IS_NOT_DIRECTED(DestinationAddress, &ResultOfAddressCheck);
+
+ //
+ // Handle the directed packet case first
+ //
+ if (!ResultOfAddressCheck)
+ {
+ UINT IsNotOurs;
+
+ //
+ // If it is a directed packet, then check if the combined packet
+ // filter is PROMISCUOUS, if it is check if it is directed towards
+ // us
+ //
+ IsNotOurs = FALSE; // Assume it is
+ if (Filter->CombinedPacketFilter & (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_LOCAL |
+ NDIS_PACKET_TYPE_ALL_FUNCTIONAL))
+ {
+ TR_COMPARE_NETWORK_ADDRESSES_EQ(Filter->AdapterAddress,
+ DestinationAddress,
+ &IsNotOurs);
+ }
+
+ //
+ // We definitely have a directed packet so lets indicate it now.
+ //
+ // Walk the directed list and indicate up the packets.
+ //
+ for (LocalOpen = Filter->DirectedList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextDirected;
+
+ //
+ // Ignore if not directed to us and if the binding is not promiscuous
+ //
+ if (((LocalOpen->PacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) == 0) &&
+ IsNotOurs)
+ {
+ continue;
+ }
+
+ pOpenBlock = (PNDIS_OPEN_BLOCK)(LocalOpen->NdisBindingContext);
+ LocalOpen->ReceivedAPacket = TRUE;
+ LocalOpen->References++;
+ NumIndicates ++;
+
+ fPmode = (LocalOpen->PacketFilters & (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_LOCAL)) ?
+ TRUE : FALSE;
+ IndicateToProtocol(Miniport,
+ Filter,
+ pOpenBlock,
+ Packet,
+ Address,
+ PacketSize,
+ pOob->HeaderSize,
+ &fFallBack,
+ fPmode,
+ NdisMedium802_5);
+
+ LocalOpen->References--;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down. We have to remove it.
+ //
+ trRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+
+ if (FixRef)
+ {
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount++;
+ if (PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount != 0)
+ {
+ NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_PENDING);
+ }
+ }
+ continue; // Done with this packet
+ }
+
+ TR_IS_SOURCE_ROUTING(SourceAddress, &IsSourceRouting);
+ IsMacFrame = TR_IS_MAC_FRAME(Address);
+
+ //
+ // 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)
+ {
+ TR_CHECK_FOR_INVALID_BROADCAST_INDICATION(Filter);
+
+ 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
+ {
+ // Runt Packet
+ AddressType = NDIS_PACKET_TYPE_PROMISCUOUS;
+ IsSourceRouting = FALSE;
+ }
+
+ //
+ // At this point we know that the packet is either:
+ // - Runt packet - indicated by AddressType = NDIS_PACKET_TYPE_PROMISCUOUS (OR)
+ // - Broadcast packet - indicated by AddressType = NDIS_PACKET_TYPE_BROADCAST (OR)
+ // - Functional packet - indicated by AddressType = NDIS_PACKET_TYPE_FUNCTIONAL
+ //
+ // Walk the broadcast/functional list and indicate up the packets.
+ //
+ // The packet is indicated if it meets the following criteria:
+ //
+ // if ((Binding is promiscuous) OR
+ // ((Packet is broadcast) AND (Binding is Broadcast)) OR
+ // ((Packet is functional) AND
+ // ((Binding is all-functional) OR
+ // ((Binding is functional) AND (binding using functional address)))) OR
+ // ((Packet is a group packet) AND (Intersection of filters uses group addresses)) OR
+ // ((Packet is a macframe) AND (Binding wants mac frames)) OR
+ // ((Packet is a source routing packet) AND (Binding wants source routing packetss)))
+ //
+ for (LocalOpen = Filter->BFGList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ UINT LocalFilter = LocalOpen->PacketFilters;
+ UINT IntersectionOfFilters = LocalFilter & AddressType;
+ UINT IndexOfAddress;
+
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = LocalOpen->NextBFG;
+
+ if ((LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_BROADCAST) &&
+ (LocalFilter & NDIS_PACKET_TYPE_BROADCAST)) ||
+
+ ((AddressType == NDIS_PACKET_TYPE_FUNCTIONAL) &&
+ ((LocalFilter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) ||
+ ((LocalFilter & NDIS_PACKET_TYPE_FUNCTIONAL) &&
+ (FunctionalAddress & LocalOpen->FunctionalAddress)))) ||
+
+ ((IntersectionOfFilters & NDIS_PACKET_TYPE_GROUP) &&
+ (LocalOpen->UsingGroupAddress)) ||
+
+ ((LocalFilter & NDIS_PACKET_TYPE_SOURCE_ROUTING) &&
+ IsSourceRouting) ||
+
+ ((LocalFilter & NDIS_PACKET_TYPE_MAC_FRAME) &&
+ IsMacFrame))
+ {
+ pOpenBlock = (PNDIS_OPEN_BLOCK)(LocalOpen->NdisBindingContext);
+ LocalOpen->ReceivedAPacket = TRUE;
+ LocalOpen->References++;
+ NumIndicates ++;
+
+ fPmode = (LocalFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) ?
+ TRUE : FALSE;
+ IndicateToProtocol(Miniport,
+ Filter,
+ pOpenBlock,
+ Packet,
+ Address,
+ PacketSize,
+ pOob->HeaderSize,
+ &fFallBack,
+ fPmode,
+ NdisMedium802_5);
+
+ LocalOpen->References--;
+ if (LocalOpen->References == 0)
+ {
+ //
+ // This binding is shutting down.
+ //
+ trRemoveAndFreeBinding(Filter, LocalOpen, TRUE);
+ }
+ }
+ }
+
+ if (FixRef)
+ {
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount++;
+ if (PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount != 0)
+ {
+ NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_PENDING);
+ }
+ }
+ }
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
+
+ if (NumIndicates > 0)
+ {
+ TrFilterDprIndicateReceiveComplete(Filter);
+ }
+}
+
+
+
+VOID
+TrFilterDprIndicateReceiveCompleteFullMac(
+ 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, NextOpen;
+
+ //
+ // We need to aquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+ for (LocalOpen = Filter->OpenList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ LocalOpen->References++;
+ NextOpen = LocalOpen->NextOpen;
+
+ if (LocalOpen->ReceivedAPacket)
+ {
+ //
+ // Indicate the binding.
+ //
+
+ LocalOpen->ReceivedAPacket = FALSE;
+
+ NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+ NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ }
+
+ if ((--(LocalOpen->References)) == 0)
+ {
+ //
+ // This binding is shutting down.
+ //
+ trRemoveBindingFromLists(Filter, LocalOpen);
+
+ //
+ // 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);
+ }
+ }
+}
+
+
+
+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;
+
+ NDIS_ACQUIRE_SPIN_LOCK(Filter->Lock, &OldIrql);
+ TrFilterDprIndicateReceiveCompleteFullMac(Filter);
+ NDIS_RELEASE_SPIN_LOCK(Filter->Lock, OldIrql);
+}
+
+
+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, NextOpen;
+
+ //
+ // We need to aquire the filter exclusively while we're finding
+ // bindings to indicate to.
+ //
+ for (LocalOpen = Filter->OpenList;
+ LocalOpen != NULL;
+ LocalOpen = NextOpen)
+ {
+ LocalOpen->References++;
+ NextOpen = LocalOpen->NextOpen;
+
+ if (LocalOpen->ReceivedAPacket)
+ {
+ //
+ // Indicate the binding.
+ //
+
+ LocalOpen->ReceivedAPacket = FALSE;
+
+// NDIS_RELEASE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+
+ FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext);
+
+// NDIS_ACQUIRE_SPIN_LOCK_DPC(Filter->Lock);
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
+ }
+
+ if ((--(LocalOpen->References)) == 0)
+ {
+ //
+ // This binding is shutting down.
+ //
+ trRemoveBindingFromLists(Filter, LocalOpen);
+
+ //
+ // 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);
+ }
+ }
+}
+
+
+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.
+
+--*/
+{
+ BOOLEAN fLoopback, fSelfDirected;
+
+ TrShouldAddressLoopBackMacro(Filter,
+ DestinationAddress,
+ SourceAddress,
+ &fLoopback,
+ &fSelfDirected);
+
+ return(fLoopback);
+}
+
+
diff --git a/private/ntos/ndis/ndis40/timer.c b/private/ntos/ndis/ndis40/timer.c
new file mode 100644
index 000000000..821d62b2e
--- /dev/null
+++ b/private/ntos/ndis/ndis40/timer.c
@@ -0,0 +1,794 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ timer.c
+
+Abstract:
+
+ NDIS wrapper functions for full mac drivers isr/timer
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 05-Oct-93
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+ Jameel Hyder (JameelH) Re-organization 01-Jun-95
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+#include <stdarg.h>
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_TIMER
+
+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.
+
+--*/
+{
+ INITIALIZE_TIMER(&(NdisTimer)->Timer);
+
+ //
+ // Initialize our dpc. If Dpc was previously initialized, this will
+ // reinitialize it.
+ //
+
+ INITIALIZE_DPC(&NdisTimer->Dpc,
+ (PKDEFERRED_ROUTINE)TimerFunction,
+ FunctionContext);
+
+ SET_PROCESSOR_DPC(&NdisTimer->Dpc,
+ ndisValidProcessors[ndisCurrentProcessor]);
+
+ SET_DPC_IMPORTANCE(&NdisTimer->Dpc);
+}
+
+
+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
+ //
+ SET_TIMER(&NdisTimer->Timer, FireUpTime, &NdisTimer->Dpc);
+}
+
+
+#undef NdisCancelTimer
+
+VOID
+NdisCancelTimer(
+ IN PNDIS_TIMER Timer,
+ OUT PBOOLEAN TimerCancelled
+ )
+{
+ *TimerCancelled = KeCancelTimer(&Timer->Timer);
+}
+
+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, &Interrupt->DpcCountLock);
+
+ if (!(QUEUE_DPC(&NdisInterrupt->InterruptDpc)))
+ {
+ //
+ // 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, &Interrupt->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.
+ //
+
+ INITIALIZE_DPC(&NdisInterrupt->InterruptDpc,
+ ndisLastCountRemovedFunction,
+ (PVOID)(&NdisInterrupt->DpcsCompletedEvent));
+
+ //
+ // When ndisLastCountRemovedFunction runs it will set
+ // the event.
+ //
+
+ QUEUE_DPC (&NdisInterrupt->InterruptDpc);
+ }
+ }
+
+ return TRUE;
+ }
+
+ return 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, &Interrupt->DpcCountLock);
+
+ if (NdisInterrupt->Removing && (NdisInterrupt->DpcCount==0))
+ {
+ SET_EVENT(&NdisInterrupt->DpcsCompletedEvent);
+ }
+}
+
+
+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)ALLOC_FROM_POOL(sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ NumberOfElements,
+ NDIS_TAG_RSRC_LIST);
+
+ if (Resources == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ if ((IsAMiniport ?
+ Miniport->Resources :
+ AdptrP->Resources) != NULL)
+ {
+ CopyMemory(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)
+ {
+ FREE_POOL((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);
+
+ CopyMemory(((PUCHAR)errorLogEntry) + sizeof(IO_ERROR_LOG_PACKET),
+ 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)
+ {
+ Character = L'0' + (WCHAR)(Value / 10);
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ Place += sizeof(WCHAR);
+
+ Value -= 10;
+ }
+
+ Character = L'0' + (WCHAR)Value;
+
+ 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)
+ {
+ INITIALIZE_SPIN_LOCK(&MiniportInterrupt->DpcCountLock);
+ Miniport->Interrupt = MiniportInterrupt;
+ MiniportInterrupt->DpcCount = 0;
+ MiniportInterrupt->MiniportIdField = NULL;
+ MiniportInterrupt->Miniport = Miniport;
+ MiniportInterrupt->MiniportIsr = Miniport->DriverHandle->MiniportCharacteristics.ISRHandler;
+ MiniportInterrupt->MiniportDpc = Miniport->HandleInterruptHandler;
+ MiniportInterrupt->SharedInterrupt = SharedInterrupt;
+ MiniportInterrupt->IsrRequested = (BOOLEAN)DeferredProcessingRoutine;
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+ }
+ else
+ {
+ NdisInterrupt->MacIsr = InterruptServiceRoutine;
+ NdisInterrupt->MacDpc = DeferredProcessingRoutine;
+ NdisInterrupt->InterruptContext = InterruptContext;
+ INITIALIZE_SPIN_LOCK(&NdisInterrupt->DpcCountLock);
+ NdisInterrupt->DpcCount = 0;
+ NdisInterrupt->Removing = FALSE;
+ }
+
+ //
+ // This is used to tell when all Dpcs are completed after the
+ // interrupt has been removed.
+ //
+
+ INITIALIZE_EVENT(IsAMiniport ?
+ &MiniportInterrupt->DpcsCompletedEvent :
+ &NdisInterrupt->DpcsCompletedEvent);
+
+ //
+ // Initialize our dpc.
+ //
+
+ if (IsAMiniport)
+ {
+ INITIALIZE_DPC(&MiniportInterrupt->InterruptDpc,
+ (Miniport->Flags & fMINIPORT_IS_CO) ?
+ ndisMCoDpc : ndisMDpc,
+ MiniportInterrupt);
+
+ SET_DPC_IMPORTANCE(&MiniportInterrupt->InterruptDpc);
+
+ SET_PROCESSOR_DPC(&MiniportInterrupt->InterruptDpc,
+ ndisValidProcessors[ndisCurrentProcessor]);
+ }
+ else
+ {
+ INITIALIZE_DPC(&NdisInterrupt->InterruptDpc,
+ (PKDEFERRED_ROUTINE) ndisDpc,
+ NdisInterrupt);
+
+ SET_DPC_IMPORTANCE(&NdisInterrupt->InterruptDpc);
+
+ SET_PROCESSOR_DPC(&NdisInterrupt->InterruptDpc,
+ ndisValidProcessors[ndisCurrentProcessor]);
+ }
+
+ //
+ // 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;
+ }
+}
+
+
+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;
+ BOOLEAN fIsMiniport;
+
+ //
+ // Determine if this is a miniport's interrupt.
+ //
+ fIsMiniport = (BOOLEAN)(MiniportInterrupt->MiniportIdField == NULL);
+
+ //
+ // Mark the interrupt as being removed.
+ //
+ if (fIsMiniport)
+ {
+ MINIPORT_SET_FLAG(
+ MiniportInterrupt->Miniport,
+ fMINIPORT_BEING_REMOVED);
+ }
+ 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 it completes first, or we may
+ // wait for a little while for it to complete.
+ //
+ if (fIsMiniport)
+ {
+ if (MiniportInterrupt->DpcCount > 0)
+ {
+ //
+ // Now we wait for all dpcs to complete.
+ //
+ WAIT_FOR_OBJECT(&MiniportInterrupt->DpcsCompletedEvent, NULL);
+
+ RESET_EVENT(&MiniportInterrupt->DpcsCompletedEvent);
+ }
+ }
+ else
+ {
+ if (Interrupt->DpcCount > 0)
+ {
+ //
+ // Now we wait for all dpcs to complete.
+ //
+ WAIT_FOR_OBJECT(&Interrupt->DpcsCompletedEvent, NULL);
+
+ RESET_EVENT(&Interrupt->DpcsCompletedEvent);
+ }
+ }
+}
+
+
+
+
diff --git a/private/ntos/ndis/ndis40/timerm.c b/private/ntos/ndis/ndis40/timerm.c
new file mode 100644
index 000000000..20ff1b7e6
--- /dev/null
+++ b/private/ntos/ndis/ndis40/timerm.c
@@ -0,0 +1,1080 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ timerm.c
+
+Abstract:
+
+ NDIS wrapper functions for miniport isr/timer
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 05-Oct-93
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Jameel Hyder (JameelH) Re-organization 01-Jun-95
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_TIMERM
+
+//
+// Timers
+//
+VOID
+ndisMTimerDpc(
+ IN PKDPC Dpc,
+ IN PVOID Context,
+ IN PVOID SystemContext1,
+ IN 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);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ do
+ {
+ //
+ // Attempt to acquire the local lock.
+ //
+ LOCK_MINIPORT(Miniport, LocalLock);
+ if (!LocalLock || MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IN_INITIALIZE))
+ {
+ //
+ // Unlock the miniport in the case of the in-initialize flag.
+ //
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Queue a work item for the timer.
+ //
+ NDISM_QUEUE_NEW_WORK_ITEM(Miniport,
+ NdisWorkItemTimer,
+ &MiniportTimer->Dpc,
+ NULL);
+
+ break;
+ }
+
+ //
+ // Call Miniport timer function
+ //
+ TimerFunction = MiniportTimer->MiniportTimerFunction;
+
+ (*TimerFunction)(NULL, MiniportTimer->MiniportTimerContext, NULL, NULL);
+
+#if _SEND_PRIORITY
+ //
+ // If we are not reseting and not halting then give priority to sends
+ // at this point.
+ //
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_REQUESTED) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ ndisMProcessDeferredFullDuplexPrioritySends(Miniport);
+ }
+ else
+ {
+ ndisMProcessDeferredPrioritySends(Miniport);
+ }
+ }
+ else
+#endif
+ {
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ } while (FALSE);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+}
+
+
+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.
+
+--*/
+{
+ INITIALIZE_TIMER(&(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.
+ //
+ INITIALIZE_DPC(&MiniportTimer->Dpc,
+ (MiniportTimer->Miniport->Flags & fMINIPORT_IS_CO) ?
+ (PKDEFERRED_ROUTINE)ndisMCoTimerDpc :
+ (PKDEFERRED_ROUTINE)ndisMTimerDpc,
+ (PVOID)MiniportTimer);
+
+ SET_PROCESSOR_DPC(&MiniportTimer->Dpc,
+ ndisValidProcessors[ndisCurrentProcessor]);
+}
+
+
+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 = CANCEL_TIMER(&((((PNDIS_TIMER)(Timer))->Timer)));
+}
+
+
+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 (SYNC_WITH_ISR((Interrupt)->InterruptObject,
+ SynchronizeFunction,
+ SynchronizeContext));
+}
+
+
+
+VOID
+ndisMWakeUpDpc(
+ IN PKDPC Dpc,
+ IN PVOID Context,
+ IN PVOID SystemContext1,
+ IN 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;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+ PSINGLE_LIST_ENTRY Link;
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(SystemContext1);
+ UNREFERENCED_PARAMETER(SystemContext2);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ do
+ {
+ //
+ // If the miniport is halting then do nothing.
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
+ {
+ break;
+ }
+
+ //
+ // Does some other DPC have the miniport lock?
+ //
+ LOCK_MINIPORT(Miniport, LocalLock);
+ if (!LocalLock ||
+ MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS) ||
+ MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_REQUESTED))
+ {
+ //
+ // Release the local lock in case we are here due to
+ // a reset in progress.
+ //
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // A DPC or timer is already running, assume that
+ // means things are fine.
+ //
+ break;
+ }
+
+ //
+ // Call Miniport stall checker.
+ //
+ if (Miniport->DriverHandle->MiniportCharacteristics.CheckForHangHandler != NULL)
+ {
+ Hung = (Miniport->DriverHandle->MiniportCharacteristics.CheckForHangHandler)(
+ Miniport->MiniportAdapterContext);
+ }
+
+ //
+ // Check the internal wrapper states for the miniport and
+ // see if we think the miniport should be reset.
+ //
+ if (!Hung) do
+ {
+ //
+ // Should we check the request queue?
+ //
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IGNORE_REQUEST_QUEUE))
+ {
+ //
+ // Did a request pend to long?
+ //
+ if (Miniport->MiniportRequest != NULL)
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_REQUEST_TIMEOUT))
+ {
+ Hung = TRUE;
+ break;
+ }
+ else
+ {
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_REQUEST_TIMEOUT);
+ }
+ }
+ }
+
+ //
+ // Should we ignore the packet queue's?
+ //
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IGNORE_PACKET_QUEUE))
+ {
+ //
+ // Grab the send lock.
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+
+ //
+ // Does the miniport have possession of any packets?
+ //
+ if (Miniport->FirstPacket != NULL)
+ {
+ //
+ // Has the packet timed out?
+ //
+ if (MINIPORT_TEST_PACKET_FLAG(Miniport->FirstPacket, fPACKET_HAS_TIMED_OUT))
+ {
+ //
+ // Reset the miniport.
+ //
+ Hung = TRUE;
+ }
+ else
+ {
+ //
+ // Set the packet flag and wait to see if it is still
+ // there next time in.
+ //
+ MINIPORT_SET_PACKET_FLAG(Miniport->FirstPacket, fPACKET_HAS_TIMED_OUT);
+ }
+ }
+
+ //
+ // Release the send lock.
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+
+ //
+ // If we are hung then we don't need to check for token ring
+ // errors.
+ //
+ if (Hung)
+ {
+ break;
+ }
+ }
+
+ //
+ // Are we ignoring token ring errors?
+ //
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IGNORE_TOKEN_RING_ERRORS))
+ {
+ //
+ // Token Ring reset...
+ //
+ if (Miniport->TrResetRing == 1)
+ {
+ Hung = TRUE;
+ break;
+ }
+ else if (Miniport->TrResetRing > 1)
+ {
+ Miniport->TrResetRing--;
+ }
+ }
+ } while (FALSE);
+
+ //
+ // If the miniport is hung then queue a workitem to reset it.
+ //
+ if (Hung)
+ {
+ //
+ // Queue a reset requested workitem.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemResetRequested, Miniport, NULL);
+ }
+
+ //
+ // Process any changes that have occurred.
+ //
+ NDISM_PROCESS_DEFERRED(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ } while (FALSE);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+}
+
+
+//
+// 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;
+
+ do
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS))
+ {
+ //
+ // Call to disable the interrupt
+ //
+ MINIPORT_DISABLE_INTERRUPT(Miniport);
+
+ InterruptRecognized = TRUE;
+
+ goto queue_dpc;
+
+ break;
+ }
+
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
+ {
+ //
+ // Call MiniportIsr
+ //
+
+ Interrupt->MiniportIsr(
+ &InterruptRecognized,
+ &QueueDpc,
+ Miniport->MiniportAdapterContext);
+
+ if (QueueDpc)
+ {
+queue_dpc:
+ Increment((PLONG)&Interrupt->DpcCount, &Interrupt->DpcCountLock);
+
+ if (QUEUE_DPC(&Interrupt->InterruptDpc))
+ {
+ break;
+ }
+
+ //
+ // 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_TEST_FLAG(Miniport, fMINIPORT_HALTING) &&
+ (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.
+ //
+
+ INITIALIZE_DPC(&Interrupt->InterruptDpc,
+ ndisLastCountRemovedFunction,
+ (PVOID)&Interrupt->DpcsCompletedEvent);
+
+ //
+ // When ndisLastCountRemovedFunction runs it will set
+ // the event.
+ //
+
+ QUEUE_DPC(&Interrupt->InterruptDpc);
+ }
+ }
+
+ break;
+ }
+
+ if (!Interrupt->SharedInterrupt &&
+ !Interrupt->IsrRequested &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IN_INITIALIZE))
+ {
+ //
+ // Call to disable the interrupt
+ //
+ ASSERT(Miniport->DisableInterruptHandler != NULL);
+
+ MINIPORT_DISABLE_INTERRUPT(Miniport);
+ InterruptRecognized = TRUE;
+
+ break;
+ }
+
+ //
+ // Call MiniportIsr, but don't queue a DPC.
+ //
+ Interrupt->MiniportIsr(
+ &InterruptRecognized,
+ &QueueDpc,
+ Miniport->MiniportAdapterContext);
+
+ } while (FALSE);
+
+ 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;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ do
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
+ {
+ Decrement((PLONG)&Interrupt->DpcCount, &Interrupt->DpcCountLock);
+
+ if (Interrupt->DpcCount==0)
+ {
+ SET_EVENT(&Interrupt->DpcsCompletedEvent);
+ }
+
+ break;
+ }
+
+ LOCK_MINIPORT(Miniport, LocalLock);
+ if (!LocalLock)
+ {
+ //
+ // A DPC is already running, queue this for later.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemDpc, &Miniport->Dpc, NULL);
+ Decrement((PLONG)&Interrupt->DpcCount, &Interrupt->DpcCountLock);
+
+ break;
+ }
+
+ //
+ // Call MiniportDpc
+ //
+ (*MiniportDpc)(Miniport->MiniportAdapterContext);
+
+ Decrement((PLONG)&Interrupt->DpcCount, &Interrupt->DpcCountLock);
+
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
+ {
+ //
+ // Enable interrupts
+ //
+
+ MINIPORT_SYNC_ENABLE_INTERRUPT(Miniport);
+
+#if _SEND_PRIORITY
+ //
+ // If we are not reseting and not halting then give priority to sends
+ // at this point.
+ //
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_REQUESTED) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ ndisMProcessDeferredFullDuplexPrioritySends(Miniport);
+ }
+ else
+ {
+ ndisMProcessDeferredPrioritySends(Miniport);
+ }
+ }
+ else
+#endif
+ {
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+ }
+ else
+ {
+ if (Interrupt->DpcCount == 0)
+ {
+ SET_EVENT(&Interrupt->DpcsCompletedEvent);
+ }
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ } while (FALSE);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+}
+
+
+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->HandleInterruptHandler;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ do
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IN_INITIALIZE))
+ {
+ break;
+ }
+
+ LOCK_MINIPORT(Miniport, LocalLock);
+ if (!LocalLock)
+ {
+ //
+ // A DPC is already running, queue this for later.
+ //
+ NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemDpc, &Miniport->Dpc, NULL);
+ break;
+ }
+
+ //
+ // Disable the interrupts.
+ //
+ MINIPORT_SYNC_DISABLE_INTERRUPT(Miniport);
+
+ //
+ // Call MiniportDpc
+ //
+ if (MiniportDpc != NULL)
+ {
+ (*MiniportDpc)(Miniport->MiniportAdapterContext);
+ }
+
+ //
+ // Enable interrupts
+ //
+ MINIPORT_SYNC_ENABLE_INTERRUPT(Miniport);
+
+#if _SEND_PRIORITY
+ //
+ // If we are not reseting and not halting then give priority to sends
+ // at this point.
+ //
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_REQUESTED) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ ndisMProcessDeferredFullDuplexPrioritySends(Miniport);
+ }
+ else
+ {
+ ndisMProcessDeferredPrioritySends(Miniport);
+ }
+ }
+ else
+#endif
+ {
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ } while (FALSE);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+}
+
+
+VOID
+ndisMDeferredTimerDpc(
+ IN PKDPC Dpc,
+ IN PVOID Context,
+ IN PVOID SystemContext1,
+ IN PVOID SystemContext2
+ )
+
+/*++
+
+Routine Description:
+
+ This is a DPC routine that is queue'd by some of the [full-duplex] routines
+ in order to get ndisMProcessDeferred[FullDuplex] to run outside of their
+ context.
+
+Arguments:
+
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = Context;
+ BOOLEAN LocalLock;
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(SystemContext1);
+ UNREFERENCED_PARAMETER(SystemContext2);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ LOCK_MINIPORT(Miniport, LocalLock);
+ if (!LocalLock)
+ {
+ //
+ // Queue this to run later.
+ //
+ NDISM_DEFER_PROCESS_DEFERRED(Miniport);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ return;
+ }
+
+#if _SEND_PRIORITY
+ //
+ // If we are not reseting and not halting then give priority to sends
+ // at this point.
+ //
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_REQUESTED) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ ndisMProcessDeferredFullDuplexPrioritySends(Miniport);
+ }
+ else
+ {
+ ndisMProcessDeferredPrioritySends(Miniport);
+ }
+ }
+ else
+#endif
+ {
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+}
+
+
+VOID
+ndisMCoDpc(
+ 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;
+
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
+ {
+ Decrement((PLONG)&Interrupt->DpcCount, &Interrupt->DpcCountLock);
+
+ if (Interrupt->DpcCount==0)
+ {
+ SET_EVENT(&Interrupt->DpcsCompletedEvent);
+ }
+ }
+ else
+ {
+ //
+ // Call MiniportDpc
+ //
+ (*MiniportDpc)(Miniport->MiniportAdapterContext);
+
+ Decrement((PLONG)&Interrupt->DpcCount, &Interrupt->DpcCountLock);
+
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
+ {
+ //
+ // Enable interrupts
+ //
+
+ MINIPORT_SYNC_ENABLE_INTERRUPT(Miniport);
+ }
+ else
+ {
+ if (Interrupt->DpcCount == 0)
+ {
+ SET_EVENT(&Interrupt->DpcsCompletedEvent);
+ }
+ }
+
+ }
+}
+
+
+VOID
+ndisMCoDpcTimer(
+ 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->HandleInterruptHandler;
+
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IN_INITIALIZE))
+ {
+ //
+ // Disable the interrupts.
+ //
+ MINIPORT_SYNC_DISABLE_INTERRUPT(Miniport);
+
+ //
+ // Call MiniportDpc
+ //
+ if (MiniportDpc != NULL)
+ {
+ (*MiniportDpc)(Miniport->MiniportAdapterContext);
+ }
+
+ //
+ // Enable interrupts
+ //
+ MINIPORT_SYNC_ENABLE_INTERRUPT(Miniport);
+
+ }
+}
+
+VOID
+ndisMCoTimerDpc(
+ IN PKDPC Dpc,
+ IN PVOID Context,
+ IN PVOID SystemContext1,
+ IN 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_MINIPORT_BLOCK Miniport = MiniportTimer->Miniport;
+ BOOLEAN LocalLock;
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(SystemContext1);
+ UNREFERENCED_PARAMETER(SystemContext2);
+
+ //
+ // Call Miniport timer function
+ //
+ (*MiniportTimer->MiniportTimerFunction)(NULL, MiniportTimer->MiniportTimerContext, NULL, NULL);
+}
+
+
+
diff --git a/private/ntos/ndis/ndis40/up/makefile b/private/ntos/ndis/ndis40/up/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/ndis40/up/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/ndis40/up/ndis.prf b/private/ntos/ndis/ndis40/up/ndis.prf
new file mode 100644
index 000000000..7c294f08e
--- /dev/null
+++ b/private/ntos/ndis/ndis40/up/ndis.prf
@@ -0,0 +1,136 @@
+_allmul
+NdisQueryBuffer@12
+@InterlockedDecrement@4
+NdisQueryBufferOffset@12
+@InterlockedIncrement@4
+@InterlockedExchange@8
+NDIS_BUFFER_TO_SPAN_PAGES@4
+NdisAllocateBuffer@20
+NdisSetTimer@8
+NdisUnchainBufferAtFront@8
+@ndisMSyncSend@8
+@ndisMProcessDeferredPrioritySends@4
+ndisMIsr@8
+@ndisMQueueWorkItem@16
+ndisMDpc@16
+@ndisMIsLoopbackPacket@8
+@ndisMStartSends@4
+@ndisMProcessDeferred@4
+ndisMWakeUpDpc@16
+NdisMSendComplete@12
+@ndisMDeQueueWorkItem@16
+NdisMSendResourcesAvailable@4
+NdisMStartBufferPhysicalMapping@24
+NdisMCompleteBufferPhysicalMapping@12
+ndisMDeferredTimerDpc@16
+@ndisMIndicateLoopback@4
+ndisMCopyFromPacketToBuffer@20
+ndisMTimerDpc@16
+ndisMSend@8
+EthFilterDprIndicateReceiveComplete@4
+EthFilterDprIndicateReceivePacket@12
+NdisReturnPackets@8
+NdisAllocateMemory@20
+NdisWritePciSlotInformation@20
+NdisCopyBuffer@24
+NdisUnchainBufferAtBack@8
+NdisDereferenceRef@4
+ndisAllocationExecutionRoutine@16
+ndisDereferencePackage@4
+ndisReportResources@20
+ndisAddResource@28
+NdisFreeMemory@12
+ndisMFinishPendingOpen@4
+NdisAllocateBufferPool@12
+ndisMFinishQueuedPendingOpen@4
+NdisAllocateSharedMemory@20
+NdisSystemProcessorCount@0
+NdisInitializeTimer@12
+NdisMSetPeriodicTimer@8
+NdisInitializeRef@4
+NdisFreeBufferPool@4
+NdisAllocatePacket@12
+NdisAllocatePacketPool@16
+NdisCopyFromPacketToPacket@24
+ndisReferencePackage@4
+NdisReadPciSlotInformation@20
+NdisReferenceRef@4
+ndisMRequestQueryInformationPost@12
+DriverEntry@8
+ndisReadParameters@24
+ndisReadRegistry@0
+ArcCreateFilter@24
+ArcDeleteFilter@4
+ndisMQueryMaximumTotalSize@8
+TrCreateFilter@28
+NdisMRegisterMiniport@12
+ethUpdateBroadcastBindingList@12
+EthCreateFilter@28
+EthNoteFilterOpenAdapter@16
+EthDeleteFilter@4
+ethUpdateDirectedBindingList@12
+ethUpdateSpecificBindingLists@8
+NdisOpenAdapter@44
+ndisDereferenceProtocol@4
+NdisRegisterProtocol@16
+NdisMRegisterAdapterShutdownHandler@12
+ndisMSetInformation@8
+ndisMSyncQueryInformationComplete@8
+NdisIMRegisterLayeredMiniport@16
+ndisMQueryMaximumFrameSize@8
+ndisDereferenceMiniport@4
+ndisMDoRequests@4
+TrDeleteFilter@4
+ndisMQueueRequest@12
+NdisMInitializeTimer@16
+NdisMRegisterInterrupt@28
+ndisDereferenceDriver@4
+ndisQueueMiniportOnDriver@8
+NdisMAllocateSharedMemory@20
+ndisMChangeClass@20
+NdisMRegisterIoPortRange@16
+ndisMRequest@8
+FddiCreateFilter@36
+ndisMSetCurrentLookahead@8
+FddiDeleteFilter@4
+ndisMQueryNetworkAddress@8
+@ndisMQueueNewWorkItem@16
+ndisMSetPacketFilter@8
+EthFilterAdjust@20
+ndisMRequestSetInformationPost@12
+ndisMSyncSetInformationComplete@8
+ndisSaveParameters@24
+ndisQueueOpenOnProtocol@8
+NdisInitializeInterrupt@40
+ndisUpdateDriverInstance@16
+ndisMDummyTransferData@24
+ndisCheckRoute@24
+NdisOpenConfiguration@12
+NdisInitializeWrapper@16
+ndisProtocolAlreadyBound@8
+NdisOverrideBusNumber@12
+ndisSaveLinkage@24
+ndisMInitializeAdapter@16
+ndisMOpenAdapter@48
+ndisMDoMiniportOp@24
+NdisMAllocateMapRegisters@20
+ndisCreateIrpHandler@8
+ndisSuccessIrpHandler@8
+ndisInitializePackage@8
+ndisDispatchRequest@8
+NdisRegisterTdiCallBack@4
+ndisQueuedProtocolNotification@4
+ndisHandlePnPRequest@4
+ndisHandleLegacyTransport@4
+ndisHandleProtocolNotification@4
+NdisReadNetworkAddress@16
+NdisCloseConfiguration@4
+ndisInitializeAdapter@8
+NdisReadConfiguration@20
+ndisInitializeBindings@12
+ndisCheckProtocolBinding@16
+NdisMSetAttributes@16
+ndisMUndoBogusFilters@4
+ndisInitializeAllAdapterInstances@8
+ndisMQueryInformation@8
+ndisMDpcTimer@16
diff --git a/private/ntos/ndis/ndis40/up/sources b/private/ntos/ndis/ndis40/up/sources
new file mode 100644
index 000000000..85cdb3764
--- /dev/null
+++ b/private/ntos/ndis/ndis40/up/sources
@@ -0,0 +1,29 @@
+!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
+
+UP_DRIVER=yes
+
+TARGETPATH=obj
+
+!include ..\sources.inc
diff --git a/private/ntos/ndis/ndis40/wrapper.h b/private/ntos/ndis/ndis40/wrapper.h
new file mode 100644
index 000000000..e53e3e0ce
--- /dev/null
+++ b/private/ntos/ndis/ndis40/wrapper.h
@@ -0,0 +1,681 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ wrapper.h
+
+Abstract:
+
+ NDIS wrapper definitions
+
+Author:
+
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ Jun-95 Jameel Hyder Split up from a monolithic file
+--*/
+
+#ifndef _WRAPPPER_
+#define _WRAPPPER_
+
+#include <ntos.h>
+#include <ndismain.h>
+#include <ndisprot.h>
+#include <ndismac.h>
+#include <ndismini.h>
+#include <ndisco.h>
+#include <zwapi.h>
+#include <ndisdbg.h>
+#include <ndistags.h>
+
+extern UCHAR ndisValidProcessors[];
+extern ULONG ndisMaximumProcessor;
+extern ULONG ndisCurrentProcessor;
+extern UCHAR ndisInternalEaName[4];
+extern UCHAR ndisInternalEaValue[8];
+extern TDI_REGISTER_CALLBACK ndisTdiRegisterCallback;
+extern BOOLEAN ndisSkipProcessorAffinity;
+extern BOOLEAN ndisMediaTypeCl[NdisMediumMax];
+
+#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))))
+
+//
+// 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) ? FALSE : TRUE)
+
+//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
+
+//
+// This constant is used for places where NdisAllocateMemory
+// needs to be called and the HighestAcceptableAddress does
+// not matter.
+//
+#define RetrieveUlong(Destination, Source) \
+{ \
+ PUCHAR _S = (Source); \
+ *(Destination) = ((ULONG)(*_S) << 24) | \
+ ((ULONG)(*(_S+1)) << 16) | \
+ ((ULONG)(*(_S+2)) << 8) | \
+ ((ULONG)(*(_S+3))); \
+}
+
+
+//
+// This is the number of extra OIDs that ARCnet with Ethernet encapsulation
+// supports.
+//
+#define ARC_NUMBER_OF_EXTRA_OIDS 2
+
+//
+// ZZZ NonPortable definitions.
+//
+#define AllocPhys(s, l) NdisAllocateMemory((PVOID *)(s), (l), 0, HighestAcceptableMax)
+#define FreePhys(s, l) NdisFreeMemory((PVOID)(s), (l), 0)
+
+//
+// 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;
+
+ //
+ // Kernel bugcheck record for bugcheck handling.
+ //
+
+ KBUGCHECK_CALLBACK_RECORD BugcheckCallbackRecord;
+
+ //
+ // 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;
+
+//
+// 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.
+//
+typedef struct _NDIS_USER_OPEN_CONTEXT
+{
+ PDEVICE_OBJECT DeviceObject;
+ union
+ {
+ PNDIS_MINIPORT_BLOCK MiniportBlock;
+ PNDIS_ADAPTER_BLOCK AdapterBlock;
+ };
+ ULONG OidCount;
+ PNDIS_OID OidArray;
+ ULONG FullOidCount;
+ PNDIS_OID FullOidArray;
+} 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;
+
+//
+// An temporary request used during init
+//
+typedef struct _NDIS_QS_REQUEST
+{
+ NDIS_REQUEST Request;
+ NDIS_STATUS NdisStatus;
+ KEVENT Event;
+} NDIS_QS_REQUEST, *PNDIS_QS_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;
+
+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))
+
+//
+// This is used to keep track of pci/eisa/mca cards in the system so that
+// if they move, then the bus#/slot# can be fixed up appropriately.
+//
+typedef struct _BUS_SLOT_DB
+{
+ struct _BUS_SLOT_DB *Next;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ ULONG SlotNumber;
+ ULONG BusId;
+} BUS_SLOT_DB, *PBUS_SLOT_DB;
+
+extern PBUS_SLOT_DB ndisGlobalDb;
+extern KSPIN_LOCK ndisGlobalDbLock;
+
+//
+// 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[5];
+ PDRIVER_OBJECT DriverObject;
+ PUNICODE_STRING DriverBaseName;
+ BUS_SLOT_DB Db;
+} NDIS_WRAPPER_CONFIGURATION_HANDLE, *PNDIS_WRAPPER_CONFIGURATION_HANDLE;
+
+//
+// Describes an open NDIS file
+//
+
+//
+// Context for Bind Adapter.
+//
+typedef struct _NDIS_BIND_CONTEXT
+{
+ struct _NDIS_BIND_CONTEXT * Next;
+ PNDIS_PROTOCOL_BLOCK Protocol;
+ NDIS_STRING ProtocolSection;
+ PNDIS_STRING DeviceName;
+ WORK_QUEUE_ITEM WorkItem;
+ NDIS_STATUS BindStatus;
+ KEVENT Event;
+ KEVENT ThreadDoneEvent;
+} NDIS_BIND_CONTEXT, *PNDIS_BIND_CONTEXT;
+
+typedef struct _NDIS_FILE_DESCRIPTOR
+{
+ PVOID Data;
+ KSPIN_LOCK Lock;
+ BOOLEAN Mapped;
+} NDIS_FILE_DESCRIPTOR, *PNDIS_FILE_DESCRIPTOR;
+
+//
+// The following structure is used to queue openadapter/closeadapter calls to
+// worker threads so that they can complete at LOW_LEVEL.
+//
+typedef struct _QUEUED_OPEN_CLOSE
+{
+ PNDIS_OPEN_BLOCK OpenP;
+ NDIS_STATUS Status;
+ NDIS_STATUS OpenErrorStatus;
+ WORK_QUEUE_ITEM WorkItem;
+ BOOLEAN FreeIt;
+} QUEUED_OPEN_CLOSE, *PQUEUED_OPEN_CLOSE;
+
+
+typedef struct _QueuedProtocolNotification
+{
+ WORK_QUEUE_ITEM WorkItem;
+ PNDIS_M_DRIVER_BLOCK MiniBlock;
+ UNICODE_STRING UpCaseDeviceInstance;
+ WCHAR Buffer[1];
+} QUEUED_PROTOCOL_NOTIFICATION, *PQUEUED_PROTOCOL_NOTIFICATION;
+
+#if defined(_ALPHA_)
+
+typedef struct _NDIS_LOOKAHEAD_ELEMENT
+{
+ ULONG Length;
+ struct _NDIS_LOOKAHEAD_ELEMENT *Next;
+
+} NDIS_LOOKAHEAD_ELEMENT, *PNDIS_LOOKAHEAD_ELEMENT;
+
+#endif
+
+
+typedef struct _PKG_REF
+{
+ KSPIN_LOCK ReferenceLock;
+ ULONG ReferenceCount;
+ PVOID ImageHandle;
+ KEVENT PagedInEvent;
+} PKG_REF, *PPKG_REF;
+
+//
+// Structures for dealing with making the module specific routines pagable
+//
+
+extern PKG_REF ProtocolPkg;
+extern PKG_REF MacPkg;
+extern PKG_REF CoPkg;
+extern PKG_REF InitPkg;
+extern PKG_REF PnPPkg;
+extern PKG_REF MiniportPkg;
+extern PKG_REF ArcPkg;
+extern PKG_REF EthPkg;
+extern PKG_REF TrPkg;
+extern PKG_REF FddiPkg;
+
+extern PNDIS_PROTOCOL_BLOCK ndisProtocolList;
+
+//
+// Work item structure
+//
+typedef struct _NDIS_MINIPORT_WORK_ITEM
+{
+ //
+ // Link for the list of work items of this type.
+ //
+ SINGLE_LIST_ENTRY Link;
+
+ //
+ // type of work item and context information.
+ //
+ NDIS_WORK_ITEM_TYPE WorkItemType;
+ PVOID WorkItemContext1;
+ PVOID WorkItemContext2;
+} NDIS_MINIPORT_WORK_ITEM, *PNDIS_MINIPORT_WORK_ITEM;
+
+//
+// This does most of the work of dequeueing a workitem.
+//
+#define NDISM_DEQUEUE_WORK_ITEM_MACRO(_M, _WT, _pWC1, _pWC2) \
+{ \
+}
+
+#define NDISM_QUEUE_WORK_ITEM_MACRO(_M, _WT, _WC1, _WC2, _pS) \
+{ \
+ PSINGLE_LIST_ENTRY _Link; \
+ PNDIS_MINIPORT_WORK_ITEM _WorkItem; \
+ \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("==>ndisMQueueWorkItem()\n")); \
+ \
+ _Link = PopEntryList(&(_M)->SingleWorkItems[(_WT)]); \
+ if (NULL != _Link) \
+ { \
+ _WorkItem = CONTAINING_RECORD(_Link, NDIS_MINIPORT_WORK_ITEM, Link); \
+ _WorkItem->WorkItemType = (_WT); \
+ _WorkItem->WorkItemContext1 = (_WC1); \
+ _WorkItem->WorkItemContext2 = (_WC2); \
+ PushEntryList(&(_M)->WorkQueue[(_WT)], _Link); \
+ *(_pS) = NDIS_STATUS_SUCCESS; \
+ } \
+ else \
+ { \
+ *(_pS) = NDIS_STATUS_NOT_ACCEPTED; \
+ } \
+ \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("<==ndisMQueueWorkItem()\n")); \
+}
+
+#define NDISM_QUEUE_WORK_ITEM_FULL_DUPLEX_MACRO(_M, _WT, _WC1, _WC2, _pS) \
+{ \
+ PSINGLE_LIST_ENTRY _Link; \
+ PNDIS_MINIPORT_WORK_ITEM _WorkItem; \
+ \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("==>ndisMQueueWorkItemFullDuplex()\n")); \
+ \
+ ACQUIRE_SPIN_LOCK_DPC(&(_M)->WorkLock); \
+ \
+ _Link = PopEntryList(&(_M)->SingleWorkItems[(_WT)]); \
+ if (NULL != _Link) \
+ { \
+ _WorkItem = CONTAINING_RECORD(_Link, NDIS_MINIPORT_WORK_ITEM, Link); \
+ _WorkItem->WorkItemType = (_WT); \
+ _WorkItem->WorkItemContext1 = (_WC1); \
+ _WorkItem->WorkItemContext2 = (_WC2); \
+ PushEntryList(&(_M)->WorkQueue[(_WT)], \
+ _Link); \
+ \
+ *(_pS) = NDIS_STATUS_SUCCESS; \
+ } \
+ else \
+ { \
+ *(_pS) = NDIS_STATUS_NOT_ACCEPTED; \
+ } \
+ \
+ RELEASE_SPIN_LOCK_DPC(&(_M)->WorkLock); \
+ \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("<==ndisMQueueWorkItemFullDuplex()\n")); \
+}
+
+#define NDISM_QUEUE_NEW_WORK_ITEM_MACRO(_M, _WT, _WC1, _WC2, _pS) \
+{ \
+ PSINGLE_LIST_ENTRY _Link; \
+ PNDIS_MINIPORT_WORK_ITEM _WorkItem; \
+ \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("==>ndisMQueueNewWorkItem()\n")); \
+ \
+ ASSERT(((_WT) < NUMBER_OF_WORK_ITEM_TYPES) && ((_WT) > NUMBER_OF_SINGLE_WORK_ITEMS)); \
+ \
+ do \
+ { \
+ _Link = PopEntryList(&(_M)->WorkItemFreeQueue); \
+ if (NULL == _Link) \
+ { \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("Allocate a workitem from the pool.\n")); \
+ \
+ _WorkItem = ALLOC_FROM_POOL(sizeof(NDIS_MINIPORT_WORK_ITEM), NDIS_TAG_WORK_ITEM);\
+ if (NULL == _WorkItem) \
+ { \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_FATAL, \
+ ("Failed to allocate a workitem from the pool!\n")); \
+ DBGBREAK(DBG_COMP_WORK_ITEM, DBG_LEVEL_FATAL); \
+ \
+ *(_pS) = NDIS_STATUS_FAILURE; \
+ \
+ break; \
+ } \
+ (_M)->NumberOfAllocatedWorkItems++; \
+ } \
+ else \
+ { \
+ _WorkItem = CONTAINING_RECORD(_Link, NDIS_MINIPORT_WORK_ITEM, Link); \
+ } \
+ \
+ ZeroMemory(_WorkItem, sizeof(NDIS_MINIPORT_WORK_ITEM)); \
+ _WorkItem->WorkItemType = (_WT); \
+ _WorkItem->WorkItemContext1 = (_WC1); \
+ _WorkItem->WorkItemContext2 = (_WC2); \
+ \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("WorkItem 0x%x\n", _WorkItem)); \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("WorkItem Type 0x%x\n", (_WT))); \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("WorkItem Context2 0x%x\n", (_WC1))); \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("WorkItem Context1 0x%x\n", (_WC2))); \
+ \
+ PushEntryList(&(_M)->WorkQueue[(_WT)], &_WorkItem->Link); \
+ \
+ *(_pS) = NDIS_STATUS_SUCCESS; \
+ \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("<==ndisMQueueNewWorkItem()\n")); \
+ } while (FALSE); \
+}
+
+#define NDISM_QUEUE_NEW_WORK_ITEM_FULL_DUPLEX_MACRO(_M, _WT, _WC1, _WC2, _pS) \
+{ \
+ PSINGLE_LIST_ENTRY _Link; \
+ PNDIS_MINIPORT_WORK_ITEM _WorkItem; \
+ \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("==>ndisMQueueNewWorkItemFullDuplex()\n")); \
+ \
+ ASSERT(((_WT) < NUMBER_OF_WORK_ITEM_TYPES) && ((_WT) > NUMBER_OF_SINGLE_WORK_ITEMS)); \
+ \
+ ACQUIRE_SPIN_LOCK_DPC(&(_M)->WorkLock); \
+ \
+ do \
+ { \
+ _Link = PopEntryList(&(_M)->WorkItemFreeQueue); \
+ if (NULL == _Link) \
+ { \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("Allocate a workitem from the pool.\n")); \
+ \
+ _WorkItem = ALLOC_FROM_POOL(sizeof(NDIS_MINIPORT_WORK_ITEM), NDIS_TAG_WORK_ITEM);\
+ if (NULL == _WorkItem) \
+ { \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_FATAL, \
+ ("Failed to allocate a workitem from the pool!\n")); \
+ DBGBREAK(DBG_COMP_WORK_ITEM, DBG_LEVEL_FATAL); \
+ \
+ *(_pS) = NDIS_STATUS_FAILURE; \
+ \
+ break; \
+ } \
+ \
+ (_M)->NumberOfAllocatedWorkItems++; \
+ } \
+ else \
+ { \
+ _WorkItem = CONTAINING_RECORD(_Link, NDIS_MINIPORT_WORK_ITEM, Link); \
+ } \
+ \
+ ZeroMemory(_WorkItem, sizeof(NDIS_MINIPORT_WORK_ITEM)); \
+ _WorkItem->WorkItemType = (_WT); \
+ _WorkItem->WorkItemContext1 = (_WC1); \
+ _WorkItem->WorkItemContext2 = (_WC2); \
+ \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("WorkItem 0x%x\n", _WorkItem)); \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("WorkItem Type 0x%x\n", (_WT))); \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("WorkItem Context2 0x%x\n", (_WC1))); \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("WorkItem Context1 0x%x\n", (_WC2))); \
+ \
+ PushEntryList(&(_M)->WorkQueue[(_WT)], &_WorkItem->Link); \
+ \
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO, \
+ ("<==ndisMQueueNewWorkItemFullDuplex()\n")); \
+ } while (FALSE); \
+ \
+ RELEASE_SPIN_LOCK_DPC(&(_M)->WorkLock); \
+}
+
+#define NDISM_QUEUE_WORK_ITEM(_M, _WT, _WC1, _WC2) (_M)->QueueWorkItemHandler(_M, _WT, _WC1, _WC2)
+
+#define NDISM_QUEUE_NEW_WORK_ITEM(_M, _WT, _WC1, _WC2) (_M)->QueueNewWorkItemHandler(_M, _WT, _WC1, _WC2)
+
+#define NDISM_DEQUEUE_WORK_ITEM(_M, _WT, _pWC1, _pWC2) (_M)->DeQueueWorkItemHandler(_M, _WT, _pWC1, _pWC2)
+
+#define NDISM_PROCESS_DEFERRED(_M) (_M)->ProcessDeferredHandler((_M))
+
+#endif // _WRAPPPER_
+
diff --git a/private/ntos/ndis/ndis40/wrapper.txt b/private/ntos/ndis/ndis40/wrapper.txt
new file mode 100644
index 000000000..2e52189f0
--- /dev/null
+++ b/private/ntos/ndis/ndis40/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