From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/ntos/ndis/ndis40/afilter.c | 2617 +++++++++++++++++++++ private/ntos/ndis/ndis40/bus.c | 1009 +++++++++ private/ntos/ndis/ndis40/common.c | 3452 ++++++++++++++++++++++++++++ private/ntos/ndis/ndis40/config.c | 2788 +++++++++++++++++++++++ private/ntos/ndis/ndis40/configm.c | 2077 +++++++++++++++++ private/ntos/ndis/ndis40/data.c | 190 ++ private/ntos/ndis/ndis40/debug.c | 422 ++++ private/ntos/ndis/ndis40/dirs | 23 + private/ntos/ndis/ndis40/dummy.c | 56 + private/ntos/ndis/ndis40/efilter.c | 2845 +++++++++++++++++++++++ private/ntos/ndis/ndis40/ffilter.c | 3869 +++++++++++++++++++++++++++++++ private/ntos/ndis/ndis40/filter.h | 181 ++ private/ntos/ndis/ndis40/init.c | 1415 ++++++++++++ private/ntos/ndis/ndis40/initpnp.c | 2463 ++++++++++++++++++++ private/ntos/ndis/ndis40/mac.c | 3591 +++++++++++++++++++++++++++++ private/ntos/ndis/ndis40/mac.h | 48 + private/ntos/ndis/ndis40/makefile | 6 + private/ntos/ndis/ndis40/makefile.inc | 11 + private/ntos/ndis/ndis40/mini.h | 251 +++ private/ntos/ndis/ndis40/minint.c | 1293 +++++++++++ private/ntos/ndis/ndis40/miniport.c | 3180 ++++++++++++++++++++++++++ private/ntos/ndis/ndis40/minisub.c | 569 +++++ private/ntos/ndis/ndis40/mp/makefile | 6 + private/ntos/ndis/ndis40/mp/ndis.prf | 136 ++ private/ntos/ndis/ndis40/mp/sources | 29 + private/ntos/ndis/ndis40/ndis.c | 1349 +++++++++++ private/ntos/ndis/ndis40/ndis.rc | 39 + private/ntos/ndis/ndis40/ndis.src | 328 +++ private/ntos/ndis/ndis40/ndis_co.c | 3873 ++++++++++++++++++++++++++++++++ private/ntos/ndis/ndis40/ndisdbg.h | 270 +++ private/ntos/ndis/ndis40/ndisnt.h | 325 +++ private/ntos/ndis/ndis40/ndistags.h | 53 + private/ntos/ndis/ndis40/pragma.h | 733 ++++++ private/ntos/ndis/ndis40/precomp.h | 17 + private/ntos/ndis/ndis40/protocol.c | 1757 +++++++++++++++ private/ntos/ndis/ndis40/protos.h | 1991 ++++++++++++++++ private/ntos/ndis/ndis40/requestm.c | 3994 +++++++++++++++++++++++++++++++++ private/ntos/ndis/ndis40/sendm.c | 3212 ++++++++++++++++++++++++++ private/ntos/ndis/ndis40/sendm.h | 334 +++ private/ntos/ndis/ndis40/sources.inc | 77 + private/ntos/ndis/ndis40/tfilter.c | 2813 +++++++++++++++++++++++ private/ntos/ndis/ndis40/timer.c | 794 +++++++ private/ntos/ndis/ndis40/timerm.c | 1080 +++++++++ private/ntos/ndis/ndis40/up/makefile | 6 + private/ntos/ndis/ndis40/up/ndis.prf | 136 ++ private/ntos/ndis/ndis40/up/sources | 29 + private/ntos/ndis/ndis40/wrapper.h | 681 ++++++ private/ntos/ndis/ndis40/wrapper.txt | 120 + 48 files changed, 56538 insertions(+) create mode 100644 private/ntos/ndis/ndis40/afilter.c create mode 100644 private/ntos/ndis/ndis40/bus.c create mode 100644 private/ntos/ndis/ndis40/common.c create mode 100644 private/ntos/ndis/ndis40/config.c create mode 100644 private/ntos/ndis/ndis40/configm.c create mode 100644 private/ntos/ndis/ndis40/data.c create mode 100644 private/ntos/ndis/ndis40/debug.c create mode 100644 private/ntos/ndis/ndis40/dirs create mode 100644 private/ntos/ndis/ndis40/dummy.c create mode 100644 private/ntos/ndis/ndis40/efilter.c create mode 100644 private/ntos/ndis/ndis40/ffilter.c create mode 100644 private/ntos/ndis/ndis40/filter.h create mode 100644 private/ntos/ndis/ndis40/init.c create mode 100644 private/ntos/ndis/ndis40/initpnp.c create mode 100644 private/ntos/ndis/ndis40/mac.c create mode 100644 private/ntos/ndis/ndis40/mac.h create mode 100644 private/ntos/ndis/ndis40/makefile create mode 100644 private/ntos/ndis/ndis40/makefile.inc create mode 100644 private/ntos/ndis/ndis40/mini.h create mode 100644 private/ntos/ndis/ndis40/minint.c create mode 100644 private/ntos/ndis/ndis40/miniport.c create mode 100644 private/ntos/ndis/ndis40/minisub.c create mode 100644 private/ntos/ndis/ndis40/mp/makefile create mode 100644 private/ntos/ndis/ndis40/mp/ndis.prf create mode 100644 private/ntos/ndis/ndis40/mp/sources create mode 100644 private/ntos/ndis/ndis40/ndis.c create mode 100644 private/ntos/ndis/ndis40/ndis.rc create mode 100644 private/ntos/ndis/ndis40/ndis.src create mode 100644 private/ntos/ndis/ndis40/ndis_co.c create mode 100644 private/ntos/ndis/ndis40/ndisdbg.h create mode 100644 private/ntos/ndis/ndis40/ndisnt.h create mode 100644 private/ntos/ndis/ndis40/ndistags.h create mode 100644 private/ntos/ndis/ndis40/pragma.h create mode 100644 private/ntos/ndis/ndis40/precomp.h create mode 100644 private/ntos/ndis/ndis40/protocol.c create mode 100644 private/ntos/ndis/ndis40/protos.h create mode 100644 private/ntos/ndis/ndis40/requestm.c create mode 100644 private/ntos/ndis/ndis40/sendm.c create mode 100644 private/ntos/ndis/ndis40/sendm.h create mode 100644 private/ntos/ndis/ndis40/sources.inc create mode 100644 private/ntos/ndis/ndis40/tfilter.c create mode 100644 private/ntos/ndis/ndis40/timer.c create mode 100644 private/ntos/ndis/ndis40/timerm.c create mode 100644 private/ntos/ndis/ndis40/up/makefile create mode 100644 private/ntos/ndis/ndis40/up/ndis.prf create mode 100644 private/ntos/ndis/ndis40/up/sources create mode 100644 private/ntos/ndis/ndis40/wrapper.h create mode 100644 private/ntos/ndis/ndis40/wrapper.txt (limited to 'private/ntos/ndis/ndis40') 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 +#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 +#pragma hdrstop + +#include + +// +// 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 +#pragma hdrstop + +#include + +// +// 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 +#pragma hdrstop + +#include + +// +// 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; iPhysicalMapRegistersNeeded; 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; iPhysicalMapRegistersNeeded; 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 +#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; iPhysicalMapRegistersNeeded; 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; iPhysicalMapRegistersNeeded; 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 +#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 +#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 +#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 +#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 +#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 +#include +#pragma hdrstop + +#include + +// +// 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 +#pragma hdrstop + +#include + +// +// 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\ + // 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 +#pragma hdrstop + +#include + +// +// 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; CurrentOidOidCount; 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; iPhysicalMapRegistersNeeded; 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 +#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 +#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 +#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 +#include + +/*-----------------------------------------------*/ +/* 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 +#include +#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 +#include +#include +#include + +#include "pragma.h" + +#include +#include + 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 +#pragma hdrstop + +#include + +// +// 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 +#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 +#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 +#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 +#pragma hdrstop + +#include + +// +// 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 +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +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 -- cgit v1.2.3