diff options
Diffstat (limited to 'private/ntos/ndis/ndis30')
23 files changed, 45217 insertions, 0 deletions
diff --git a/private/ntos/ndis/ndis30/afilter.c b/private/ntos/ndis/ndis30/afilter.c new file mode 100644 index 000000000..9d50eedc9 --- /dev/null +++ b/private/ntos/ndis/ndis30/afilter.c @@ -0,0 +1,2083 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + afilter.c + +Abstract: + + This module implements a set of library routines to handle packet + filtering for NDIS MAC drivers. It also provides routines for collecting fragmented packets and + breaking up a packet into fragmented packets + +Author: + + Alireza Dabagh 3-22-1993, (partially borrowed from EFILTER.C) + + +Revision History: + +--*/ + +#include <precomp.h> +#pragma hdrstop + +#if DBG +UINT AfilterDebugFlag = 0; +#endif + +// +// This constant is used for places where NdisAllocateMemory +// needs to be called and the HighestAcceptableAddress does +// not matter. +// + +static const NDIS_PHYSICAL_ADDRESS HighestAcceptableMax = + NDIS_PHYSICAL_ADDRESS_CONST(-1,-1); + +// +// A set of macros to manipulate bitmasks. +// + +//VOID +//CLEAR_BIT_IN_MASK( +// IN UINT Offset, +// IN OUT PMASK MaskToClear +// ) +// +///*++ +// +//Routine Description: +// +// Clear a bit in the bitmask pointed to by the parameter. +// +//Arguments: +// +// Offset - The offset (from 0) of the bit to altered. +// +// MaskToClear - Pointer to the mask to be adjusted. +// +//Return Value: +// +// None. +// +//--*/ +// +#define CLEAR_BIT_IN_MASK(Offset,MaskToClear) *MaskToClear &= (~(1 << Offset)) + +//VOID +//SET_BIT_IN_MASK( +// IN UINT Offset, +// IN OUT PMASK MaskToSet +// ) +// +///*++ +// +//Routine Description: +// +// Set a bit in the bitmask pointed to by the parameter. +// +//Arguments: +// +// Offset - The offset (from 0) of the bit to altered. +// +// MaskToSet - Pointer to the mask to be adjusted. +// +//Return Value: +// +// None. +// +//--*/ +#define SET_BIT_IN_MASK(Offset,MaskToSet) *MaskToSet |= (1 << Offset) + +//BOOLEAN +//IS_BIT_SET_IN_MASK( +// IN UINT Offset, +// IN MASK MaskToTest +// ) +// +///*++ +// +//Routine Description: +// +// Tests if a particular bit in the bitmask pointed to by the parameter is +// set. +// +//Arguments: +// +// Offset - The offset (from 0) of the bit to test. +// +// MaskToTest - The mask to be tested. +// +//Return Value: +// +// Returns TRUE if the bit is set. +// +//--*/ +#define IS_BIT_SET_IN_MASK(Offset,MaskToTest) \ +((MaskToTest & (1 << Offset))?(TRUE):(FALSE)) + +//BOOLEAN +//IS_MASK_CLEAR( +// IN MASK MaskToTest +// ) +// +///*++ +// +//Routine Description: +// +// Tests whether there are *any* bits enabled in the mask. +// +//Arguments: +// +// MaskToTest - The bit mask to test for all clear. +// +//Return Value: +// +// Will return TRUE if no bits are set in the mask. +// +//--*/ +#define IS_MASK_CLEAR(MaskToTest) ((!MaskToTest)?(TRUE):(FALSE)) + +//VOID +//CLEAR_MASK( +// IN OUT PMASK MaskToClear +// ); +// +///*++ +// +//Routine Description: +// +// Clears a mask. +// +//Arguments: +// +// MaskToClear - The bit mask to adjust. +// +//Return Value: +// +// None. +// +//--*/ +#define CLEAR_MASK(MaskToClear) *MaskToClear = 0 + +// +// VOID +// ARC_FILTER_ALLOC_OPEN( +// IN PETH_FILTER Filter, +// OUT PUINT FilterIndex +// ) +// +///*++ +// +//Routine Description: +// +// Allocates an open block. This only allocate the index, not memory for +// the open block. +// +//Arguments: +// +// Filter - DB from which to allocate the space +// +// FilterIndex - pointer to place to store the index. +// +//Return Value: +// +// FilterIndex of the new open +// +//--*/ +#define ARC_FILTER_ALLOC_OPEN(Filter, FilterIndex)\ +{\ + UINT i; \ + for (i=0; i < ARC_FILTER_MAX_OPENS; i++) { \ + if (IS_BIT_SET_IN_MASK(i,(Filter)->FreeBindingMask)) { \ + *(FilterIndex) = i; \ + CLEAR_BIT_IN_MASK(i, &((Filter)->FreeBindingMask)); \ + break; \ + } \ + } \ +} + +// +// VOID +// ARC_FILTER_FREE_OPEN( +// IN PETH_FILTER Filter, +// IN PARC_BINDING_INFO LocalOpen +// ) +// +///*++ +// +//Routine Description: +// +// Frees an open block. Also frees the memory associated with the open. +// +//Arguments: +// +// Filter - DB from which to allocate the space +// +// FilterIndex - Index to free +// +//Return Value: +// +// FilterIndex of the new open +// +//--*/ +#define ARC_FILTER_FREE_OPEN(Filter, LocalOpen)\ +{\ + SET_BIT_IN_MASK(((LocalOpen)->FilterIndex), &((Filter)->FreeBindingMask)); \ + NdisFreeMemory((LocalOpen), sizeof(ARC_BINDING_INFO), 0);\ +} + + + +NDIS_SPIN_LOCK ArcReferenceLock = {0}; +KEVENT ArcPagedInEvent = {0}; +ULONG ArcReferenceCount = 0; +PVOID ArcImageHandle = {0}; + +VOID +ArcInitializePackage(VOID) +{ + NdisAllocateSpinLock(&ArcReferenceLock); + KeInitializeEvent( + &ArcPagedInEvent, + NotificationEvent, + FALSE + ); +} + +VOID +ArcReferencePackage(VOID) +{ + ACQUIRE_SPIN_LOCK(&ArcReferenceLock); + + ArcReferenceCount++; + + if (ArcReferenceCount == 1) { + + KeResetEvent( + &ArcPagedInEvent + ); + + RELEASE_SPIN_LOCK(&ArcReferenceLock); + + // + // Page in all the functions + // + ArcImageHandle = MmLockPagableCodeSection(ArcCreateFilter); + + // + // Signal to everyone to go + // + KeSetEvent( + &ArcPagedInEvent, + 0L, + FALSE + ); + + } else { + + RELEASE_SPIN_LOCK(&ArcReferenceLock); + + // + // Wait for everything to be paged in + // + KeWaitForSingleObject( + &ArcPagedInEvent, + Executive, + KernelMode, + TRUE, + NULL + ); + + } + +} + +VOID +ArcDereferencePackage(VOID) +{ + ACQUIRE_SPIN_LOCK(&ArcReferenceLock); + + ArcReferenceCount--; + + if (ArcReferenceCount == 0) { + + RELEASE_SPIN_LOCK(&ArcReferenceLock); + + // + // Page out all the functions + // + MmUnlockPagableImageSection(ArcImageHandle); + + } else { + + RELEASE_SPIN_LOCK(&ArcReferenceLock); + + } + +} + + +// +// Defines for resource growth +// +#define ARC_BUFFER_SIZE 1024 +#define ARC_BUFFER_ALLOCATION_UNIT 8 +#define ARC_PACKET_ALLOCATION_UNIT 2 + + +// +// Forward declarations +// +NDIS_STATUS +ArcAllocateBuffers( + IN PARC_FILTER Filter + ); + +NDIS_STATUS +ArcAllocatePackets( + IN PARC_FILTER Filter + ); + +VOID +ArcDiscardPacketBuffers( + IN PARC_FILTER Filter, + IN PARC_PACKET Packet + ); + +VOID +ArcDestroyPacket( + IN PARC_FILTER Filter, + IN PARC_PACKET Packet + ); + +BOOLEAN +ArcConvertToNdisPacket( + IN PARC_FILTER Filter, + IN PARC_PACKET Packet, + IN BOOLEAN ConvertWholePacket + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGENDSA, ArcFilterTransferData) +#pragma alloc_text(PAGENDSA, ArcFilterDprIndicateReceiveComplete) +#pragma alloc_text(PAGENDSA, ArcFilterDoIndication) +#pragma alloc_text(PAGENDSA, ArcFilterAdjust) +#pragma alloc_text(PAGENDSA, ArcDeleteFilterOpenAdapter) +#pragma alloc_text(PAGENDSA, ArcNoteFilterOpenAdapter) +#pragma alloc_text(PAGENDSA, ArcCreateFilter) +#pragma alloc_text(PAGENDSA, ArcFilterDprIndicateReceive) +#pragma alloc_text(PAGENDSA, ArcConvertToNdisPacket) +#pragma alloc_text(PAGENDSA, ArcDestroyPacket) +#pragma alloc_text(PAGENDSA, ArcFreeNdisPacket) +#pragma alloc_text(PAGENDSA, ArcDiscardPacketBuffers) +#pragma alloc_text(PAGENDSA, ArcAllocatePackets) +#pragma alloc_text(PAGENDSA, ArcAllocateBuffers) +#pragma alloc_text(PAGENDSA, ArcConvertOidListToEthernet) +#endif + + + +NDIS_STATUS +ArcAllocateBuffers( + IN PARC_FILTER Filter + ) +/*++ + +Routine Description: + + This routine allocates Receive buffers for the filter database. + +Arguments: + + Filter - The filter db to allocate for. + +Returns: + + NDIS_STATUS_SUCCESS if any buffer was allocated. + +--*/ +{ + ULONG i; + PARC_BUFFER_LIST Buffer; + PVOID DataBuffer; + + for (i = ARC_BUFFER_ALLOCATION_UNIT; i != 0 ; i--) { + + NdisAllocateMemory((PVOID)&Buffer, + sizeof(ARC_BUFFER_LIST), + 0, + HighestAcceptableMax + ); + + if (Buffer == NULL) { + + if (i == ARC_BUFFER_ALLOCATION_UNIT) { + return(NDIS_STATUS_FAILURE); + } + + return(NDIS_STATUS_SUCCESS); + + } + + NdisAllocateMemory((PVOID)&DataBuffer, + ARC_BUFFER_SIZE, + 0, + HighestAcceptableMax + ); + + if (DataBuffer == NULL) { + + NdisFreeMemory(Buffer, sizeof(ARC_BUFFER_LIST), 0); + + if (i == ARC_BUFFER_ALLOCATION_UNIT) { + return(NDIS_STATUS_FAILURE); + } + + // + // We allocated some packets, that is good enough for now + // + return(NDIS_STATUS_SUCCESS); + + } + + Buffer->BytesLeft = Buffer->Size = ARC_BUFFER_SIZE; + Buffer->Buffer = DataBuffer; + Buffer->Next = Filter->FreeBufferList; + Filter->FreeBufferList = Buffer; + + } + + return(NDIS_STATUS_SUCCESS); + +} + + +NDIS_STATUS +ArcAllocatePackets( + IN PARC_FILTER Filter + ) +/*++ + +Routine Description: + + This routine allocates Receive packets for the filter database. + +Arguments: + + Filter - The filter db to allocate for. + +Returns: + + NDIS_STATUS_SUCCESS if any packet was allocated. + +--*/ +{ + ULONG i; + PARC_PACKET Packet; + + for (i = ARC_PACKET_ALLOCATION_UNIT; i != 0 ; i--) { + + NdisAllocateMemory((PVOID)&Packet, + sizeof(ARC_PACKET), + 0, + HighestAcceptableMax + ); + + if (Packet == NULL) { + + if (i == ARC_BUFFER_ALLOCATION_UNIT) { + return(NDIS_STATUS_FAILURE); + } + + return(NDIS_STATUS_SUCCESS); + + } + + NdisZeroMemory(Packet, sizeof(ARC_PACKET)); + + NdisReinitializePacket(&(Packet->TmpNdisPacket)); + + Packet->Next = Filter->FreePackets; + Filter->FreePackets = Packet; + + } + + return(NDIS_STATUS_SUCCESS); +} + + +VOID +ArcDiscardPacketBuffers( + IN PARC_FILTER Filter, + IN PARC_PACKET Packet + ) +/*++ + +Routine description: + + This routine takes an arcnet packet that contains buffers of data and + puts the buffers on the free list. + + NOTE: This assumes that LastBuffer points to the real last buffer + in the chain. + +Arguments: + + Filter - The filter to free the buffers to. + + Packet - The packet to free up. + +Return values: + + None + +--*/ +{ + PARC_BUFFER_LIST Buffer; + + // + // Reset Packet info + // + Packet->LastFrame = FALSE; + Packet->TotalLength = 0; + + // + // Reset buffer sizes + // + Buffer = Packet->FirstBuffer; + while (Buffer != NULL) { + Buffer->BytesLeft = Buffer->Size; + Buffer = Buffer->Next; + } + + // + // Put buffers on free list + // + if (Packet->LastBuffer != NULL) { + + Packet->LastBuffer->Next = Filter->FreeBufferList; + Filter->FreeBufferList = Packet->FirstBuffer; + Packet->FirstBuffer = Packet->LastBuffer = NULL; + + } + +} + + +VOID +ArcFreeNdisPacket( + IN PARC_PACKET Packet + ) +/*++ + +Routine description: + + This routine takes an arcnet packet and frees up the corresponding + Ndis packet built for it. + +Arguments: + + Packet - The packet to free up. + +Return values: + + None + +--*/ +{ + PNDIS_BUFFER NdisBuffer, NextNdisBuffer; + + NdisQueryPacket( + &(Packet->TmpNdisPacket), + NULL, + NULL, + &NdisBuffer, + NULL + ); + + while (NdisBuffer != NULL) { + + NdisGetNextBuffer( + NdisBuffer, + &NextNdisBuffer + ); + + NdisFreeBuffer( + NdisBuffer + ); + + NdisBuffer = NextNdisBuffer; + } + + NdisReinitializePacket(&(Packet->TmpNdisPacket)); + +} + + +VOID +ArcDestroyPacket( + IN PARC_FILTER Filter, + IN PARC_PACKET Packet + ) +/*++ + +Routine description: + + This routine takes an arcnet packet and frees up the entire packet. + +Arguments: + + Filter - Filter to free to. + + Packet - The packet to free up. + +Return values: + + None + +--*/ +{ + ArcFreeNdisPacket(Packet); + ArcDiscardPacketBuffers(Filter, Packet); + + // + // Now put packet on free list + // + Packet->Next = Filter->FreePackets; + Filter->FreePackets = Packet; +} + + +BOOLEAN +ArcConvertToNdisPacket( + IN PARC_FILTER Filter, + IN PARC_PACKET Packet, + IN BOOLEAN ConvertWholePacket + ) +/*++ + +Routine description: + + This routine builds a corresponding NDIS_PACKET in TmpNdisPacket, + that corresponds to the arcnet packet. The flag ConvertWholePacket + is used to convert only part of the arcnet packet, or the whole + stream. If the flag is FALSE, then only the buffers that have + free space (starting with buffer LastBuffer on up) are converted. + + NOTE: It assumes TmpNdisPacket is an initialized ndis_packet structure. + +Arguments: + + Filter - Filter to allocate from. + + Packet - The packet to convert. + + ConvertWholePacket - Convert the whole stream, or only part? + +Return values: + + TRUE - If successful, else FALSE + +--*/ +{ + PNDIS_BUFFER NdisBuffer; + PARC_BUFFER_LIST Buffer; + NDIS_STATUS NdisStatus; + + Buffer = Packet->FirstBuffer; + + while (Buffer != NULL) { + + NdisAllocateBuffer( + &NdisStatus, + &NdisBuffer, + Filter->ReceiveBufferPool, + Buffer->Buffer, + Buffer->Size - Buffer->BytesLeft + ); + + if (NdisStatus != NDIS_STATUS_SUCCESS) { + + return(FALSE); + + } + + NdisChainBufferAtBack( + &(Packet->TmpNdisPacket), + NdisBuffer + ); + + Buffer = Buffer->Next; + + } + + return(TRUE); +} + + +VOID +ArcFilterDprIndicateReceive( + IN PARC_FILTER Filter, // Pointer to filter database + IN PUCHAR pRawHeader, // Pointer to Arcnet frame header + IN PUCHAR pData, // Pointer to data portion of Arcnet frame + IN UINT Length // Data Length + ) +{ + ARC_PACKET_HEADER NewFrameInfo; + PARC_PACKET Packet, PrevPacket; + BOOLEAN FrameOk, NewFrame, LastFrame; + PARC_BUFFER_LIST Buffer; + UCHAR TmpUchar; + UINT TmpLength; + UINT TotalLength = Length; + PUCHAR OrigpData = pData; + USHORT TmpUshort; + + // + // Check for ethernet encapsulation first + // + + NdisReadRegisterUchar(pData, &TmpUchar); + + if ( TmpUchar == 0xE8 ) { + + // + // Yes! Indicate it to the wrapper for indicating to all + // protocols running ethernet on top of the arcnet miniport + // driver. + // + + NdisMArcIndicateEthEncapsulatedReceive( + Filter->Miniport, // miniport. + pRawHeader, // 878.2 header. + pData + 1, // ethernet header. + Length - 1 // length of ethernet frame. + ); + + // + // We're done. + // + + return; + } + + // + // Get information from packet + // + + NdisReadRegisterUchar(pRawHeader, + &(NewFrameInfo.ProtHeader.SourceId[0]) + ); + + NdisReadRegisterUchar(pRawHeader + 1, + &(NewFrameInfo.ProtHeader.DestId[0]) + ); + + NewFrameInfo.ProtHeader.ProtId = TmpUchar; + + // + // Read the split flag. If this is an exception packet (i.e. + // TmpUChar == 0xFF then we need to add an extra 3 onto + // pData to skip the series of 0xFF 0xFF 0xFF. + // + + pData++; //... Skip the SC byte. + + NdisReadRegisterUchar(pData, &TmpUchar); //... Read split flag. + + if ( TmpUchar == 0xFF ) { + + pData += 4; + Length -= 4; + + // + // Re-read the split flag. + // + + NdisReadRegisterUchar(pData, &TmpUchar); + } + + // + // Save off the split flag. + // + + NewFrameInfo.SplitFlag = TmpUchar; + + // + // Read the sequence number, which follows the split flag. + // + + NdisReadRegisterUchar(pData + 1, &TmpUshort); + NdisReadRegisterUchar(pData + 2, &TmpUchar); + TmpUshort = TmpUshort | (TmpUchar << 8); + NewFrameInfo.FrameSequence = TmpUshort; + + // + // Point pData at protocol data. + // + + pData += 3; //... Beginning of protocol data. + Length -= 4; //... Length of protocol data. + + // + // NOTE: Length is now the Length of the data portion of this packet + // + +#if DBG + if ( AfilterDebugFlag ){ + + DbgPrint("ArcFilter: Frame received: SourceId= %#1x\nDestId=%#1x\nProtId=%#1x\nSplitFlag=%#1x\nFrameSeq=%d\n", + (USHORT)NewFrameInfo.ProtHeader.SourceId[0], + (USHORT)NewFrameInfo.ProtHeader.DestId[0], + (USHORT)NewFrameInfo.ProtHeader.ProtId, + (USHORT)NewFrameInfo.SplitFlag, + NewFrameInfo.FrameSequence + ); + DbgPrint("ArcFilter: Data at address: %lx, Length = %ld\n", pData, Length); + + } +#endif + + FrameOk = TRUE; + NewFrame = TRUE; + LastFrame = TRUE; + + PrevPacket = NULL; + Packet = Filter->OutstandingPackets; + + // + // Walk throgh all outstanding packet to see if this frame belongs to any one of them + // + + while ( Packet != NULL ) { + + if (Packet->Header.ProtHeader.SourceId[0] == NewFrameInfo.ProtHeader.SourceId[0]){ + + // + // A packet received from the same source, check packet Sequence number and throw away + // outstanding packet if they don't match. We are allowed to do this since we know + // all the frames belonging to one packet are sent before starting a new packet. We + // HAVE to do this, because this is how we find out that a send at the other end, was aborted + // after some of the frames were already sent and received here. + // + + if(Packet->Header.FrameSequence == NewFrameInfo.FrameSequence && + Packet->Header.ProtHeader.DestId[0] == NewFrameInfo.ProtHeader.DestId[0] && + Packet->Header.ProtHeader.ProtId == NewFrameInfo.ProtHeader.ProtId){ + + // + // We found a packet that this frame belongs to, check split flag + // + if (Packet->Header.FramesReceived * 2 == NewFrameInfo.SplitFlag){ + + // + // A packet found for this frame and SplitFlag is OK, check to see if it is + // the last frame of the packet + // + NewFrame = FALSE; + LastFrame = (BOOLEAN)(NewFrameInfo.SplitFlag == Packet->Header.LastSplitFlag); + + } else { + + // + // compare current split flag with the one from the last frame, if not equal + // the whole packet should be dropped. + // + + if (Packet->Header.SplitFlag != NewFrameInfo.SplitFlag){ + + // + // Corrupted incomplete packet, get rid of it, but keep the new frame + // and we will re-use this Packet pointer. + // + ArcDiscardPacketBuffers(Filter, Packet); + break; + + } else { + + // + // We see to have received a duplicate frame. Ignore it. + // + return; + + } + + } + + } else { + + // + // We received a frame from a source that already has an incomplete packet outstanding + // But Frame Seq. or DestId or ProtId are not the same. + // We have to discard the old packet and check the new frame for validity, + // we will re-use this packet pointer below. + // + ArcDiscardPacketBuffers(Filter, Packet); + + } + + break; + + } else { + + PrevPacket = Packet; + Packet = Packet->Next; + + } + + } + + + if (NewFrame) { + + // + // first frame of a packet, split flag must be odd or zero + // NewFrame is already TRUE + // LastFrame is already TRUE + // + if (NewFrameInfo.SplitFlag) { + + if (!(NewFrameInfo.SplitFlag & 0x01)) { + + // + // This frame is the middle of another split, but we + // don't have it on file. Drop the frame. + // + return; + + } + + // + // First Frame of a multiple frame packet + // + NewFrameInfo.LastSplitFlag = NewFrameInfo.SplitFlag + 1; + NewFrameInfo.FramesReceived = 1; + LastFrame = FALSE; // New packet and SplitFlag not zero + + } else { + + // + // The frame is fully contained in this packet. + // + } + + // + // allocate a new packet descriptor if it is a new packet + // + if (Packet == NULL) { + + if (Filter->FreePackets == NULL) { + + ArcAllocatePackets(Filter); + + if (Filter->FreePackets == NULL) { + + return; + + } + + } + + Packet = Filter->FreePackets; + Filter->FreePackets = Packet->Next; + + if (!LastFrame) { + + // + // Insert the packet in list of outstanding packets + // + Packet->Next = Filter->OutstandingPackets; + Filter->OutstandingPackets = Packet; + + } + + } else { + + if (LastFrame) { + + // + // remove it from the list + // + if (PrevPacket == NULL) { + + Filter->OutstandingPackets = Packet->Next; + + } else { + + PrevPacket->Next = Packet->Next; + + } + + } + + } + + Packet->Header = NewFrameInfo; + + } else { + + if (LastFrame) { + + // + // Remove it from the queue + // + + if (PrevPacket == NULL) { + + Filter->OutstandingPackets = Packet->Next; + + } else { + + PrevPacket->Next = Packet->Next; + + } + + } + + Packet->Header.FramesReceived++; + + // + // keep track of last split flag to detect duplicate frames + // + Packet->Header.SplitFlag=NewFrameInfo.SplitFlag; + + } + + // + // At this point we know Packet points to the packet to receive + // the buffer into. If this is the LastFrame, then Packet will + // have been removed from the OutstandingPackets list, otw it will + // be in the list. + // + // Now get around to getting space for the buffer. + // + + // + // Find the last buffer in the packet + // + Buffer = Packet->LastBuffer; + + if (Buffer == NULL) { + + // + // Allocate a new buffer to hold the packet + // + if (Filter->FreeBufferList == NULL) { + + if (ArcAllocateBuffers(Filter) != NDIS_STATUS_SUCCESS) { + + ArcDiscardPacketBuffers(Filter,Packet); + // + // Do not have to discard any packet that may have + // been allocated above, as it will get discarded + // the next time a packet comes in from that source. + // + return; + + } + + } + + Buffer = Filter->FreeBufferList; + Filter->FreeBufferList = Buffer->Next; + + Packet->FirstBuffer = Packet->LastBuffer = Buffer; + Buffer->Next = NULL; + + } + + // Copy the data off into the ARC_PACKET list. + // If it doesn't fit within the current buffer, we'll need to + // allocate more + + TmpLength = Length; + + while ( Buffer->BytesLeft < TmpLength ) { + + // + // Copy the data + // + + NdisMoveFromMappedMemory( + (PUCHAR) Buffer->Buffer + (Buffer->Size - Buffer->BytesLeft), + pData, + Buffer->BytesLeft + ); + + pData += Buffer->BytesLeft; + TmpLength -= Buffer->BytesLeft; + Buffer->BytesLeft = 0; + + // + // Need to allocate more + // + if (Filter->FreeBufferList == NULL) { + + if (ArcAllocateBuffers(Filter) != NDIS_STATUS_SUCCESS) { + + ArcDiscardPacketBuffers(Filter,Packet); + // + // Do not have to discard any packet that may have + // been allocated above, as it will get discarded + // the next time a packet comes in from that source. + // + return; + + } + + } + + Buffer->Next = Filter->FreeBufferList; + Filter->FreeBufferList = Filter->FreeBufferList->Next; + Buffer = Buffer->Next; + Buffer->Next = NULL; + + Packet->LastBuffer->Next = Buffer; + Packet->LastBuffer = Buffer; + } + + // + // Copy the last bit + // + + NdisMoveFromMappedMemory( + (PUCHAR) Buffer->Buffer + (Buffer->Size - Buffer->BytesLeft), + pData, + TmpLength + ); + + + Buffer->BytesLeft -= TmpLength; + Packet->TotalLength += Length; + + // + // And now we can start indicating the packet to the bindings that want it + // + + if (LastFrame){ + + ArcFilterDoIndication( + Filter, + Packet + ); + + ArcDestroyPacket(Filter, Packet); + + } + +} + + + +BOOLEAN +ArcCreateFilter( + IN PNDIS_MINIPORT_BLOCK Miniport, + IN ARC_FILTER_CHANGE FilterChangeAction, + IN ARC_DEFERRED_CLOSE CloseAction, + UCHAR AdapterAddress, + IN PNDIS_SPIN_LOCK Lock, + OUT PARC_FILTER *Filter + ) + +/*++ + +Routine Description: + + This routine is used to create and initialize the Arcnet filter database. + +Arguments: + + Miniport - Pointer to the mini-port object. + + ChangeAction - Action routine to call when a binding sets or clears + a particular filter class and it is the first or only binding using + the filter class. + + CloseAction - This routine is called if a binding closes while + it is being indicated to via NdisIndicateReceive. It will be + called upon return from NdisIndicateReceive. + + AdapterAddress - the address of the adapter associated with this filter + database. + + Lock - Pointer to the lock that should be held when mutual exclusion + is required. + + Filter - A pointer to an ARC_FILTER. This is what is allocated and + created by this routine. + +Return Value: + + If the function returns false then one of the parameters exceeded + what the filter was willing to support. + +--*/ + +{ + + PARC_FILTER LocalFilter; + NDIS_STATUS AllocStatus; + + // + // Allocate the database and it's associated arrays. + // + + AllocStatus = NdisAllocateMemory(&LocalFilter, sizeof(ARC_FILTER), 0, HighestAcceptableMax); + *Filter = LocalFilter; + + if (AllocStatus != NDIS_STATUS_SUCCESS) { + return FALSE; + } + + NdisZeroMemory( + LocalFilter, + sizeof(ARC_FILTER) + ); + + LocalFilter->Miniport = Miniport; + LocalFilter->FreeBindingMask = (ULONG)(-1); + LocalFilter->OpenList = NULL; + LocalFilter->AdapterAddress = AdapterAddress ; + LocalFilter->Lock = Lock; + LocalFilter->FilterChangeAction = FilterChangeAction; + LocalFilter->CloseAction = CloseAction; + + NdisAllocateBufferPool( + &AllocStatus, + (PNDIS_HANDLE)(&LocalFilter->ReceiveBufferPool), + ARC_RECEIVE_BUFFERS + ); + + if (AllocStatus != NDIS_STATUS_SUCCESS) { + + NdisFreeMemory(LocalFilter, sizeof(ARC_FILTER), 0); + return(FALSE); + } + + ArcReferencePackage(); + + return TRUE; + +} + +// +// NOTE: THIS CANNOT BE PAGEABLE +// +VOID +ArcDeleteFilter( + IN PARC_FILTER Filter + ) + +/*++ + +Routine Description: + + This routine is used to delete the memory associated with a filter + database. Note that this routines *ASSUMES* that the database + has been cleared of any active filters. + +Arguments: + + Filter - A pointer to an ARC_FILTER to be deleted. + +Return Value: + + None. + +--*/ + +{ + PARC_PACKET Packet; + PARC_BUFFER_LIST Buffer; + + ASSERT(Filter->FreeBindingMask == (MASK)-1); + ASSERT(Filter->OpenList == NULL); + + + NdisFreeBufferPool(Filter->ReceiveBufferPool); + + // + // Free all ARC_PACKETS + // + + while (Filter->OutstandingPackets != NULL) { + + Packet = Filter->OutstandingPackets; + Filter->OutstandingPackets = Packet->Next; + + // + // This puts all the component parts on the free lists. + // + ArcDestroyPacket(Filter, Packet); + + } + + while (Filter->FreePackets != NULL) { + + Packet = Filter->FreePackets; + Filter->FreePackets = Packet->Next; + + ExFreePool(Packet); + + } + + while (Filter->FreeBufferList) { + + Buffer = Filter->FreeBufferList; + Filter->FreeBufferList = Buffer->Next; + + ExFreePool(Buffer->Buffer); + ExFreePool(Buffer); + + } + + NdisFreeMemory(Filter, sizeof(ARC_FILTER), 0); + + ArcDereferencePackage(); + +} + + +BOOLEAN +ArcNoteFilterOpenAdapter( + IN PARC_FILTER Filter, + IN NDIS_HANDLE MacBindingHandle, + IN NDIS_HANDLE NdisBindingContext, + OUT PNDIS_HANDLE NdisFilterHandle + ) + +/*++ + +Routine Description: + + This routine is used to add a new binding to the filter database. + + NOTE: THIS ROUTINE ASSUMES THAT THE DATABASE IS LOCKED WHEN + IT IS CALLED. + +Arguments: + + Filter - A pointer to the previously created and initialized filter + database. + + MacBindingHandle - The MAC supplied value to the protocol in response + to a call to NdisOpenAdapter. + + NdisBindingContext - An NDIS supplied value to the call to NdisOpenAdapter. + + NdisFilterHandle - A pointer to this open. + +Return Value: + + Will return false if creating a new filter index will cause the maximum + number of filter indexes to be exceeded. + +--*/ + +{ + + // + // Will hold the value of the filter index so that we + // need not indirectly address through pointer parameter. + // + UINT LocalIndex; + + NDIS_STATUS AllocStatus; + + // + // Pointer to new open block. + // + PARC_BINDING_INFO LocalOpen; + + + // + // Get the first free binding slot and remove that slot from + // the free list. We check to see if the list is empty. + // + + + if (Filter->FreeBindingMask == 0) { + + return FALSE; + + } + + AllocStatus = NdisAllocateMemory( + &LocalOpen, + sizeof(ARC_BINDING_INFO), + 0, + HighestAcceptableMax + ); + + if (AllocStatus != NDIS_STATUS_SUCCESS) { + + return FALSE; + + } + + // + // Get place for the open and insert it. + // + + ARC_FILTER_ALLOC_OPEN(Filter, &LocalIndex); + + LocalOpen->NextOpen = Filter->OpenList; + + if (Filter->OpenList != NULL) { + Filter->OpenList->PrevOpen = LocalOpen; + } + + LocalOpen->PrevOpen = NULL; + + Filter->OpenList = LocalOpen; + + LocalOpen->FilterIndex = (UCHAR)LocalIndex; + LocalOpen->References = 1; + LocalOpen->MacBindingHandle = MacBindingHandle; + LocalOpen->NdisBindingContext = NdisBindingContext; + LocalOpen->PacketFilters = 0; + LocalOpen->ReceivedAPacket = FALSE; + + *NdisFilterHandle = (NDIS_HANDLE)LocalOpen; + + return TRUE; + +} + + +NDIS_STATUS +ArcDeleteFilterOpenAdapter( + IN PARC_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest + ) + +/*++ + +Routine Description: + + When an adapter is being closed this routine should + be called to delete knowledge of the adapter from + the filter database. This routine is likely to call + action routines associated with clearing filter classes + and addresses. + + NOTE: THIS ROUTINE SHOULD ****NOT**** BE CALLED IF THE ACTION + ROUTINES FOR DELETING THE FILTER CLASSES OR THE MULTICAST ADDRESSES + HAVE ANY POSSIBILITY OF RETURNING A STATUS OTHER THAN NDIS_STATUS_PENDING + OR NDIS_STATUS_SUCCESS. WHILE THESE ROUTINES WILL NOT BUGCHECK IF + SUCH A THING IS DONE, THE CALLER WILL PROBABLY FIND IT DIFFICULT + TO CODE A CLOSE ROUTINE! + + NOTE: THIS ROUTINE ASSUMES THAT IT IS CALLED WITH THE LOCK HELD. + +Arguments: + + Filter - A pointer to the filter database. + + NdisFilterHandle - Pointer to the open. + + NdisRequest - If it is necessary to call the action routines, + this will be passed to it. + +Return Value: + + If action routines are called by the various address and filtering + routines the this routine will likely return the status returned + by those routines. The exception to this rule is noted below. + + Given that the filter and address deletion routines return a status + NDIS_STATUS_PENDING or NDIS_STATUS_SUCCESS this routine will then + try to return the filter index to the freelist. If the routine + detects that this binding is currently being indicated to via + NdisIndicateReceive, this routine will return a status of + NDIS_STATUS_CLOSING_INDICATING. + +--*/ + +{ + + // + // Holds the status returned from the packet filter and address + // deletion routines. Will be used to return the status to + // the caller of this routine. + // + NDIS_STATUS StatusToReturn; + + // + // Local variable. + // + PARC_BINDING_INFO LocalOpen = (PARC_BINDING_INFO)NdisFilterHandle; + + StatusToReturn = ArcFilterAdjust( + Filter, + NdisFilterHandle, + NdisRequest, + (UINT)0, + FALSE + ); + + if ((StatusToReturn == NDIS_STATUS_SUCCESS) || + (StatusToReturn == NDIS_STATUS_PENDING)) { + + // + // Remove the reference from the original open. + // + + if (--(LocalOpen->References) == 0) { + + // + // Remove it from the list. + // + + if (LocalOpen->NextOpen != NULL) { + + LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen; + + } + + if (LocalOpen->PrevOpen != NULL) { + + LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen; + + } else { + + Filter->OpenList = LocalOpen->NextOpen; + + } + + + // + // First we finish any NdisIndicateReceiveComplete that + // may be needed for this binding. + // + + if (LocalOpen->ReceivedAPacket) { + + RELEASE_SPIN_LOCK_DPC(Filter->Lock); + + FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext); + + ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + + } + ARC_FILTER_FREE_OPEN(Filter, LocalOpen); + + } else { + + // + // Let the caller know that there is a reference to the open + // by the receive indication. The close action routine will be + // called upon return from NdisIndicateReceive. + // + + StatusToReturn = NDIS_STATUS_CLOSING_INDICATING; + + } + + } + + return StatusToReturn; + +} + + +NDIS_STATUS +ArcFilterAdjust( + IN PARC_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest, + IN UINT FilterClasses, + IN BOOLEAN Set + ) + +/*++ + +Routine Description: + + The FilterAdjust routine will call an action routine when a + particular filter class is changes from not being used by any + binding to being used by at least one binding or vice versa. + + If the action routine returns a value other than pending or + success then this routine has no effect on the packet filters + for the open or for the adapter as a whole. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + +Arguments: + + Filter - A pointer to the filter database. + + NdisFilterHandle - A pointer to the open. + + NdisRequest - If it is necessary to call the action routine, + this will be passed to it. + + FilterClasses - The filter classes that are to be added or + deleted. + + Set - A boolean that determines whether the filter classes + are being adjusted due to a set or because of a close. (The filtering + routines don't care, the MAC might.) + +Return Value: + + If it calls the action routine then it will return the + status returned by the action routine. If the status + returned by the action routine is anything other than + NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database + will be returned to the state it was in upon entrance to this + routine. + + If the action routine is not called this routine will return + the following statum: + + NDIS_STATUS_SUCCESS - If the new packet filters doesn't change + the combined mask of all bindings packet filters. + +--*/ + +{ + // + // Contains the value of the combined filter classes before + // it is adjusted. + // + UINT OldCombined = Filter->CombinedPacketFilter; + + PARC_BINDING_INFO LocalOpen = (PARC_BINDING_INFO)NdisFilterHandle; + PARC_BINDING_INFO OpenList; + + // + // Contains the value of the particlar opens packet filters + // prior to the change. We save this incase the action + // routine (if called) returns an "error" status. + // + UINT OldOpenFilters = LocalOpen->PacketFilters; + + // + // Holds the status returned to the user of this routine, if the + // action routine is not called then the status will be success, + // otherwise, it is whatever the action routine returns. + // + NDIS_STATUS StatusOfAdjust; + + // + // Set the new filter information for the open. + // + + LocalOpen->PacketFilters = FilterClasses; + + // + // We always have to reform the compbined filter since + // this filter index may have been the only filter index + // to use a particular bit. + // + + + for ( + OpenList = Filter->OpenList, + Filter->CombinedPacketFilter = 0; + OpenList != NULL; + OpenList = OpenList->NextOpen + ) { + + Filter->CombinedPacketFilter |= + OpenList->PacketFilters; + + } + + if (OldCombined != Filter->CombinedPacketFilter) { + + StatusOfAdjust = Filter->FilterChangeAction( + OldCombined, + Filter->CombinedPacketFilter, + LocalOpen->MacBindingHandle, + NdisRequest, + Set + ); + + if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) && + (StatusOfAdjust != NDIS_STATUS_PENDING)) { + + // + // The user returned a bad status. Put things back as + // they were. + // + + LocalOpen->PacketFilters = OldOpenFilters; + Filter->CombinedPacketFilter = OldCombined; + + } + + } else { + + StatusOfAdjust = NDIS_STATUS_SUCCESS; + + } + + return StatusOfAdjust; + +} + + +VOID +ArcFilterDoIndication( + IN PARC_FILTER Filter, + IN PARC_PACKET Packet + ) + +/*++ + +Routine Description: + + This routine is called by the filter package only to indicate + that a packet is ready to be indicated to procotols. + +Arguments: + + Filter - Pointer to the filter database. + + Packet - Packet to indicate. + +Return Value: + + None. + +--*/ + +{ + + // + // Will hold the type of address that we know we've got. + // + UINT AddressType; + + NDIS_STATUS StatusOfReceive; + + // + // Will hold the filter classes of the binding being indicated. + // + UINT BindingFilters; + + // + // Current Open to indicate to. + // + PARC_BINDING_INFO LocalOpen; + + if (Packet->Header.ProtHeader.DestId[0] != 0x00) { + AddressType = NDIS_PACKET_TYPE_DIRECTED; + } else { + AddressType = NDIS_PACKET_TYPE_BROADCAST; + } + + // + // We need to acquire the filter exclusively while we're finding + // bindings to indicate to. + // + + LocalOpen = Filter->OpenList; + + if (!ArcConvertToNdisPacket(Filter, Packet, TRUE)) { + + // + // Out of resources, abort. + // + return; + + } + + while (LocalOpen != NULL) { + + // + // Reference the open during indication. + // + + BindingFilters = LocalOpen->PacketFilters; + + if (BindingFilters & AddressType){ + + LocalOpen->References++; + + RELEASE_SPIN_LOCK_DPC(Filter->Lock); + + // + // Indicate the packet to the binding. + // + FilterIndicateReceive( + &StatusOfReceive, + LocalOpen->NdisBindingContext, + &Packet->TmpNdisPacket, + &(Packet->Header.ProtHeader), + 3, + Packet->FirstBuffer->Buffer, + Packet->FirstBuffer->Size - Packet->FirstBuffer->BytesLeft, + Packet->TotalLength + ); + + ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + + LocalOpen->ReceivedAPacket = TRUE; + + if ((--(LocalOpen->References)) == 0) { + + PARC_BINDING_INFO NextOpen = LocalOpen->NextOpen; + + // + // This binding is shutting down. We have to remove it. + // + + // + // Remove it from the list. + // + + if (LocalOpen->NextOpen != NULL) { + + LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen; + + } + + if (LocalOpen->PrevOpen != NULL) { + + LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen; + + } else { + + Filter->OpenList = LocalOpen->NextOpen; + + } + + + + // + // Call the IndicateComplete routine. + // + + + if (LocalOpen->ReceivedAPacket) { + + RELEASE_SPIN_LOCK_DPC(Filter->Lock); + + FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext); + + ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + + } + + // + // Call the macs action routine so that they know we + // are no longer referencing this open binding. + // + + Filter->CloseAction(LocalOpen->MacBindingHandle); + + + ARC_FILTER_FREE_OPEN(Filter, LocalOpen); + + LocalOpen = NextOpen; + + continue; + + } // end of if binding is shutting down + + } // end of if any binding wants the packet + + LocalOpen = LocalOpen->NextOpen; + + } // end of there are more open bindings + +} + + +VOID +ArcFilterDprIndicateReceiveComplete( + IN PARC_FILTER Filter + ) + +/*++ + +Routine Description: + + This routine is called by to indicate that the receive + process is complete to all bindings. Only those bindings which + have received packets will be notified. + +Arguments: + + Filter - Pointer to the filter database. + +Return Value: + + None. + +--*/ +{ + + PARC_BINDING_INFO LocalOpen; + + // + // We need to acquire the filter exclusively while we're finding + // bindings to indicate to. + // + + LocalOpen = Filter->OpenList; + + while (LocalOpen != NULL) { + + if (LocalOpen->ReceivedAPacket) { + + // + // Indicate the binding. + // + + LocalOpen->ReceivedAPacket = FALSE; + + LocalOpen->References++; + + RELEASE_SPIN_LOCK_DPC(Filter->Lock); + + FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext); + + ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + + if ((--(LocalOpen->References)) == 0) { + + PARC_BINDING_INFO NextOpen = LocalOpen->NextOpen; + + // + // This binding is shutting down. We have to kill it. + // + + // + // Remove it from the list. + // + + if (LocalOpen->NextOpen != NULL) { + + LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen; + + } + + if (LocalOpen->PrevOpen != NULL) { + + LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen; + + } else { + + Filter->OpenList = LocalOpen->NextOpen; + + } + + + // + // Call the macs action routine so that they know we + // are no longer referencing this open binding. + // + + Filter->CloseAction(LocalOpen->MacBindingHandle); + + + ARC_FILTER_FREE_OPEN(Filter, LocalOpen); + + LocalOpen = NextOpen; + + continue; + + } + + } + + LocalOpen = LocalOpen->NextOpen; + + } + +} + + +NDIS_STATUS ArcConvertOidListToEthernet( + IN PNDIS_OID pOidList, + IN PULONG pcOidList, + IN PNDIS_OID pTmpBuffer +) + +/*++ + +Routine Description: + + This routine converts an arcnet supported OID list into + an ethernet OID list by replacing or removing arcnet + OID's. + +Arguments: + +Return Value: + + None. + +--*/ + +{ + ULONG c; + ULONG cArcOids; + ULONG cMaxOids; + NDIS_OID EthernetOidList[ARC_NUMBER_OF_EXTRA_OIDS] = { + OID_802_3_MULTICAST_LIST, + OID_802_3_MAXIMUM_LIST_SIZE + }; + + // + // Now we need to copy the returned results into the callers buffer, + // removing arcnet OID's and adding in ethernet OID's. At this point + // we do not know if the callers buffer is big enough since we may + // remove some entries, checking it up front may not yield correct + // results (i.e. it may actually be big enough). + // + for (c = 0, cArcOids = 0; c < *pcOidList; c++) + { + switch (pOidList[c]) + { + case OID_ARCNET_PERMANENT_ADDRESS: + pTmpBuffer[cArcOids++] = OID_802_3_PERMANENT_ADDRESS; + break; + + case OID_ARCNET_CURRENT_ADDRESS: + pTmpBuffer[cArcOids++] = OID_802_3_CURRENT_ADDRESS; + break; + + case OID_ARCNET_RECONFIGURATIONS: + break; + + default: + if ((pOidList[c] & 0xFFF00000) != 0x06000000) + pTmpBuffer[cArcOids++] = pOidList[c]; + + break; + } + } + + // + // Copy the ARCnet OIDs from the temp buffer to the + // callers buffer. + // + RtlCopyMemory(pOidList, pTmpBuffer, cArcOids * sizeof(NDIS_OID)); + + // + // Add the ethernet OIDs. + // + RtlCopyMemory( + (PUCHAR)pOidList + (cArcOids * sizeof(NDIS_OID)), + EthernetOidList, + ARC_NUMBER_OF_EXTRA_OIDS * sizeof(NDIS_OID) + ); + + // + // Update the size of the buffer to send back to the caller. + // + *pcOidList = cArcOids + ARC_NUMBER_OF_EXTRA_OIDS; + + return(NDIS_STATUS_SUCCESS); +} diff --git a/private/ntos/ndis/ndis30/afilter.h b/private/ntos/ndis/ndis30/afilter.h new file mode 100644 index 000000000..1bfa9e97f --- /dev/null +++ b/private/ntos/ndis/ndis30/afilter.h @@ -0,0 +1,339 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + afilter.h + +Abstract: + + Header file for the address filtering library for NDIS MAC's. + +Author: + + Alireza Dabagh creation-date 3-22-1993, mostly borrowed from efilter.h + +Revision History: + +--*/ + +#ifndef _ARC_FILTER_DEFS_ +#define _ARC_FILTER_DEFS_ + +// +// Number of Ndis buffers in the buffer pool +// +#define ARC_RECEIVE_BUFFERS 64 + +// +// Linked list Structure for keeping track of allocated memory so we can free them later +// +typedef struct _ARC_BUFFER_LIST{ + PVOID Buffer; + UINT Size; + UINT BytesLeft; + struct _ARC_BUFFER_LIST *Next; +} ARC_BUFFER_LIST, *PARC_BUFFER_LIST; + +// +// This is the structure that is passed to the protocol as the packet +// header during receive indication. It is also the header expected from the protocol. +// This header is NOT the same as the header passed to the mac driver +// + +#define ARCNET_ADDRESS_LEN 1 + +typedef struct _ARC_PROTOCOL_HEADER { + UCHAR SourceId[ARCNET_ADDRESS_LEN]; // Source Address + UCHAR DestId[ARCNET_ADDRESS_LEN]; // Destination Address + UCHAR ProtId; // Protocol ID +} ARC_PROTOCOL_HEADER, *PARC_PROTOCOL_HEADER; + +// +// This structure keeps track of information about a received packet +// +typedef struct _ARC_PACKET_HEADER { + ARC_PROTOCOL_HEADER ProtHeader; // Protocol header + USHORT FrameSequence; // Frame sequence Number + UCHAR SplitFlag; // Split flag + UCHAR LastSplitFlag; // Split Flag for the last frame + UCHAR FramesReceived; // Frames in This Packet +} ARC_PACKET_HEADER, * PARC_PACKET_HEADER; + +// +// Arcnet specific packet header +// +typedef struct _ARC_PACKET { + ARC_PACKET_HEADER Header; // Information about the packet + struct _ARC_PACKET * Next; // Next packet in use by filter + ULONG TotalLength; + BOOLEAN LastFrame; + PARC_BUFFER_LIST FirstBuffer; + PARC_BUFFER_LIST LastBuffer; + NDIS_PACKET TmpNdisPacket; +} ARC_PACKET, * PARC_PACKET; + + +#define ARC_PROTOCOL_HEADER_SIZE (sizeof(ARC_PROTOCOL_HEADER)) +#define ARC_MAX_FRAME_SIZE 504 +#define ARC_MAX_ADDRESS_IDS 256 +#define ARC_MAX_FRAME_HEADER_SIZE 6 +#define ARC_MAX_PACKET_SIZE 576 + + +// +// Check whether an address is broadcast. +// + +#define ARC_IS_BROADCAST(Address) \ + (BOOLEAN)(!(Address)) + + +// +// An action routine type. The routines are called +// when a filter type is set for the first time or +// no more bindings require a particular type of filter. +// +// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED. +// +typedef +NDIS_STATUS +(*ARC_FILTER_CHANGE)( + IN UINT OldFilterClasses, + IN UINT NewFilterClasses, + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest, + IN BOOLEAN Set + ); + + +// +// This action routine is called when the mac requests a close for +// a particular binding *WHILE THE BINDING IS BEING INDICATED TO +// THE PROTOCOL*. The filtering package can't get rid of the open +// right away. So this routine will be called as soon as the +// NdisIndicateReceive returns. +// +// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED. +// +typedef +VOID +(*ARC_DEFERRED_CLOSE)( + IN NDIS_HANDLE MacBindingHandle + ); + +typedef ULONG MASK,*PMASK; + +// +// Maximum number of opens the filter package will support. This is +// the max so that bit masks can be used instead of a spaghetti of +// pointers. +// +#define ARC_FILTER_MAX_OPENS (sizeof(ULONG) * 8) + + +// +// The binding info is threaded on two lists. When +// the binding is free it is on a single freelist. +// +// When the binding is being used it is on a doubly linked +// index list. +// +typedef struct _ARC_BINDING_INFO { + NDIS_HANDLE MacBindingHandle; + NDIS_HANDLE NdisBindingContext; + UINT PacketFilters; + ULONG References; + struct _ARC_BINDING_INFO *NextOpen; + struct _ARC_BINDING_INFO *PrevOpen; + BOOLEAN ReceivedAPacket; + UCHAR FilterIndex; +} ARC_BINDING_INFO,*PARC_BINDING_INFO; + +// +// An opaque type that contains a filter database. +// The MAC need not know how it is structured. +// +typedef struct _ARC_FILTER { + + // + // For accessing the mini-port. + // + struct _NDIS_MINIPORT_BLOCK *Miniport; + + // + // Spin lock used to protect the filter from multiple accesses. + // + PNDIS_SPIN_LOCK Lock; + + // + // Combination of all the filters of all the open bindings. + // + UINT CombinedPacketFilter; + + // + // Pointer for traversing the open list. + // + PARC_BINDING_INFO OpenList; + + // + // Action routines to be invoked on notable changes in the filter. + // + + ARC_FILTER_CHANGE FilterChangeAction; + ARC_DEFERRED_CLOSE CloseAction; + + // + // Bit mask of opens that are available. + // + ULONG FreeBindingMask; + + NDIS_HANDLE ReceiveBufferPool; + + PARC_BUFFER_LIST FreeBufferList; + PARC_PACKET FreePackets; + + PARC_PACKET OutstandingPackets; + + // + // Address of the adapter. + // + UCHAR AdapterAddress; + +} ARC_FILTER,*PARC_FILTER; + + + + +// +//UINT +//ARC_QUERY_FILTER_CLASSES( +// IN PARC_FILTER Filter +// ) +// +// This macro returns the currently enabled filter classes. +// +// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD. +// +#define ARC_QUERY_FILTER_CLASSES(Filter) ((Filter)->CombinedPacketFilter) + + +// +//UINT +//ARC_QUERY_PACKET_FILTER( +// IN ARC_FILTER Filter, +// IN NDIS_HANDLE NdisFilterHandle +// ) +// +// This macro returns the currently enabled filter classes for a specific +// open instance. +// +// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD. +// +#define ARC_QUERY_PACKET_FILTER(Filter, NdisFilterHandle) \ + (((PARC_BINDING_INFO)(NdisFilterHandle))->PacketFilters) + +// +// Only for internal wrapper use. +// +VOID +ArcInitializePackage( + VOID + ); + +VOID +ArcReferencePackage( + VOID + ); + +VOID +ArcDereferencePackage( + VOID + ); + + +// +// Exported routines +// + +BOOLEAN +ArcCreateFilter( + IN struct _NDIS_MINIPORT_BLOCK *Miniport, + IN ARC_FILTER_CHANGE FilterChangeAction, + IN ARC_DEFERRED_CLOSE CloseAction, + IN UCHAR AdapterAddress, + IN PNDIS_SPIN_LOCK Lock, + OUT PARC_FILTER *Filter + ); + +VOID +ArcDeleteFilter( + IN PARC_FILTER Filter + ); + +BOOLEAN +ArcNoteFilterOpenAdapter( + IN PARC_FILTER Filter, + IN NDIS_HANDLE MacBindingHandle, + IN NDIS_HANDLE NdisBindingContext, + OUT PNDIS_HANDLE NdisFilterHandle + ); + +NDIS_STATUS +ArcDeleteFilterOpenAdapter( + IN PARC_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest + ); + +NDIS_STATUS +ArcFilterAdjust( + IN PARC_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest, + IN UINT FilterClasses, + IN BOOLEAN Set + ); + +VOID +ArcFilterDprIndicateReceiveComplete( + IN PARC_FILTER Filter + ); + +VOID +ArcFilterDprIndicateReceive( + IN PARC_FILTER Filter, // Pointer to filter database + IN PUCHAR pRawHeader, // Pointer to Arcnet frame header + IN PUCHAR pData, // Pointer to data portion of Arcnet frame + IN UINT Length // Data Length + ); + +NDIS_STATUS +ArcFilterTransferData( + IN PARC_FILTER Filter, + IN NDIS_HANDLE MacReceiveContext, + IN UINT ByteOffset, + IN UINT BytesToTransfer, + OUT PNDIS_PACKET Packet, + OUT PUINT BytesTransfered + ); + +VOID +ArcFreeNdisPacket( + IN PARC_PACKET Packet + ); + +VOID +ArcFilterDoIndication( + IN PARC_FILTER Filter, + IN PARC_PACKET Packet + ); + +VOID +ArcDestroyPacket( + IN PARC_FILTER Filter, + IN PARC_PACKET Packet + ); + +#endif // _ARC_FILTER_DEFS_ diff --git a/private/ntos/ndis/ndis30/efilter.c b/private/ntos/ndis/ndis30/efilter.c new file mode 100644 index 000000000..98ebac0c3 --- /dev/null +++ b/private/ntos/ndis/ndis30/efilter.c @@ -0,0 +1,2252 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + efilter.c + +Abstract: + + This module implements a set of library routines to handle packet + filtering for NDIS MAC drivers. + +Author: + + Anthony V. Ercolano (Tonye) 03-Aug-1990 + +Environment: + + Kernel Mode - Or whatever is the equivalent on OS/2 and DOS. + +Revision History: + + Adam Barr (adamba) 28-Nov-1990 + + - Added AddressContexts + + Adam Barr (adamba) 28-May-1991 + + - renamed MacXXX to EthXXX, changed filter.c to efilter.c + + +--*/ + +#include <precomp.h> +#pragma hdrstop + +// +// This constant is used for places where NdisAllocateMemory +// needs to be called and the HighestAcceptableAddress does +// not matter. +// + +static const NDIS_PHYSICAL_ADDRESS HighestAcceptableMax = + NDIS_PHYSICAL_ADDRESS_CONST(-1,-1); + +// +// ZZZ NonPortable definitions. +// +#define AllocPhys(s, l) NdisAllocateMemory((PVOID *)(s), (l), 0, HighestAcceptableMax) +#define FreePhys(s, l) NdisFreeMemory((PVOID)(s), (l), 0) + +#ifdef NDIS_NT + +#define MoveMemory(Destination,Source,Length) RtlMoveMemory(Destination,Source,Length) +#define ZeroMemory(Destination,Length) RtlZeroMemory(Destination,Length) + +#endif + +#ifdef NDIS_DOS + +#define MoveMemory(Destination,Source,Length) NdisMoveOverlappedMemory(Destination,Source,Length) +#define ZeroMemory(Destination,Length) NdisZeroMemory(Destination,Length) + +#endif + +#if DBG +extern BOOLEAN NdisCheckBadDrivers; +#endif + +// +// A set of macros to manipulate bitmasks. +// + +//VOID +//CLEAR_BIT_IN_MASK( +// IN UINT Offset, +// IN OUT PETH_MASK MaskToClear +// ) +// +///*++ +// +//Routine Description: +// +// Clear a bit in the bitmask pointed to by the parameter. +// +//Arguments: +// +// Offset - The offset (from 0) of the bit to altered. +// +// MaskToClear - Pointer to the mask to be adjusted. +// +//Return Value: +// +// None. +// +//--*/ +// +#define CLEAR_BIT_IN_MASK(Offset,MaskToClear) *MaskToClear &= (~(1 << Offset)) + +//VOID +//SET_BIT_IN_MASK( +// IN UINT Offset, +// IN OUT PETH_MASK MaskToSet +// ) +// +///*++ +// +//Routine Description: +// +// Set a bit in the bitmask pointed to by the parameter. +// +//Arguments: +// +// Offset - The offset (from 0) of the bit to altered. +// +// MaskToSet - Pointer to the mask to be adjusted. +// +//Return Value: +// +// None. +// +//--*/ +#define SET_BIT_IN_MASK(Offset,MaskToSet) *MaskToSet |= (1 << Offset) + +//BOOLEAN +//IS_BIT_SET_IN_MASK( +// IN UINT Offset, +// IN ETH_MASK MaskToTest +// ) +// +///*++ +// +//Routine Description: +// +// Tests if a particular bit in the bitmask pointed to by the parameter is +// set. +// +//Arguments: +// +// Offset - The offset (from 0) of the bit to test. +// +// MaskToTest - The mask to be tested. +// +//Return Value: +// +// Returns TRUE if the bit is set. +// +//--*/ +#define IS_BIT_SET_IN_MASK(Offset,MaskToTest) \ +((MaskToTest & (1 << Offset))?(TRUE):(FALSE)) + +//BOOLEAN +//IS_MASK_CLEAR( +// IN ETH_MASK MaskToTest +// ) +// +///*++ +// +//Routine Description: +// +// Tests whether there are *any* bits enabled in the mask. +// +//Arguments: +// +// MaskToTest - The bit mask to test for all clear. +// +//Return Value: +// +// Will return TRUE if no bits are set in the mask. +// +//--*/ +#define IS_MASK_CLEAR(MaskToTest) ((!MaskToTest)?(TRUE):(FALSE)) + +//VOID +//CLEAR_MASK( +// IN OUT PETH_MASK MaskToClear +// ); +// +///*++ +// +//Routine Description: +// +// Clears a mask. +// +//Arguments: +// +// MaskToClear - The bit mask to adjust. +// +//Return Value: +// +// None. +// +//--*/ +#define CLEAR_MASK(MaskToClear) *MaskToClear = 0 + +// +// VOID +// ETH_FILTER_ALLOC_OPEN( +// IN PETH_FILTER Filter, +// OUT PUINT FilterIndex +// ) +// +///*++ +// +//Routine Description: +// +// Allocates an open block. This only allocate the index, not memory for +// the open block. +// +//Arguments: +// +// Filter - DB from which to allocate the space +// +// FilterIndex - pointer to place to store the index. +// +//Return Value: +// +// FilterIndex of the new open +// +//--*/ +#define ETH_FILTER_ALLOC_OPEN(Filter, FilterIndex)\ +{\ + UINT i; \ + for (i=0; i < ETH_FILTER_MAX_OPENS; i++) { \ + if (IS_BIT_SET_IN_MASK(i,(Filter)->FreeBindingMask)) { \ + *(FilterIndex) = i; \ + CLEAR_BIT_IN_MASK(i, &((Filter)->FreeBindingMask)); \ + break; \ + } \ + } \ +} + +// +// VOID +// ETH_FILTER_FREE_OPEN( +// IN PETH_FILTER Filter, +// IN PETH_BINDING_INFO LocalOpen +// ) +// +///*++ +// +//Routine Description: +// +// Frees an open block. Also frees the memory associated with the open. +// +//Arguments: +// +// Filter - DB from which to allocate the space +// +// FilterIndex - Index to free +// +//Return Value: +// +// FilterIndex of the new open +// +//--*/ +#define ETH_FILTER_FREE_OPEN(Filter, LocalOpen)\ +{\ + SET_BIT_IN_MASK(((LocalOpen)->FilterIndex), &((Filter)->FreeBindingMask)); \ + FreePhys((LocalOpen), sizeof(ETH_BINDING_INFO));\ +} + + + +NDIS_SPIN_LOCK EthReferenceLock = {0}; +KEVENT EthPagedInEvent = {0}; +ULONG EthReferenceCount = 0; +PVOID EthImageHandle = {0}; + +VOID +EthInitializePackage(VOID) +{ + NdisAllocateSpinLock(&EthReferenceLock); + KeInitializeEvent( + &EthPagedInEvent, + NotificationEvent, + FALSE + ); +} + +VOID +EthReferencePackage(VOID) +{ + + ACQUIRE_SPIN_LOCK(&EthReferenceLock); + + EthReferenceCount++; + + if (EthReferenceCount == 1) { + + KeResetEvent( + &EthPagedInEvent + ); + + RELEASE_SPIN_LOCK(&EthReferenceLock); + + // + // Page in all the functions + // + EthImageHandle = MmLockPagableCodeSection(EthCreateFilter); + + // + // Signal to everyone to go + // + KeSetEvent( + &EthPagedInEvent, + 0L, + FALSE + ); + + } else { + + RELEASE_SPIN_LOCK(&EthReferenceLock); + + // + // Wait for everything to be paged in + // + KeWaitForSingleObject( + &EthPagedInEvent, + Executive, + KernelMode, + TRUE, + NULL + ); + + } + +} + +VOID +EthDereferencePackage(VOID) +{ + ACQUIRE_SPIN_LOCK(&EthReferenceLock); + + EthReferenceCount--; + + if (EthReferenceCount == 0) { + + RELEASE_SPIN_LOCK(&EthReferenceLock); + + // + // Page out all the functions + // + MmUnlockPagableImageSection(EthImageHandle); + + } else { + + RELEASE_SPIN_LOCK(&EthReferenceLock); + + } + +} + + +static +BOOLEAN +FindMulticast( + IN UINT NumberOfAddresses, + IN CHAR AddressArray[][ETH_LENGTH_OF_ADDRESS], + IN CHAR MulticastAddress[ETH_LENGTH_OF_ADDRESS], + OUT PUINT ArrayIndex + ); + + +#ifdef ALLOC_PRAGMA +//#pragma alloc_text(PAGENDSE, EthShouldAddressLoopBack) +#pragma alloc_text(PAGENDSE, FindMulticast) +//#pragma alloc_text(PAGENDSE, EthFilterDprIndicateReceiveComplete) +#pragma alloc_text(PAGENDSE, EthFilterIndicateReceiveComplete) +//#pragma alloc_text(PAGENDSE, EthFilterDprIndicateReceive) +#pragma alloc_text(PAGENDSE, EthFilterIndicateReceive) +#pragma alloc_text(PAGENDSE, EthQueryGlobalFilterAddresses) +#pragma alloc_text(PAGENDSE, EthQueryOpenFilterAddresses) +#pragma alloc_text(PAGENDSE, EthNumberOfOpenFilterAddresses) +#pragma alloc_text(PAGENDSE, EthFilterAdjust) +#pragma alloc_text(PAGENDSE, EthChangeFilterAddresses) +#pragma alloc_text(PAGENDSE, EthDeleteFilterOpenAdapter) +#pragma alloc_text(PAGENDSE, EthNoteFilterOpenAdapter) +#pragma alloc_text(PAGENDSE, EthCreateFilter) + +#endif + + + +BOOLEAN +EthCreateFilter( + IN UINT MaximumMulticastAddresses, + IN ETH_ADDRESS_CHANGE AddressChangeAction, + IN ETH_FILTER_CHANGE FilterChangeAction, + IN ETH_DEFERRED_CLOSE CloseAction, + IN PUCHAR AdapterAddress, + IN PNDIS_SPIN_LOCK Lock, + OUT PETH_FILTER *Filter + ) + +/*++ + +Routine Description: + + This routine is used to create and initialize the filter database. + +Arguments: + + MaximumMulticastAddresses - The maximum number of multicast addresses + that the MAC will support. + + AddressChangeAction - Action routine to call when the list of + multicast addresses the card must enable has changed. + + ChangeAction - Action routine to call when a binding sets or clears + a particular filter class and it is the first or only binding using + the filter class. + + CloseAction - This routine is called if a binding closes while + it is being indicated to via NdisIndicateReceive. It will be + called upon return from NdisIndicateReceive. + + AdapterAddress - the address of the adapter associated with this filter + database. + + Lock - Pointer to the lock that should be held when mutual exclusion + is required. + + Filter - A pointer to an ETH_FILTER. This is what is allocated and + created by this routine. + +Return Value: + + If the function returns false then one of the parameters exceeded + what the filter was willing to support. + +--*/ + +{ + + PETH_FILTER LocalFilter; + NDIS_STATUS AllocStatus; + + // + // Allocate the database and it's associated arrays. + // + + AllocStatus = AllocPhys(&LocalFilter, sizeof(ETH_FILTER)); + *Filter = LocalFilter; + + if (AllocStatus != NDIS_STATUS_SUCCESS) { + return FALSE; + } + + ZeroMemory( + LocalFilter, + sizeof(ETH_FILTER) + ); + + if (MaximumMulticastAddresses == 0) { + + // + // Why 2 and not 1? Why not. A protocol is going to need at least + // one to run on this, so let's give one extra one for any user stuff + // that may need it. + // + + MaximumMulticastAddresses = 2; + + } + + { + PVOID TmpAlloc; + + AllocStatus = AllocPhys( + &TmpAlloc, + 2*ETH_LENGTH_OF_ADDRESS*MaximumMulticastAddresses + ); + + LocalFilter->MulticastAddresses = TmpAlloc; + + } + + if (AllocStatus != NDIS_STATUS_SUCCESS) { + + EthDeleteFilter(LocalFilter); + return FALSE; + + } + + AllocStatus = AllocPhys( + &LocalFilter->BindingsUsingAddress, + 2*sizeof(ETH_MASK)*MaximumMulticastAddresses + ); + + if (AllocStatus != NDIS_STATUS_SUCCESS) { + + EthDeleteFilter(LocalFilter); + return FALSE; + + } + + EthReferencePackage(); + + LocalFilter->FreeBindingMask = (ULONG)(-1); + LocalFilter->OpenList = NULL; + + ETH_COPY_NETWORK_ADDRESS(LocalFilter->AdapterAddress, AdapterAddress); + LocalFilter->Lock = Lock; + LocalFilter->AddressChangeAction = AddressChangeAction; + LocalFilter->FilterChangeAction = FilterChangeAction; + LocalFilter->CloseAction = CloseAction; + LocalFilter->NumberOfAddresses = 0; + LocalFilter->MaximumMulticastAddresses = MaximumMulticastAddresses; + + return TRUE; +} + + +// +// NOTE: THIS FUNCTION CANNOT BE PAGEABLE +// +VOID +EthDeleteFilter( + IN PETH_FILTER Filter + ) + +/*++ + +Routine Description: + + This routine is used to delete the memory associated with a filter + database. Note that this routines *ASSUMES* that the database + has been cleared of any active filters. + +Arguments: + + Filter - A pointer to an ETH_FILTER to be deleted. + +Return Value: + + None. + +--*/ + +{ + + ASSERT(Filter->FreeBindingMask == (ETH_MASK)-1); + ASSERT(Filter->OpenList == NULL); + + if (Filter->MulticastAddresses) { + + FreePhys( + Filter->MulticastAddresses, + 2*ETH_LENGTH_OF_ADDRESS*Filter->MaximumMulticastAddresses + ); + + } + + if (Filter->BindingsUsingAddress) { + + FreePhys( + Filter->BindingsUsingAddress, + 2*sizeof(ETH_MASK)*Filter->MaximumMulticastAddresses + ); + + } + + FreePhys(Filter, sizeof(ETH_FILTER)); + + EthDereferencePackage(); + +} + + +BOOLEAN +EthNoteFilterOpenAdapter( + IN PETH_FILTER Filter, + IN NDIS_HANDLE MacBindingHandle, + IN NDIS_HANDLE NdisBindingContext, + OUT PNDIS_HANDLE NdisFilterHandle + ) + +/*++ + +Routine Description: + + This routine is used to add a new binding to the filter database. + + NOTE: THIS ROUTINE ASSUMES THAT THE DATABASE IS LOCKED WHEN + IT IS CALLED. + +Arguments: + + Filter - A pointer to the previously created and initialized filter + database. + + MacBindingHandle - The MAC supplied value to the protocol in response + to a call to EthOpenAdapter. + + NdisBindingContext - An NDIS supplied value to the call to EthOpenAdapter. + + NdisFilterHandle - A pointer to this open. + +Return Value: + + Will return false if creating a new filter index will cause the maximum + number of filter indexes to be exceeded. + +--*/ + +{ + + // + // Will hold the value of the filter index so that we + // need not indirectly address through pointer parameter. + // + UINT LocalIndex; + + NDIS_STATUS AllocStatus; + + // + // Pointer to new open block. + // + PETH_BINDING_INFO LocalOpen; + + PNDIS_OPEN_BLOCK NdisOpen = (PNDIS_OPEN_BLOCK)NdisBindingContext; + + // + // Get the first free binding slot and remove that slot from + // the free list. We check to see if the list is empty. + // + + + if (Filter->FreeBindingMask == 0) { + + return FALSE; + + } + + AllocStatus = AllocPhys( + &LocalOpen, + sizeof(ETH_BINDING_INFO) + ); + + if (AllocStatus != NDIS_STATUS_SUCCESS) { + + return FALSE; + + } + + // + // Get place for the open and insert it. + // + + ETH_FILTER_ALLOC_OPEN(Filter, &LocalIndex); + + LocalOpen->NextOpen = Filter->OpenList; + + if (Filter->OpenList != NULL) { + Filter->OpenList->PrevOpen = LocalOpen; + } + + LocalOpen->PrevOpen = NULL; + + Filter->OpenList = LocalOpen; + + LocalOpen->FilterIndex = (UCHAR)LocalIndex; + LocalOpen->References = 1; + LocalOpen->MacBindingHandle = MacBindingHandle; + LocalOpen->NdisBindingContext = NdisBindingContext; + LocalOpen->PacketFilters = 0; + LocalOpen->ReceivedAPacket = FALSE; + + *NdisFilterHandle = (NDIS_HANDLE)LocalOpen; + + return TRUE; + +} + + +NDIS_STATUS +EthDeleteFilterOpenAdapter( + IN PETH_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest + ) + +/*++ + +Routine Description: + + When an adapter is being closed this routine should + be called to delete knowledge of the adapter from + the filter database. This routine is likely to call + action routines associated with clearing filter classes + and addresses. + + NOTE: THIS ROUTINE SHOULD ****NOT**** BE CALLED IF THE ACTION + ROUTINES FOR DELETING THE FILTER CLASSES OR THE MULTICAST ADDRESSES + HAVE ANY POSSIBILITY OF RETURNING A STATUS OTHER THAN NDIS_STATUS_PENDING + OR NDIS_STATUS_SUCCESS. WHILE THESE ROUTINES WILL NOT BUGCHECK IF + SUCH A THING IS DONE, THE CALLER WILL PROBABLY FIND IT DIFFICULT + TO CODE A CLOSE ROUTINE! + + NOTE: THIS ROUTINE ASSUMES THAT IT IS CALLED WITH THE LOCK HELD. + +Arguments: + + Filter - A pointer to the filter database. + + NdisFilterHandle - Pointer to the open. + + NdisRequest - If it is necessary to call the action routines, + this will be passed to it. + +Return Value: + + If action routines are called by the various address and filtering + routines the this routine will likely return the status returned + by those routines. The exception to this rule is noted below. + + Given that the filter and address deletion routines return a status + NDIS_STATUS_PENDING or NDIS_STATUS_SUCCESS this routine will then + try to return the filter index to the freelist. If the routine + detects that this binding is currently being indicated to via + NdisIndicateReceive, this routine will return a status of + NDIS_STATUS_CLOSING_INDICATING. + +--*/ + +{ + + // + // Holds the status returned from the packet filter and address + // deletion routines. Will be used to return the status to + // the caller of this routine. + // + NDIS_STATUS StatusToReturn; + + // + // Local variable. + // + PETH_BINDING_INFO LocalOpen = (PETH_BINDING_INFO)NdisFilterHandle; + + StatusToReturn = EthFilterAdjust( + Filter, + NdisFilterHandle, + NdisRequest, + (UINT)0, + FALSE + ); + + if (StatusToReturn == NDIS_STATUS_SUCCESS || + StatusToReturn == NDIS_STATUS_PENDING) { + + NDIS_STATUS StatusToReturn2; + + StatusToReturn2 = EthChangeFilterAddresses( + Filter, + NdisFilterHandle, + NdisRequest, + 0, + NULL, + FALSE + ); + + if (StatusToReturn2 != NDIS_STATUS_SUCCESS) { + + StatusToReturn = StatusToReturn2; + + } + + } + + + if ((StatusToReturn == NDIS_STATUS_SUCCESS) || + (StatusToReturn == NDIS_STATUS_PENDING)) { + + // + // Remove the reference from the original open. + // + + if (--(LocalOpen->References) == 0) { + + // + // Remove it from the list. + // + + if (LocalOpen->NextOpen != NULL) { + + LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen; + + } + + if (LocalOpen->PrevOpen != NULL) { + + LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen; + + } else { + + Filter->OpenList = LocalOpen->NextOpen; + + } + + + // + // First we finish any NdisIndicateReceiveComplete that + // may be needed for this binding. + // + + if (LocalOpen->ReceivedAPacket) { + + RELEASE_SPIN_LOCK_DPC(Filter->Lock); + + FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext); + + ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + + } + + ETH_FILTER_FREE_OPEN(Filter, LocalOpen); + + } else { + + // + // Let the caller know that there is a reference to the open + // by the receive indication. The close action routine will be + // called upon return from NdisIndicateReceive. + // + + StatusToReturn = NDIS_STATUS_CLOSING_INDICATING; + + } + + } + + return StatusToReturn; + +} + + +NDIS_STATUS +EthChangeFilterAddresses( + IN PETH_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest, + IN UINT AddressCount, + IN CHAR Addresses[][ETH_LENGTH_OF_ADDRESS], + IN BOOLEAN Set + ) + +/*++ + +Routine Description: + + The ChangeFilterAddress routine will call an action + routine when the overall multicast address list for the adapter + has changed. + + If the action routine returns a value other than pending or + success then this routine has no effect on the multicast address + list for the open or for the adapter as a whole. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + +Arguments: + + Filter - A pointer to the filter database. + + NdisFilterHandle - Pointer to the open. + + NdisRequest - If it is necessary to call the action routine, + this will be passed to it. + + AddressCount - The number of elements (addresses, + not bytes) in MulticastAddressList. + + Addresses - The new multicast address list for this + binding. This is a sequence of ETH_LENGTH_OF_ADDRESS byte + addresses, with no padding between them. + + Set - A boolean that determines whether the multicast addresses + are being adjusted due to a set or because of a close. (The filtering + routines don't care, the MAC might.) + +Return Value: + + If it calls the action routine then it will return the + status returned by the action routine. If the status + returned by the action routine is anything other than + NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database + will be returned to the state it was in upon entrance to this + routine. + + If the action routine is not called this routine will return + the following statum: + + NDIS_STATUS_SUCCESS - If the new packet filters doesn't change + the combined mask of all bindings packet filters. + +--*/ + +{ + // + // Holds the status returned to the user of this routine, if the + // action routine is not called then the status will be success, + // otherwise, it is whatever the action routine returns. + // + NDIS_STATUS StatusOfChange; + + // + // Saves the original length of the address array. + // + UINT InitialArraySize; + + // + // Set true when the address array changes + // + UINT AddressesChanged = 0; + + // + // Use to save data if needed. + // + PVOID TmpAddressArray, TmpMaskArray; + + // + // Simple iteration variables. + // + UINT ArrayIndex, i; + + + // + // Simple Temp variable + // + PCHAR CurrentAddress; + + PETH_BINDING_INFO LocalOpen = (PETH_BINDING_INFO)NdisFilterHandle; + + + TmpAddressArray = + (PUCHAR)Filter->MulticastAddresses + + (ETH_LENGTH_OF_ADDRESS*Filter->MaximumMulticastAddresses); + + TmpMaskArray = + (PUCHAR)Filter->BindingsUsingAddress + + (sizeof(ETH_MASK)*Filter->MaximumMulticastAddresses); + + + // + // We have to save the old mask array in + // case we need to restore it. If we need + // to save the address array too we will + // do that later. + // + + MoveMemory( + TmpMaskArray, + (PVOID)Filter->BindingsUsingAddress, + Filter->NumberOfAddresses * sizeof(ETH_MASK) + ); + + // + // We have to save the old address array in + // case we need to restore it. If we need + // to save the address array too we will + // do that later. + // + + MoveMemory( + TmpAddressArray, + (PVOID)Filter->MulticastAddresses, + Filter->NumberOfAddresses * ETH_LENGTH_OF_ADDRESS + ); + + InitialArraySize = Filter->NumberOfAddresses; + + + // + // Now modify the original array... + // + + // + // First go through and turn off the bit for this + // binding throughout the array. + // + + for (i=0; i<(Filter->NumberOfAddresses); i++) { + + CLEAR_BIT_IN_MASK( + LocalOpen->FilterIndex, + &(Filter->BindingsUsingAddress[i]) + ); + + } + + // + // First we have to remove any addresses from + // the multicast array if they have no bits on any more. + // + for (ArrayIndex = 0; ArrayIndex < Filter->NumberOfAddresses; ) { + + if (IS_MASK_CLEAR(Filter->BindingsUsingAddress[ArrayIndex])) { + + // + // yes it is clear, so we have to shift everything + // above it down one. + // + + MoveMemory( + Filter->MulticastAddresses[ArrayIndex], + Filter->MulticastAddresses[ArrayIndex+1], + (Filter->NumberOfAddresses-(ArrayIndex+1)) + *ETH_LENGTH_OF_ADDRESS + ); + + MoveMemory( + &Filter->BindingsUsingAddress[ArrayIndex], + &Filter->BindingsUsingAddress[ArrayIndex+1], + (Filter->NumberOfAddresses-(ArrayIndex+1))*(sizeof(ETH_MASK)) + ); + + Filter->NumberOfAddresses--; + + } else { + + ArrayIndex++; + + } + + } + + + // + // Now go through the new addresses for this binding, + // and insert them into the array. + // + + for (i=0; i<AddressCount; i++) { + + CurrentAddress = ((PCHAR)Addresses) + (i*ETH_LENGTH_OF_ADDRESS); + + if (FindMulticast( + Filter->NumberOfAddresses, + Filter->MulticastAddresses, + CurrentAddress, + &ArrayIndex)) { + + // + // The address is there, so just turn the bit + // back on. + // + + SET_BIT_IN_MASK( + LocalOpen->FilterIndex, + &Filter->BindingsUsingAddress[ArrayIndex] + ); + + } else { + + // + // The address was not found, add it. + // + + if (Filter->NumberOfAddresses < Filter->MaximumMulticastAddresses) { + + // + // Save the address array if it hasn't been. + // + + MoveMemory( + Filter->MulticastAddresses[ArrayIndex+1], + Filter->MulticastAddresses[ArrayIndex], + (Filter->NumberOfAddresses-ArrayIndex)*ETH_LENGTH_OF_ADDRESS + ); + + ETH_COPY_NETWORK_ADDRESS( + Filter->MulticastAddresses[ArrayIndex], + CurrentAddress + ); + + MoveMemory( + &(Filter->BindingsUsingAddress[ArrayIndex+1]), + &(Filter->BindingsUsingAddress[ArrayIndex]), + (Filter->NumberOfAddresses-ArrayIndex)*sizeof(ETH_MASK) + ); + + CLEAR_MASK(&Filter->BindingsUsingAddress[ArrayIndex]); + + SET_BIT_IN_MASK( + LocalOpen->FilterIndex, + &Filter->BindingsUsingAddress[ArrayIndex] + ); + + Filter->NumberOfAddresses++; + + } else { + + // + // No room in the array, oh well. + // + + MoveMemory( + (PVOID)Filter->MulticastAddresses, + TmpAddressArray, + InitialArraySize * ETH_LENGTH_OF_ADDRESS + ); + + MoveMemory( + (PVOID)Filter->BindingsUsingAddress, + TmpMaskArray, + InitialArraySize * sizeof(ETH_MASK) + ); + + Filter->NumberOfAddresses = InitialArraySize; + + return NDIS_STATUS_MULTICAST_FULL; + + } + + } + + } + + // Check to see if address array has chnaged + + AddressesChanged = Filter->NumberOfAddresses - InitialArraySize; + + for (i=0; i<InitialArraySize && AddressesChanged==0; i++) { + + ETH_COMPARE_NETWORK_ADDRESSES_EQ(Filter->MulticastAddresses[i], + (PUCHAR)TmpAddressArray + i * ETH_LENGTH_OF_ADDRESS, + &AddressesChanged); + + } + + // + // If the address array has changed, we have to call the + // action array to inform the adapter of this. + // + + if (AddressesChanged != 0) { + + StatusOfChange = Filter->AddressChangeAction( + InitialArraySize, + TmpAddressArray, + Filter->NumberOfAddresses, + Filter->MulticastAddresses, + LocalOpen->MacBindingHandle, + NdisRequest, + Set + ); + + if ((StatusOfChange != NDIS_STATUS_SUCCESS) && + (StatusOfChange != NDIS_STATUS_PENDING)) { + + // + // The user returned a bad status. Put things back as + // they were. + // + + MoveMemory( + (PVOID)Filter->MulticastAddresses, + TmpAddressArray, + InitialArraySize * ETH_LENGTH_OF_ADDRESS + ); + + MoveMemory( + (PVOID)Filter->MulticastAddresses, + TmpAddressArray, + InitialArraySize * ETH_LENGTH_OF_ADDRESS + ); + + } + + } else { + + StatusOfChange = NDIS_STATUS_SUCCESS; + + } + + + return StatusOfChange; + + +} + + +NDIS_STATUS +EthFilterAdjust( + IN PETH_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest, + IN UINT FilterClasses, + IN BOOLEAN Set + ) + +/*++ + +Routine Description: + + The FilterAdjust routine will call an action routine when a + particular filter class is changes from not being used by any + binding to being used by at least one binding or vice versa. + + If the action routine returns a value other than pending or + success then this routine has no effect on the packet filters + for the open or for the adapter as a whole. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + +Arguments: + + Filter - A pointer to the filter database. + + NdisFilterHandle - A pointer to the open. + + NdisRequest - If it is necessary to call the action routine, + this will be passed to it. + + FilterClasses - The filter classes that are to be added or + deleted. + + Set - A boolean that determines whether the filter classes + are being adjusted due to a set or because of a close. (The filtering + routines don't care, the MAC might.) + +Return Value: + + If it calls the action routine then it will return the + status returned by the action routine. If the status + returned by the action routine is anything other than + NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database + will be returned to the state it was in upon entrance to this + routine. + + If the action routine is not called this routine will return + the following statum: + + NDIS_STATUS_SUCCESS - If the new packet filters doesn't change + the combined mask of all bindings packet filters. + +--*/ + +{ + // + // Contains the value of the combined filter classes before + // it is adjusted. + // + UINT OldCombined = Filter->CombinedPacketFilter; + + PETH_BINDING_INFO LocalOpen = (PETH_BINDING_INFO)NdisFilterHandle; + PETH_BINDING_INFO OpenList; + + // + // Contains the value of the particlar opens packet filters + // prior to the change. We save this incase the action + // routine (if called) returns an "error" status. + // + UINT OldOpenFilters = LocalOpen->PacketFilters; + + // + // Holds the status returned to the user of this routine, if the + // action routine is not called then the status will be success, + // otherwise, it is whatever the action routine returns. + // + NDIS_STATUS StatusOfAdjust; + + // + // Set the new filter information for the open. + // + + LocalOpen->PacketFilters = FilterClasses; + + // + // We always have to reform the compbined filter since + // this filter index may have been the only filter index + // to use a particular bit. + // + + + for ( + OpenList = Filter->OpenList, + Filter->CombinedPacketFilter = 0; + OpenList != NULL; + OpenList = OpenList->NextOpen + ) { + + Filter->CombinedPacketFilter |= + OpenList->PacketFilters; + + } + + if (OldCombined != Filter->CombinedPacketFilter) { + + StatusOfAdjust = Filter->FilterChangeAction( + OldCombined, + Filter->CombinedPacketFilter, + LocalOpen->MacBindingHandle, + NdisRequest, + Set + ); + + if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) && + (StatusOfAdjust != NDIS_STATUS_PENDING)) { + + // + // The user returned a bad status. Put things back as + // they were. + // + + LocalOpen->PacketFilters = OldOpenFilters; + Filter->CombinedPacketFilter = OldCombined; + + } + + } else { + + StatusOfAdjust = NDIS_STATUS_SUCCESS; + + } + + return StatusOfAdjust; + +} + + +UINT +EthNumberOfOpenFilterAddresses( + IN PETH_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle + ) + +/*++ + +Routine Description: + + This routine counts the number of multicast addresses that a specific + open has. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + +Arguments: + + Filter - A pointer to the filter database. + + NdisFilterHandle - Pointer to open block. + + +Return Value: + + None. + +--*/ +{ + + UINT IndexOfAddress; + UINT CountOfAddresses = 0; + + UINT FilterIndex = ((PETH_BINDING_INFO)NdisFilterHandle)->FilterIndex; + + for(IndexOfAddress=0; + IndexOfAddress < Filter->NumberOfAddresses; + IndexOfAddress++ + ){ + + if (IS_BIT_SET_IN_MASK(FilterIndex, + Filter->BindingsUsingAddress[IndexOfAddress])) { + + CountOfAddresses++; + + + } + + } + + return(CountOfAddresses); + +} + + +VOID +EthQueryOpenFilterAddresses( + OUT PNDIS_STATUS Status, + IN PETH_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN UINT SizeOfArray, + OUT PUINT NumberOfAddresses, + OUT CHAR AddressArray[][ETH_LENGTH_OF_ADDRESS] + ) + +/*++ + +Routine Description: + + The routine should be used by the MAC before + it actually alters the hardware registers to effect a + filtering hardware. This is usefull if another binding + has altered the address list since the action routine + is called. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + +Arguments: + + Status - A pointer to the status of the call, NDIS_STATUS_SUCCESS or + NDIS_STATUS_FAILURE. Use EthNumberOfOpenAddresses() to get the + size that is needed. + + Filter - A pointer to the filter database. + + NdisFilterHandle - Pointer to the open block + + SizeOfArray - The byte count of the AddressArray. + + NumberOfAddresses - The number of addresses written to the array. + + AddressArray - Will be filled with the addresses currently in the + multicast address list. + +Return Value: + + None. + +--*/ + +{ + + UINT IndexOfAddress; + UINT CountOfAddresses = 0; + UINT FilterIndex = ((PETH_BINDING_INFO)NdisFilterHandle)->FilterIndex; + + for(IndexOfAddress=0; + IndexOfAddress < Filter->NumberOfAddresses; + IndexOfAddress++ + ){ + + if (IS_BIT_SET_IN_MASK(FilterIndex, + Filter->BindingsUsingAddress[IndexOfAddress])) { + + if (SizeOfArray < ETH_LENGTH_OF_ADDRESS) { + + *Status = NDIS_STATUS_FAILURE; + + *NumberOfAddresses = 0; + + return; + + } + + SizeOfArray -= ETH_LENGTH_OF_ADDRESS; + + MoveMemory( + AddressArray[CountOfAddresses], + Filter->MulticastAddresses[IndexOfAddress], + ETH_LENGTH_OF_ADDRESS + ); + + CountOfAddresses++; + + } + + } + + *Status = NDIS_STATUS_SUCCESS; + + *NumberOfAddresses = CountOfAddresses; + + return; + +} + + +VOID +EthQueryGlobalFilterAddresses( + OUT PNDIS_STATUS Status, + IN PETH_FILTER Filter, + IN UINT SizeOfArray, + OUT PUINT NumberOfAddresses, + IN OUT CHAR AddressArray[][ETH_LENGTH_OF_ADDRESS] + ) + +/*++ + +Routine Description: + + The routine should be used by the MAC before + it actually alters the hardware registers to effect a + filtering hardware. This is usefull if another binding + has altered the address list since the action routine + is called. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + +Arguments: + + Status - A pointer to the status of the call, NDIS_STATUS_SUCCESS or + NDIS_STATUS_FAILURE. Use ETH_NUMBER_OF_GLOBAL_ADDRESSES() to get the + size that is needed. + + Filter - A pointer to the filter database. + + SizeOfArray - The byte count of the AddressArray. + + NumberOfAddresses - A pointer to the number of addresses written to the + array. + + AddressArray - Will be filled with the addresses currently in the + multicast address list. + +Return Value: + + None. + +--*/ + +{ + + if (SizeOfArray < (Filter->NumberOfAddresses * ETH_LENGTH_OF_ADDRESS)) { + + *Status = NDIS_STATUS_FAILURE; + + *NumberOfAddresses = 0; + + } else { + + *Status = NDIS_STATUS_SUCCESS; + + *NumberOfAddresses = Filter->NumberOfAddresses; + + MoveMemory( + AddressArray[0], + Filter->MulticastAddresses[0], + Filter->NumberOfAddresses*ETH_LENGTH_OF_ADDRESS + ); + + } + +} + + +VOID +EthFilterIndicateReceive( + IN PETH_FILTER Filter, + IN NDIS_HANDLE MacReceiveContext, + IN PCHAR Address, + IN PVOID HeaderBuffer, + IN UINT HeaderBufferSize, + IN PVOID LookaheadBuffer, + IN UINT LookaheadBufferSize, + IN UINT PacketSize + ) +{ + KIRQL oldIrql; + KeRaiseIrql( DISPATCH_LEVEL, &oldIrql ); + ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + EthFilterDprIndicateReceive( + Filter, + MacReceiveContext, + Address, + HeaderBuffer, + HeaderBufferSize, + LookaheadBuffer, + LookaheadBufferSize, + PacketSize + ); + RELEASE_SPIN_LOCK_DPC(Filter->Lock); + KeLowerIrql( oldIrql ); + return; +} + + +VOID +EthFilterDprIndicateReceive( + IN PETH_FILTER Filter, + IN NDIS_HANDLE MacReceiveContext, + IN PCHAR Address, + IN PVOID HeaderBuffer, + IN UINT HeaderBufferSize, + IN PVOID LookaheadBuffer, + IN UINT LookaheadBufferSize, + IN UINT PacketSize + ) + +/*++ + +Routine Description: + + This routine is called by the MAC to indicate a packet to + all bindings. The packet will be filtered so that only the + appropriate bindings will receive the packet. + +Arguments: + + Filter - Pointer to the filter database. + + MacReceiveContext - A MAC supplied context value that must be + returned by the protocol if it calls MacTransferData. + + Address - The destination address from the received packet. + + HeaderBuffer - A virtual address of the virtually contiguous + buffer containing the MAC header of the packet. + + HeaderBufferSize - An unsigned integer indicating the size of + the header buffer, in bytes. + + LookaheadBuffer - A virtual address of the virtually contiguous + buffer containing the first LookaheadBufferSize bytes of data + of the packet. The packet buffer is valid only within the current + call to the receive event handler. + + LookaheadBufferSize - An unsigned integer indicating the size of + the lookahead buffer, in bytes. + + PacketSize - An unsigned integer indicating the size of the received + packet, in bytes. This number has nothing to do with the lookahead + buffer, but indicates how large the arrived packet is so that a + subsequent MacTransferData request can be made to transfer the entire + packet as necessary. + +Return Value: + + None. + +--*/ + +{ + + // + // Will hold the type of address that we know we've got. + // + UINT AddressType; + + // + // Will hold the status of indicating the receive packet. + // ZZZ For now this isn't used. + // + NDIS_STATUS StatusOfReceive; + + // + // Will hold the filter classes of the binding being indicated. + // + UINT BindingFilters; + UINT IntersectionOfFilters; + + // + // Current Open to indicate to. + // + PETH_BINDING_INFO LocalOpen; + + // + // If the packet is a runt packet, then only indicate to PROMISCUOUS + // + + if ( HeaderBufferSize >= 14 && PacketSize != 0 ) { + + // + // Valid ethernet header + // + + // + // Determine whether the input address is a simple direct, + // a broadcast, or a multicast address. + // + // + // First check if it *at least* has the multicast address bit. + // + + if (ETH_IS_MULTICAST(Address)) { + + // + // It is at least a multicast address. Check to see if + // it is a broadcast address. + // + + if (ETH_IS_BROADCAST(Address)) { + + +#if DBG + +if (NdisCheckBadDrivers) { + + if (!(Filter->CombinedPacketFilter & NDIS_PACKET_TYPE_BROADCAST)) { + + // + // We should never receive directed packets + // to someone else unless in p-mode. + // + DbgPrint("NDIS: Bad driver, indicating broadcast\n"); + DbgPrint("NDIS: packets when not set to.\n"); + DbgBreakPoint(); + + } + +} + +#endif + + AddressType = NDIS_PACKET_TYPE_BROADCAST; + + } else { + + AddressType = NDIS_PACKET_TYPE_MULTICAST; + + } + + } else { + + // + // Verify that the address is directed to the adapter. We + // have to check for this because of the following senario. + // + // Adapter A is in promiscuous mode. + // Adapter B only wants directed packets to this adapter. + // + // The MAC will indicate *all* packets. + // + // The filter package needs to filter directed packets to + // other adapters from ones directed to this adapter. + // + + if (Filter->CombinedPacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS) { + + // + // The result of comparing an element of the address + // array and the multicast address. + // + // Result < 0 Implies the adapter address is greater. + // Result > 0 Implies the address is greater. + // Result = 0 Implies that the they are equal. + // + INT Result; + + ETH_COMPARE_NETWORK_ADDRESSES_EQ( + Filter->AdapterAddress, + Address, + &Result + ); + + if (Result == 0) { + + AddressType = NDIS_PACKET_TYPE_DIRECTED; + + } else { + + // + // This will cause binding that only want a specific + // address type to not be indicated. + // + + AddressType = NDIS_PACKET_TYPE_PROMISCUOUS; + + } + + } else { + +#if DBG + +if (NdisCheckBadDrivers) { + + // + // The result of comparing an element of the address + // array and the multicast address. + // + // Result < 0 Implies the adapter address is greater. + // Result > 0 Implies the address is greater. + // Result = 0 Implies that the they are equal. + // + INT Result; + + ETH_COMPARE_NETWORK_ADDRESSES_EQ( + Filter->AdapterAddress, + Address, + &Result + ); + + if (Result != 0) { + + // + // We should never receive directed packets + // to someone else unless in p-mode. + // + DbgPrint("NDIS: Bad driver, indicating packets\n"); + DbgPrint("NDIS: to another station when not in\n"); + DbgPrint("NDIS: promiscuous mode.\n"); + DbgBreakPoint(); + + + } + +} + +#endif + + AddressType = NDIS_PACKET_TYPE_DIRECTED; + + } + + } + + } else { + + // + // runt packet + // + + AddressType = NDIS_PACKET_TYPE_PROMISCUOUS; + + } + + // + // We need to acquire the filter exclusively while we're finding + // bindings to indicate to. + // + + LocalOpen = Filter->OpenList; + + while (LocalOpen != NULL) { + + BindingFilters = LocalOpen->PacketFilters; + IntersectionOfFilters = BindingFilters & AddressType; + + // + // if the binding wants direct packets and this is a directly + // addressed packet then the binding gets the packet. + // + // + // if the binding wants broadcast packets and the packet + // is a broadcast packet it will get the packet. + // + + if (IntersectionOfFilters & (NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST)) { + + goto IndicatePacket; + + } + + // + // if the binding wants multicast packets and the packet + // is a multicast packet and it's in the list of addresses + // it will get the packet. + // + + if (IntersectionOfFilters & NDIS_PACKET_TYPE_MULTICAST) { + + // + // Will hold the index of the multicast + // address if it finds it. + // + UINT IndexOfAddress; + + if (FindMulticast( + Filter->NumberOfAddresses, + Filter->MulticastAddresses, + Address, + &IndexOfAddress + )) { + + if (IS_BIT_SET_IN_MASK( + LocalOpen->FilterIndex, + Filter->BindingsUsingAddress[IndexOfAddress] + )) { + + goto IndicatePacket; + + } + + } + + } + + // + // if the binding wants all multicast packets and the packet + // has a multicast address it will get the packet + // + + if ((AddressType & NDIS_PACKET_TYPE_MULTICAST) && + (BindingFilters & NDIS_PACKET_TYPE_ALL_MULTICAST)) { + + goto IndicatePacket; + + } + + // + // if the binding is promiscuous then it will get the packet + // + + if (BindingFilters & NDIS_PACKET_TYPE_PROMISCUOUS) { + + goto IndicatePacket; + + } + + goto GetNextBinding; + +IndicatePacket:; + + LocalOpen->References++; + + RELEASE_SPIN_LOCK_DPC(Filter->Lock); + + // + // Indicate the packet to the binding. + // + + FilterIndicateReceive( + &StatusOfReceive, + LocalOpen->NdisBindingContext, + MacReceiveContext, + HeaderBuffer, + HeaderBufferSize, + LookaheadBuffer, + LookaheadBufferSize, + PacketSize + ); + + ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + + LocalOpen->ReceivedAPacket = TRUE; + + if ((--(LocalOpen->References)) == 0) { + + PETH_BINDING_INFO NextOpen = LocalOpen->NextOpen; + + // + // This binding is shutting down. We have to remove it. + // + + // + // Remove it from the list. + // + + if (LocalOpen->NextOpen != NULL) { + + LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen; + + } + + if (LocalOpen->PrevOpen != NULL) { + + LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen; + + } else { + + Filter->OpenList = LocalOpen->NextOpen; + + } + + + + // + // Call the IndicateComplete routine. + // + + + if (LocalOpen->ReceivedAPacket) { + + RELEASE_SPIN_LOCK_DPC(Filter->Lock); + + FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext); + + ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + + } + + // + // Call the macs action routine so that they know we + // are no longer referencing this open binding. + // + + Filter->CloseAction(LocalOpen->MacBindingHandle); + + + ETH_FILTER_FREE_OPEN(Filter, LocalOpen); + + LocalOpen = NextOpen; + + continue; + + } + +GetNextBinding: + + LocalOpen = LocalOpen->NextOpen; + + } + +} + + +VOID +EthFilterIndicateReceiveComplete( + IN PETH_FILTER Filter + ) +{ + KIRQL oldIrql; + KeRaiseIrql( DISPATCH_LEVEL, &oldIrql ); + ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + EthFilterDprIndicateReceiveComplete( + Filter + ); + RELEASE_SPIN_LOCK_DPC(Filter->Lock); + KeLowerIrql( oldIrql ); + return; +} + + +VOID +EthFilterDprIndicateReceiveComplete( + IN PETH_FILTER Filter + ) + +/*++ + +Routine Description: + + This routine is called by the MAC to indicate that the receive + process is complete to all bindings. Only those bindings which + have received packets will be notified. + +Arguments: + + Filter - Pointer to the filter database. + +Return Value: + + None. + +--*/ +{ + + PETH_BINDING_INFO LocalOpen; + + // + // We need to aquire the filter exclusively while we're finding + // bindings to indicate to. + // + + LocalOpen = Filter->OpenList; + + while (LocalOpen != NULL) { + + if (LocalOpen->ReceivedAPacket) { + + // + // Indicate the binding. + // + + LocalOpen->ReceivedAPacket = FALSE; + + LocalOpen->References++; + + RELEASE_SPIN_LOCK_DPC(Filter->Lock); + + FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext); + + ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + + if ((--(LocalOpen->References)) == 0) { + + PETH_BINDING_INFO NextOpen = LocalOpen->NextOpen; + + // + // This binding is shutting down. We have to kill it. + // + + // + // Remove it from the list. + // + + if (LocalOpen->NextOpen != NULL) { + + LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen; + + } + + if (LocalOpen->PrevOpen != NULL) { + + LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen; + + } else { + + Filter->OpenList = LocalOpen->NextOpen; + + } + + + // + // Call the macs action routine so that they know we + // are no longer referencing this open binding. + // + + Filter->CloseAction(LocalOpen->MacBindingHandle); + + + ETH_FILTER_FREE_OPEN(Filter, LocalOpen); + + LocalOpen = NextOpen; + + continue; + + } + + } + + LocalOpen = LocalOpen->NextOpen; + + } + +} + + +static +BOOLEAN +FindMulticast( + IN UINT NumberOfAddresses, + IN CHAR AddressArray[][ETH_LENGTH_OF_ADDRESS], + IN CHAR MulticastAddress[ETH_LENGTH_OF_ADDRESS], + OUT PUINT ArrayIndex + ) + +/*++ + +Routine Description: + + Given an array of multicast addresses search the array for + a particular multicast address. It is assumed that the + address array is already sorted. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + + NOTE: This ordering is arbitrary but consistant. + +Arguments: + + NumberOfAddresses - The number of addresses currently in the + address array. + + AddressArray - An array of multicast addresses. + + MulticastAddress - The address to search for in the address array. + + ArrayIndex - Will point to where the MulticastAddress is in + the AddressArray, or if it isn't in the array, where it should + be in the array. + +Return Value: + + If the address is in the sorted list this routine will return + TRUE, otherwise FALSE. + +--*/ + +{ + + // + // Indices into the address array so that we may do a binary + // search. + // + UINT Bottom = 0; + UINT Middle = NumberOfAddresses / 2; + UINT Top; + + if (NumberOfAddresses) { + + Top = NumberOfAddresses - 1; + + while ((Middle <= Top) && (Middle >= Bottom)) { + + // + // The result of comparing an element of the address + // array and the multicast address. + // + // Result < 0 Implies the multicast address is greater. + // Result > 0 Implies the address array element is greater. + // Result = 0 Implies that the array element and the address + // are equal. + // + INT Result; + + ETH_COMPARE_NETWORK_ADDRESSES( + AddressArray[Middle], + MulticastAddress, + &Result + ); + + if (Result == 0) { + + *ArrayIndex = Middle; + return(TRUE); + + } else if (Result > 0) { + + if (Middle == 0) break; + Top = Middle - 1; + + + } else { + + Bottom = Middle+1; + + } + + Middle = Bottom + (((Top+1) - Bottom)/2); + + } + + } + + *ArrayIndex = Middle; + + return(FALSE); + +} + + +BOOLEAN +EthShouldAddressLoopBack( + IN PETH_FILTER Filter, + IN CHAR Address[ETH_LENGTH_OF_ADDRESS] + ) + +/*++ + +Routine Description: + + Do a quick check to see whether the input address should + loopback. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + + NOTE: THIS ROUTINE DOES NOT CHECK THE SPECIAL CASE OF SOURCE + EQUALS DESTINATION. + +Arguments: + + Filter - Pointer to the filter database. + + Address - A network address to check for loopback. + + +Return Value: + + Returns TRUE if the address is *likely* to need loopback. It + will return FALSE if there is *no* chance that the address would + require loopback. + +--*/ +{ + BOOLEAN fLoopback, fSelfDirected; + + EthShouldAddressLoopBackMacro(Filter, Address, &fLoopback, &fSelfDirected); + + return(fLoopback); +} diff --git a/private/ntos/ndis/ndis30/efilter.h b/private/ntos/ndis/ndis30/efilter.h new file mode 100644 index 000000000..c33749973 --- /dev/null +++ b/private/ntos/ndis/ndis30/efilter.h @@ -0,0 +1,605 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + efilter.h + +Abstract: + + Header file for the address filtering library for NDIS MAC's. + +Author: + + Anthony V. Ercolano (tonye) creation-date 3-Aug-1990 + +Environment: + + Runs in the context of a single MAC driver. + +Notes: + + None. + +Revision History: + + Adam Barr (adamba) 28-May-1991 + + - renamed MacXXX to EthXXX, changed filter.h to efilter.h + + +--*/ + +#ifndef _ETH_FILTER_DEFS_ +#define _ETH_FILTER_DEFS_ + +#define ETH_LENGTH_OF_ADDRESS 6 + + +// +// ZZZ This is a little-endian specific check. +// +#define ETH_IS_MULTICAST(Address) \ + (((PUCHAR)(Address))[0] & ((UCHAR)0x01)) + + +// +// Check whether an address is broadcast. +// +#define ETH_IS_BROADCAST(Address) \ + ((*((ULONG UNALIGNED *) \ + (&(((PUCHAR) \ + Address \ + )[2] \ + ) \ + ) \ + ) == \ + ((ULONG)0xffffffff) \ + ) && \ + (((PUCHAR)Address)[0] == ((UCHAR)0xff)) && \ + (((PUCHAR)Address)[1] == ((UCHAR)0xff))) + + +// +// This macro will compare network addresses. +// +// A - Is a network address. +// +// B - Is a network address. +// +// Result - The result of comparing two network address. +// +// Result < 0 Implies the B address is greater. +// Result > 0 Implies the A element is greater. +// Result = 0 Implies equality. +// +// Note that this is an arbitrary ordering. There is not +// defined relation on network addresses. This is ad-hoc! +// +// +#define ETH_COMPARE_NETWORK_ADDRESSES(A,B,Result) \ +{ \ + PUCHAR _A = (PUCHAR)(A); \ + PUCHAR _B = (PUCHAR)(B); \ + if ( *(ULONG UNALIGNED *)&_A[2] > \ + *(ULONG UNALIGNED *)&_B[2] ) { \ + *Result = 1; \ + } else if ( *(ULONG UNALIGNED *)&_A[2] < \ + *(ULONG UNALIGNED *)&_B[2] ) { \ + *Result = (UINT)-1; \ + } else if ( *(USHORT UNALIGNED *)_A > \ + *(USHORT UNALIGNED *)_B ) { \ + *Result = 1; \ + } else if ( *(USHORT UNALIGNED *)_A < \ + *(USHORT UNALIGNED *)_B ) { \ + *Result = (UINT)-1; \ + } else { \ + *Result = 0; \ + } \ +} + +// +// This macro will compare network addresses. +// +// A - Is a network address. +// +// B - Is a network address. +// +// Result - The result of comparing two network address. +// +// Result != 0 Implies inequality. +// Result == 0 Implies equality. +// +// +#define ETH_COMPARE_NETWORK_ADDRESSES_EQ(A,B,Result) \ +{ \ + PUCHAR _A = (PUCHAR)(A); \ + PUCHAR _B = (PUCHAR)(B); \ + if ( ( *(ULONG UNALIGNED *)&_A[2] == \ + *(ULONG UNALIGNED *)&_B[2] ) && \ + ( *(USHORT UNALIGNED *)_A == \ + *(USHORT UNALIGNED *)_B ) ) { \ + *Result = 0; \ + } else { \ + *Result = 1; \ + } \ +} + + +// +// This macro is used to copy from one network address to +// another. +// +#define ETH_COPY_NETWORK_ADDRESS(D,S) \ +{ \ + PCHAR _D = (D); \ + PCHAR _S = (S); \ + *((ULONG UNALIGNED *)_D) = *((ULONG UNALIGNED *)_S); \ + _D[4] = _S[4]; \ + _D[5] = _S[5]; \ +} + + +// +//UINT +//ETH_QUERY_FILTER_CLASSES( +// IN PETH_FILTER Filter +// ) +// +// This macro returns the currently enabled filter classes. +// +// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD. +// +#define ETH_QUERY_FILTER_CLASSES(Filter) ((Filter)->CombinedPacketFilter) + + +// +//UINT +//ETH_QUERY_PACKET_FILTER( +// IN PETH_FILTER Filter, +// IN NDIS_HANDLE NdisFilterHandle +// ) +// +// This macro returns the currently enabled filter classes for a specific +// open instance. +// +// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD. +// +#define ETH_QUERY_PACKET_FILTER(Filter, NdisFilterHandle) \ + (((PETH_BINDING_INFO)(NdisFilterHandle))->PacketFilters) + + +// +//UINT +//ETH_NUMBER_OF_GLOBAL_FILTER_ADDRESSES( +// IN PETH_FILTER Filter +// ) +// +// This macro returns the number of multicast addresses in the +// multicast address list. +// +// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD. +// +#define ETH_NUMBER_OF_GLOBAL_FILTER_ADDRESSES(Filter) ((Filter)->NumberOfAddresses) + + +// +// An action routine type. The routines are called +// when a filter type is set for the first time or +// no more bindings require a particular type of filter. +// +// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED. +// +typedef +NDIS_STATUS +(*ETH_FILTER_CHANGE)( + IN UINT OldFilterClasses, + IN UINT NewFilterClasses, + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest, + IN BOOLEAN Set + ); + +// +// This action routine is called when a new multicast address +// list is given to the filter. The action routine is given +// arrays containing the old and new multicast addresses. +// +// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED. +// +typedef +NDIS_STATUS +(*ETH_ADDRESS_CHANGE)( + IN UINT OldAddressCount, + IN CHAR OldAddresses[][ETH_LENGTH_OF_ADDRESS], + IN UINT NewAddressCount, + IN CHAR NewAddresses[][ETH_LENGTH_OF_ADDRESS], + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest, + IN BOOLEAN Set + ); + +#if 0 +// This action routine is called when a unique multicast address +// is added to the filter. The action routine is passed an array +// filled with all of the addresses that are being filtered, as +// well as the index into this array of the unique address just +// added. It is also passed an array of contexts, associated +// with each address; it can store a context for the new address +// in AddressContexts[NewAddress]. The contexts are passed +// back to the delete action routine. +// +// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED. +// +typedef +NDIS_STATUS +(*ETH_ADDRESS_ADD)( + IN UINT CurrentAddressCount, + IN CHAR CurrentAddresses[][ETH_LENGTH_OF_ADDRESS], + IN UINT NewAddress, + IN OUT NDIS_HANDLE AddressContexts[], + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest + ); + +// +// This action routine is called when a unique multicast address +// is no longer requested for filtering by any binding. The +// action routine is passed an array filled with the all of the +// addresses that are *still* being used for multicast filtering. +// It is also passed the array of contexts for those addresses. +// The routine is also passed the address of the address being deleted, +// and the context of the address being deleted (as set during +// the add action routine). +// +// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED. +// +typedef +NDIS_STATUS +(*ETH_ADDRESS_DELETE)( + IN UINT CurrentAddressCount, + IN CHAR CurrentAddresses[][ETH_LENGTH_OF_ADDRESS], + IN CHAR OldAddress[ETH_LENGTH_OF_ADDRESS], + IN NDIS_HANDLE AddressContexts[], + IN NDIS_HANDLE OldAddressContext, + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest + ); +#endif + +// +// This action routine is called when the mac requests a close for +// a particular binding *WHILE THE BINDING IS BEING INDICATED TO +// THE PROTOCOL*. The filtering package can't get rid of the open +// right away. So this routine will be called as soon as the +// NdisIndicateReceive returns. +// +// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED. +// +typedef +VOID +(*ETH_DEFERRED_CLOSE)( + IN NDIS_HANDLE MacBindingHandle + ); + +typedef ULONG ETH_MASK,*PETH_MASK; + +// +// Maximum number of opens the filter package will support. This is +// the max so that bit masks can be used instead of a spaghetti of +// pointers. +// +#define ETH_FILTER_MAX_OPENS (sizeof(ULONG) * 8) + +// +// The binding info is threaded on two lists. When +// the binding is free it is on a single freelist. +// +// When the binding is being used it is on a doubly linked +// index list. +// +typedef struct _ETH_BINDING_INFO { + NDIS_HANDLE MacBindingHandle; + NDIS_HANDLE NdisBindingContext; + UINT PacketFilters; + ULONG References; + struct _ETH_BINDING_INFO *NextOpen; + struct _ETH_BINDING_INFO *PrevOpen; + BOOLEAN ReceivedAPacket; + UCHAR FilterIndex; +} ETH_BINDING_INFO,*PETH_BINDING_INFO; + +// +// An opaque type that contains a filter database. +// The MAC need not know how it is structured. +// +typedef struct _ETH_FILTER { + + // + // Spin lock used to protect the filter from multiple accesses. + // + PNDIS_SPIN_LOCK Lock; + + // + // Pointer to an array of 6 character arrays holding the + // multicast addresses requested for filtering. + // + CHAR (*MulticastAddresses)[ETH_LENGTH_OF_ADDRESS]; + + // + // Pointer to an array of ETH_MASKS that work in conjuction with + // the MulticastAddress array. In the masks, a bit being enabled + // indicates that the binding with the given FilterIndex is using + // the corresponding address. + // + ETH_MASK *BindingsUsingAddress; + + // + // Combination of all the filters of all the open bindings. + // + UINT CombinedPacketFilter; + + // + // Pointer for traversing the open list. + // + PETH_BINDING_INFO OpenList; + + + // + // Action routines to be invoked on notable changes in the filter. + // + + ETH_ADDRESS_CHANGE AddressChangeAction; + ETH_FILTER_CHANGE FilterChangeAction; + ETH_DEFERRED_CLOSE CloseAction; + + // + // The maximum number of addresses used for filtering. + // + UINT MaximumMulticastAddresses; + + // + // The current number of addresses in the address filter. + // + UINT NumberOfAddresses; + + // + // Bit mask of opens that are available. + // + ULONG FreeBindingMask; + + // + // Address of the adapter. + // + UCHAR AdapterAddress[ETH_LENGTH_OF_ADDRESS]; + +} ETH_FILTER,*PETH_FILTER; + + +// +// Only for internal wrapper use. +// +VOID +EthInitializePackage( + VOID + ); + +VOID +EthReferencePackage( + VOID + ); + +VOID +EthDereferencePackage( + VOID + ); + +// +// Exported functions +// +EXPORT +BOOLEAN +EthCreateFilter( + IN UINT MaximumMulticastAddresses, + IN ETH_ADDRESS_CHANGE AddressChangeAction, + IN ETH_FILTER_CHANGE FilterChangeAction, + IN ETH_DEFERRED_CLOSE CloseAction, + IN PUCHAR AdapterAddress, + IN PNDIS_SPIN_LOCK Lock, + OUT PETH_FILTER *Filter + ); + +EXPORT +VOID +EthDeleteFilter( + IN PETH_FILTER Filter + ); + +EXPORT +BOOLEAN +EthNoteFilterOpenAdapter( + IN PETH_FILTER Filter, + IN NDIS_HANDLE MacBindingHandle, + IN NDIS_HANDLE NdisBindingContext, + OUT PNDIS_HANDLE NdisFilterHandle + ); + +EXPORT +NDIS_STATUS +EthDeleteFilterOpenAdapter( + IN PETH_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest + ); + +EXPORT +NDIS_STATUS +EthChangeFilterAddresses( + IN PETH_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest, + IN UINT AddressCount, + IN CHAR Addresses[][ETH_LENGTH_OF_ADDRESS], + IN BOOLEAN Set + ); + + +#define EthShouldAddressLoopBackMacro(_Filter, _Address, _pfLoopback, _pfSelfDirected) \ +{ \ + UINT CombinedFilters; \ + \ + CombinedFilters = ETH_QUERY_FILTER_CLASSES(_Filter); \ + \ + *(_pfLoopback) = FALSE; \ + *(_pfSelfDirected) = FALSE; \ + \ + do \ + { \ + /* \ + * First check if the filter is promiscuous. \ + */ \ + \ + if (CombinedFilters & NDIS_PACKET_TYPE_PROMISCUOUS) \ + { \ + *(_pfLoopback) = TRUE; \ + break; \ + } \ + \ + /* \ + * Check if it *at least* has the multicast address bit. \ + */ \ + \ + if (ETH_IS_MULTICAST(_Address)) \ + { \ + /* \ + * It is at least a multicast address. Check to see if \ + * it is a broadcast address. \ + */ \ + \ + if (ETH_IS_BROADCAST(_Address)) \ + { \ + if (CombinedFilters & NDIS_PACKET_TYPE_BROADCAST) \ + { \ + *(_pfLoopback) = TRUE; \ + break; \ + } \ + else \ + { \ + break; \ + } \ + } \ + else \ + { \ + if ((CombinedFilters & NDIS_PACKET_TYPE_ALL_MULTICAST) || \ + (CombinedFilters & NDIS_PACKET_TYPE_MULTICAST)) \ + { \ + *(_pfLoopback) = TRUE; \ + break; \ + } \ + } \ + } \ + else \ + { \ + /* \ + * Directed to ourself?? \ + */ \ + \ + if ((*(ULONG UNALIGNED *)&(_Address)[2] == \ + *(ULONG UNALIGNED *)&(_Filter)->AdapterAddress[2]) && \ + (*(USHORT UNALIGNED *)&(_Address)[0] == \ + *(USHORT UNALIGNED *)&(_Filter)->AdapterAddress[0])) \ + { \ + *(_pfLoopback) = TRUE; \ + *(_pfSelfDirected) = TRUE; \ + } \ + } \ + } while (FALSE); \ +} + +EXPORT +BOOLEAN +EthShouldAddressLoopBack( + IN PETH_FILTER Filter, + IN CHAR Address[ETH_LENGTH_OF_ADDRESS] + ); + +EXPORT +NDIS_STATUS +EthFilterAdjust( + IN PETH_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest, + IN UINT FilterClasses, + IN BOOLEAN Set + ); + +EXPORT +UINT +EthNumberOfOpenFilterAddresses( + IN PETH_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle + ); + +EXPORT +VOID +EthQueryGlobalFilterAddresses( + OUT PNDIS_STATUS Status, + IN PETH_FILTER Filter, + IN UINT SizeOfArray, + OUT PUINT NumberOfAddresses, + IN OUT CHAR AddressArray[][ETH_LENGTH_OF_ADDRESS] + ); + +EXPORT +VOID +EthQueryOpenFilterAddresses( + OUT PNDIS_STATUS Status, + IN PETH_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN UINT SizeOfArray, + OUT PUINT NumberOfAddresses, + IN OUT CHAR AddressArray[][ETH_LENGTH_OF_ADDRESS] + ); + + +EXPORT +VOID +EthFilterIndicateReceive( + IN PETH_FILTER Filter, + IN NDIS_HANDLE MacReceiveContext, + IN PCHAR Address, + IN PVOID HeaderBuffer, + IN UINT HeaderBufferSize, + IN PVOID LookaheadBuffer, + IN UINT LookaheadBufferSize, + IN UINT PacketSize + ); + +EXPORT +VOID +EthFilterDprIndicateReceive( + IN PETH_FILTER Filter, + IN NDIS_HANDLE MacReceiveContext, + IN PCHAR Address, + IN PVOID HeaderBuffer, + IN UINT HeaderBufferSize, + IN PVOID LookaheadBuffer, + IN UINT LookaheadBufferSize, + IN UINT PacketSize + ); + +EXPORT +VOID +EthFilterIndicateReceiveComplete( + IN PETH_FILTER Filter + ); + +EXPORT +VOID +EthFilterDprIndicateReceiveComplete( + IN PETH_FILTER Filter + ); + +#endif // _ETH_FILTER_DEFS_ + diff --git a/private/ntos/ndis/ndis30/ffilter.c b/private/ntos/ndis/ndis30/ffilter.c new file mode 100644 index 000000000..6a6397669 --- /dev/null +++ b/private/ntos/ndis/ndis30/ffilter.c @@ -0,0 +1,3193 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + ffilter.c + +Abstract: + + This module implements a set of library routines to handle packet + filtering for NDIS MAC drivers. + +Author: + + Anthony V. Ercolano (Tonye) 03-Aug-1990 + +Environment: + + Kernel Mode - Or whatever is the equivalent on OS/2 and DOS. + +Revision History: + + Sean Selitrennikoff (SeanSe) converted Efilter.* for FDDI filtering. + + +--*/ + +#include <precomp.h> +#pragma hdrstop + +// +// This constant is used for places where NdisAllocateMemory +// needs to be called and the HighestAcceptableAddress does +// not matter. +// + +static const NDIS_PHYSICAL_ADDRESS HighestAcceptableMax = + NDIS_PHYSICAL_ADDRESS_CONST(-1,-1); + +// +// ZZZ NonPortable definitions. +// +#define AllocPhys(s, l) NdisAllocateMemory((PVOID *)(s), (l), 0, HighestAcceptableMax) +#define FreePhys(s, l) NdisFreeMemory((PVOID)(s), (l), 0) +#ifdef NDIS_NT +#define MoveMemory(Destination,Source,Length) RtlMoveMemory(Destination,Source,Length) +#define ZeroMemory(Destination,Length) RtlZeroMemory(Destination,Length) +#endif + +#ifdef NDIS_DOS +#define MoveMemory(Destination,Source,Length) memcpy(Destination,Source,Length) +#define ZeroMemory(Destination,Length) memset(Destination,0,Length) +#endif + +#if DBG +extern BOOLEAN NdisCheckBadDrivers; +#endif + +// +// A set of macros to manipulate bitmasks. +// + +//VOID +//CLEAR_BIT_IN_MASK( +// IN UINT Offset, +// IN OUT PFDDI_MASK MaskToClear +// ) +// +///*++ +// +//Routine Description: +// +// Clear a bit in the bitmask pointed to by the parameter. +// +//Arguments: +// +// Offset - The offset (from 0) of the bit to altered. +// +// MaskToClear - Pointer to the mask to be adjusted. +// +//Return Value: +// +// None. +// +//--*/ +// +#define CLEAR_BIT_IN_MASK(Offset,MaskToClear) *MaskToClear &= (~(1 << Offset)) + +//VOID +//SET_BIT_IN_MASK( +// IN UINT Offset, +// IN OUT PFDDI_MASK MaskToSet +// ) +// +///*++ +// +//Routine Description: +// +// Set a bit in the bitmask pointed to by the parameter. +// +//Arguments: +// +// Offset - The offset (from 0) of the bit to altered. +// +// MaskToSet - Pointer to the mask to be adjusted. +// +//Return Value: +// +// None. +// +//--*/ +#define SET_BIT_IN_MASK(Offset,MaskToSet) *MaskToSet |= (1 << Offset) + +//BOOLEAN +//IS_BIT_SET_IN_MASK( +// IN UINT Offset, +// IN FDDI_MASK MaskToTest +// ) +// +///*++ +// +//Routine Description: +// +// Tests if a particular bit in the bitmask pointed to by the parameter is +// set. +// +//Arguments: +// +// Offset - The offset (from 0) of the bit to test. +// +// MaskToTest - The mask to be tested. +// +//Return Value: +// +// Returns TRUE if the bit is set. +// +//--*/ +#define IS_BIT_SET_IN_MASK(Offset,MaskToTest) \ +((MaskToTest & (1 << Offset))?(TRUE):(FALSE)) + +//BOOLEAN +//IS_MASK_CLEAR( +// IN FDDI_MASK MaskToTest +// ) +// +///*++ +// +//Routine Description: +// +// Tests whether there are *any* bits enabled in the mask. +// +//Arguments: +// +// MaskToTest - The bit mask to test for all clear. +// +//Return Value: +// +// Will return TRUE if no bits are set in the mask. +// +//--*/ +#define IS_MASK_CLEAR(MaskToTest) ((!MaskToTest)?(TRUE):(FALSE)) + +//VOID +//CLEAR_MASK( +// IN OUT PFDDI_MASK MaskToClear +// ); +// +///*++ +// +//Routine Description: +// +// Clears a mask. +// +//Arguments: +// +// MaskToClear - The bit mask to adjust. +// +//Return Value: +// +// None. +// +//--*/ +#define CLEAR_MASK(MaskToClear) *MaskToClear = 0 + +// +// VOID +// FDDI_FILTER_ALLOC_OPEN( +// IN PFDDI_FILTER Filter, +// OUT PUINT FilterIndex +// ) +// +///*++ +// +//Routine Description: +// +// Allocates an open block. This only allocate the index, not memory for +// the open block. +// +//Arguments: +// +// Filter - DB from which to allocate the space +// +// FilterIndex - pointer to place to store the index. +// +//Return Value: +// +// FilterIndex of the new open +// +//--*/ +#define FDDI_FILTER_ALLOC_OPEN(Filter, FilterIndex)\ +{\ + UINT i; \ + for (i=0; i < FDDI_FILTER_MAX_OPENS; i++) { \ + if (IS_BIT_SET_IN_MASK(i,(Filter)->FreeBindingMask)) { \ + *(FilterIndex) = i; \ + CLEAR_BIT_IN_MASK(i, &((Filter)->FreeBindingMask)); \ + break; \ + } \ + } \ +} + +// +// VOID +// FDDI_FILTER_FREE_OPEN( +// IN PFDDI_FILTER Filter, +// IN PFDDI_BINDING_INFO LocalOpen +// ) +// +///*++ +// +//Routine Description: +// +// Frees an open block. Also frees the memory associated with the open. +// +//Arguments: +// +// Filter - DB from which to allocate the space +// +// FilterIndex - Index to free +// +//Return Value: +// +// FilterIndex of the new open +// +//--*/ +#define FDDI_FILTER_FREE_OPEN(Filter, LocalOpen)\ +{\ + SET_BIT_IN_MASK(((LocalOpen)->FilterIndex), &((Filter)->FreeBindingMask)); \ + FreePhys((LocalOpen), sizeof(FDDI_BINDING_INFO));\ +} + + +NDIS_SPIN_LOCK FddiReferenceLock = {0}; +KEVENT FddiPagedInEvent = {0}; +ULONG FddiReferenceCount = 0; +PVOID FddiImageHandle = {0}; + +VOID +FddiInitializePackage(VOID) +{ + NdisAllocateSpinLock(&FddiReferenceLock); + KeInitializeEvent( + &FddiPagedInEvent, + NotificationEvent, + FALSE + ); +} + +VOID +FddiReferencePackage(VOID) +{ + + ACQUIRE_SPIN_LOCK(&FddiReferenceLock); + + FddiReferenceCount++; + + if (FddiReferenceCount == 1) { + + KeResetEvent( + &FddiPagedInEvent + ); + + RELEASE_SPIN_LOCK(&FddiReferenceLock); + + // + // Page in all the functions + // + FddiImageHandle = MmLockPagableCodeSection(FddiCreateFilter); + + // + // Signal to everyone to go + // + KeSetEvent( + &FddiPagedInEvent, + 0L, + FALSE + ); + + } else { + + RELEASE_SPIN_LOCK(&FddiReferenceLock); + + // + // Wait for everything to be paged in + // + KeWaitForSingleObject( + &FddiPagedInEvent, + Executive, + KernelMode, + TRUE, + NULL + ); + + } + +} + +VOID +FddiDereferencePackage(VOID) +{ + ACQUIRE_SPIN_LOCK(&FddiReferenceLock); + + FddiReferenceCount--; + + if (FddiReferenceCount == 0) { + + RELEASE_SPIN_LOCK(&FddiReferenceLock); + + // + // Page out all the functions + // + MmUnlockPagableImageSection(FddiImageHandle); + + } else { + + RELEASE_SPIN_LOCK(&FddiReferenceLock); + + } + +} + +static +BOOLEAN +FindMulticastLongAddress( + IN UINT NumberOfAddresses, + IN CHAR AddressArray[][FDDI_LENGTH_OF_LONG_ADDRESS], + IN CHAR MulticastAddress[FDDI_LENGTH_OF_LONG_ADDRESS], + OUT PUINT ArrayIndex + ); + +static +BOOLEAN +FindMulticastShortAddress( + IN UINT NumberOfAddresses, + IN CHAR AddressArray[][FDDI_LENGTH_OF_SHORT_ADDRESS], + IN CHAR MulticastAddress[FDDI_LENGTH_OF_SHORT_ADDRESS], + OUT PUINT ArrayIndex + ); + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGENDSF, FddiShouldAddressLoopBack) +#pragma alloc_text(PAGENDSF, FindMulticastShortAddress) +#pragma alloc_text(PAGENDSF, FindMulticastLongAddress) +#pragma alloc_text(PAGENDSF, FddiFilterDprIndicateReceiveComplete) +#pragma alloc_text(PAGENDSF, FddiFilterIndicateReceiveComplete) +#pragma alloc_text(PAGENDSF, FddiFilterDprIndicateReceive) +#pragma alloc_text(PAGENDSF, FddiFilterIndicateReceive) +#pragma alloc_text(PAGENDSF, FddiQueryGlobalFilterShortAddresses) +#pragma alloc_text(PAGENDSF, FddiQueryGlobalFilterLongAddresses) +#pragma alloc_text(PAGENDSF, FddiQueryOpenFilterShortAddresses) +#pragma alloc_text(PAGENDSF, FddiQueryOpenFilterLongAddresses) +#pragma alloc_text(PAGENDSF, FddiNumberOfOpenFilterShortAddresses) +#pragma alloc_text(PAGENDSF, FddiNumberOfOpenFilterLongAddresses) +#pragma alloc_text(PAGENDSF, FddiFilterAdjust) +#pragma alloc_text(PAGENDSF, FddiChangeFilterShortAddresses) +#pragma alloc_text(PAGENDSF, FddiChangeFilterLongAddresses) +#pragma alloc_text(PAGENDSF, FddiDeleteFilterOpenAdapter) +#pragma alloc_text(PAGENDSF, FddiNoteFilterOpenAdapter) +#pragma alloc_text(PAGENDSF, FddiCreateFilter) + +#endif + + + + +BOOLEAN +FddiCreateFilter( + IN UINT MaximumMulticastLongAddresses, + IN UINT MaximumMulticastShortAddresses, + IN FDDI_ADDRESS_CHANGE AddressChangeAction, + IN FDDI_FILTER_CHANGE FilterChangeAction, + IN FDDI_DEFERRED_CLOSE CloseAction, + IN PUCHAR AdapterLongAddress, + IN PUCHAR AdapterShortAddress, + IN PNDIS_SPIN_LOCK Lock, + OUT PFDDI_FILTER *Filter + ) + +/*++ + +Routine Description: + + This routine is used to create and initialize the filter database. + +Arguments: + + MaximumMulticastLongAddresses - The maximum number of Long multicast addresses + that the MAC will support. + + MaximumMulticastShortAddresses - The maximum number of short multicast addresses + that the MAC will support. + + AddressChangeAction - Action routine to call when the list of + multicast addresses the card must enable has changed. + + ChangeAction - Action routine to call when a binding sets or clears + a particular filter class and it is the first or only binding using + the filter class. + + CloseAction - This routine is called if a binding closes while + it is being indicated to via NdisIndicateReceive. It will be + called upon return from NdisIndicateReceive. + + AdapterLongAddress - the long address of the adapter associated with this filter + database. + + AdapterShortAddress - the short address of the adapter associated with this filter + database. + + Lock - Pointer to the lock that should be held when mutual exclusion + is required.w + + Filter - A pointer to an FDDI_FILTER. This is what is allocated and + created by this routine. + +Return Value: + + If the function returns false then one of the parameters exceeded + what the filter was willing to support. + +--*/ + +{ + + PFDDI_FILTER LocalFilter; + NDIS_STATUS AllocStatus; + + // + // Allocate the database and it's associated arrays. + // + + AllocStatus = AllocPhys(&LocalFilter, sizeof(FDDI_FILTER)); + *Filter = LocalFilter; + + if (AllocStatus != NDIS_STATUS_SUCCESS) { + return FALSE; + } + + ZeroMemory( + LocalFilter, + sizeof(FDDI_FILTER) + ); + + if (MaximumMulticastLongAddresses == 0) { + + // + // Why 2 and not 1? Why not. A protocol is going to need at least + // one to run on this, so let's give one extra one for any user stuff + // that may need it. + // + + MaximumMulticastLongAddresses = 2; + + } + + if (MaximumMulticastShortAddresses == 0) { + + // + // Why 2 and not 1? Why not. A protocol is going to need at least + // one to run on this, so let's give one extra one for any user stuff + // that may need it. + // + + MaximumMulticastShortAddresses = 2; + + } + + { + PVOID TmpAlloc; + + AllocStatus = AllocPhys( + &TmpAlloc, + 2*FDDI_LENGTH_OF_LONG_ADDRESS*MaximumMulticastLongAddresses + ); + + LocalFilter->MulticastLongAddresses = TmpAlloc; + + } + + if (AllocStatus != NDIS_STATUS_SUCCESS) { + + FddiDeleteFilter(LocalFilter); + return FALSE; + + } + + { + PVOID TmpAlloc; + + AllocStatus = AllocPhys( + &TmpAlloc, + 2*FDDI_LENGTH_OF_SHORT_ADDRESS*MaximumMulticastShortAddresses + ); + + LocalFilter->MulticastShortAddresses = TmpAlloc; + + } + + if (AllocStatus != NDIS_STATUS_SUCCESS) { + + FddiDeleteFilter(LocalFilter); + return FALSE; + + } + + AllocStatus = AllocPhys( + &LocalFilter->BindingsUsingLongAddress, + 2*sizeof(FDDI_MASK)*MaximumMulticastLongAddresses + ); + + if (AllocStatus != NDIS_STATUS_SUCCESS) { + + FddiDeleteFilter(LocalFilter); + return FALSE; + + } + + AllocStatus = AllocPhys( + &LocalFilter->BindingsUsingShortAddress, + 2*sizeof(FDDI_MASK)*MaximumMulticastShortAddresses + ); + + if (AllocStatus != NDIS_STATUS_SUCCESS) { + + FddiDeleteFilter(LocalFilter); + return FALSE; + + } + + FddiReferencePackage(); + + LocalFilter->FreeBindingMask = (ULONG)(-1); + LocalFilter->OpenList = NULL; + + FDDI_COPY_NETWORK_ADDRESS(LocalFilter->AdapterLongAddress, + AdapterLongAddress, + FDDI_LENGTH_OF_LONG_ADDRESS + ); + + FDDI_COPY_NETWORK_ADDRESS(LocalFilter->AdapterShortAddress, + AdapterShortAddress, + FDDI_LENGTH_OF_SHORT_ADDRESS + ); + + LocalFilter->Lock = Lock; + LocalFilter->AddressChangeAction = AddressChangeAction; + LocalFilter->FilterChangeAction = FilterChangeAction; + LocalFilter->CloseAction = CloseAction; + LocalFilter->NumberOfLongAddresses = 0; + LocalFilter->NumberOfShortAddresses = 0; + LocalFilter->MaximumMulticastLongAddresses = MaximumMulticastLongAddresses; + LocalFilter->MaximumMulticastShortAddresses = MaximumMulticastShortAddresses; + + return TRUE; +} + +// +// NOTE: THIS CANNOT BE PAGABLE +// +VOID +FddiDeleteFilter( + IN PFDDI_FILTER Filter + ) + +/*++ + +Routine Description: + + This routine is used to delete the memory associated with a filter + database. Note that this routines *ASSUMES* that the database + has been cleared of any active filters. + +Arguments: + + Filter - A pointer to an FDDI_FILTER to be deleted. + +Return Value: + + None. + +--*/ + +{ + + ASSERT(Filter->FreeBindingMask == (FDDI_MASK)-1); + ASSERT(Filter->OpenList == NULL); + + if (Filter->MulticastLongAddresses) { + + FreePhys( + Filter->MulticastLongAddresses, + 2*FDDI_LENGTH_OF_LONG_ADDRESS*Filter->MaximumMulticastLongAddresses + ); + + } + + if (Filter->MulticastShortAddresses) { + + FreePhys( + Filter->MulticastShortAddresses, + 2*FDDI_LENGTH_OF_SHORT_ADDRESS*Filter->MaximumMulticastShortAddresses + ); + + } + + if (Filter->BindingsUsingLongAddress) { + + FreePhys( + Filter->BindingsUsingLongAddress, + 2*sizeof(FDDI_MASK)*Filter->MaximumMulticastLongAddresses + ); + + } + + if (Filter->BindingsUsingShortAddress) { + + FreePhys( + Filter->BindingsUsingShortAddress, + 2*sizeof(FDDI_MASK)*Filter->MaximumMulticastShortAddresses + ); + + } + + FreePhys(Filter, sizeof(FDDI_FILTER)); + + FddiDereferencePackage(); +} + + +BOOLEAN +FddiNoteFilterOpenAdapter( + IN PFDDI_FILTER Filter, + IN NDIS_HANDLE MacBindingHandle, + IN NDIS_HANDLE NdisBindingContext, + OUT PNDIS_HANDLE NdisFilterHandle + ) + +/*++ + +Routine Description: + + This routine is used to add a new binding to the filter database. + + NOTE: THIS ROUTINE ASSUMES THAT THE DATABASE IS LOCKED WHEN + IT IS CALLED. + +Arguments: + + Filter - A pointer to the previously created and initialized filter + database. + + MacBindingHandle - The MAC supplied value to the protocol in response + to a call to FddiOpenAdapter. + + NdisBindingContext - An NDIS supplied value to the call to FddiOpenAdapter. + + NdisFilterHandle - A pointer to this open. + +Return Value: + + Will return false if creating a new filter index will cause the maximum + number of filter indexes to be exceeded. + +--*/ + +{ + + // + // Will hold the value of the filter index so that we + // need not indirectly address through pointer parameter. + // + UINT LocalIndex; + + NDIS_STATUS AllocStatus; + + // + // Pointer to new open block. + // + PFDDI_BINDING_INFO LocalOpen; + + PNDIS_OPEN_BLOCK NdisOpen = (PNDIS_OPEN_BLOCK)NdisBindingContext; + + + // + // Get the first free binding slot and remove that slot from + // the free list. We check to see if the list is empty. + // + + + if (Filter->FreeBindingMask == 0) { + + return FALSE; + + } + + AllocStatus = AllocPhys( + &LocalOpen, + sizeof(FDDI_BINDING_INFO) + ); + + if (AllocStatus != NDIS_STATUS_SUCCESS) { + + return FALSE; + + } + + // + // Get place for the open and insert it. + // + + FDDI_FILTER_ALLOC_OPEN(Filter, &LocalIndex); + + LocalOpen->NextOpen = Filter->OpenList; + + if (Filter->OpenList != NULL) { + Filter->OpenList->PrevOpen = LocalOpen; + } + + LocalOpen->PrevOpen = NULL; + + Filter->OpenList = LocalOpen; + + LocalOpen->FilterIndex = (UCHAR)LocalIndex; + LocalOpen->References = 1; + LocalOpen->MacBindingHandle = MacBindingHandle; + LocalOpen->NdisBindingContext = NdisBindingContext; + LocalOpen->PacketFilters = 0; + LocalOpen->ReceivedAPacket = FALSE; + + *NdisFilterHandle = (NDIS_HANDLE)LocalOpen; + + return TRUE; + +} + + +NDIS_STATUS +FddiDeleteFilterOpenAdapter( + IN PFDDI_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest + ) + +/*++ + +Routine Description: + + When an adapter is being closed this routine should + be called to delete knowledge of the adapter from + the filter database. This routine is likely to call + action routines associated with clearing filter classes + and addresses. + + NOTE: THIS ROUTINE SHOULD ****NOT**** BE CALLED IF THE ACTION + ROUTINES FOR DELETING THE FILTER CLASSES OR THE MULTICAST ADDRESSES + HAVE ANY POSSIBILITY OF RETURNING A STATUS OTHER THAN NDIS_STATUS_PENDING + OR NDIS_STATUS_SUCCESS. WHILE THESE ROUTINES WILL NOT BUGCHECK IF + SUCH A THING IS DONE, THE CALLER WILL PROBABLY FIND IT DIFFICULT + TO CODE A CLOSE ROUTINE! + + NOTE: THIS ROUTINE ASSUMES THAT IT IS CALLED WITH THE LOCK HELD. + +Arguments: + + Filter - A pointer to the filter database. + + NdisFilterHandle - Pointer to the open. + + NdisRequest - If it is necessary to call the action routines, + this will be passed to it. + +Return Value: + + If action routines are called by the various address and filtering + routines the this routine will likely return the status returned + by those routines. The exception to this rule is noted below. + + Given that the filter and address deletion routines return a status + NDIS_STATUS_PENDING or NDIS_STATUS_SUCCESS this routine will then + try to return the filter index to the freelist. If the routine + detects that this binding is currently being indicated to via + NdisIndicateReceive, this routine will return a status of + NDIS_STATUS_CLOSING_INDICATING. + +--*/ + +{ + + // + // Holds the status returned from the packet filter and address + // deletion routines. Will be used to return the status to + // the caller of this routine. + // + NDIS_STATUS StatusToReturn; + + // + // Local variable. + // + PFDDI_BINDING_INFO LocalOpen = (PFDDI_BINDING_INFO)NdisFilterHandle; + + StatusToReturn = FddiFilterAdjust( + Filter, + NdisFilterHandle, + NdisRequest, + (UINT)0, + FALSE + ); + + if (StatusToReturn == NDIS_STATUS_SUCCESS || + StatusToReturn == NDIS_STATUS_PENDING) { + + NDIS_STATUS StatusToReturn2; + + StatusToReturn2 = FddiChangeFilterLongAddresses( + Filter, + NdisFilterHandle, + NdisRequest, + 0, + NULL, + FALSE + ); + + if (StatusToReturn2 != NDIS_STATUS_SUCCESS) { + + StatusToReturn = StatusToReturn2; + + } + + if ((StatusToReturn == NDIS_STATUS_SUCCESS) || + (StatusToReturn == NDIS_STATUS_PENDING)) { + + + StatusToReturn2 = FddiChangeFilterShortAddresses( + Filter, + NdisFilterHandle, + NdisRequest, + 0, + NULL, + FALSE + ); + + if (StatusToReturn2 != NDIS_STATUS_SUCCESS) { + + StatusToReturn = StatusToReturn2; + + } + + } + + } + + + if ((StatusToReturn == NDIS_STATUS_SUCCESS) || + (StatusToReturn == NDIS_STATUS_PENDING)) { + + // + // Remove the reference from the original open. + // + + if (--(LocalOpen->References) == 0) { + + // + // Remove it from the list. + // + + if (LocalOpen->NextOpen != NULL) { + + LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen; + + } + + if (LocalOpen->PrevOpen != NULL) { + + LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen; + + } else { + + Filter->OpenList = LocalOpen->NextOpen; + + } + + + // + // First we finish any NdisIndicateReceiveComplete that + // may be needed for this binding. + // + + if (LocalOpen->ReceivedAPacket) { + + RELEASE_SPIN_LOCK_DPC(Filter->Lock); + + FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext); + + ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + + } + + FDDI_FILTER_FREE_OPEN(Filter, LocalOpen); + + } else { + + // + // Let the caller know that there is a reference to the open + // by the receive indication. The close action routine will be + // called upon return from NdisIndicateReceive. + // + + StatusToReturn = NDIS_STATUS_CLOSING_INDICATING; + + } + + } + + return StatusToReturn; + +} + + +NDIS_STATUS +FddiChangeFilterLongAddresses( + IN PFDDI_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest, + IN UINT AddressCount, + IN CHAR Addresses[][FDDI_LENGTH_OF_LONG_ADDRESS], + IN BOOLEAN Set + ) + +/*++ + +Routine Description: + + The ChangeFilterAddress routine will call an action + routine when the overall multicast address list for the adapter + has changed. + + If the action routine returns a value other than pending or + success then this routine has no effect on the multicast address + list for the open or for the adapter as a whole. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + +Arguments: + + Filter - A pointer to the filter database. + + NdisFilterHandle - Pointer to the open. + + NdisRequest - If it is necessary to call the action routine, + this will be passed to it. + + AddressCount - The number of elements (addresses, + not bytes) in MulticastAddressList. + + Addresses - The new multicast address list for this + binding. This is a sequence of FDDI_LENGTH_OF_LONG_ADDRESS byte + addresses, with no padding between them. + + Set - A boolean that determines whether the multicast addresses + are being adjusted due to a set or because of a close. (The filtering + routines don't care, the MAC might.) + +Return Value: + + If it calls the action routine then it will return the + status returned by the action routine. If the status + returned by the action routine is anything other than + NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database + will be returned to the state it was in upon entrance to this + routine. + + If the action routine is not called this routine will return + the following statum: + + NDIS_STATUS_SUCCESS - If the new packet filters doesn't change + the combined mask of all bindings packet filters. + +--*/ + +{ + // + // Holds the status returned to the user of this routine, if the + // action routine is not called then the status will be success, + // otherwise, it is whatever the action routine returns. + // + NDIS_STATUS StatusOfChange; + + // + // Saves the original length of the address array. + // + UINT InitialArraySize; + + // + // Set true when the address array changes + // + BOOLEAN AddressesChanged = FALSE; + + // + // Use to save data if needed. + // + PVOID TmpAddressArray, TmpMaskArray; + + // + // Simple iteration variables. + // + UINT ArrayIndex, i; + + + // + // Simple Temp variable + // + PCHAR CurrentAddress; + + PFDDI_BINDING_INFO LocalOpen = (PFDDI_BINDING_INFO)NdisFilterHandle; + + + TmpAddressArray = + (PUCHAR)Filter->MulticastLongAddresses + + (FDDI_LENGTH_OF_LONG_ADDRESS*Filter->MaximumMulticastLongAddresses); + + TmpMaskArray = + (PUCHAR)Filter->BindingsUsingLongAddress + + (sizeof(FDDI_MASK)*Filter->MaximumMulticastLongAddresses); + + + // + // We have to save the old mask array in + // case we need to restore it. If we need + // to save the address array too we will + // do that later. + // + + MoveMemory( + TmpMaskArray, + (PVOID)Filter->BindingsUsingLongAddress, + Filter->NumberOfLongAddresses * sizeof(FDDI_MASK) + ); + + // + // We have to save the old address array in + // case we need to restore it. If we need + // to save the address array too we will + // do that later. + // + + MoveMemory( + TmpAddressArray, + (PVOID)Filter->MulticastLongAddresses, + Filter->NumberOfLongAddresses * FDDI_LENGTH_OF_LONG_ADDRESS + ); + + InitialArraySize = Filter->NumberOfLongAddresses; + + + // + // Now modify the original array... + // + + // + // First go through and turn off the bit for this + // binding throughout the array. + // + + for (i=0; i<(Filter->NumberOfLongAddresses); i++) { + + CLEAR_BIT_IN_MASK( + LocalOpen->FilterIndex, + &(Filter->BindingsUsingLongAddress[i]) + ); + + } + + + // + // Now go through the new addresses for this binding, + // and insert them into the array. + // + + for (i=0; i<AddressCount; i++) { + + CurrentAddress = ((PCHAR)Addresses) + (i*FDDI_LENGTH_OF_LONG_ADDRESS); + + if (FindMulticastLongAddress( + Filter->NumberOfLongAddresses, + Filter->MulticastLongAddresses, + CurrentAddress, + &ArrayIndex)) { + + // + // The address is there, so just turn the bit + // back on. + // + + SET_BIT_IN_MASK( + LocalOpen->FilterIndex, + &Filter->BindingsUsingLongAddress[ArrayIndex] + ); + + } else { + + // + // The address was not found, add it. + // + // NOTE: Here we temporarily need more array + // space then we may finally, but for now this + // will work. + // + + if (Filter->NumberOfLongAddresses < Filter->MaximumMulticastLongAddresses) { + + // + // Save the address array if it hasn't been. + // + + AddressesChanged = TRUE; + + MoveMemory( + Filter->MulticastLongAddresses[ArrayIndex+1], + Filter->MulticastLongAddresses[ArrayIndex], + (Filter->NumberOfLongAddresses-ArrayIndex)*FDDI_LENGTH_OF_LONG_ADDRESS + ); + + FDDI_COPY_NETWORK_ADDRESS( + Filter->MulticastLongAddresses[ArrayIndex], + CurrentAddress, + FDDI_LENGTH_OF_LONG_ADDRESS + ); + + MoveMemory( + &(Filter->BindingsUsingLongAddress[ArrayIndex+1]), + &(Filter->BindingsUsingLongAddress[ArrayIndex]), + (Filter->NumberOfLongAddresses-ArrayIndex)*sizeof(FDDI_MASK) + ); + + CLEAR_MASK(&Filter->BindingsUsingLongAddress[ArrayIndex]); + + SET_BIT_IN_MASK( + LocalOpen->FilterIndex, + &Filter->BindingsUsingLongAddress[ArrayIndex] + ); + + Filter->NumberOfLongAddresses++; + + } else { + + // + // No room in the array, oh well. + // + + MoveMemory( + (PVOID)Filter->MulticastLongAddresses, + TmpAddressArray, + InitialArraySize * FDDI_LENGTH_OF_LONG_ADDRESS + ); + + MoveMemory( + (PVOID)Filter->BindingsUsingLongAddress, + TmpMaskArray, + InitialArraySize * sizeof(FDDI_MASK) + ); + + Filter->NumberOfLongAddresses = InitialArraySize; + + return NDIS_STATUS_MULTICAST_FULL; + + } + + } + + } + + + // + // Finally we have to remove any addresses from + // the multicast array if they have no bits on any more. + // + for (ArrayIndex = 0; ArrayIndex < Filter->NumberOfLongAddresses; ) { + + if (IS_MASK_CLEAR(Filter->BindingsUsingLongAddress[ArrayIndex])) { + + // + // yes it is clear, so we have to shift everything + // above it down one. + // + + AddressesChanged = TRUE; + + MoveMemory( + Filter->MulticastLongAddresses[ArrayIndex], + Filter->MulticastLongAddresses[ArrayIndex+1], + (Filter->NumberOfLongAddresses-(ArrayIndex+1)) + *FDDI_LENGTH_OF_LONG_ADDRESS + ); + + MoveMemory( + &Filter->BindingsUsingLongAddress[ArrayIndex], + &Filter->BindingsUsingLongAddress[ArrayIndex+1], + (Filter->NumberOfLongAddresses-(ArrayIndex+1))*(sizeof(FDDI_MASK)) + ); + + Filter->NumberOfLongAddresses--; + + } else { + + ArrayIndex++; + + } + + } + + // + // If the address array has changed, we have to call the + // action array to inform the adapter of this. + // + + if (AddressesChanged) { + + StatusOfChange = Filter->AddressChangeAction( + InitialArraySize, + TmpAddressArray, + Filter->NumberOfLongAddresses, + Filter->MulticastLongAddresses, + Filter->NumberOfShortAddresses, + Filter->MulticastShortAddresses, + Filter->NumberOfShortAddresses, + Filter->MulticastShortAddresses, + LocalOpen->MacBindingHandle, + NdisRequest, + Set + ); + + if ((StatusOfChange != NDIS_STATUS_SUCCESS) && + (StatusOfChange != NDIS_STATUS_PENDING)) { + + // + // The user returned a bad status. Put things back as + // they were. + // + + MoveMemory( + (PVOID)Filter->MulticastLongAddresses, + TmpAddressArray, + InitialArraySize * FDDI_LENGTH_OF_LONG_ADDRESS + ); + + MoveMemory( + (PVOID)Filter->MulticastLongAddresses, + TmpAddressArray, + InitialArraySize * FDDI_LENGTH_OF_LONG_ADDRESS + ); + + } + + } else { + + StatusOfChange = NDIS_STATUS_SUCCESS; + + } + + + return StatusOfChange; + + +} + + +NDIS_STATUS +FddiChangeFilterShortAddresses( + IN PFDDI_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest, + IN UINT AddressCount, + IN CHAR Addresses[][FDDI_LENGTH_OF_SHORT_ADDRESS], + IN BOOLEAN Set + ) + +/*++ + +Routine Description: + + The ChangeFilterAddress routine will call an action + routine when the overall multicast address list for the adapter + has changed. + + If the action routine returns a value other than pending or + success then this routine has no effect on the multicast address + list for the open or for the adapter as a whole. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + +Arguments: + + Filter - A pointer to the filter database. + + NdisFilterHandle - Pointer to the open. + + NdisRequest - If it is necessary to call the action routine, + this will be passed to it. + + AddressCount - The number of elements (addresses, + not bytes) in MulticastAddressList. + + Addresses - The new multicast address list for this + binding. This is a sequence of FDDI_LENGTH_OF_SHORT_ADDRESS byte + addresses, with no padding between them. + + Set - A boolean that determines whether the multicast addresses + are being adjusted due to a set or because of a close. (The filtering + routines don't care, the MAC might.) + +Return Value: + + If it calls the action routine then it will return the + status returned by the action routine. If the status + returned by the action routine is anything other than + NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database + will be returned to the state it was in upon entrance to this + routine. + + If the action routine is not called this routine will return + the following statum: + + NDIS_STATUS_SUCCESS - If the new packet filters doesn't change + the combined mask of all bindings packet filters. + +--*/ + +{ + // + // Holds the status returned to the user of this routine, if the + // action routine is not called then the status will be success, + // otherwise, it is whatever the action routine returns. + // + NDIS_STATUS StatusOfChange; + + // + // Saves the original length of the address array. + // + UINT InitialArraySize; + + // + // Set true when the address array changes + // + BOOLEAN AddressesChanged = FALSE; + + // + // Use to save data if needed. + // + PVOID TmpAddressArray, TmpMaskArray; + + // + // Simple iteration variables. + // + UINT ArrayIndex, i; + + + // + // Simple Temp variable + // + PCHAR CurrentAddress; + + PFDDI_BINDING_INFO LocalOpen = (PFDDI_BINDING_INFO)NdisFilterHandle; + + + TmpAddressArray = + (PUCHAR)Filter->MulticastShortAddresses + + (FDDI_LENGTH_OF_SHORT_ADDRESS*Filter->MaximumMulticastShortAddresses); + + TmpMaskArray = + (PUCHAR)Filter->BindingsUsingShortAddress + + (sizeof(FDDI_MASK)*Filter->MaximumMulticastShortAddresses); + + + // + // We have to save the old mask array in + // case we need to restore it. If we need + // to save the address array too we will + // do that later. + // + + MoveMemory( + TmpMaskArray, + (PVOID)Filter->BindingsUsingShortAddress, + Filter->NumberOfShortAddresses * sizeof(FDDI_MASK) + ); + + // + // We have to save the old address array in + // case we need to restore it. If we need + // to save the address array too we will + // do that later. + // + + MoveMemory( + TmpAddressArray, + (PVOID)Filter->MulticastShortAddresses, + Filter->NumberOfShortAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS + ); + + InitialArraySize = Filter->NumberOfShortAddresses; + + + // + // Now modify the original array... + // + + // + // First go through and turn off the bit for this + // binding throughout the array. + // + + for (i=0; i<(Filter->NumberOfShortAddresses); i++) { + + CLEAR_BIT_IN_MASK( + LocalOpen->FilterIndex, + &(Filter->BindingsUsingShortAddress[i]) + ); + + } + + + // + // Now go through the new addresses for this binding, + // and insert them into the array. + // + + for (i=0; i<AddressCount; i++) { + + CurrentAddress = ((PCHAR)Addresses) + (i*FDDI_LENGTH_OF_SHORT_ADDRESS); + + if (FindMulticastShortAddress( + Filter->NumberOfShortAddresses, + Filter->MulticastShortAddresses, + CurrentAddress, + &ArrayIndex)) { + + // + // The address is there, so just turn the bit + // back on. + // + + SET_BIT_IN_MASK( + LocalOpen->FilterIndex, + &Filter->BindingsUsingShortAddress[ArrayIndex] + ); + + } else { + + // + // The address was not found, add it. + // + // NOTE: Here we temporarily need more array + // space then we may finally, but for now this + // will work. + // + + if (Filter->NumberOfShortAddresses < Filter->MaximumMulticastShortAddresses) { + + // + // Save the address array if it hasn't been. + // + + AddressesChanged = TRUE; + + MoveMemory( + Filter->MulticastShortAddresses[ArrayIndex+1], + Filter->MulticastShortAddresses[ArrayIndex], + (Filter->NumberOfShortAddresses-ArrayIndex)*FDDI_LENGTH_OF_SHORT_ADDRESS + ); + + FDDI_COPY_NETWORK_ADDRESS( + Filter->MulticastShortAddresses[ArrayIndex], + CurrentAddress, + FDDI_LENGTH_OF_SHORT_ADDRESS + ); + + MoveMemory( + &(Filter->BindingsUsingShortAddress[ArrayIndex+1]), + &(Filter->BindingsUsingShortAddress[ArrayIndex]), + (Filter->NumberOfShortAddresses-ArrayIndex)*sizeof(FDDI_MASK) + ); + + CLEAR_MASK(&Filter->BindingsUsingShortAddress[ArrayIndex]); + + SET_BIT_IN_MASK( + LocalOpen->FilterIndex, + &Filter->BindingsUsingShortAddress[ArrayIndex] + ); + + Filter->NumberOfShortAddresses++; + + } else { + + // + // No room in the array, oh well. + // + + MoveMemory( + (PVOID)Filter->MulticastShortAddresses, + TmpAddressArray, + InitialArraySize * FDDI_LENGTH_OF_SHORT_ADDRESS + ); + + MoveMemory( + (PVOID)Filter->BindingsUsingShortAddress, + TmpMaskArray, + InitialArraySize * sizeof(FDDI_MASK) + ); + + Filter->NumberOfShortAddresses = InitialArraySize; + + return NDIS_STATUS_MULTICAST_FULL; + + } + + } + + } + + + // + // Finally we have to remove any addresses from + // the multicast array if they have no bits on any more. + // + for (ArrayIndex = 0; ArrayIndex < Filter->NumberOfShortAddresses; ) { + + if (IS_MASK_CLEAR(Filter->BindingsUsingShortAddress[ArrayIndex])) { + + // + // yes it is clear, so we have to shift everything + // above it down one. + // + + AddressesChanged = TRUE; + + MoveMemory( + Filter->MulticastShortAddresses[ArrayIndex], + Filter->MulticastShortAddresses[ArrayIndex+1], + (Filter->NumberOfShortAddresses-(ArrayIndex+1)) + *FDDI_LENGTH_OF_SHORT_ADDRESS + ); + + MoveMemory( + &Filter->BindingsUsingShortAddress[ArrayIndex], + &Filter->BindingsUsingShortAddress[ArrayIndex+1], + (Filter->NumberOfShortAddresses-(ArrayIndex+1))*(sizeof(FDDI_MASK)) + ); + + Filter->NumberOfShortAddresses--; + + } else { + + ArrayIndex++; + + } + + } + + // + // If the address array has changed, we have to call the + // action array to inform the adapter of this. + // + + if (AddressesChanged) { + + StatusOfChange = Filter->AddressChangeAction( + Filter->NumberOfLongAddresses, + Filter->MulticastLongAddresses, + Filter->NumberOfLongAddresses, + Filter->MulticastLongAddresses, + InitialArraySize, + TmpAddressArray, + Filter->NumberOfShortAddresses, + Filter->MulticastShortAddresses, + LocalOpen->MacBindingHandle, + NdisRequest, + Set + ); + + if ((StatusOfChange != NDIS_STATUS_SUCCESS) && + (StatusOfChange != NDIS_STATUS_PENDING)) { + + // + // The user returned a bad status. Put things back as + // they were. + // + + MoveMemory( + (PVOID)Filter->MulticastShortAddresses, + TmpAddressArray, + InitialArraySize * FDDI_LENGTH_OF_SHORT_ADDRESS + ); + + MoveMemory( + (PVOID)Filter->MulticastShortAddresses, + TmpAddressArray, + InitialArraySize * FDDI_LENGTH_OF_SHORT_ADDRESS + ); + + } + + } else { + + StatusOfChange = NDIS_STATUS_SUCCESS; + + } + + + return StatusOfChange; + +} + + +NDIS_STATUS +FddiFilterAdjust( + IN PFDDI_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest, + IN UINT FilterClasses, + IN BOOLEAN Set + ) + +/*++ + +Routine Description: + + The FilterAdjust routine will call an action routine when a + particular filter class is changes from not being used by any + binding to being used by at least one binding or vice versa. + + If the action routine returns a value other than pending or + success then this routine has no effect on the packet filters + for the open or for the adapter as a whole. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + +Arguments: + + Filter - A pointer to the filter database. + + NdisFilterHandle - A pointer to the open. + + NdisRequest - If it is necessary to call the action routine, + this will be passed to it. + + FilterClasses - The filter classes that are to be added or + deleted. + + Set - A boolean that determines whether the filter classes + are being adjusted due to a set or because of a close. (The filtering + routines don't care, the MAC might.) + +Return Value: + + If it calls the action routine then it will return the + status returned by the action routine. If the status + returned by the action routine is anything other than + NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database + will be returned to the state it was in upon entrance to this + routine. + + If the action routine is not called this routine will return + the following statum: + + NDIS_STATUS_SUCCESS - If the new packet filters doesn't change + the combined mask of all bindings packet filters. + +--*/ + +{ + // + // Contains the value of the combined filter classes before + // it is adjusted. + // + UINT OldCombined = Filter->CombinedPacketFilter; + + PFDDI_BINDING_INFO LocalOpen = (PFDDI_BINDING_INFO)NdisFilterHandle; + PFDDI_BINDING_INFO OpenList; + + // + // Contains the value of the particlar opens packet filters + // prior to the change. We save this incase the action + // routine (if called) returns an "error" status. + // + UINT OldOpenFilters = LocalOpen->PacketFilters; + + // + // Holds the status returned to the user of this routine, if the + // action routine is not called then the status will be success, + // otherwise, it is whatever the action routine returns. + // + NDIS_STATUS StatusOfAdjust; + + // + // Set the new filter information for the open. + // + + LocalOpen->PacketFilters = FilterClasses; + + // + // We always have to reform the compbined filter since + // this filter index may have been the only filter index + // to use a particular bit. + // + + + for ( + OpenList = Filter->OpenList, + Filter->CombinedPacketFilter = 0; + OpenList != NULL; + OpenList = OpenList->NextOpen + ) { + + Filter->CombinedPacketFilter |= + OpenList->PacketFilters; + + } + + if (OldCombined != Filter->CombinedPacketFilter) { + + StatusOfAdjust = Filter->FilterChangeAction( + OldCombined, + Filter->CombinedPacketFilter, + LocalOpen->MacBindingHandle, + NdisRequest, + Set + ); + + if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) && + (StatusOfAdjust != NDIS_STATUS_PENDING)) { + + // + // The user returned a bad status. Put things back as + // they were. + // + + LocalOpen->PacketFilters = OldOpenFilters; + Filter->CombinedPacketFilter = OldCombined; + + } + + } else { + + StatusOfAdjust = NDIS_STATUS_SUCCESS; + + } + + return StatusOfAdjust; + +} + + +UINT +FddiNumberOfOpenFilterLongAddresses( + IN PFDDI_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle + ) + +/*++ + +Routine Description: + + This routine counts the number of multicast addresses that a specific + open has. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + +Arguments: + + Filter - A pointer to the filter database. + + NdisFilterHandle - Pointer to open block. + + +Return Value: + + None. + +--*/ +{ + + UINT IndexOfAddress; + UINT CountOfAddresses = 0; + + UINT FilterIndex = ((PFDDI_BINDING_INFO)NdisFilterHandle)->FilterIndex; + + for(IndexOfAddress=0; + IndexOfAddress < Filter->NumberOfLongAddresses; + IndexOfAddress++ + ){ + + if (IS_BIT_SET_IN_MASK(FilterIndex, + Filter->BindingsUsingLongAddress[IndexOfAddress])) { + + CountOfAddresses++; + + + } + + } + + return(CountOfAddresses); + +} + + +UINT +FddiNumberOfOpenFilterShortAddresses( + IN PFDDI_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle + ) + +/*++ + +Routine Description: + + This routine counts the number of multicast addresses that a specific + open has. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + +Arguments: + + Filter - A pointer to the filter database. + + NdisFilterHandle - Pointer to open block. + + +Return Value: + + None. + +--*/ +{ + + UINT IndexOfAddress; + UINT CountOfAddresses = 0; + + UINT FilterIndex = ((PFDDI_BINDING_INFO)NdisFilterHandle)->FilterIndex; + + for(IndexOfAddress=0; + IndexOfAddress < Filter->NumberOfShortAddresses; + IndexOfAddress++ + ){ + + if (IS_BIT_SET_IN_MASK(FilterIndex, + Filter->BindingsUsingShortAddress[IndexOfAddress])) { + + CountOfAddresses++; + + + } + + } + + return(CountOfAddresses); + +} + + +VOID +FddiQueryOpenFilterLongAddresses( + OUT PNDIS_STATUS Status, + IN PFDDI_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN UINT SizeOfArray, + OUT PUINT NumberOfAddresses, + OUT CHAR AddressArray[][FDDI_LENGTH_OF_LONG_ADDRESS] + ) + +/*++ + +Routine Description: + + The routine should be used by the MAC before + it actually alters the hardware registers to effect a + filtering hardware. This is usefull if another binding + has altered the address list since the action routine + is called. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + +Arguments: + + Status - A pointer to the status of the call, NDIS_STATUS_SUCCESS or + NDIS_STATUS_FAILURE. Use EthNumberOfOpenAddresses() to get the + size that is needed. + + Filter - A pointer to the filter database. + + NdisFilterHandle - Pointer to the open block + + SizeOfArray - The byte count of the AddressArray. + + NumberOfAddresses - The number of addresses written to the array. + + AddressArray - Will be filled with the addresses currently in the + multicast address list. + +Return Value: + + None. + +--*/ + +{ + + UINT IndexOfAddress; + UINT CountOfAddresses = 0; + UINT FilterIndex = ((PFDDI_BINDING_INFO)NdisFilterHandle)->FilterIndex; + + for(IndexOfAddress=0; + IndexOfAddress < Filter->NumberOfLongAddresses; + IndexOfAddress++ + ){ + + if (IS_BIT_SET_IN_MASK(FilterIndex, + Filter->BindingsUsingLongAddress[IndexOfAddress])) { + + if (SizeOfArray < FDDI_LENGTH_OF_LONG_ADDRESS) { + + *Status = NDIS_STATUS_FAILURE; + + *NumberOfAddresses = 0; + + return; + + } + + SizeOfArray -= FDDI_LENGTH_OF_LONG_ADDRESS; + + MoveMemory( + AddressArray[CountOfAddresses], + Filter->MulticastLongAddresses[IndexOfAddress], + FDDI_LENGTH_OF_LONG_ADDRESS + ); + + CountOfAddresses++; + + } + + } + + *Status = NDIS_STATUS_SUCCESS; + + *NumberOfAddresses = CountOfAddresses; + + return; + +} + + +VOID +FddiQueryOpenFilterShortAddresses( + OUT PNDIS_STATUS Status, + IN PFDDI_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN UINT SizeOfArray, + OUT PUINT NumberOfAddresses, + OUT CHAR AddressArray[][FDDI_LENGTH_OF_SHORT_ADDRESS] + ) + +/*++ + +Routine Description: + + The routine should be used by the MAC before + it actually alters the hardware registers to effect a + filtering hardware. This is usefull if another binding + has altered the address list since the action routine + is called. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + +Arguments: + + Status - A pointer to the status of the call, NDIS_STATUS_SUCCESS or + NDIS_STATUS_FAILURE. Use EthNumberOfOpenAddresses() to get the + size that is needed. + + Filter - A pointer to the filter database. + + NdisFilterHandle - Pointer to the open block + + SizeOfArray - The byte count of the AddressArray. + + NumberOfAddresses - The number of addresses written to the array. + + AddressArray - Will be filled with the addresses currently in the + multicast address list. + +Return Value: + + None. + +--*/ + +{ + + UINT IndexOfAddress; + UINT CountOfAddresses = 0; + UINT FilterIndex = ((PFDDI_BINDING_INFO)NdisFilterHandle)->FilterIndex; + + for(IndexOfAddress=0; + IndexOfAddress < Filter->NumberOfShortAddresses; + IndexOfAddress++ + ){ + + if (IS_BIT_SET_IN_MASK(FilterIndex, + Filter->BindingsUsingShortAddress[IndexOfAddress])) { + + if (SizeOfArray < FDDI_LENGTH_OF_SHORT_ADDRESS) { + + *Status = NDIS_STATUS_FAILURE; + + *NumberOfAddresses = 0; + + return; + + } + + SizeOfArray -= FDDI_LENGTH_OF_SHORT_ADDRESS; + + MoveMemory( + AddressArray[CountOfAddresses], + Filter->MulticastShortAddresses[IndexOfAddress], + FDDI_LENGTH_OF_SHORT_ADDRESS + ); + + CountOfAddresses++; + + } + + } + + *Status = NDIS_STATUS_SUCCESS; + + *NumberOfAddresses = CountOfAddresses; + + return; + +} + + +VOID +FddiQueryGlobalFilterLongAddresses( + OUT PNDIS_STATUS Status, + IN PFDDI_FILTER Filter, + IN UINT SizeOfArray, + OUT PUINT NumberOfAddresses, + IN OUT CHAR AddressArray[][FDDI_LENGTH_OF_LONG_ADDRESS] + ) + +/*++ + +Routine Description: + + The routine should be used by the MAC before + it actually alters the hardware registers to effect a + filtering hardware. This is usefull if another binding + has altered the address list since the action routine + is called. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + +Arguments: + + Status - A pointer to the status of the call, NDIS_STATUS_SUCCESS or + NDIS_STATUS_FAILURE. Use FDDI_NUMBER_OF_GLOBAL_LONG_ADDRESSES() to get the + size that is needed. + + Filter - A pointer to the filter database. + + SizeOfArray - The byte count of the AddressArray. + + NumberOfAddresses - A pointer to the number of addresses written to the + array. + + AddressArray - Will be filled with the addresses currently in the + multicast address list. + +Return Value: + + None. + +--*/ + +{ + + if (SizeOfArray < (Filter->NumberOfLongAddresses * FDDI_LENGTH_OF_LONG_ADDRESS)) { + + *Status = NDIS_STATUS_FAILURE; + + *NumberOfAddresses = 0; + + } else { + + *Status = NDIS_STATUS_SUCCESS; + + *NumberOfAddresses = Filter->NumberOfLongAddresses; + + MoveMemory( + AddressArray[0], + Filter->MulticastLongAddresses[0], + Filter->NumberOfLongAddresses*FDDI_LENGTH_OF_LONG_ADDRESS + ); + + } + +} + + +VOID +FddiQueryGlobalFilterShortAddresses( + OUT PNDIS_STATUS Status, + IN PFDDI_FILTER Filter, + IN UINT SizeOfArray, + OUT PUINT NumberOfAddresses, + IN OUT CHAR AddressArray[][FDDI_LENGTH_OF_SHORT_ADDRESS] + ) + +/*++ + +Routine Description: + + The routine should be used by the MAC before + it actually alters the hardware registers to effect a + filtering hardware. This is usefull if another binding + has altered the address list since the action routine + is called. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + +Arguments: + + Status - A pointer to the status of the call, NDIS_STATUS_SUCCESS or + NDIS_STATUS_FAILURE. Use FDDI_NUMBER_OF_GLOBAL_SHORT_ADDRESSES() to get the + size that is needed. + + Filter - A pointer to the filter database. + + SizeOfArray - The byte count of the AddressArray. + + NumberOfAddresses - A pointer to the number of addresses written to the + array. + + AddressArray - Will be filled with the addresses currently in the + multicast address list. + +Return Value: + + None. + +--*/ + +{ + + if (SizeOfArray < (Filter->NumberOfShortAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS)) { + + *Status = NDIS_STATUS_FAILURE; + + *NumberOfAddresses = 0; + + } else { + + *Status = NDIS_STATUS_SUCCESS; + + *NumberOfAddresses = Filter->NumberOfShortAddresses; + + MoveMemory( + AddressArray[0], + Filter->MulticastShortAddresses[0], + Filter->NumberOfShortAddresses*FDDI_LENGTH_OF_SHORT_ADDRESS + ); + + } + +} + + +VOID +FddiFilterIndicateReceive( + IN PFDDI_FILTER Filter, + IN NDIS_HANDLE MacReceiveContext, + IN PCHAR Address, + IN UINT AddressLength, + IN PVOID HeaderBuffer, + IN UINT HeaderBufferSize, + IN PVOID LookaheadBuffer, + IN UINT LookaheadBufferSize, + IN UINT PacketSize + ) + +/*++ + +Routine Description: + + This routine is called by the MAC to indicate a packet to + all bindings. The packet will be filtered so that only the + appropriate bindings will receive the packet. + +Arguments: + + Filter - Pointer to the filter database. + + MacReceiveContext - A MAC supplied context value that must be + returned by the protocol if it calls MacTransferData. + + Address - The destination address from the received packet. + + AddressLength - The length of the above address. + + HeaderBuffer - A virtual address of the virtually contiguous + buffer containing the MAC header of the packet. + + HeaderBufferSize - An unsigned integer indicating the size of + the header buffer, in bytes. + + LookaheadBuffer - A virtual address of the virtually contiguous + buffer containing the first LookaheadBufferSize bytes of data + of the packet. The packet buffer is valid only within the current + call to the receive event handler. + + LookaheadBufferSize - An unsigned integer indicating the size of + the lookahead buffer, in bytes. + + PacketSize - An unsigned integer indicating the size of the received + packet, in bytes. This number has nothing to do with the lookahead + buffer, but indicates how large the arrived packet is so that a + subsequent MacTransferData request can be made to transfer the entire + packet as necessary. + +Return Value: + + None. + +--*/ + +{ + KIRQL oldIrql; + KeRaiseIrql( DISPATCH_LEVEL, &oldIrql ); + ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + FddiFilterDprIndicateReceive( + Filter, + MacReceiveContext, + Address, + AddressLength, + HeaderBuffer, + HeaderBufferSize, + LookaheadBuffer, + LookaheadBufferSize, + PacketSize + ); + RELEASE_SPIN_LOCK_DPC(Filter->Lock); + KeLowerIrql( oldIrql ); + return; +} + + +VOID +FddiFilterDprIndicateReceive( + IN PFDDI_FILTER Filter, + IN NDIS_HANDLE MacReceiveContext, + IN PCHAR Address, + IN UINT AddressLength, + IN PVOID HeaderBuffer, + IN UINT HeaderBufferSize, + IN PVOID LookaheadBuffer, + IN UINT LookaheadBufferSize, + IN UINT PacketSize + ) + +/*++ + +Routine Description: + + This routine is called by the MAC to indicate a packet to + all bindings. The packet will be filtered so that only the + appropriate bindings will receive the packet. + + Called at DPC_LEVEL. + +Arguments: + + Filter - Pointer to the filter database. + + MacReceiveContext - A MAC supplied context value that must be + returned by the protocol if it calls MacTransferData. + + Address - The destination address from the received packet. + + AddressLength - The length of the above address. + + HeaderBuffer - A virtual address of the virtually contiguous + buffer containing the MAC header of the packet. + + HeaderBufferSize - An unsigned integer indicating the size of + the header buffer, in bytes. + + LookaheadBuffer - A virtual address of the virtually contiguous + buffer containing the first LookaheadBufferSize bytes of data + of the packet. The packet buffer is valid only within the current + call to the receive event handler. + + LookaheadBufferSize - An unsigned integer indicating the size of + the lookahead buffer, in bytes. + + PacketSize - An unsigned integer indicating the size of the received + packet, in bytes. This number has nothing to do with the lookahead + buffer, but indicates how large the arrived packet is so that a + subsequent MacTransferData request can be made to transfer the entire + packet as necessary. + +Return Value: + + None. + +--*/ + +{ + + // + // Will hold the type of address that we know we've got. + // + UINT AddressType; + + // + // Will hold the status of indicating the receive packet. + // ZZZ For now this isn't used. + // + NDIS_STATUS StatusOfReceive; + + // + // Will hold the filter classes of the binding being indicated. + // + UINT BindingFilters; + + // + // Holds BindingFilters intersected with the packet type + // + UINT IntersectionOfFilters; + + // + // Current Open to indicate to. + // + PFDDI_BINDING_INFO LocalOpen; + + // + // Holds the result of address determinations. + // + INT ResultOfAddressCheck; + + // + // If the packet is a runt packet, then only indicate to PROMISCUOUS + // + + if ( HeaderBufferSize > (2 * AddressLength) && PacketSize != 0 ) { + + // + // + // Determine whether the input address is a simple direct, + // a broadcast, a multicast, or an SMT address. + // + + // + // First check if it *at least* has the multicast address bit. + // + + FDDI_IS_SMT( + *((PCHAR)HeaderBuffer), + &ResultOfAddressCheck + ); + + if (ResultOfAddressCheck) { + + AddressType = NDIS_PACKET_TYPE_SMT; + + } else { + + FDDI_IS_MULTICAST( + Address, + AddressLength, + &ResultOfAddressCheck + ); + + if (ResultOfAddressCheck) { + + // + // It is at least a multicast address. Check to see if + // it is a broadcast address. + // + + FDDI_IS_BROADCAST( + Address, + AddressLength, + &ResultOfAddressCheck + ); + + if (ResultOfAddressCheck) { + + +#if DBG + +if (NdisCheckBadDrivers) { + + if (!(Filter->CombinedPacketFilter & NDIS_PACKET_TYPE_BROADCAST)) { + + // + // We should never receive directed packets + // to someone else unless in p-mode. + // + DbgPrint("NDIS: Bad driver, indicating broadcast\n"); + DbgPrint("NDIS: packets when not set to.\n"); + DbgBreakPoint(); + + } + +} + +#endif + + AddressType = NDIS_PACKET_TYPE_BROADCAST; + + } else { + + AddressType = NDIS_PACKET_TYPE_MULTICAST; + + } + + } else { + + // + // Verify that the address is directed to the adapter. We + // have to check for this because of the following senario. + // + // Adapter A is in promiscuous mode. + // Adapter B only wants directed packets to this adapter. + // + // The MAC will indicate *all* packets. + // + // The filter package needs to filter directed packets to + // other adapters from ones directed to this adapter. + // + + if (Filter->CombinedPacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS) { + + // + // The result of comparing an element of the address + // array and the multicast address. + // + // Result < 0 Implies the adapter address is greater. + // Result > 0 Implies the address is greater. + // Result = 0 Implies that the they are equal. + // + INT Result; + + if (AddressLength == FDDI_LENGTH_OF_LONG_ADDRESS) { + + FDDI_COMPARE_NETWORK_ADDRESSES_EQ( + Filter->AdapterLongAddress, + Address, + FDDI_LENGTH_OF_LONG_ADDRESS, + &Result + ); + + if (Result == 0) { + + AddressType = NDIS_PACKET_TYPE_DIRECTED; + + } else { + + AddressType = 0; + + } + + } else if (AddressLength == FDDI_LENGTH_OF_SHORT_ADDRESS) { + + FDDI_COMPARE_NETWORK_ADDRESSES_EQ( + Filter->AdapterShortAddress, + Address, + FDDI_LENGTH_OF_SHORT_ADDRESS, + &Result + ); + + if (Result == 0) { + + AddressType = NDIS_PACKET_TYPE_DIRECTED; + + } else { + + AddressType = 0; + + } + + } else { + + // + // This will cause binding that only want a specific + // address type to not be indicated. + // + + AddressType = 0; + + } + + } else { + +#if DBG + +if (NdisCheckBadDrivers) { + + // + // The result of comparing an element of the address + // array and the multicast address. + // + // Result < 0 Implies the adapter address is greater. + // Result > 0 Implies the address is greater. + // Result = 0 Implies that the they are equal. + // + INT Result = 0; + + if (AddressLength == FDDI_LENGTH_OF_LONG_ADDRESS) { + + FDDI_COMPARE_NETWORK_ADDRESSES_EQ( + Filter->AdapterLongAddress, + Address, + FDDI_LENGTH_OF_LONG_ADDRESS, + &Result + ); + + } else if (AddressLength == FDDI_LENGTH_OF_SHORT_ADDRESS) { + + FDDI_COMPARE_NETWORK_ADDRESSES_EQ( + Filter->AdapterShortAddress, + Address, + FDDI_LENGTH_OF_SHORT_ADDRESS, + &Result + ); + + } + + if (Result != 0) { + + // + // We should never receive directed packets + // to someone else unless in p-mode. + // + DbgPrint("NDIS: Bad driver, indicating packets\n"); + DbgPrint("NDIS: to another station when not in\n"); + DbgPrint("NDIS: promiscuous mode.\n"); + DbgBreakPoint(); + + + } + +} + +#endif + + AddressType = NDIS_PACKET_TYPE_DIRECTED; + + } + + } + + } + + } else { + + // + // Runt + // + + AddressType = NDIS_PACKET_TYPE_PROMISCUOUS; + + } + + // + // We need to acquire the filter exclusively while we're finding + // bindings to indicate to. + // + + LocalOpen = Filter->OpenList; + + while (LocalOpen != NULL) { + + BindingFilters = LocalOpen->PacketFilters; + + IntersectionOfFilters = BindingFilters & AddressType; + + // + // if the binding wants direct packets and this is a directly + // addressed packet then the binding gets the packet. + // if Smt and wanted, or broadcast and wanted, indicate it. + // + + if (IntersectionOfFilters & (NDIS_PACKET_TYPE_SMT | + NDIS_PACKET_TYPE_DIRECTED | + NDIS_PACKET_TYPE_BROADCAST)) { + + goto IndicatePacket; + + } + + + // + // if the binding wants multicast packets and the packet + // is a multicast packet and it's in the list of addresses + // it will get the packet. + // + + if (AddressType & (BindingFilters & NDIS_PACKET_TYPE_MULTICAST)) { + + // + // Will hold the index of the multicast + // address if it finds it. + // + UINT IndexOfAddress; + + if (AddressLength == FDDI_LENGTH_OF_LONG_ADDRESS) { + + if (FindMulticastLongAddress( + Filter->NumberOfLongAddresses, + Filter->MulticastLongAddresses, + Address, + &IndexOfAddress + )) { + + if (IS_BIT_SET_IN_MASK( + LocalOpen->FilterIndex, + Filter->BindingsUsingLongAddress[IndexOfAddress] + )) { + + goto IndicatePacket; + + } + + } + + } else { + + if (FindMulticastShortAddress( + Filter->NumberOfShortAddresses, + Filter->MulticastShortAddresses, + Address, + &IndexOfAddress + )) { + + if (IS_BIT_SET_IN_MASK( + LocalOpen->FilterIndex, + Filter->BindingsUsingShortAddress[IndexOfAddress] + )) { + + goto IndicatePacket; + + } + + } + + } + } + + // + // if the binding wants all multicast packets and the packet + // has a multicast address it will get the packet + // + + if ((AddressType & NDIS_PACKET_TYPE_MULTICAST) && + (BindingFilters & NDIS_PACKET_TYPE_ALL_MULTICAST)) { + + goto IndicatePacket; + + } + + // + // if the binding is promiscuous then it will get the packet + // + + if (BindingFilters & NDIS_PACKET_TYPE_PROMISCUOUS) { + + goto IndicatePacket; + + } + + goto GetNextBinding; + +IndicatePacket:; + + LocalOpen->References++; + + RELEASE_SPIN_LOCK_DPC(Filter->Lock); + + // + // Indicate the packet to the binding. + // + + FilterIndicateReceive( + &StatusOfReceive, + LocalOpen->NdisBindingContext, + MacReceiveContext, + HeaderBuffer, + HeaderBufferSize, + LookaheadBuffer, + LookaheadBufferSize, + PacketSize + ); + + ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + + LocalOpen->ReceivedAPacket = TRUE; + + if ((--(LocalOpen->References)) == 0) { + + PFDDI_BINDING_INFO NextOpen = LocalOpen->NextOpen; + + // + // This binding is shutting down. We have to remove it. + // + + // + // Remove it from the list. + // + + if (LocalOpen->NextOpen != NULL) { + + LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen; + + } + + if (LocalOpen->PrevOpen != NULL) { + + LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen; + + } else { + + Filter->OpenList = LocalOpen->NextOpen; + + } + + + + // + // Call the IndicateComplete routine. + // + + + if (LocalOpen->ReceivedAPacket) { + + RELEASE_SPIN_LOCK_DPC(Filter->Lock); + + FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext); + + ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + + } + + // + // Call the macs action routine so that they know we + // are no longer referencing this open binding. + // + + Filter->CloseAction(LocalOpen->MacBindingHandle); + + + FDDI_FILTER_FREE_OPEN(Filter, LocalOpen); + + LocalOpen = NextOpen; + + continue; + + } + +GetNextBinding: + + LocalOpen = LocalOpen->NextOpen; + + } + +} + + +VOID +FddiFilterIndicateReceiveComplete( + IN PFDDI_FILTER Filter + ) + +/*++ + +Routine Description: + + This routine is called by the MAC to indicate that the receive + process is complete to all bindings. Only those bindings which + have received packets will be notified. + +Arguments: + + Filter - Pointer to the filter database. + +Return Value: + + None. + +--*/ +{ + KIRQL oldIrql; + KeRaiseIrql( DISPATCH_LEVEL, &oldIrql ); + ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + FddiFilterDprIndicateReceiveComplete( + Filter + ); + RELEASE_SPIN_LOCK_DPC(Filter->Lock); + KeLowerIrql( oldIrql ); + return; +} + + +VOID +FddiFilterDprIndicateReceiveComplete( + IN PFDDI_FILTER Filter + ) + +/*++ + +Routine Description: + + This routine is called by the MAC to indicate that the receive + process is complete to all bindings. Only those bindings which + have received packets will be notified. + + Called at DPC_LEVEL. + +Arguments: + + Filter - Pointer to the filter database. + +Return Value: + + None. + +--*/ +{ + + PFDDI_BINDING_INFO LocalOpen; + + // + // We need to aquire the filter exclusively while we're finding + // bindings to indicate to. + // + + LocalOpen = Filter->OpenList; + + while (LocalOpen != NULL) { + + if (LocalOpen->ReceivedAPacket) { + + // + // Indicate the binding. + // + + LocalOpen->ReceivedAPacket = FALSE; + + LocalOpen->References++; + + RELEASE_SPIN_LOCK_DPC(Filter->Lock); + + FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext); + + ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + + if ((--(LocalOpen->References)) == 0) { + + PFDDI_BINDING_INFO NextOpen = LocalOpen->NextOpen; + + // + // This binding is shutting down. We have to kill it. + // + + // + // Remove it from the list. + // + + if (LocalOpen->NextOpen != NULL) { + + LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen; + + } + + if (LocalOpen->PrevOpen != NULL) { + + LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen; + + } else { + + Filter->OpenList = LocalOpen->NextOpen; + + } + + + // + // Call the macs action routine so that they know we + // are no longer referencing this open binding. + // + + Filter->CloseAction(LocalOpen->MacBindingHandle); + + + FDDI_FILTER_FREE_OPEN(Filter, LocalOpen); + + LocalOpen = NextOpen; + + continue; + } + + } + + LocalOpen = LocalOpen->NextOpen; + + } + +} + + +BOOLEAN +FindMulticastLongAddress( + IN UINT NumberOfAddresses, + IN CHAR AddressArray[][FDDI_LENGTH_OF_LONG_ADDRESS], + IN CHAR MulticastAddress[FDDI_LENGTH_OF_LONG_ADDRESS], + OUT PUINT ArrayIndex + ) + +/*++ + +Routine Description: + + Given an array of multicast addresses search the array for + a particular multicast address. It is assumed that the + address array is already sorted. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + + NOTE: This ordering is arbitrary but consistant. + +Arguments: + + NumberOfAddresses - The number of addresses currently in the + address array. + + AddressArray - An array of multicast addresses. + + MulticastAddress - The address to search for in the address array. + + ArrayIndex - Will point to where the MulticastAddress is in + the AddressArray, or if it isn't in the array, where it should + be in the array. + +Return Value: + + If the address is in the sorted list this routine will return + TRUE, otherwise FALSE. + +--*/ + +{ + + // + // Indices into the address array so that we may do a binary + // search. + // + UINT Bottom = 0; + UINT Middle = NumberOfAddresses / 2; + UINT Top; + + if (NumberOfAddresses) { + + Top = NumberOfAddresses - 1; + + while ((Middle <= Top) && (Middle >= Bottom)) { + + // + // The result of comparing an element of the address + // array and the multicast address. + // + // Result < 0 Implies the multicast address is greater. + // Result > 0 Implies the address array element is greater. + // Result = 0 Implies that the array element and the address + // are equal. + // + INT Result; + + FDDI_COMPARE_NETWORK_ADDRESSES( + AddressArray[Middle], + MulticastAddress, + FDDI_LENGTH_OF_LONG_ADDRESS, + &Result + ); + + if (Result == 0) { + + *ArrayIndex = Middle; + return(TRUE); + + } else if (Result > 0) { + + if (Middle == 0) break; + Top = Middle - 1; + + + } else { + + Bottom = Middle+1; + + } + + Middle = Bottom + (((Top+1) - Bottom)/2); + + } + + } + + *ArrayIndex = Middle; + + return(FALSE); + +} + + +BOOLEAN +FindMulticastShortAddress( + IN UINT NumberOfAddresses, + IN CHAR AddressArray[][FDDI_LENGTH_OF_SHORT_ADDRESS], + IN CHAR MulticastAddress[FDDI_LENGTH_OF_SHORT_ADDRESS], + OUT PUINT ArrayIndex + ) + +/*++ + +Routine Description: + + Given an array of multicast addresses search the array for + a particular multicast address. It is assumed that the + address array is already sorted. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + + NOTE: This ordering is arbitrary but consistant. + +Arguments: + + NumberOfAddresses - The number of addresses currently in the + address array. + + AddressArray - An array of multicast addresses. + + MulticastAddress - The address to search for in the address array. + + ArrayIndex - Will point to where the MulticastAddress is in + the AddressArray, or if it isn't in the array, where it should + be in the array. + +Return Value: + + If the address is in the sorted list this routine will return + TRUE, otherwise FALSE. + +--*/ + +{ + + // + // Indices into the address array so that we may do a binary + // search. + // + UINT Bottom = 0; + UINT Middle = NumberOfAddresses / 2; + UINT Top; + + if (NumberOfAddresses) { + + Top = NumberOfAddresses - 1; + + while ((Middle <= Top) && (Middle >= Bottom)) { + + // + // The result of comparing an element of the address + // array and the multicast address. + // + // Result < 0 Implies the multicast address is greater. + // Result > 0 Implies the address array element is greater. + // Result = 0 Implies that the array element and the address + // are equal. + // + INT Result; + + FDDI_COMPARE_NETWORK_ADDRESSES( + AddressArray[Middle], + MulticastAddress, + FDDI_LENGTH_OF_SHORT_ADDRESS, + &Result + ); + + if (Result == 0) { + + *ArrayIndex = Middle; + return(TRUE); + + } else if (Result > 0) { + + if (Middle == 0) break; + Top = Middle - 1; + + + } else { + + Bottom = Middle+1; + + } + + Middle = Bottom + (((Top+1) - Bottom)/2); + + } + + } + + *ArrayIndex = Middle; + + return(FALSE); + +} + + +BOOLEAN +FddiShouldAddressLoopBack( + IN PFDDI_FILTER Filter, + IN CHAR Address[], + IN UINT AddressLength + ) + +/*++ + +Routine Description: + + Do a quick check to see whether the input address should + loopback. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + + NOTE: THIS ROUTINE DOES NOT CHECK THE SPECIAL CASE OF SOURCE + EQUALS DESTINATION. + +Arguments: + + Filter - Pointer to the filter database. + + Address - A network address to check for loopback. + + AddressLength - Length of the above address in bytes. + +Return Value: + + Returns TRUE if the address needs to be loopback. It + will return FALSE if there is *no* chance that the address would + require loopback. + +--*/ +{ + BOOLEAN fLoopback, fSelfDirected; + + FddiShouldAddressLoopBackMacro(Filter, Address, AddressLength, &fLoopback, &fSelfDirected); + + return(fLoopback); +} diff --git a/private/ntos/ndis/ndis30/ffilter.h b/private/ntos/ndis/ndis30/ffilter.h new file mode 100644 index 000000000..ae3ae8120 --- /dev/null +++ b/private/ntos/ndis/ndis30/ffilter.h @@ -0,0 +1,692 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + ffilter.h + +Abstract: + + Header file for the address filtering library for NDIS MAC's. + +Author: + + Anthony V. Ercolano (tonye) creation-date 3-Aug-1990 + +Environment: + + Runs in the context of a single MAC driver. + +Notes: + + None. + +Revision History: + + Sean Selitrennikoff (SeanSe) - converter efilter.* for FDDI support. + + +--*/ + +#ifndef _FDDI_FILTER_DEFS_ +#define _FDDI_FILTER_DEFS_ + +#define FDDI_LENGTH_OF_LONG_ADDRESS 6 +#define FDDI_LENGTH_OF_SHORT_ADDRESS 2 + + +// +// ZZZ This is a little-endian specific check. +// +#define FDDI_IS_MULTICAST(Address, AddressLength, Result) \ +{ \ + PUCHAR _A = Address; \ + *Result = (BOOLEAN)(_A[0] & ((UCHAR)0x01)); \ +} + +// +// Check whether the frame is SMT or not. +// +#define FDDI_IS_SMT(FcByte, Result) \ +{ \ + *Result = ((FcByte & ((UCHAR)0xf0)) == 0x40); \ +} + + +// +// Check whether an address is broadcast. +// +#define FDDI_IS_BROADCAST(Address, AddressLength, Result) \ +{ \ + PUCHAR _A = Address; \ + PUCHAR _E = _A + AddressLength;\ + *Result = TRUE;\ + for (; _A < _E ; _A++) {\ + if (*_A != 0xFF) {\ + *Result = FALSE;\ + break;\ + }\ + }\ +} + + +// +// This macro will compare network addresses. +// +// A - Is a network address. +// +// B - Is a network address. +// +// Result - The result of comparing two network address. +// +// Result < 0 Implies the B address is greater. +// Result > 0 Implies the A element is greater. +// Result = 0 Implies equality. +// +// Note that this is an arbitrary ordering. There is not +// defined relation on network addresses. This is ad-hoc! +// +// +#define FDDI_COMPARE_NETWORK_ADDRESSES(A,B,_AddressLength,Result) \ +{ \ + PUCHAR _A = (PUCHAR)(A); \ + PUCHAR _B = (PUCHAR)(B); \ + if ( *(USHORT UNALIGNED *)_A > \ + *(USHORT UNALIGNED *)_B ) { \ + *Result = 1; \ + } else if ( *(USHORT UNALIGNED *)_A < \ + *(USHORT UNALIGNED *)_B ) { \ + *Result = (UINT)-1; \ + } else if (_AddressLength == 2) { \ + *Result = 0; \ + } else if ( *(ULONG UNALIGNED *)&_A[2] > \ + *(ULONG UNALIGNED *)&_B[2] ) { \ + *Result = 1; \ + } else if ( *(ULONG UNALIGNED *)&_A[2] < \ + *(ULONG UNALIGNED *)&_B[2] ) { \ + *Result = (UINT)-1; \ + } else { \ + *Result = 0; \ + } \ +} + +// +// This macro will compare network addresses. +// +// A - Is a network address. +// +// B - Is a network address. +// +// Result - The result of comparing two network address. +// +// Result != 0 Implies inequality. +// Result == 0 Implies equality. +// +// +#define FDDI_COMPARE_NETWORK_ADDRESSES_EQ(A,B,_AddressLength,Result) \ +{ \ + PUCHAR _A = (PUCHAR)(A); \ + PUCHAR _B = (PUCHAR)(B); \ + if ( ( *(USHORT UNALIGNED *)_A == \ + *(USHORT UNALIGNED *)_B ) && \ + ( ( (_AddressLength) == 2 ) || \ + ( *(ULONG UNALIGNED *)&_A[2] == \ + *(ULONG UNALIGNED *)&_B[2] ) ) ) { \ + *Result = 0; \ + } else { \ + *Result = 1; \ + } \ +} + + +// +// This macro is used to copy from one network address to +// another. +// +#define FDDI_COPY_NETWORK_ADDRESS(D,S,AddressLength) \ +{ \ + PCHAR _D = (D); \ + PCHAR _S = (S); \ + UINT _C = (AddressLength);\ + for ( ; _C > 0 ; _D++, _S++, _C--) {\ + *_D = *_S;\ + }\ +} + + +// +//UINT +//FDDI_QUERY_FILTER_CLASSES( +// IN PFDDI_FILTER Filter +// ) +// +// This macro returns the currently enabled filter classes. +// +// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD. +// +#define FDDI_QUERY_FILTER_CLASSES(Filter) ((Filter)->CombinedPacketFilter) + + +// +//UINT +//FDDI_QUERY_PACKET_FILTER( +// IN PFDDI_FILTER Filter, +// IN NDIS_HANDLE NdisFilterHandle +// ) +// +// This macro returns the currently enabled filter classes for a specific +// open instance. +// +// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD. +// +#define FDDI_QUERY_PACKET_FILTER(Filter, NdisFilterHandle) \ + (((PFDDI_BINDING_INFO)(NdisFilterHandle))->PacketFilters) + + +// +//UINT +//FDDI_NUMBER_OF_GLOBAL_FILTER_LONG_ADDRESSES( +// IN PFDDI_FILTER Filter +// ) +// +// This macro returns the number of multicast addresses in the +// multicast address list. +// +// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD. +// +#define FDDI_NUMBER_OF_GLOBAL_FILTER_LONG_ADDRESSES(Filter) ((Filter)->NumberOfLongAddresses) + + +// +//UINT +//FDDI_NUMBER_OF_GLOBAL_FILTER_SHORT_ADDRESSES( +// IN PFDDI_FILTER Filter +// ) +// +// This macro returns the number of multicast addresses in the +// multicast address list. +// +// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD. +// +#define FDDI_NUMBER_OF_GLOBAL_FILTER_SHORT_ADDRESSES(Filter) ((Filter)->NumberOfShortAddresses) + + +// +// An action routine type. The routines are called +// when a filter type is set for the first time or +// no more bindings require a particular type of filter. +// +// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED. +// +typedef +NDIS_STATUS +(*FDDI_FILTER_CHANGE)( + IN UINT OldFilterClasses, + IN UINT NewFilterClasses, + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest, + IN BOOLEAN Set + ); + +// +// This action routine is called when a new multicast address +// list is given to the filter. The action routine is given +// arrays containing the old and new multicast addresses. +// +// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED. +// +typedef +NDIS_STATUS +(*FDDI_ADDRESS_CHANGE)( + IN UINT OldLongAddressCount, + IN CHAR OldLongAddresses[][FDDI_LENGTH_OF_LONG_ADDRESS], + IN UINT NewLongAddressCount, + IN CHAR NewLongAddresses[][FDDI_LENGTH_OF_LONG_ADDRESS], + IN UINT OldShortAddressCount, + IN CHAR OldShortAddresses[][FDDI_LENGTH_OF_SHORT_ADDRESS], + IN UINT NewShortAddressCount, + IN CHAR NewShortAddresses[][FDDI_LENGTH_OF_SHORT_ADDRESS], + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest, + IN BOOLEAN Set + ); + +// +// This action routine is called when the mac requests a close for +// a particular binding *WHILE THE BINDING IS BEING INDICATED TO +// THE PROTOCOL*. The filtering package can't get rid of the open +// right away. So this routine will be called as soon as the +// NdisIndicateReceive returns. +// +// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED. +// +typedef +VOID +(*FDDI_DEFERRED_CLOSE)( + IN NDIS_HANDLE MacBindingHandle + ); + +typedef ULONG FDDI_MASK,*PFDDI_MASK; + +// +// Maximum number of opens the filter package will support. This is +// the max so that bit masks can be used instead of a spaghetti of +// pointers. +// +#define FDDI_FILTER_MAX_OPENS (sizeof(ULONG) * 8) + +// +// The binding info is threaded on two lists. When +// the binding is free it is on a single freelist. +// +// When the binding is being used it is on a doubly linked +// index list. +// +typedef struct _FDDI_BINDING_INFO { + NDIS_HANDLE MacBindingHandle; + NDIS_HANDLE NdisBindingContext; + UINT PacketFilters; + ULONG References; + struct _FDDI_BINDING_INFO *NextOpen; + struct _FDDI_BINDING_INFO *PrevOpen; + BOOLEAN ReceivedAPacket; + UCHAR FilterIndex; +} FDDI_BINDING_INFO,*PFDDI_BINDING_INFO; + +// +// An opaque type that contains a filter database. +// The MAC need not know how it is structured. +// +typedef struct _FDDI_FILTER { + + // + // Spin lock used to protect the filter from multiple accesses. + // + PNDIS_SPIN_LOCK Lock; + + // + // Pointer to an array of 6 character arrays holding the + // multicast addresses requested for filtering. + // + CHAR (*MulticastLongAddresses)[FDDI_LENGTH_OF_LONG_ADDRESS]; + + // + // Pointer to an array of FDDI_MASKS that work in conjuction with + // the MulticastLongAddress array. In the masks, a bit being enabled + // indicates that the binding with the given FilterIndex is using + // the corresponding address. + // + FDDI_MASK *BindingsUsingLongAddress; + + // + // Pointer to an array of 2 character arrays holding the + // multicast addresses requested for filtering. + // + CHAR (*MulticastShortAddresses)[FDDI_LENGTH_OF_SHORT_ADDRESS]; + + // + // Pointer to an array of FDDI_MASKS that work in conjuction with + // the MulticastShortAddress array. In the masks, a bit being enabled + // indicates that the binding with the given FilterIndex is using + // the corresponding address. + // + FDDI_MASK *BindingsUsingShortAddress; + + // + // Combination of all the filters of all the open bindings. + // + UINT CombinedPacketFilter; + + // + // Pointer for traversing the open list. + // + PFDDI_BINDING_INFO OpenList; + + + // + // Action routines to be invoked on notable changes in the filter. + // + + FDDI_ADDRESS_CHANGE AddressChangeAction; + FDDI_FILTER_CHANGE FilterChangeAction; + FDDI_DEFERRED_CLOSE CloseAction; + + // + // The maximum number of long addresses used for filtering. + // + UINT MaximumMulticastLongAddresses; + + // + // The maximum number of short addresses used for filtering. + // + UINT MaximumMulticastShortAddresses; + + // + // The current number of addresses in the LongAddress filter. + // + UINT NumberOfLongAddresses; + + // + // The current number of addresses in the ShortAddress filter. + // + UINT NumberOfShortAddresses; + + // + // Bit mask of opens that are available. + // + ULONG FreeBindingMask; + + // + // Long Address of the adapter. + // + UCHAR AdapterLongAddress[FDDI_LENGTH_OF_LONG_ADDRESS]; + + // + // Short Address of the adapter. + // + UCHAR AdapterShortAddress[FDDI_LENGTH_OF_SHORT_ADDRESS]; + +} FDDI_FILTER,*PFDDI_FILTER; + +// +// Only for internal wrapper use. +// +VOID +FddiInitializePackage( + VOID + ); + +VOID +FddiReferencePackage( + VOID + ); + +VOID +FddiDereferencePackage( + VOID + ); + +// +// Exported routines +// + +EXPORT +BOOLEAN +FddiCreateFilter( + IN UINT MaximumMulticastLongAddresses, + IN UINT MaximumMulticastShortAddresses, + IN FDDI_ADDRESS_CHANGE AddressChangeAction, + IN FDDI_FILTER_CHANGE FilterChangeAction, + IN FDDI_DEFERRED_CLOSE CloseAction, + IN PUCHAR AdapterLongAddress, + IN PUCHAR AdapterShortAddress, + IN PNDIS_SPIN_LOCK Lock, + OUT PFDDI_FILTER *Filter + ); + +EXPORT +VOID +FddiDeleteFilter( + IN PFDDI_FILTER Filter + ); + +EXPORT +BOOLEAN +FddiNoteFilterOpenAdapter( + IN PFDDI_FILTER Filter, + IN NDIS_HANDLE MacBindingHandle, + IN NDIS_HANDLE NdisBindingContext, + OUT PNDIS_HANDLE NdisFilterHandle + ); + +EXPORT +NDIS_STATUS +FddiDeleteFilterOpenAdapter( + IN PFDDI_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest + ); + +EXPORT +NDIS_STATUS +FddiChangeFilterLongAddresses( + IN PFDDI_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest, + IN UINT AddressCount, + IN CHAR Addresses[][FDDI_LENGTH_OF_LONG_ADDRESS], + IN BOOLEAN Set + ); + +EXPORT +NDIS_STATUS +FddiChangeFilterShortAddresses( + IN PFDDI_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest, + IN UINT AddressCount, + IN CHAR Addresses[][FDDI_LENGTH_OF_SHORT_ADDRESS], + IN BOOLEAN Set + ); + + +#define FddiShouldAddressLoopBackMacro(_Filter, _Address, _AddressLength, _pfLoopBack, _pfSelfDirected)\ +{ \ + /* \ + * Holds the result of address determinations. \ + */ \ + INT ResultOfAddressCheck; \ + \ + UINT CombinedFilters; \ + \ + CombinedFilters = FDDI_QUERY_FILTER_CLASSES(_Filter); \ + \ + *(_pfLoopBack) = FALSE; \ + *(_pfSelfDirected) = FALSE; \ + \ + do \ + { \ + if (CombinedFilters & NDIS_PACKET_TYPE_PROMISCUOUS) \ + { \ + *(_pfLoopBack) = TRUE; \ + break; \ + } \ + \ + /* \ + * First check if it *at least* has the multicast address bit. \ + */ \ + \ + FDDI_IS_MULTICAST( \ + _Address, \ + _AddressLength, \ + &ResultOfAddressCheck \ + ); \ + \ + if (ResultOfAddressCheck) \ + { \ + /* \ + * It is at least a multicast address. Check to see if \ + * it is a broadcast address. \ + */ \ + \ + FDDI_IS_BROADCAST( \ + _Address, \ + _AddressLength, \ + &ResultOfAddressCheck \ + ); \ + \ + if (ResultOfAddressCheck) \ + { \ + if (CombinedFilters & NDIS_PACKET_TYPE_BROADCAST) \ + { \ + *(_pfLoopBack) = TRUE; \ + break; \ + } \ + else \ + { \ + break; \ + } \ + \ + } else { \ + \ + if ((CombinedFilters & NDIS_PACKET_TYPE_ALL_MULTICAST) || \ + (CombinedFilters & NDIS_PACKET_TYPE_MULTICAST)) \ + { \ + *(_pfLoopBack) = TRUE; \ + break; \ + } \ + else \ + { \ + break; \ + } \ + } \ + } \ + else \ + { \ + /* \ + * Directed to ourself? \ + */ \ + if (AddressLength == FDDI_LENGTH_OF_LONG_ADDRESS) \ + { \ + FDDI_COMPARE_NETWORK_ADDRESSES_EQ((_Filter)->AdapterLongAddress, \ + _Address, \ + FDDI_LENGTH_OF_LONG_ADDRESS, \ + &ResultOfAddressCheck \ + ); \ + } \ + else \ + { \ + FDDI_COMPARE_NETWORK_ADDRESSES_EQ((_Filter)->AdapterShortAddress, \ + _Address, \ + FDDI_LENGTH_OF_SHORT_ADDRESS, \ + &ResultOfAddressCheck \ + ); \ + } \ + \ + if (ResultOfAddressCheck == 0) \ + { \ + *(_pfLoopBack) = TRUE; \ + *(_pfSelfDirected) = TRUE; \ + break; \ + } \ + } \ + } while (FALSE); \ +} + +EXPORT +BOOLEAN +FddiShouldAddressLoopBack( + IN PFDDI_FILTER Filter, + IN CHAR Address[], + IN UINT LengthOfAddress + ); + +EXPORT +NDIS_STATUS +FddiFilterAdjust( + IN PFDDI_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest, + IN UINT FilterClasses, + IN BOOLEAN Set + ); + +EXPORT +UINT +FddiNumberOfOpenFilterLongAddresses( + IN PFDDI_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle + ); + +EXPORT +UINT +FddiNumberOfOpenFilterShortAddresses( + IN PFDDI_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle + ); + +EXPORT +VOID +FddiQueryGlobalFilterLongAddresses( + OUT PNDIS_STATUS Status, + IN PFDDI_FILTER Filter, + IN UINT SizeOfArray, + OUT PUINT NumberOfAddresses, + IN OUT CHAR AddressArray[][FDDI_LENGTH_OF_LONG_ADDRESS] + ); + +EXPORT +VOID +FddiQueryGlobalFilterShortAddresses( + OUT PNDIS_STATUS Status, + IN PFDDI_FILTER Filter, + IN UINT SizeOfArray, + OUT PUINT NumberOfAddresses, + IN OUT CHAR AddressArray[][FDDI_LENGTH_OF_SHORT_ADDRESS] + ); + +EXPORT +VOID +FddiQueryOpenFilterLongAddresses( + OUT PNDIS_STATUS Status, + IN PFDDI_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN UINT SizeOfArray, + OUT PUINT NumberOfAddresses, + IN OUT CHAR AddressArray[][FDDI_LENGTH_OF_LONG_ADDRESS] + ); + +EXPORT +VOID +FddiQueryOpenFilterShortAddresses( + OUT PNDIS_STATUS Status, + IN PFDDI_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN UINT SizeOfArray, + OUT PUINT NumberOfAddresses, + IN OUT CHAR AddressArray[][FDDI_LENGTH_OF_SHORT_ADDRESS] + ); + +EXPORT +VOID +FddiFilterIndicateReceive( + IN PFDDI_FILTER Filter, + IN NDIS_HANDLE MacReceiveContext, + IN PCHAR Address, + IN UINT AddressLength, + IN PVOID HeaderBuffer, + IN UINT HeaderBufferSize, + IN PVOID LookaheadBuffer, + IN UINT LookaheadBufferSize, + IN UINT PacketSize + ); + +EXPORT +VOID +FddiFilterDprIndicateReceive( + IN PFDDI_FILTER Filter, + IN NDIS_HANDLE MacReceiveContext, + IN PCHAR Address, + IN UINT AddressLength, + IN PVOID HeaderBuffer, + IN UINT HeaderBufferSize, + IN PVOID LookaheadBuffer, + IN UINT LookaheadBufferSize, + IN UINT PacketSize + ); + +EXPORT +VOID +FddiFilterIndicateReceiveComplete( + IN PFDDI_FILTER Filter + ); + +EXPORT +VOID +FddiFilterDprIndicateReceiveComplete( + IN PFDDI_FILTER Filter + ); + +#endif // _FDDI_FILTER_DEFS_ + diff --git a/private/ntos/ndis/ndis30/makefile b/private/ntos/ndis/ndis30/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/ntos/ndis/ndis30/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/ntos/ndis/ndis30/makefile.inc b/private/ntos/ndis/ndis30/makefile.inc new file mode 100644 index 000000000..9462059e7 --- /dev/null +++ b/private/ntos/ndis/ndis30/makefile.inc @@ -0,0 +1,2 @@ +obj\$(TARGET_DIRECTORY)\ndis.def: ndis.src + $(TARGET_CPP) -nologo -EP $(TARGET_DEFINES) $(TARGET_DBG_DEFINES) ndis.src > obj\$(TARGET_DIRECTORY)\ndis.def diff --git a/private/ntos/ndis/ndis30/miniport.c b/private/ntos/ndis/ndis30/miniport.c new file mode 100644 index 000000000..efef74ebb --- /dev/null +++ b/private/ntos/ndis/ndis30/miniport.c @@ -0,0 +1,10214 @@ +/*++ +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + miniport.c + +Abstract: + + NDIS wrapper functions + +Author: + + Sean Selitrennikoff (SeanSe) 05-Oct-93 + +Environment: + + Kernel mode, FSD + +Revision History: + +--*/ + + +#include <precomp.h> +#pragma hdrstop + +PNDIS_M_DRIVER_BLOCK NdisDriverList = NULL; +NDIS_SPIN_LOCK NdisDriverListLock = {0}; + +extern UCHAR NdisInternalEaName[4]; +extern UCHAR NdisInternalEaValue[8]; + +#define BYTE_SWAP(_word) (\ + (USHORT) (((_word) >> 8) | ((_word) << 8)) ) + +#define LOW_WORD(_dword) (\ + (USHORT) ((_dword) & 0x0000FFFF) ) + +#define HIGH_WORD(_dword) (\ + (USHORT) (((_dword) >> 16) & 0x0000FFFF) ) + +#define BYTE_SWAP_ULONG(_ulong) (\ + (ULONG)((ULONG)(BYTE_SWAP(LOW_WORD(_ulong)) << 16) + \ + BYTE_SWAP(HIGH_WORD(_ulong)))) + +// +// This is the number of extra OIDs that ARCnet with Ethernet encapsulation +// supports. +// +#define ARC_NUMBER_OF_EXTRA_OIDS 2 + + + +#if DBG + +#define MINIPORT_DEBUG_LOUD 0x01 +#define MINIPORT_DEBUG_VERY_LOUD 0x02 +#define MINIPORT_DEBUG_PACKETS 0x04 +ULONG MiniportDebug = 0; // MINIPORT_DEBUG_LOUD; +#define LOUD_DEBUG(A) if (MiniportDebug & MINIPORT_DEBUG_LOUD) { A ; } +#define VERY_LOUD_DEBUG(A) if (MiniportDebug & MINIPORT_DEBUG_VERY_LOUD) { A ; } +#define PACKET_DEBUG(A) if (MiniportDebug & MINIPORT_DEBUG_PACKETS) { A ; } + +#else + +#define LOUD_DEBUG(A) +#define VERY_LOUD_DEBUG(A) +#define PACKET_DEBUG(A) + +#endif + +// +// Define constants used internally to identify regular opens from +// query global statistics ones. +// + +#define NDIS_OPEN_INTERNAL 1 +#define NDIS_OPEN_QUERY_STATISTICS 2 + +// +// An active query single statistic request. +// + +typedef struct _NDIS_QUERY_GLOBAL_REQUEST { + PIRP Irp; + NDIS_REQUEST Request; +} NDIS_QUERY_GLOBAL_REQUEST, *PNDIS_QUERY_GLOBAL_REQUEST; + +// +// An active query all statistics request. +// + +typedef struct _NDIS_QUERY_ALL_REQUEST { + PIRP Irp; + NDIS_REQUEST Request; + NDIS_STATUS NdisStatus; + KEVENT Event; +} NDIS_QUERY_ALL_REQUEST, *PNDIS_QUERY_ALL_REQUEST; + + +// +// An temporary request used during an open. +// + +typedef struct _NDIS_QUERY_OPEN_REQUEST { + PIRP Irp; + NDIS_REQUEST Request; + NDIS_STATUS NdisStatus; + KEVENT Event; +} NDIS_QUERY_OPEN_REQUEST, *PNDIS_QUERY_OPEN_REQUEST; + + +#define NDIS_STATISTICS_HEADER_SIZE FIELD_OFFSET(NDIS_STATISTICS_VALUE,Data[0]) + + +// +// Timeout values +// +#define NDIS_MINIPORT_WAKEUP_TIMEOUT 2000 // Wakeup DPC +#define NDIS_MINIPORT_TR_RESET_TIMEOUT 15 // Number of WakeUps per reset attempt + +extern +NTSTATUS +WrapperSaveParameters( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ); + +extern +NTSTATUS +WrapperSaveLinkage( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ); + +extern +NTSTATUS +WrapperCheckRoute( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ); + + +NTSTATUS +NdisCreateIrpHandler( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ); + +NTSTATUS +NdisDeviceControlIrpHandler( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ); + +NTSTATUS +NdisCloseIrpHandler( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ); + +NTSTATUS +NdisSuccessIrpHandler( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ); + +VOID +HaltOneMiniport( + PNDIS_MINIPORT_BLOCK Miniport + ); + +VOID +MiniportArcCopyFromBufferToPacket( + IN PCHAR Buffer, + IN UINT BytesToCopy, + IN PNDIS_PACKET Packet, + IN UINT Offset, + OUT PUINT BytesCopied + ); + +VOID +NdisInitReferencePackage(VOID); + +VOID +NdisInitDereferencePackage(VOID); + +VOID +MiniportFinishPendingOpens( + PNDIS_MINIPORT_BLOCK Miniport + ); + +// +// Some Wan functions that crept in because +// the send/receive paths for WAN drivers is different +// + +VOID +NdisMWanSendComplete( + IN NDIS_HANDLE MiniportAdapterHandle, + IN PNDIS_PACKET Packet, + IN NDIS_STATUS Status + ); + +NDIS_STATUS +NdisMWanSend( + IN NDIS_HANDLE NdisBindingHandle, + IN NDIS_HANDLE NdisLinkHandle, + IN PVOID Packet + ); + +VOID +NdisMWanIndicateReceive( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_HANDLE NdisLinkContext, + IN PUCHAR Packet, + IN ULONG PacketSize + ); + +VOID +NdisMWanIndicateReceiveComplete( + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_HANDLE NdisLinkContext + ); + +// +// Internal definitions +// + +typedef struct _NDIS_PACKET_RESERVED { + PNDIS_PACKET Next; + PNDIS_M_OPEN_BLOCK Open; +} NDIS_PACKET_RESERVED, *PNDIS_PACKET_RESERVED; + + +#define PNDIS_RESERVED_FROM_PNDIS_PACKET(_packet) \ + ((PNDIS_PACKET_RESERVED)((_packet)->WrapperReserved)) + + +#define MINIPORT_ENABLE_INTERRUPT(_M_) \ +{ \ + if (_M_->DriverHandle->MiniportCharacteristics.EnableInterruptHandler != NULL) { \ + (_M_->DriverHandle->MiniportCharacteristics.EnableInterruptHandler)( \ + _M_->MiniportAdapterContext \ + ); \ + } \ +} + +#define MINIPORT_SYNC_ENABLE_INTERRUPT(_M_) \ +{ \ + if (_M_->DriverHandle->MiniportCharacteristics.EnableInterruptHandler != NULL) { \ + KeSynchronizeExecution( \ + (_M_)->Interrupt->InterruptObject, \ + (PKSYNCHRONIZE_ROUTINE)(_M_->DriverHandle->MiniportCharacteristics.EnableInterruptHandler),\ + _M_->MiniportAdapterContext \ + ); \ + } \ +} + + +#define ARC_PACKET_IS_ENCAPSULATED(Packet) \ + ( PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Open->UsingEthEncapsulation ) + + +#if DBG + +// +// Packet log. +// + +typedef struct _PACKET_LOG { + + PNDIS_MINIPORT_BLOCK Miniport; + PNDIS_PACKET Packet; + ULONG Ident; + ULONG Time; +} PACKET_LOG, *PPACKET_LOG; + +#define PACKET_LOG_SIZE 1024 + +UINT CurrentLogEntry = (PACKET_LOG_SIZE - 1); +PPACKET_LOG PacketLogHead = NULL; +PACKET_LOG PacketLog[PACKET_LOG_SIZE] = {0}; +NDIS_SPIN_LOCK PacketLogSpinLock = { 0 }; + +VOID NDIS_LOG_PACKET(PNDIS_MINIPORT_BLOCK Miniport, PNDIS_PACKET Packet, UINT Ident) +{ + LARGE_INTEGER li; + + ACQUIRE_SPIN_LOCK(&PacketLogSpinLock); + + PacketLogHead = &PacketLog[CurrentLogEntry]; + PacketLogHead->Miniport = Miniport; + PacketLogHead->Packet = Packet; + PacketLogHead->Ident = Ident; + KeQuerySystemTime(&li); + PacketLogHead->Time = li.LowPart; + + if ( CurrentLogEntry-- == 0 ) { + + CurrentLogEntry = (PACKET_LOG_SIZE - 1); + } + + RELEASE_SPIN_LOCK(&PacketLogSpinLock); +} + +// +// Send log. +// + +UCHAR SendLog[256] = {0}; +UCHAR SendLogPlace = 0; +#define LOG(ch) \ +{\ + SendLog[SendLogPlace++] = (UCHAR)ch;\ + SendLog[SendLogPlace] = ' ';\ + if (SendLogPlace > 250) {\ + SendLogPlace = 0;\ + }\ +} + +UCHAR SendResourcesBuffer[512] = {0}; +ULONG SendResourcesPlace = 0; + +ULONG StartCount = 0x7C; + +ULONG +CountMiniportPackets( + PNDIS_MINIPORT_BLOCK Miniport + ) +{ + ULONG Foo = 0; + PNDIS_PACKET Tmp; + + Tmp = Miniport->FirstPacket; + + while (Tmp != Miniport->FirstPendingPacket) { + Foo++; + Tmp = PNDIS_RESERVED_FROM_PNDIS_PACKET(Tmp)->Next; + } + return(Foo); +} + +#define REMOVE_RESOURCE(W, C) {\ + W->SendResourcesAvailable--; \ + SendResourcesBuffer[SendResourcesPlace++] = (UCHAR)C; \ + SendResourcesBuffer[SendResourcesPlace++] = (UCHAR)'R'; \ + SendResourcesBuffer[SendResourcesPlace++] = (UCHAR)W->SendResourcesAvailable;\ + SendResourcesBuffer[SendResourcesPlace] = (UCHAR)'X'; \ + if (SendResourcesPlace >= 500) {\ + SendResourcesPlace = 0;\ + }\ +} + +#define ADD_RESOURCE(W, C) {\ + W->SendResourcesAvailable=0xffffff;\ + SendResourcesBuffer[SendResourcesPlace++] = (UCHAR)C; \ + SendResourcesBuffer[SendResourcesPlace++] = (UCHAR)'A';\ + SendResourcesBuffer[SendResourcesPlace++] = (UCHAR)W->SendResourcesAvailable;\ + SendResourcesBuffer[SendResourcesPlace] = (UCHAR)'X'; \ + if (SendResourcesPlace >= 500) {\ + SendResourcesPlace = 0;\ + }\ +} + +#define CLEAR_RESOURCE(W, C) {\ + W->SendResourcesAvailable = 0;\ + SendResourcesBuffer[SendResourcesPlace++] = (UCHAR)C; \ + SendResourcesBuffer[SendResourcesPlace++] = (UCHAR)'C';\ + SendResourcesBuffer[SendResourcesPlace++] = (UCHAR)W->SendResourcesAvailable;\ + if (SendResourcesPlace >= 500) {\ + SendResourcesPlace = 0;\ + }\ +} + +#else + +#define NDIS_LOG_PACKET(Miniport, Packet, Ident) +#define LOG(ch) + +#define REMOVE_RESOURCE(W, C) W->SendResourcesAvailable-- +#define ADD_RESOURCE(W, C) W->SendResourcesAvailable = 0xffffff +#define CLEAR_RESOURCE(W, C) W->SendResourcesAvailable = 0 + +#endif + +/*++ + +VOID +MiniportFindPacket( + PNDIS_MINIPORT_BLOCK Miniport, + PNDIS_PACKET Packet, + PNDIS_PACKET *PrevPacket + ) + +Routine Description: + + Searchs the miniport send queue for a packet. + +Arguments: + + Miniport - Miniport to send to. + Packet - Packet to find. + +Return Value: + + Pointer to packet which immediately preceeds the packet to search for or + NULL if the packet is not found. + +--*/ + +#define MiniportFindPacket(_Miniport, _Packet, _PrevPacket) \ +{ \ + PNDIS_PACKET CurrPacket = ((PNDIS_MINIPORT_BLOCK)(_Miniport))->FirstPacket; \ + PNDIS_PACKET TempPacket = NULL; \ + \ + ASSERT( CurrPacket != NULL ); \ + \ + do { \ + \ + if ( CurrPacket == ((PNDIS_PACKET)(_Packet)) ) { \ + \ + break; \ + } \ + \ + TempPacket = CurrPacket; \ + CurrPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(CurrPacket)->Next; \ + } \ + while( CurrPacket != NULL ); \ + \ + *((PNDIS_PACKET *)(_PrevPacket)) = TempPacket; \ + \ + ASSERT( CurrPacket != NULL ); \ +} + +// +// Routines for dealing with making the entire miniport package pagable +// + +NDIS_SPIN_LOCK MiniportReferenceLock = {0}; +KEVENT MiniportPagedInEvent = {0}; +ULONG MiniportReferenceCount = 0; +PVOID MiniportImageHandle = {0}; + +VOID +MiniportInitializePackage(VOID) +{ + // + // Allocate the spin lock + // + NdisAllocateSpinLock(&MiniportReferenceLock); + + // + // Initialize the "in page" event. + // + KeInitializeEvent( + &MiniportPagedInEvent, + NotificationEvent, + FALSE + ); +} + +VOID +MiniportReferencePackage(VOID) +{ + + // + // Grab the spin lock + // + ACQUIRE_SPIN_LOCK(&MiniportReferenceLock); + + // + // Increment the reference count + // + MiniportReferenceCount++; + + if (MiniportReferenceCount == 1) { + + // + // We are the first reference. Page everything in. + // + + // + // Clear the event + // + KeResetEvent( + &MiniportPagedInEvent + ); + + // + // Set the spin lock free + // + RELEASE_SPIN_LOCK(&MiniportReferenceLock); + + // + // Page in all the functions + // + MiniportImageHandle = MmLockPagableCodeSection(NdisMReset); + + // + // Signal to everyone to go + // + KeSetEvent( + &MiniportPagedInEvent, + 0L, + FALSE + ); + + } else { + + // + // Set the spin lock free + // + RELEASE_SPIN_LOCK(&MiniportReferenceLock); + + // + // Wait for everything to be paged in + // + KeWaitForSingleObject( + &MiniportPagedInEvent, + Executive, + KernelMode, + TRUE, + NULL + ); + + } + +} + +VOID +MiniportDereferencePackage(VOID) +{ + + // + // Get the spin lock + // + ACQUIRE_SPIN_LOCK(&MiniportReferenceLock); + + MiniportReferenceCount--; + + if (MiniportReferenceCount == 0) { + + // + // Let next one in + // + RELEASE_SPIN_LOCK(&MiniportReferenceLock); + + // + // Page out all the functions + // + MmUnlockPagableImageSection(MiniportImageHandle); + + } else { + + // + // Let next one in + // + RELEASE_SPIN_LOCK(&MiniportReferenceLock); + + } + +} + + +// +// Forward declarations +// + +VOID +MiniportArcCopyFromBufferToPacket( + IN PCHAR Buffer, + IN UINT BytesToCopy, + IN PNDIS_PACKET Packet, + IN UINT Offset, + OUT PUINT BytesCopied + ); + + +VOID +NdisMTimerDpc( + PKDPC Dpc, + PVOID Context, + PVOID SystemContext1, + PVOID SystemContext2 + ); + +VOID +AbortMiniportPacketsAndPending( + PNDIS_MINIPORT_BLOCK Miniport + ); + +VOID +AbortQueryStatisticsRequest( + PNDIS_REQUEST Request, + NDIS_STATUS Status + ); + +VOID +FASTCALL +MiniportStartSends( + PNDIS_MINIPORT_BLOCK Miniport + ); + +BOOLEAN +FASTCALL +MiniportSendLoopback( + PNDIS_MINIPORT_BLOCK Miniport, + PNDIS_PACKET Packet + ); + +VOID +MiniportDoRequests( + PNDIS_MINIPORT_BLOCK Miniport + ); + +NDIS_STATUS +MiniportAdjustMaximumLookahead( + IN PNDIS_MINIPORT_BLOCK Miniport + ); + +VOID +MiniportCopyFromPacketToBuffer( + IN PNDIS_PACKET Packet, + IN UINT Offset, + IN UINT BytesToCopy, + OUT PCHAR Buffer, + OUT PUINT BytesCopied + ); + +NTSTATUS +NdisMShutdown( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ); + +VOID +NdisMUnload( + IN PDRIVER_OBJECT DriverObject + ); + +NTSTATUS +NdisMQueryOidList( + PNDIS_M_USER_OPEN_CONTEXT OpenContext, + PIRP Irp + ); + +VOID +FinishClose( + PNDIS_MINIPORT_BLOCK Miniport, + PNDIS_M_OPEN_BLOCK Open + ); + +BOOLEAN +NdisMKillOpen( + PNDIS_OPEN_BLOCK OldOpenP + ); + +#if !defined(BUILD_FOR_3_1) +VOID +NdisBugcheckHandler( + IN PNDIS_WRAPPER_CONTEXT WrapperContext, + IN ULONG Size + ); +#endif + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGENDSM, NdisMReadDmaCounter) +#pragma alloc_text(PAGENDSM, NdisMCancelTimer) +#pragma alloc_text(PAGENDSM, MiniportArcCopyFromBufferToPacket) +#pragma alloc_text(PAGENDSM, NdisMArcTransferData) +#pragma alloc_text(PAGENDSM, NdisMArcIndicateEthEncapsulatedReceive) +#pragma alloc_text(PAGENDSM, HaltOneMiniport) +#pragma alloc_text(PAGENDSM, NdisMDeregisterDmaChannel) +#pragma alloc_text(PAGENDSM, NdisMRegisterDmaChannel) +#pragma alloc_text(PAGENDSM, NdisMFreeSharedMemory) +#pragma alloc_text(PAGENDSM, NdisMAllocateSharedMemory) +#pragma alloc_text(PAGENDSM, NdisMSynchronizeWithInterrupt) +#pragma alloc_text(PAGENDSM, NdisMDeregisterInterrupt) +#pragma alloc_text(PAGENDSM, NdisMRegisterInterrupt) +#pragma alloc_text(PAGENDSM, NdisMUnmapIoSpace) +#pragma alloc_text(PAGENDSM, NdisMMapIoSpace) +#pragma alloc_text(PAGENDSM, NdisMRequest) +#pragma alloc_text(PAGENDSM, NdisMReset) +//#pragma alloc_text(PAGENDSM, NdisMTransferDataSync) +//#pragma alloc_text(PAGENDSM, NdisMTransferData) +//#pragma alloc_text(PAGENDSM, NdisMSend) +#pragma alloc_text(PAGENDSM, NdisMQueryInformationComplete) +#pragma alloc_text(PAGENDSM, NdisMTransferDataComplete) +#pragma alloc_text(PAGENDSM, NdisMResetComplete) +#pragma alloc_text(PAGENDSM, NdisMSetInformationComplete) +#pragma alloc_text(PAGENDSM, NdisMSendResourcesAvailable) +//#pragma alloc_text(PAGENDSM, NdisMSendComplete) +#pragma alloc_text(PAGENDSM, NdisMIndicateStatusComplete) +#pragma alloc_text(PAGENDSM, NdisMIndicateStatus) +#pragma alloc_text(PAGENDSI, NdisMSetAttributes) +#pragma alloc_text(PAGENDSM, NdisMDeregisterIoPortRange) +#pragma alloc_text(PAGENDSM, NdisMRegisterIoPortRange) +#pragma alloc_text(PAGENDSM, NdisMDpcTimer) +//#pragma alloc_text(PAGENDSM, NdisMDpc) +//#pragma alloc_text(PAGENDSM, NdisMIsr) +#pragma alloc_text(PAGENDSM, NdisMFreeMapRegisters) +#pragma alloc_text(PAGENDSI, NdisMAllocateMapRegisters) +//#pragma alloc_text(PAGENDSM, NdisMWakeUpDpc) +#pragma alloc_text(PAGENDSM, NdisMInitializeTimer) +#pragma alloc_text(PAGENDSM, NdisMTimerDpc) +//#pragma alloc_text(PAGENDSM, MiniportProcessDeferred) +#pragma alloc_text(PAGENDSM, AbortMiniportPacketsAndPending) +#pragma alloc_text(PAGENDSM, AbortQueryStatisticsRequest) +//#pragma alloc_text(PAGENDSM, MiniportStartSends) +//#pragma alloc_text(PAGENDSM, MiniportSendLoopback) +#pragma alloc_text(PAGENDSM, MiniportDoRequests) +#pragma alloc_text(PAGENDSM, MiniportAdjustMaximumLookahead) +//#pragma alloc_text(PAGENDSM, MiniportCopyFromPacketToBuffer) +#pragma alloc_text(PAGENDSM, NdisMShutdown) +#pragma alloc_text(PAGENDSM, NdisMUnload) +#pragma alloc_text(PAGENDSM, NdisDequeueMiniportOnDriver) +#pragma alloc_text(PAGENDSM, NdisQueueMiniportOnDriver) +#pragma alloc_text(PAGENDSM, NdisDereferenceMiniport) +#pragma alloc_text(PAGENDSM, NdisDereferenceDriver) +#pragma alloc_text(PAGENDSM, NdisMQueryOidList) +#pragma alloc_text(PAGENDSM, NdisMChangeFddiAddresses) +#pragma alloc_text(PAGENDSM, NdisMChangeGroupAddress) +#pragma alloc_text(PAGENDSM, NdisMChangeFunctionalAddress) +#pragma alloc_text(PAGENDSM, NdisMCloseAction) +#pragma alloc_text(PAGENDSM, FinishClose) +#pragma alloc_text(PAGENDSM, NdisMChangeClass) +#pragma alloc_text(PAGENDSM, NdisMChangeEthAddresses) +#pragma alloc_text(PAGENDSM, NdisMKillOpen) + +#pragma alloc_text(PAGENDSM, NdisMWanSend) +#pragma alloc_text(PAGENDSM, NdisMWanSendComplete) +#pragma alloc_text(PAGENDSM, NdisMWanIndicateReceive) +#pragma alloc_text(PAGENDSM, NdisMWanIndicateReceiveComplete) + +#pragma alloc_text(PAGENDSM, NdisMRegisterAdapterShutdownHandler) +#pragma alloc_text(PAGENDSM, NdisMDeregisterAdapterShutdownHandler) +#pragma alloc_text(PAGENDSM, NdisMPciAssignResources) + +#endif + +// +// Routines for dealing with opens +// + + +BOOLEAN +NdisMKillOpen( + PNDIS_OPEN_BLOCK OldOpenP + ) + +/*++ + +Routine Description: + + Closes an open. Used when NdisCloseAdapter is called, and also + for internally generated closes. + +Arguments: + + OldOpenP - The open to be closed. + +Return Value: + + TRUE if the open finished, FALSE if it pended. + +--*/ + +{ + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(OldOpenP->AdapterHandle); + PNDIS_M_OPEN_BLOCK MiniportOpen; + BOOLEAN LocalLock; + NDIS_STATUS Status; + KIRQL OldIrql; + + // + // Find the Miniport open block + // + MiniportOpen = Miniport->OpenQueue; + while (MiniportOpen != NULL) { + + if (MiniportOpen->FakeOpen == OldOpenP) { + + break; + + } + + MiniportOpen = MiniportOpen->MiniportNextOpen; + } + + ASSERT(MiniportOpen != NULL); + + ACQUIRE_SPIN_LOCK(&MiniportOpen->SpinLock); + + // + // See if this open is already closing. + // + + if (MiniportOpen->Closing) { + RELEASE_SPIN_LOCK(&MiniportOpen->SpinLock); + return TRUE; + } + + + // + // Indicate to others that this open is closing. + // + + MiniportOpen->Closing = TRUE; + RELEASE_SPIN_LOCK(&MiniportOpen->SpinLock); + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + LOCK_MINIPORT(Miniport, LocalLock); + + // + // Remove us from the filter package + // + switch (Miniport->MediaType) { + + case NdisMediumArcnet878_2: + + if ( !MiniportOpen->UsingEthEncapsulation ) { + + Status = ArcDeleteFilterOpenAdapter( + Miniport->ArcDB, + MiniportOpen->FilterHandle, + NULL + ); + + break; + } + + // + // If we're using encapsulation then we + // didn't open an arcnet filter but rather + // an ethernet filter. + // + + case NdisMedium802_3: + + Status = EthDeleteFilterOpenAdapter( + Miniport->EthDB, + MiniportOpen->FilterHandle, + NULL + ); + break; + + case NdisMedium802_5: + + Status = TrDeleteFilterOpenAdapter( + Miniport->TrDB, + MiniportOpen->FilterHandle, + NULL + ); + break; + + case NdisMediumFddi: + + Status = FddiDeleteFilterOpenAdapter( + Miniport->FddiDB, + MiniportOpen->FilterHandle, + NULL + ); + break; + } + + if (Status != NDIS_STATUS_CLOSING_INDICATING) { + + // + // Otherwise the close action routine will fix this up. + // + MiniportOpen->References--; + } + + // + // If we're able to grab the local lock then we can do some + // deferred processing now. + // + + if ( LocalLock ) { + + // + // Process any changes that may have occured. + // + + if (!Miniport->ProcessingDeferred) { + + MiniportProcessDeferred(Miniport); + + } + } + + UNLOCK_MINIPORT(Miniport, LocalLock); + + // + // Remove us from the adapter and protocol open queues. + // + + if (MiniportOpen->References != 0) { + + // + // Wait for close to complete, reference count will drop to 0. + // + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + KeLowerIrql(OldIrql); + + return FALSE; + + } else { + + // + // This sends an IRP_MJ_CLOSE IRP. + // + ObDereferenceObject((PVOID)(OldOpenP->FileObject)); + + NdisDeQueueOpenOnProtocol(OldOpenP, OldOpenP->ProtocolHandle); + NdisDeQueueOpenOnMiniport(MiniportOpen, MiniportOpen->MiniportHandle); + + NdisDereferenceProtocol(OldOpenP->ProtocolHandle); + NdisDereferenceMiniport(MiniportOpen->MiniportHandle); + + NdisFreeSpinLock(&MiniportOpen->SpinLock); + ExFreePool((PVOID)MiniportOpen); + ExFreePool(OldOpenP); + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + KeLowerIrql(OldIrql); + + return TRUE; + } + +} + + +// +// Filter package callback handlers +// + +#define PNDIS_M_OPEN_FROM_BINDING_HANDLE(_handle) ((PNDIS_M_OPEN_BLOCK)(_handle)) + + +NDIS_STATUS +NdisMChangeEthAddresses( + IN UINT OldAddressCount, + IN CHAR OldAddresses[][ETH_LENGTH_OF_ADDRESS], + IN UINT NewAddressCount, + IN CHAR NewAddresses[][ETH_LENGTH_OF_ADDRESS], + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest, + IN BOOLEAN Set + ) + +/*++ + +Routine Description: + + Action routine that will get called when the multicast address + list has changed. + + NOTE: This routine assumes that it is called with the lock + acquired. + +Arguments: + + OldAddressCount - The number of addresses in OldAddresses. + + OldAddresses - The old multicast address list. + + NewAddressCount - The number of addresses in NewAddresses. + + NewAddresses - The new multicast address list. + + MacBindingHandle - The context value returned by the driver when the + adapter was opened. In reality, it is a pointer to W_OPEN_BLOCK. + + RequestHandle - A value supplied by the NDIS interface that the driver + must use when completing this request. + + Set - If true the change resulted from a set, otherwise the + change resulted from a open closing. + +Return Value: + + None. + + +--*/ + +{ + PNDIS_M_OPEN_BLOCK Open = PNDIS_M_OPEN_FROM_BINDING_HANDLE(MacBindingHandle); + + LOUD_DEBUG(DbgPrint("NdisM: Enter ChangeEthAddresses\n");) + + if ((Open->MiniportHandle->MediaType == NdisMediumArcnet878_2) && + (Open->UsingEthEncapsulation)) { + + if (NewAddressCount > 0) { + + // + // Turn on broadcast acceptance. + // + Open->MiniportHandle->ArcnetBroadcastSet = TRUE; + + } else { + + // + // Unset the broadcast filter. + // + Open->MiniportHandle->ArcnetBroadcastSet = FALSE; + + } + + Open->MiniportHandle->NeedToUpdatePacketFilter = TRUE; + Open->MiniportHandle->RunDoRequests = TRUE; + Open->MiniportHandle->ProcessOddDeferredStuff = TRUE; + + return(NDIS_STATUS_SUCCESS); + } + + // + // Queue a call to fix this up. + // + Open->MiniportHandle->NeedToUpdateEthAddresses = TRUE; + Open->MiniportHandle->RunDoRequests = TRUE; + Open->MiniportHandle->ProcessOddDeferredStuff = TRUE; + + LOUD_DEBUG(DbgPrint("NdisM: Exit ChangeEthAddresses\n");) + + return(NDIS_STATUS_SUCCESS); +} + + +NDIS_STATUS +NdisMChangeClass( + IN UINT OldFilterClasses, + IN UINT NewFilterClasses, + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest, + IN BOOLEAN Set + ) + +/*++ + +Routine Description: + + Action routine that will get called when a particular filter + class is first used or last cleared. + + NOTE: This routine assumes that it is called with the lock + acquired. + +Arguments: + + OldFilterClasses - The values of the class filter before it + was changed. + + NewFilterClasses - The current value of the class filter + + MacBindingHandle - The context value returned by the driver when the + adapter was opened. In reality, it is a pointer to W_OPEN_BLOCK. + + RequestHandle - A value supplied by the NDIS interface that the driver + must use when completing this request. + + Set - If true the change resulted from a set, otherwise the + change resulted from a open closing. + +Return Value: + + None. + + +--*/ + +{ + PNDIS_M_OPEN_BLOCK Open = PNDIS_M_OPEN_FROM_BINDING_HANDLE(MacBindingHandle); + + LOUD_DEBUG(DbgPrint("NdisM: Enter change class\n");) + + // + // Queue a call to fix this up. + // + Open->MiniportHandle->NeedToUpdatePacketFilter = TRUE; + Open->MiniportHandle->RunDoRequests = TRUE; + Open->MiniportHandle->ProcessOddDeferredStuff = TRUE; + + LOUD_DEBUG(DbgPrint("NdisM: Exit change class\n");) + + return(NDIS_STATUS_SUCCESS); +} + + +VOID +FinishClose( + PNDIS_MINIPORT_BLOCK Miniport, + PNDIS_M_OPEN_BLOCK Open + ) + +/*++ + +Routine Description: + + Finishes off a close adapter call. + + CALLED WITH LOCK HELD!! + +Arguments: + + Miniport - The mini-port the open is queued on. + + Open - The open to close + +Return Value: + + None. + + +--*/ + + +{ + + ASSERT(Open->Closing); + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + + (Open->ProtocolHandle->ProtocolCharacteristics.CloseAdapterCompleteHandler) ( + Open->ProtocolBindingContext, + NDIS_STATUS_SUCCESS + ); + + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + NdisDeQueueOpenOnProtocol(Open->FakeOpen, Open->ProtocolHandle); + NdisDeQueueOpenOnMiniport(Open, Open->MiniportHandle); + ExFreePool(Open->FakeOpen); + + NdisDereferenceMiniport(Open->MiniportHandle); + NdisDereferenceProtocol(Open->ProtocolHandle); + + NdisFreeSpinLock(&Open->SpinLock); + + // + // This sends an IRP_MJ_CLOSE IRP. + // + + ObDereferenceObject((PVOID)(Open->FileObject)); + + ExFreePool((PVOID)Open); + +} + + +VOID +NdisMCloseAction( + IN NDIS_HANDLE MacBindingHandle + ) + +/*++ + +Routine Description: + + Action routine that will get called when a particular binding + was closed while it was indicating through NdisIndicateReceive + + All this routine needs to do is to decrement the reference count + of the binding. + + NOTE: This routine assumes that it is called with the lock acquired. + +Arguments: + + MacBindingHandle - The context value returned by the driver when the + adapter was opened. In reality, it is a pointer to W_OPEN_BLOCK. + +Return Value: + + None. + + +--*/ + +{ + PNDIS_M_OPEN_BLOCK Open = PNDIS_M_OPEN_FROM_BINDING_HANDLE(MacBindingHandle); + PNDIS_MINIPORT_BLOCK Miniport = Open->MiniportHandle; + + Open->References--; + if (Open->References == 0) { + + FinishClose(Miniport,Open); + + } + +} + + +NDIS_STATUS +NdisMChangeFunctionalAddress( + IN TR_FUNCTIONAL_ADDRESS OldFunctionalAddress, + IN TR_FUNCTIONAL_ADDRESS NewFunctionalAddress, + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest, + IN BOOLEAN Set + ) + + +/*++ + +Routine Description: + + Action routine that will get called when an address is added to + the filter that wasn't referenced by any other open binding. + + NOTE: This routine assumes that it is called with the lock + acquired. + +Arguments: + + OldFunctionalAddress - The previous functional address. + + NewFunctionalAddress - The new functional address. + + MacBindingHandle - The context value returned by the driver when the + adapter was opened. In reality, it is a pointer to W_OPEN_BLOCK. + + NdisRequest - A pointer to the Request that submitted the set command. + + Set - If true the change resulted from a set, otherwise the + change resulted from a open closing. + +Return Value: + + None. + + +--*/ + +{ + PNDIS_M_OPEN_BLOCK Open = PNDIS_M_OPEN_FROM_BINDING_HANDLE(MacBindingHandle); + + LOUD_DEBUG(DbgPrint("NdisM: Enter change functional\n");) + + // + // Queue a call to fix this up. + // + Open->MiniportHandle->NeedToUpdateFunctionalAddress = TRUE; + Open->MiniportHandle->RunDoRequests = TRUE; + Open->MiniportHandle->ProcessOddDeferredStuff = TRUE; + + LOUD_DEBUG(DbgPrint("NdisM: Exit change functional\n");) + + return(NDIS_STATUS_SUCCESS); +} + + +NDIS_STATUS +NdisMChangeGroupAddress( + IN TR_FUNCTIONAL_ADDRESS OldGroupAddress, + IN TR_FUNCTIONAL_ADDRESS NewGroupAddress, + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest, + IN BOOLEAN Set + ) + +/*++ + +Routine Description: + + Action routine that will get called when a group address is to + be changed. + + NOTE: This routine assumes that it is called with the lock + acquired. + +Arguments: + + OldGroupAddress - The previous group address. + + NewGroupAddress - The new group address. + + MacBindingHandle - The context value returned by the driver when the + adapter was opened. In reality, it is a pointer to W_OPEN_BLOCK. + + NdisRequest - A pointer to the Request that submitted the set command. + + Set - If true the change resulted from a set, otherwise the + change resulted from a open closing. + +Return Value: + + None. + + +--*/ + +{ + PNDIS_M_OPEN_BLOCK Open = PNDIS_M_OPEN_FROM_BINDING_HANDLE(MacBindingHandle); + + LOUD_DEBUG(DbgPrint("NdisM: Enter change group\n");) + + // + // Queue a call to fix this up. + // + Open->MiniportHandle->NeedToUpdateGroupAddress = TRUE; + Open->MiniportHandle->RunDoRequests = TRUE; + Open->MiniportHandle->ProcessOddDeferredStuff = TRUE; + + LOUD_DEBUG(DbgPrint("NdisM: Exit change group\n");) + + return(NDIS_STATUS_SUCCESS); + +} + + +NDIS_STATUS +NdisMChangeFddiAddresses( + IN UINT oldLongAddressCount, + IN CHAR oldLongAddresses[][FDDI_LENGTH_OF_LONG_ADDRESS], + IN UINT newLongAddressCount, + IN CHAR newLongAddresses[][FDDI_LENGTH_OF_LONG_ADDRESS], + IN UINT oldShortAddressCount, + IN CHAR oldShortAddresses[][FDDI_LENGTH_OF_SHORT_ADDRESS], + IN UINT newShortAddressCount, + IN CHAR newShortAddresses[][FDDI_LENGTH_OF_SHORT_ADDRESS], + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest, + IN BOOLEAN Set + ) + +/*++ + +Routine Description: + + Action routine that will get called when the multicast address + list has changed. + + NOTE: This routine assumes that it is called with the lock + acquired. + +Arguments: + + oldAddressCount - The number of addresses in oldAddresses. + + oldAddresses - The old multicast address list. + + newAddressCount - The number of addresses in newAddresses. + + newAddresses - The new multicast address list. + + macBindingHandle - The context value returned by the driver when the + adapter was opened. In reality, it is a pointer to W_OPEN_BLOCK. + + requestHandle - A value supplied by the NDIS interface that the driver + must use when completing this request. + + Set - If true the change resulted from a set, otherwise the + change resulted from a open closing. + +Return Value: + + None. + + +--*/ + +{ + PNDIS_M_OPEN_BLOCK Open = PNDIS_M_OPEN_FROM_BINDING_HANDLE(MacBindingHandle); + + LOUD_DEBUG(DbgPrint("NdisM: Enter change fddi addresses\n");) + + // + // Queue a call to fix this up. + // + Open->MiniportHandle->NeedToUpdateFddiLongAddresses = TRUE; + Open->MiniportHandle->NeedToUpdateFddiShortAddresses = TRUE; + Open->MiniportHandle->RunDoRequests = TRUE; + Open->MiniportHandle->ProcessOddDeferredStuff = TRUE; + + LOUD_DEBUG(DbgPrint("NdisM: Exit change fddi addresses\n");) + + return(NDIS_STATUS_SUCCESS); + +} + +// +// IRP handlers established on behalf of NDIS devices by +// the wrapper. +// + + + +NTSTATUS +NdisMQueryOidList( + PNDIS_M_USER_OPEN_CONTEXT OpenContext, + PIRP Irp + ) + +/*++ + +Routine Description: + + This routine will take care of querying the complete OID + list for the driver and filling in OpenContext->OidArray + with the ones that are statistics. It blocks when the + driver pends and so is synchronous. + +Arguments: + + OpenContext - The open context. + Irp = The IRP that the open was done on (used at completion + to distinguish the request). + +Return Value: + + STATUS_SUCCESS if it should be. + +--*/ + +{ + NDIS_QUERY_OPEN_REQUEST OpenRequest; + NDIS_STATUS NdisStatus; + PNDIS_OID TmpBuffer; + ULONG TmpBufferLength; + UINT i, j; + PNDIS_REQUEST_RESERVED Reserved; + BOOLEAN LocalLock; + PNDIS_MINIPORT_BLOCK Miniport = OpenContext->MiniportBlock; + KIRQL OldIrql; + + LOUD_DEBUG(DbgPrint("NdisM: Enter query oid list\n");) + + KeRaiseIrql( DISPATCH_LEVEL, &OldIrql); + ACQUIRE_SPIN_LOCK_DPC(&(Miniport->Lock)); + LOCK_MINIPORT(Miniport, LocalLock); + + // + // First query the OID list with no buffer, to find out + // how big it should be. + // + + KeInitializeEvent( + &OpenRequest.Event, + NotificationEvent, + FALSE + ); + + OpenRequest.Irp = Irp; + + // + // Build fake request + // + + OpenRequest.Request.RequestType = NdisRequestQueryStatistics; + OpenRequest.Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_SUPPORTED_LIST; + OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBuffer = NULL; + OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBufferLength = 0; + OpenRequest.Request.DATA.QUERY_INFORMATION.BytesWritten = 0; + OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded = 0; + + // + // Put request on queue + // + + Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(&(OpenRequest.Request)); + Reserved->Next = NULL; + Miniport->LastPendingRequest = &(OpenRequest.Request); + + if (Miniport->FirstPendingRequest == NULL) { + + Miniport->FirstPendingRequest = &(OpenRequest.Request); + + } else { + + PNDIS_RESERVED_FROM_PNDIS_REQUEST(Miniport->LastPendingRequest)->Next = + &(OpenRequest.Request); + + } + + if (Miniport->MiniportRequest == NULL) { + + Miniport->RunDoRequests = TRUE; + Miniport->ProcessOddDeferredStuff = TRUE; + + } + + if ( LocalLock ) { + + if (!Miniport->ProcessingDeferred) { + + MiniportProcessDeferred(Miniport); + } + } + + UNLOCK_MINIPORT(Miniport, LocalLock); + RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock)); + KeLowerIrql(OldIrql); + + // + // The completion routine will set NdisRequestStatus. + // + + KeWaitForSingleObject( + &OpenRequest.Event, + Executive, + KernelMode, + TRUE, + (PLARGE_INTEGER)NULL + ); + + KeRaiseIrql( DISPATCH_LEVEL, &OldIrql); + ACQUIRE_SPIN_LOCK_DPC(&(Miniport->Lock)); + LOCK_MINIPORT(Miniport, LocalLock); + + NdisStatus = OpenRequest.NdisStatus; + + if ((NdisStatus != NDIS_STATUS_INVALID_LENGTH) && + (NdisStatus != NDIS_STATUS_BUFFER_TOO_SHORT)) { + + UNLOCK_MINIPORT(Miniport, LocalLock); + RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock)); + KeLowerIrql(OldIrql); + return(NdisStatus); + + } + + // + // Now we know how much is needed, allocate temp storage... + // + + TmpBufferLength = OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded; + TmpBuffer = ExAllocatePool(NonPagedPool, TmpBufferLength); + + if (TmpBuffer == NULL) { + UNLOCK_MINIPORT(Miniport, LocalLock); + RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock)); + KeLowerIrql(OldIrql); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // ...and query the real list. + // + + KeResetEvent( + &OpenRequest.Event + ); + + OpenRequest.Request.RequestType = NdisRequestQueryStatistics; + OpenRequest.Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_SUPPORTED_LIST; + OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBuffer = TmpBuffer; + OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBufferLength = TmpBufferLength; + OpenRequest.Request.DATA.QUERY_INFORMATION.BytesWritten = 0; + OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded = 0; + + // + // Put request on queue + // + + Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(&(OpenRequest.Request)); + Reserved->Next = NULL; + Miniport->LastPendingRequest = &(OpenRequest.Request); + + if (Miniport->FirstPendingRequest == NULL) { + + Miniport->FirstPendingRequest = &(OpenRequest.Request); + + } else { + + PNDIS_RESERVED_FROM_PNDIS_REQUEST(Miniport->LastPendingRequest)->Next = + &(OpenRequest.Request); + + } + + if (Miniport->MiniportRequest == NULL) { + + Miniport->RunDoRequests = TRUE; + Miniport->ProcessOddDeferredStuff = TRUE; + + } + + if ( LocalLock ) { + + if (!Miniport->ProcessingDeferred) { + + MiniportProcessDeferred(Miniport); + } + } + + UNLOCK_MINIPORT(Miniport, LocalLock); + RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock)); + KeLowerIrql(OldIrql); + + // + // The completion routine will set NdisRequestStatus. + // + + KeWaitForSingleObject( + &OpenRequest.Event, + Executive, + KernelMode, + TRUE, + (PLARGE_INTEGER)NULL + ); + + KeRaiseIrql( DISPATCH_LEVEL, &OldIrql); + ACQUIRE_SPIN_LOCK_DPC(&(Miniport->Lock)); + LOCK_MINIPORT(Miniport, LocalLock); + + NdisStatus = OpenRequest.NdisStatus; + + ASSERT (NdisStatus == NDIS_STATUS_SUCCESS); + + + // + // Now go through the buffer, counting the statistics OIDs. + // + + for (i=0; i<TmpBufferLength/sizeof(NDIS_OID); i++) { + if ((TmpBuffer[i] & 0x00ff0000) == 0x00020000) { + ++OpenContext->OidCount; + } + } + + // + // Now allocate storage for the real OID array. + // + + OpenContext->OidArray = ExAllocatePool (NonPagedPool, OpenContext->OidCount * sizeof(NDIS_OID)); + + if (OpenContext->OidArray == NULL) { + ExFreePool (TmpBuffer); + UNLOCK_MINIPORT(Miniport, LocalLock); + RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock)); + KeLowerIrql(OldIrql); + return STATUS_INSUFFICIENT_RESOURCES; + } + + + // + // Now go through the buffer, copying the statistics OIDs. + // + + j = 0; + for (i=0; i<TmpBufferLength/sizeof(NDIS_OID); i++) { + + if ((TmpBuffer[i] & 0x00ff0000) == 0x00020000) { + OpenContext->OidArray[j] = TmpBuffer[i]; + ++j; + } + } + + ASSERT (j == OpenContext->OidCount); + + LOUD_DEBUG(DbgPrint("NdisM: Exit query oid list\n");) + + ExFreePool (TmpBuffer); + UNLOCK_MINIPORT(Miniport, LocalLock); + RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock)); + KeLowerIrql(OldIrql); + return STATUS_SUCCESS; +} + +VOID +NdisLastCountRemovedFunction( + IN struct _KDPC *Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2 + ); + +#define NdisReferenceDriver(WDriver) NdisReferenceRef(&(WDriver)->Ref) + + +VOID +NdisDereferenceDriver( + PNDIS_M_DRIVER_BLOCK WDriver + ) +/*++ + +Routine Description: + + Removes a reference from the mini-port driver, deleting it if the count goes to 0. + +Arguments: + + Miniport - The mini-port block to dereference. + +Return Value: + + None. + +--*/ +{ + if (NdisDereferenceRef(&(WDriver)->Ref)) { + + // + // Remove it from the global list. + // + + ACQUIRE_SPIN_LOCK(&NdisDriverListLock); + + if (NdisDriverList == WDriver) { + + NdisDriverList = WDriver->NextDriver; + + } else { + + PNDIS_M_DRIVER_BLOCK TmpDriver = NdisDriverList; + + while(TmpDriver->NextDriver != WDriver) { + + TmpDriver = TmpDriver->NextDriver; + + } + + TmpDriver->NextDriver = TmpDriver->NextDriver->NextDriver; + + } + + RELEASE_SPIN_LOCK(&NdisDriverListLock); + + if (WDriver->FakeMac != NULL) { + ExFreePool((PVOID)(WDriver->FakeMac)); + } + + ExFreePool((PVOID)(WDriver)); + + } +} + + +VOID +NdisDereferenceMiniport( + PNDIS_MINIPORT_BLOCK Miniport + ) +/*++ + +Routine Description: + + Removes a reference from the mini-port driver, deleting it if the count goes to 0. + +Arguments: + + Miniport - The mini-port block to dereference. + +Return Value: + + None. + +--*/ +{ + if (NdisDereferenceRef(&(Miniport)->Ref)) { + + if (Miniport->EthDB) { + EthDeleteFilter(Miniport->EthDB); + } + + if (Miniport->TrDB) { + TrDeleteFilter(Miniport->TrDB); + } + + if (Miniport->FddiDB) { + FddiDeleteFilter(Miniport->FddiDB); + } + + if (Miniport->ArcDB) { + ArcDeleteFilter(Miniport->ArcDB); + } + + if (((PNDIS_WRAPPER_CONTEXT)Miniport->WrapperContext)->AssignedSlotResources != NULL ) { + ExFreePool( ((PNDIS_WRAPPER_CONTEXT)Miniport->WrapperContext)->AssignedSlotResources ); + } + + NdisDequeueMiniportOnDriver(Miniport, Miniport->DriverHandle); + NdisDereferenceDriver(Miniport->DriverHandle); + NdisMDeregisterAdapterShutdownHandler( Miniport ); + IoUnregisterShutdownNotification(Miniport->DeviceObject); + IoDeleteDevice(Miniport->DeviceObject); + + } +} + + + +BOOLEAN +NdisQueueMiniportOnDriver( + IN PNDIS_MINIPORT_BLOCK Miniport, + IN PNDIS_M_DRIVER_BLOCK WDriver + ) + +/*++ + +Routine Description: + + Adds an mini-port to a list of mini-port for a driver. + +Arguments: + + Miniport - The mini-port block to queue. + WDriver - The driver block to queue it to. + +Return Value: + + FALSE if the driver is closing. + TRUE otherwise. + +--*/ + +{ + ACQUIRE_SPIN_LOCK(&WDriver->Ref.SpinLock); + + LOUD_DEBUG(DbgPrint("NdisM: Enter queue mini-port on driver\n");) + LOUD_DEBUG(DbgPrint("NdisM: queue mini-port 0x%x\n", Miniport);) + LOUD_DEBUG(DbgPrint("NdisM: driver 0x%x\n", WDriver);) + + + // + // Make sure the driver is not closing. + // + + if (WDriver->Ref.Closing) { + + LOUD_DEBUG(DbgPrint("NdisM: Exit queue mini-port on driver\n");) + + RELEASE_SPIN_LOCK(&WDriver->Ref.SpinLock); + return FALSE; + } + + + // + // Add this adapter at the head of the queue + // + + Miniport->NextMiniport = WDriver->MiniportQueue; + WDriver->MiniportQueue = Miniport; + + LOUD_DEBUG(DbgPrint("NdisM: Exit queue mini-port on driver\n");) + + RELEASE_SPIN_LOCK(&WDriver->Ref.SpinLock); + return TRUE; +} + + +VOID +NdisDequeueMiniportOnDriver( + PNDIS_MINIPORT_BLOCK Miniport, + PNDIS_M_DRIVER_BLOCK WDriver + ) + +/*++ + +Routine Description: + + Removes an mini-port from a list of mini-port for a driver. + +Arguments: + + Miniport - The mini-port block to dequeue. + WDriver - The driver block to dequeue it from. + +Return Value: + + None. + +--*/ + +{ + ACQUIRE_SPIN_LOCK(&WDriver->Ref.SpinLock); + + LOUD_DEBUG(DbgPrint("NdisM: Dequeue on driver\n");) + LOUD_DEBUG(DbgPrint("NdisM: dequeue mini-port 0x%x\n", Miniport);) + LOUD_DEBUG(DbgPrint("NdisM: driver 0x%x\n", WDriver);) + + // + // Find the driver on the queue, and remove it. + // + + if (WDriver->MiniportQueue == Miniport) { + WDriver->MiniportQueue = Miniport->NextMiniport; + } else { + PNDIS_MINIPORT_BLOCK MP = WDriver->MiniportQueue; + + while (MP->NextMiniport != Miniport) { + MP = MP->NextMiniport; + } + + MP->NextMiniport = MP->NextMiniport->NextMiniport; + } + + RELEASE_SPIN_LOCK(&WDriver->Ref.SpinLock); + + if (WDriver->Unloading && (WDriver->MiniportQueue == (PNDIS_MINIPORT_BLOCK)NULL)) { + + KeSetEvent( + &WDriver->MiniportsRemovedEvent, + 0L, + FALSE + ); + + } + + LOUD_DEBUG(DbgPrint("NdisM: Exit dequeue mini-port on driver\n");) +} + + + + +VOID +NdisMUnload( + IN PDRIVER_OBJECT DriverObject + ) +/*++ + +Routine Description: + + This routine is called when a driver is supposed to unload. Ndis + converts this into a set of calls to MiniportHalt() for each + adapter that the driver has open. + +Arguments: + + DriverObject - the driver object for the mac that is to unload. + +Return Value: + + None. + +--*/ +{ + PNDIS_M_DRIVER_BLOCK WDriver; + PNDIS_MINIPORT_BLOCK Miniport, NextMiniport; + KIRQL OldIrql; + + LOUD_DEBUG(DbgPrint("NdisM: Enter unload\n");) + + // + // Search for the driver + // + + ACQUIRE_SPIN_LOCK(&NdisDriverListLock); + + WDriver = NdisDriverList; + + while (WDriver != (PNDIS_M_DRIVER_BLOCK)NULL) { + + if (WDriver->NdisDriverInfo->NdisWrapperDriver == DriverObject) { + + break; + + } + + WDriver = WDriver->NextDriver; + + } + + RELEASE_SPIN_LOCK(&NdisDriverListLock); + + if (WDriver == (PNDIS_M_DRIVER_BLOCK)NULL) { + + // + // It is already gone. Just return. + // + + LOUD_DEBUG(DbgPrint("NdisM: Exit unload\n");) + + return; + + } + + WDriver->Unloading = TRUE; + + + LOUD_DEBUG(DbgPrint("NdisM: Halting mini-port\n");) + + // + // Now call MiniportHalt() for each Miniport. + // + + Miniport = WDriver->MiniportQueue; + + while (Miniport != (PNDIS_MINIPORT_BLOCK)NULL) { + + NextMiniport = Miniport->NextMiniport; // since queue may change + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + LOUD_DEBUG(DbgPrint("NdisM: Enter shutdown\n");) + + Miniport->HaltingMiniport = TRUE; + Miniport->NormalInterrupts = FALSE; + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + KeLowerIrql(OldIrql); + + HaltOneMiniport(Miniport); + + Miniport = NextMiniport; + } + + // + // Wait for all adapters to be gonzo. + // + + KeWaitForSingleObject( + &WDriver->MiniportsRemovedEvent, + Executive, + KernelMode, + TRUE, + (PTIME)NULL + ); + + KeResetEvent( + &WDriver->MiniportsRemovedEvent + ); + + // + // Now remove the last reference (this will remove it from the list) + // + + ASSERT(WDriver->Ref.ReferenceCount == 1); + + LOUD_DEBUG(DbgPrint("NdisM: Exit unload\n");) + + NdisDereferenceDriver(WDriver); +} + + +NTSTATUS +NdisMShutdown( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) + +/*++ + +Routine Description: + + The "shutdown handler" for the SHUTDOWN Irp. Will call the Ndis + shutdown routine, if one is registered. + +Arguments: + + DeviceObject - The adapter's device object. + Irp - The IRP. + +Return Value: + + Always STATUS_SUCCESS. + +--*/ + +{ + PNDIS_WRAPPER_CONTEXT WrapperContext = (PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension; + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(WrapperContext + 1); + KIRQL OldIrql; + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + Miniport->HaltingMiniport = TRUE; + Miniport->NormalInterrupts = FALSE; + + if (WrapperContext->ShutdownHandler != NULL) { + + while (Miniport->LockAcquired) { + + // + // This can only happen on an MP system. We must now + // wait for the other processor to exit the mini-port. + // + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + KeLowerIrql(OldIrql); + + NdisStallExecution(1000); + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + } + + // + // Lock miniport so that nothing will enter it. + // + + Miniport->LockAcquired = TRUE; + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + KeLowerIrql(OldIrql); + + // + // Call the shutdown routine. + // + + if (WrapperContext->ShutdownHandler != NULL) { + WrapperContext->ShutdownHandler(WrapperContext->ShutdownContext); + } + + Miniport->LockAcquired = FALSE; + + } else { + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + KeLowerIrql(OldIrql); + + } + + Irp->IoStatus.Status = STATUS_SUCCESS; + + IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); + + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisMShutdown\n"); + + return STATUS_SUCCESS; +} + +// +// This constant is used for places where NdisAllocateMemory +// needs to be called and the HighestAcceptableAddress does +// not matter. +// + +static const NDIS_PHYSICAL_ADDRESS HighestAcceptableMax = + NDIS_PHYSICAL_ADDRESS_CONST(-1,-1); + + + + +VOID +MiniportCopyFromPacketToBuffer( + IN PNDIS_PACKET Packet, + IN UINT Offset, + IN UINT BytesToCopy, + OUT PCHAR Buffer, + OUT PUINT BytesCopied + ) + +/*++ + +Routine Description: + + Copy from an ndis packet into a buffer. + +Arguments: + + Packet - The packet to copy from. + + Offset - The offset from which to start the copy. + + BytesToCopy - The number of bytes to copy from the packet. + + Buffer - The destination of the copy. + + BytesCopied - The number of bytes actually copied. Can be less then + BytesToCopy if the packet is shorter than BytesToCopy. + +Return Value: + + None + +--*/ + +{ + + // + // Holds the number of ndis buffers comprising the packet. + // + UINT NdisBufferCount; + + // + // Points to the buffer from which we are extracting data. + // + PNDIS_BUFFER CurrentBuffer; + + // + // Holds the virtual address of the current buffer. + // + PVOID VirtualAddress; + + // + // Holds the length of the current buffer of the packet. + // + UINT CurrentLength; + + // + // Keep a local variable of BytesCopied so we aren't referencing + // through a pointer. + // + UINT LocalBytesCopied = 0; + + // + // Take care of boundary condition of zero length copy. + // + + *BytesCopied = 0; + if (!BytesToCopy) return; + + // + // Get the first buffer. + // + + NdisQueryPacket( + Packet, + NULL, + &NdisBufferCount, + &CurrentBuffer, + NULL + ); + + // + // Could have a null packet. + // + + if (!NdisBufferCount) return; + + NdisQueryBuffer( + CurrentBuffer, + &VirtualAddress, + &CurrentLength + ); + + while (LocalBytesCopied < BytesToCopy) { + + if (CurrentLength == 0) { + + NdisGetNextBuffer( + CurrentBuffer, + &CurrentBuffer + ); + + // + // We've reached the end of the packet. We return + // with what we've done so far. (Which must be shorter + // than requested. + // + + if (!CurrentBuffer) break; + + NdisQueryBuffer( + CurrentBuffer, + &VirtualAddress, + &CurrentLength + ); + continue; + + } + + // + // Try to get us up to the point to start the copy. + // + + if (Offset) { + + if (Offset > CurrentLength) { + + // + // What we want isn't in this buffer. + // + + Offset -= CurrentLength; + CurrentLength = 0; + continue; + + } else { + + VirtualAddress = (PCHAR)VirtualAddress + Offset; + CurrentLength -= Offset; + Offset = 0; + + } + + } + + // + // Copy the data. + // + + + { + + // + // Holds the amount of data to move. + // + UINT AmountToMove; + + AmountToMove = + ((CurrentLength <= (BytesToCopy - LocalBytesCopied))? + (CurrentLength):(BytesToCopy - LocalBytesCopied)); + + NdisMoveMemory( + Buffer, + VirtualAddress, + AmountToMove + ); + + Buffer = (PCHAR)Buffer + AmountToMove; + VirtualAddress = (PCHAR)VirtualAddress + AmountToMove; + + LocalBytesCopied += AmountToMove; + CurrentLength -= AmountToMove; + + } + + } + + *BytesCopied = LocalBytesCopied; + +} + + + +NDIS_STATUS +MiniportAdjustMaximumLookahead( + IN PNDIS_MINIPORT_BLOCK Miniport + ) +/*++ + +Routine Description: + + This routine finds the open with the maximum lookahead value and + stores that in the mini-port block. + +Arguments: + + Miniport - A pointer to the mini-port block. + +Returns: + + Status of the operation + +--*/ +{ + ULONG CurrentMax = 0; + PNDIS_M_OPEN_BLOCK CurrentOpen; + NDIS_STATUS Status = NDIS_STATUS_SUCCESS; + + ASSERT(MINIPORT_AT_DPC_LEVEL); + ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport)); + + CurrentOpen = Miniport->OpenQueue; + + while (CurrentOpen != NULL) { + + if (CurrentOpen->CurrentLookahead > CurrentMax) { + + CurrentMax = CurrentOpen->CurrentLookahead; + + } + + CurrentOpen = CurrentOpen->MiniportNextOpen; + } + + if (CurrentMax == 0) { + + CurrentMax = Miniport->MaximumLookahead; + + } else if (CurrentMax > Miniport->MaximumLookahead) { + + CurrentMax = Miniport->MaximumLookahead; + + } + + if (Miniport->CurrentLookahead != CurrentMax) { + + BOOLEAN CompleteRequestMyself = TRUE; + + if (Miniport->MiniportRequest) { + + CompleteRequestMyself = FALSE; + + // + // This is due to a request -- complete it before submitting a + // new one to the mini-port. + // + NdisMSetInformationComplete( + (NDIS_HANDLE)Miniport, + NDIS_STATUS_SUCCESS + ); + } + + // + // Change it + // + + NdisMoveMemory(Miniport->MulticastBuffer, &CurrentMax, sizeof(CurrentMax)); + + Miniport->CurrentLookahead = CurrentMax; + Miniport->MiniportRequest = &(Miniport->InternalRequest); + Miniport->InternalRequest.RequestType = NdisRequestSetInformation; + + Status = + (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)( + Miniport->MiniportAdapterContext, + OID_GEN_CURRENT_LOOKAHEAD, + Miniport->MulticastBuffer, + sizeof(CurrentMax), + &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesRead, + &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesNeeded + ); + + if (CompleteRequestMyself && (Status != NDIS_STATUS_PENDING)) { + + // + // This is not called from within a request, so no-one will be + // expecting to complete this, so we must do it now. + // + + NdisMSetInformationComplete( + (NDIS_HANDLE)Miniport, + Status + ); + + } + + } + + return Status; + +} + +NDIS_STATUS FilterOutOidStatistics( + PNDIS_MINIPORT_BLOCK Miniport, + PNDIS_REQUEST pRequest, + PNDIS_OID pDstOid, + PULONG pcbDestination, + PNDIS_OID pSrcOid, + ULONG cbSource +) +{ + BOOLEAN fARCnet; + ULONG cGlobalOids; + ULONG cInfoOids; + ULONG cbListSizeNeeded; + NDIS_STATUS Status = NDIS_STATUS_SUCCESS; + PNDIS_REQUEST_RESERVED pReserved = + PNDIS_RESERVED_FROM_PNDIS_REQUEST(pRequest); + + //???? + // Currently there are two different mappings: + // ARCnet -> Map Ethernet OIDs to ARCnet & remove + // non-statistics OIDs. + // Other -> Everything else is just the removal of + // statistics OIDs. + // + // Since we need to remove statistics OIDs from both we copy + // the OIDs that we want into the buffer passed to us. + // Then if the request is from an ARCnet NIC we filter into + // our temp buffer and copy it back to the callers buffer.... + // I think that this will be better than an inplace shuffle for + // the ARCnet OIDs. + //???? + + // + // Are we using ARCnet with Ethernet encapsulation> + // + fARCnet = ((Miniport->MediaType == NdisMediumArcnet878_2) && + pReserved->Open->UsingEthEncapsulation) ? TRUE : FALSE; + + // + // Count the number of non-statistics OIDs. + // + for + ( + cGlobalOids = 0, cInfoOids = 0; + cGlobalOids < (cbSource / sizeof(NDIS_OID)); + cGlobalOids++ + ) + { + if ((pSrcOid[cGlobalOids] & 0x00FF0000) != 0x00020000) + cInfoOids++; + } + + // + // Determine the list size that is needed. + // + cbListSizeNeeded = (cInfoOids * sizeof(NDIS_OID)); + if (fARCnet) + cbListSizeNeeded += (ARC_NUMBER_OF_EXTRA_OIDS * sizeof(NDIS_OID)); + + // + // Verify that the buffer passed in on the original request + // is large enough for the OID list. + // + if (cbListSizeNeeded > *pcbDestination) + { + // + // Save the correct buffer size in the + // appropriate spot. + // + *pcbDestination = cInfoOids * sizeof(NDIS_OID); + + return(NDIS_STATUS_BUFFER_TOO_SHORT); + } + + // + // Copy the information OIDs to the buffer that + // was passed with the original request. + // + for + ( + cGlobalOids = 0, cInfoOids = 0; + cGlobalOids < (cbSource / sizeof(NDIS_OID)); + cGlobalOids++ + ) + { + // + // If its not a statistic OID then save it. + // + if ((pSrcOid[cGlobalOids] & 0x00FF0000) != 0x00020000) + { + pDstOid[cInfoOids] = pSrcOid[cGlobalOids]; + cInfoOids++; + } + } + + // + // If ARCnet then do the filtering. + // + if (fARCnet) + { + Status = ArcConvertOidListToEthernet( + pDstOid, + &cInfoOids, + pSrcOid + ); + } + + // + // Save the amount of data that was kept. + // + *pcbDestination = cInfoOids * sizeof(NDIS_OID); + + return(Status); +} + + +VOID +MiniportDoRequests( + PNDIS_MINIPORT_BLOCK Miniport + ) + +/*++ + +Routine Description: + + Submits a request to the mini-port. + +Arguments: + + Miniport - Miniport to send to. + +Return Value: + + None. + +--*/ + +{ + NDIS_STATUS Status; + BOOLEAN DoneSomething = TRUE; + + LOUD_DEBUG(DbgPrint("NdisM: Enter do requests\n");) + + ASSERT(MINIPORT_AT_DPC_LEVEL); + ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport)); + + while (DoneSomething) + { + DoneSomething = FALSE; + Status = NDIS_STATUS_SUCCESS; + + if (Miniport->NeedToUpdateEthAddresses) + { + UINT NumberOfAddresses; + + DoneSomething = TRUE; + // + // This is an internal update that is needed. + // + + Miniport->MiniportRequest = &(Miniport->InternalRequest); + Miniport->NeedToUpdateEthAddresses = FALSE; + + // + // Get information needed + // + + LOUD_DEBUG(DbgPrint("NdisM: Updating eth multicast list\n");) + + EthQueryGlobalFilterAddresses( + &Status, + Miniport->EthDB, + NDIS_M_MAX_MULTI_LIST * ETH_LENGTH_OF_ADDRESS, + &NumberOfAddresses, + (PVOID)Miniport->MulticastBuffer + ); + + // + // Submit Request + // + Miniport->InternalRequest.RequestType = NdisRequestSetInformation; + + Status = + (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)( + Miniport->MiniportAdapterContext, + OID_802_3_MULTICAST_LIST, + Miniport->MulticastBuffer, + NumberOfAddresses * ETH_LENGTH_OF_ADDRESS, + &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesRead, + &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesNeeded + ); + + if ((Status == NDIS_STATUS_PENDING) && (Miniport->MiniportRequest)) { + + // + // Still outstanding + // + + LOUD_DEBUG(DbgPrint("NdisM: Exit do requests\n");) + + Miniport->RunDoRequests = FALSE; + + return; + + } + + if (Status != NDIS_STATUS_PENDING) { + NdisMSetInformationComplete( + (NDIS_HANDLE)Miniport, + Status + ); + } + + } + + if (Miniport->NeedToUpdatePacketFilter) { + + UINT PacketFilter; + + DoneSomething = TRUE; + // + // This is an internal update that is needed. + // + + Miniport->MiniportRequest = &(Miniport->InternalRequest); + Miniport->NeedToUpdatePacketFilter = FALSE; + + // + // Get information needed + // + switch (Miniport->MediaType) { + + case NdisMedium802_3: + + PacketFilter = ETH_QUERY_FILTER_CLASSES(Miniport->EthDB); + break; + + case NdisMedium802_5: + + PacketFilter = TR_QUERY_FILTER_CLASSES(Miniport->TrDB); + break; + + case NdisMediumFddi: + + PacketFilter = FDDI_QUERY_FILTER_CLASSES(Miniport->FddiDB); + break; + + case NdisMediumArcnet878_2: + + PacketFilter = ARC_QUERY_FILTER_CLASSES(Miniport->ArcDB); + PacketFilter |= ETH_QUERY_FILTER_CLASSES(Miniport->EthDB); + + if ( Miniport->ArcnetBroadcastSet || + (PacketFilter & NDIS_PACKET_TYPE_MULTICAST) ) { + + PacketFilter &= ~NDIS_PACKET_TYPE_MULTICAST; + PacketFilter |= NDIS_PACKET_TYPE_BROADCAST; + } + break; + } + + NdisMoveMemory( + Miniport->MulticastBuffer, + &PacketFilter, + sizeof(PacketFilter) + ); + + LOUD_DEBUG(DbgPrint("NdisM: Updating packet filter\n");) + + // + // Submit Request + // + Miniport->InternalRequest.RequestType = NdisRequestSetInformation; + + Status = + (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)( + Miniport->MiniportAdapterContext, + OID_GEN_CURRENT_PACKET_FILTER, + Miniport->MulticastBuffer, + sizeof(PacketFilter), + &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesRead, + &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesNeeded + ); + + if ((Status == NDIS_STATUS_PENDING) && (Miniport->MiniportRequest)) { + + // + // Still outstanding + // + LOUD_DEBUG(DbgPrint("NdisM: Exit do requests\n");) + + Miniport->RunDoRequests = FALSE; + + return; + + } + + if (Status != NDIS_STATUS_PENDING) { + NdisMSetInformationComplete( + (NDIS_HANDLE)Miniport, + Status + ); + } + + } + + if (Miniport->NeedToUpdateFunctionalAddress) { + UINT FunctionalAddress; + + DoneSomething = TRUE; + // + // This is an internal update that is needed. + // + + Miniport->MiniportRequest = &(Miniport->InternalRequest); + Miniport->NeedToUpdateFunctionalAddress = FALSE; + + // + // Get information needed + // + FunctionalAddress = TR_QUERY_FILTER_ADDRESSES(Miniport->TrDB); + FunctionalAddress = BYTE_SWAP_ULONG(FunctionalAddress); + NdisMoveMemory(Miniport->MulticastBuffer, + &FunctionalAddress, + sizeof(FunctionalAddress) + ); + + // + // Submit Request + // + LOUD_DEBUG(DbgPrint("NdisM: Updating functional address\n");) + + Miniport->InternalRequest.RequestType = NdisRequestSetInformation; + + Status = + (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)( + Miniport->MiniportAdapterContext, + OID_802_5_CURRENT_FUNCTIONAL, + Miniport->MulticastBuffer, + sizeof(FunctionalAddress), + &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesRead, + &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesNeeded + ); + + if ((Status == NDIS_STATUS_PENDING) && (Miniport->MiniportRequest)) { + + // + // Still outstanding + // + LOUD_DEBUG(DbgPrint("NdisM: Exit do requests\n");) + + Miniport->RunDoRequests = FALSE; + + return; + + } + + if (Status != NDIS_STATUS_PENDING) { + NdisMSetInformationComplete( + (NDIS_HANDLE)Miniport, + Status + ); + } + + } + + if (Miniport->NeedToUpdateGroupAddress) { + UINT GroupAddress; + + DoneSomething = TRUE; + // + // This is an internal update that is needed. + // + + Miniport->MiniportRequest = &(Miniport->InternalRequest); + Miniport->NeedToUpdateGroupAddress = FALSE; + + // + // Get information needed + // + GroupAddress = TR_QUERY_FILTER_GROUP(Miniport->TrDB); + GroupAddress = BYTE_SWAP_ULONG(GroupAddress); + NdisMoveMemory(Miniport->MulticastBuffer, + &GroupAddress, + sizeof(GroupAddress) + ); + + // + // Submit Request + // + LOUD_DEBUG(DbgPrint("NdisM: Updating group address\n");) + + Miniport->InternalRequest.RequestType = NdisRequestSetInformation; + + Status = + (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)( + Miniport->MiniportAdapterContext, + OID_802_5_CURRENT_GROUP, + Miniport->MulticastBuffer, + sizeof(GroupAddress), + &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesRead, + &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesNeeded + ); + + if ((Status == NDIS_STATUS_PENDING) && (Miniport->MiniportRequest)) { + + // + // Still outstanding + // + LOUD_DEBUG(DbgPrint("NdisM: Exit do requests\n");) + + Miniport->RunDoRequests = FALSE; + + return; + + } + + if (Status != NDIS_STATUS_PENDING) { + NdisMSetInformationComplete( + (NDIS_HANDLE)Miniport, + Status + ); + } + + } + + if (Miniport->NeedToUpdateFddiLongAddresses) { + UINT NumberOfAddresses; + + DoneSomething = TRUE; + // + // This is an internal update that is needed. + // + + Miniport->MiniportRequest = &(Miniport->InternalRequest); + Miniport->NeedToUpdateFddiLongAddresses = FALSE; + + // + // Get information needed + // + + FddiQueryGlobalFilterLongAddresses( + &Status, + Miniport->FddiDB, + NDIS_M_MAX_MULTI_LIST * FDDI_LENGTH_OF_LONG_ADDRESS, + &NumberOfAddresses, + (PVOID)Miniport->MulticastBuffer + ); + + // + // Submit Request + // + LOUD_DEBUG(DbgPrint("NdisM: Updating fddi long addresses\n");) + + Miniport->InternalRequest.RequestType = NdisRequestSetInformation; + + Status = + (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)( + Miniport->MiniportAdapterContext, + OID_FDDI_LONG_MULTICAST_LIST, + Miniport->MulticastBuffer, + NumberOfAddresses * FDDI_LENGTH_OF_LONG_ADDRESS, + &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesRead, + &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesNeeded + ); + + if ((Status == NDIS_STATUS_PENDING) && (Miniport->MiniportRequest)) { + + // + // Still outstanding + // + LOUD_DEBUG(DbgPrint("NdisM: Exit do requests\n");) + + Miniport->RunDoRequests = FALSE; + + return; + + } + + if (Status != NDIS_STATUS_PENDING) { + NdisMSetInformationComplete( + (NDIS_HANDLE)Miniport, + Status + ); + } + + } + + if (Miniport->NeedToUpdateFddiShortAddresses) { + UINT NumberOfAddresses; + + DoneSomething = TRUE; + // + // This is an internal update that is needed. + // + + Miniport->MiniportRequest = &(Miniport->InternalRequest); + Miniport->NeedToUpdateFddiShortAddresses = FALSE; + + // + // Get information needed + // + + FddiQueryGlobalFilterShortAddresses( + &Status, + Miniport->FddiDB, + NDIS_M_MAX_MULTI_LIST * FDDI_LENGTH_OF_SHORT_ADDRESS, + &NumberOfAddresses, + (PVOID)Miniport->MulticastBuffer + ); + + // + // Submit Request + // + LOUD_DEBUG(DbgPrint("NdisM: Updating fddi short addresses\n");) + + Miniport->InternalRequest.RequestType = NdisRequestSetInformation; + + Status = + (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)( + Miniport->MiniportAdapterContext, + OID_FDDI_SHORT_MULTICAST_LIST, + Miniport->MulticastBuffer, + NumberOfAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS, + &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesRead, + &Miniport->InternalRequest.DATA.SET_INFORMATION.BytesNeeded + ); + + if ((Status == NDIS_STATUS_PENDING) && (Miniport->MiniportRequest)) { + + // + // Still outstanding + // + LOUD_DEBUG(DbgPrint("NdisM: Exit do requests\n");) + + Miniport->RunDoRequests = FALSE; + + return; + + } + + if (Status != NDIS_STATUS_PENDING) { + NdisMSetInformationComplete( + (NDIS_HANDLE)Miniport, + Status + ); + } + + } + + if ( Miniport->FirstPendingRequest != NULL ) { + + PNDIS_REQUEST_RESERVED Reserved; + PNDIS_REQUEST NdisRequest; + UINT MulticastAddresses; + ULONG PacketFilter; + BOOLEAN DoMove; + PVOID MoveSource; + UINT MoveBytes; + UINT Lookahead; + ULONG GenericULong; + UCHAR Address[ETH_LENGTH_OF_ADDRESS]; + + // + // Set defaults. + // + DoMove = TRUE; + DoneSomething = TRUE; + Status = NDIS_STATUS_SUCCESS; + + // + // Remove first request + // + NdisRequest = Miniport->FirstPendingRequest; + Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(NdisRequest); + Miniport->FirstPendingRequest = Reserved->Next; + + // + // Reset the pending request timeout. + // + Miniport->PendingRequestTimeout = FALSE; + + LOUD_DEBUG(DbgPrint("NdisM: Starting protocol request 0x%x\n", NdisRequest);) + + // + // Put it on mini-port queue + // + Miniport->MiniportRequest = NdisRequest; + + // + // Submit to mini-port + // + switch (NdisRequest->RequestType) + { + case NdisRequestQueryInformation: + + MoveSource = &GenericULong; + MoveBytes = sizeof(GenericULong); + + // + // We intercept some calls + // + switch (NdisRequest->DATA.QUERY_INFORMATION.Oid) + { + case OID_GEN_SUPPORTED_LIST: + { + PNDIS_OID pOidList; + PNDIS_REQUEST pFakeRequest; + PNDIS_REQUEST_RESERVED pFakeReserved; + PNDIS_M_OPEN_BLOCK Open; + ULONG cbDestination; + BOOLEAN fAllocFailed; + + do + { + // + // Allocate our own request structure. + // We can't use the internal request structure + // since we don't have any way differentiate between + // internal requests that are blocking on an event + // and those that are not. + // + pFakeRequest = ExAllocatePool( + NonPagedPool, + sizeof(NDIS_REQUEST) + ); + if (NULL == pFakeRequest) + { + fAllocFailed = TRUE; + break; + } + + // + // Allocate a buffer to hold all possible OIDs. + // Currently there are about 196 possible OIDs for the + // FDDI case. In order to be sure that i get the whole + // OID list i allocate a buffer that can hold 250. + // + pOidList = ExAllocatePool( + NonPagedPool, + 250 * sizeof(NDIS_OID) + ); + if (NULL == pOidList) + { + fAllocFailed = TRUE; + break; + } + + // + // We succeeded with the allocations. + // + DoMove = FALSE; + fAllocFailed = FALSE; + NdisZeroMemory(pFakeRequest, sizeof(NDIS_REQUEST)); + NdisZeroMemory(pOidList, 250 * sizeof(NDIS_OID)); + + // + // Save our fake request with the miniport. + // + Miniport->MiniportRequest = pFakeRequest; + + // + // Save relevant information in the internal request structure + // in case this pends. + // + pFakeRequest->RequestType = NdisRequestQueryInformation; + pFakeRequest->DATA.QUERY_INFORMATION.Oid = OID_GEN_SUPPORTED_LIST; + pFakeRequest->DATA.QUERY_INFORMATION.InformationBuffer = pOidList; + pFakeRequest->DATA.QUERY_INFORMATION.InformationBufferLength = 250 * sizeof(NDIS_OID); + + // + // Since we are faking the request we need to save the + // pointer to the original request that was passed by + // the caller. + // + pFakeReserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(pFakeRequest); + pFakeReserved->Next = NdisRequest; + + // + // Fire off the request to the miniport. + // We let NdisMQueryInformationComplete() handle + // all situations of the return value. + // + Status = (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler)( + Miniport->MiniportAdapterContext, + OID_GEN_SUPPORTED_LIST, + pOidList, + 250 * sizeof(NDIS_OID), + &pFakeRequest->DATA.QUERY_INFORMATION.BytesWritten, + &pFakeRequest->DATA.QUERY_INFORMATION.BytesNeeded + ); + } while (FALSE); + + // + // Did our allocations fail? + // + if (fAllocFailed) + { + // + // This is the only resource that could have + // been allocated above. + // + if (NULL != pFakeRequest) + ExFreePool(pFakeRequest); + + // + // We have to notify the protocol and return + // from here. NdisMQueryInformationComplete() + // cannot handle the case where memory allocations + // failed. + // + Miniport->Timeout = FALSE; + Miniport->MiniportRequest = NULL; + Open = Reserved->Open; + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + + (Open->ProtocolHandle->ProtocolCharacteristics.RequestCompleteHandler)( + Open->ProtocolBindingContext, + NdisRequest, + NDIS_STATUS_RESOURCES + ); + + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + Open->References--; + + if (Open->References == 0) + { + FinishClose(Miniport, Open); + } + + Miniport->RunDoRequests = FALSE; + + if (Miniport->NeedToUpdateEthAddresses || + Miniport->NeedToUpdatePacketFilter || + Miniport->NeedToUpdateFunctionalAddress || + Miniport->NeedToUpdateGroupAddress || + Miniport->NeedToUpdateFddiLongAddresses || + Miniport->NeedToUpdateFddiShortAddresses || + (Miniport->FirstPendingRequest != NULL) + ) + { + Miniport->RunDoRequests = TRUE; + Miniport->ProcessOddDeferredStuff = TRUE; + } + + return; + } + } + break; + + case OID_GEN_CURRENT_PACKET_FILTER: + + switch (Miniport->MediaType) { + case NdisMedium802_3: + PacketFilter = ETH_QUERY_PACKET_FILTER( + Miniport->EthDB, + Reserved->Open->FilterHandle + ); + break; + case NdisMedium802_5: + PacketFilter = TR_QUERY_PACKET_FILTER( + Miniport->TrDB, + Reserved->Open->FilterHandle + ); + break; + case NdisMediumFddi: + PacketFilter = FDDI_QUERY_PACKET_FILTER( + Miniport->FddiDB, + Reserved->Open->FilterHandle + ); + break; + case NdisMediumArcnet878_2: + + if (Reserved->Open->UsingEthEncapsulation) { + + PacketFilter = ETH_QUERY_PACKET_FILTER( + Miniport->EthDB, + Reserved->Open->FilterHandle + ); + } else { + + PacketFilter = ARC_QUERY_PACKET_FILTER( + Miniport->ArcDB, + Reserved->Open->FilterHandle + ); + } + break; + } + GenericULong = (ULONG)(PacketFilter); + break; + + case OID_GEN_MEDIA_IN_USE: + case OID_GEN_MEDIA_SUPPORTED: + + if (Miniport->MediaType == NdisMediumArcnet878_2) { + + if (Reserved->Open->UsingEthEncapsulation) { + + GenericULong = (ULONG)(NdisMedium802_3); + + } else { + + GenericULong = (ULONG)(NdisMediumArcnet878_2); + + } + + } else { + + GenericULong = (ULONG)(Miniport->MediaType); + + } + MoveBytes = sizeof(NDIS_MEDIUM); + break; + + case OID_GEN_CURRENT_LOOKAHEAD: + GenericULong = (ULONG)(Reserved->Open->CurrentLookahead); + break; + + case OID_GEN_MAXIMUM_LOOKAHEAD: + GenericULong = (ULONG)(Miniport->MaximumLookahead); + break; + + case OID_802_3_MULTICAST_LIST: + + if ( (NdisRequest->DATA.SET_INFORMATION.InformationBufferLength % + ETH_LENGTH_OF_ADDRESS) == 0) { + + EthQueryOpenFilterAddresses( + &Status, + Miniport->EthDB, + Reserved->Open->FilterHandle, + NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength, + &MulticastAddresses, + (PVOID)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer) + ); + + MoveSource = (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer; + MoveBytes = MulticastAddresses * ETH_LENGTH_OF_ADDRESS; + } else { + // + // The data must be a multiple of the Ethernet address size. + // + + Status = NDIS_STATUS_INVALID_DATA; + } + break; + + case OID_802_3_MAXIMUM_LIST_SIZE: + GenericULong = Miniport->MaximumLongAddresses; + break; + + case OID_802_5_CURRENT_FUNCTIONAL: + GenericULong = TR_QUERY_FILTER_BINDING_ADDRESS( + Miniport->TrDB, + Reserved->Open->FilterHandle + ); + GenericULong = BYTE_SWAP_ULONG(GenericULong); + break; + + case OID_802_5_CURRENT_GROUP: + GenericULong = TR_QUERY_FILTER_GROUP( + Miniport->TrDB + ); + GenericULong = BYTE_SWAP_ULONG(GenericULong); + break; + + case OID_FDDI_LONG_MULTICAST_LIST: + FddiQueryOpenFilterLongAddresses( + &Status, + Miniport->FddiDB, + Reserved->Open->FilterHandle, + NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength, + &MulticastAddresses, + (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer + ); + + MoveSource = (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer; + MoveBytes = FDDI_LENGTH_OF_LONG_ADDRESS * + FddiNumberOfOpenFilterLongAddresses( + Miniport->FddiDB, + Reserved->Open->FilterHandle); + break; + + case OID_FDDI_LONG_MAX_LIST_SIZE: + GenericULong = Miniport->MaximumLongAddresses; + break; + + case OID_FDDI_SHORT_MULTICAST_LIST: + FddiQueryOpenFilterShortAddresses( + &Status, + Miniport->FddiDB, + Reserved->Open->FilterHandle, + NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength, + &MulticastAddresses, + (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer + ); + + MoveSource = (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer; + MoveBytes = FDDI_LENGTH_OF_SHORT_ADDRESS * + FddiNumberOfOpenFilterShortAddresses( + Miniport->FddiDB, + Reserved->Open->FilterHandle); + break; + + case OID_FDDI_SHORT_MAX_LIST_SIZE: + GenericULong = Miniport->MaximumShortAddresses; + break; + + // + // + // Start interceptions for running an ethernet + // protocol on top of an arcnet mini-port. + // + // + case OID_GEN_MAXIMUM_FRAME_SIZE: + + if (Miniport->MediaType == NdisMediumArcnet878_2) { + + if (Reserved->Open->UsingEthEncapsulation) { + + // + // 504 - 14 (ethernet header) == 490. + // + + GenericULong = ARC_MAX_FRAME_SIZE - 14; + + break; + } + } + goto SubmitToMiniportDriver; + + case OID_GEN_MAXIMUM_TOTAL_SIZE: + + if (Miniport->MediaType == NdisMediumArcnet878_2) { + + if (Reserved->Open->UsingEthEncapsulation) { + + GenericULong = ARC_MAX_FRAME_SIZE; + + break; + } + } + goto SubmitToMiniportDriver; + + case OID_802_3_PERMANENT_ADDRESS: + case OID_802_3_CURRENT_ADDRESS: + + if ( Miniport->MediaType == NdisMediumArcnet878_2 ) { + + if (Reserved->Open->UsingEthEncapsulation) { + + // + // The following stuff makes the copy code + // below copy the source address into the + // the users request buffer. + // + + MoveSource = Address; + MoveBytes = ETH_LENGTH_OF_ADDRESS; + + // + // Arcnet-to-ethernet conversion. + // + + NdisZeroMemory( + Address, + ETH_LENGTH_OF_ADDRESS + ); + + Address[5] = Miniport->ArcnetAddress; + + break; + } + } + + goto SubmitToMiniportDriver; + + default: + +SubmitToMiniportDriver: + + DoMove = FALSE; + + Status = + (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler)( + Miniport->MiniportAdapterContext, + NdisRequest->DATA.QUERY_INFORMATION.Oid, + NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer, + NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength, + &(NdisRequest->DATA.QUERY_INFORMATION.BytesWritten), + &(NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded) + ); + + break; + + } + + if (DoMove) { + + // + // This was an intercepted request. Finish it off + // + + if (Status == NDIS_STATUS_SUCCESS) { + + if (MoveBytes > + NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength) { + + // + // Not enough room in InformationBuffer. Punt + // + + NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = MoveBytes; + + Status = NDIS_STATUS_INVALID_LENGTH; + + } else { + + // + // Copy result into InformationBuffer + // + + NdisRequest->DATA.QUERY_INFORMATION.BytesWritten = MoveBytes; + + if ((MoveBytes > 0) && + (MoveSource != NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer)) { + + NdisMoveMemory( + NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer, + MoveSource, + MoveBytes + ); + } + } + + } else { + + NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = MoveBytes; + + } + + } + + break; + + case NdisRequestQueryStatistics: + + // + // Query GLOBAL statistics + // + MoveSource = &GenericULong; + MoveBytes = sizeof(GenericULong); + + // + // We intercept some calls + // + + switch (NdisRequest->DATA.QUERY_INFORMATION.Oid) { + + case OID_GEN_CURRENT_PACKET_FILTER: + + switch (Miniport->MediaType) { + case NdisMedium802_3: + PacketFilter = ETH_QUERY_FILTER_CLASSES(Miniport->EthDB); + break; + case NdisMedium802_5: + PacketFilter = TR_QUERY_FILTER_CLASSES(Miniport->TrDB); + break; + case NdisMediumFddi: + PacketFilter = FDDI_QUERY_FILTER_CLASSES(Miniport->FddiDB); + break; + case NdisMediumArcnet878_2: + PacketFilter = ARC_QUERY_FILTER_CLASSES(Miniport->ArcDB); + PacketFilter |= ETH_QUERY_FILTER_CLASSES(Miniport->EthDB); + break; + } + GenericULong = (ULONG)(PacketFilter); + break; + + case OID_GEN_MEDIA_IN_USE: + case OID_GEN_MEDIA_SUPPORTED: + MoveSource = (PVOID) (&(Miniport->MediaType)); + MoveBytes = sizeof(NDIS_MEDIUM); + break; + + case OID_GEN_CURRENT_LOOKAHEAD: + GenericULong = (ULONG)(Miniport->CurrentLookahead); + break; + + case OID_GEN_MAXIMUM_LOOKAHEAD: + GenericULong = (ULONG)(Miniport->MaximumLookahead); + break; + + case OID_802_3_MULTICAST_LIST: + + EthQueryGlobalFilterAddresses( + &Status, + Miniport->EthDB, + NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength, + &MulticastAddresses, + (PVOID)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer) + ); + + MoveSource = (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer; + MoveBytes = MulticastAddresses * ETH_LENGTH_OF_ADDRESS; + break; + + case OID_802_3_MAXIMUM_LIST_SIZE: + GenericULong = Miniport->MaximumLongAddresses; + break; + + case OID_802_5_CURRENT_FUNCTIONAL: + GenericULong = TR_QUERY_FILTER_ADDRESSES( + Miniport->TrDB + ); + GenericULong = BYTE_SWAP_ULONG(GenericULong); + break; + + case OID_802_5_CURRENT_GROUP: + GenericULong = TR_QUERY_FILTER_GROUP( + Miniport->TrDB + ); + GenericULong = BYTE_SWAP_ULONG(GenericULong); + break; + + case OID_FDDI_LONG_MULTICAST_LIST: + FddiQueryGlobalFilterLongAddresses( + &Status, + Miniport->FddiDB, + NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength, + &MulticastAddresses, + (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer); + + MoveSource = (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer; + MoveBytes = FDDI_LENGTH_OF_LONG_ADDRESS * MulticastAddresses; + break; + + case OID_FDDI_LONG_MAX_LIST_SIZE: + GenericULong = Miniport->MaximumLongAddresses; + break; + + case OID_FDDI_SHORT_MULTICAST_LIST: + FddiQueryGlobalFilterShortAddresses( + &Status, + Miniport->FddiDB, + NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength, + &MulticastAddresses, + (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer); + + MoveSource = (PVOID)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer; + MoveBytes = FDDI_LENGTH_OF_SHORT_ADDRESS * MulticastAddresses; + break; + + case OID_FDDI_SHORT_MAX_LIST_SIZE: + GenericULong = Miniport->MaximumShortAddresses; + break; + + default: + + DoMove = FALSE; + + Status = + (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler)( + Miniport->MiniportAdapterContext, + NdisRequest->DATA.QUERY_INFORMATION.Oid, + NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer, + NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength, + &(NdisRequest->DATA.QUERY_INFORMATION.BytesWritten), + &(NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded) + ); + + break; + + } + + if (DoMove) { + + // + // This was an intercepted request. Finish it off + // + + if (Status == NDIS_STATUS_SUCCESS) { + + if (MoveBytes > + NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength) { + + // + // Not enough room in InformationBuffer. Punt + // + + NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = MoveBytes; + + Status = NDIS_STATUS_INVALID_LENGTH; + + } else { + + // + // Copy result into InformationBuffer + // + + NdisRequest->DATA.QUERY_INFORMATION.BytesWritten = MoveBytes; + + if ((MoveBytes > 0) && + (MoveSource != NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer)) { + NdisMoveMemory( + NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer, + MoveSource, + MoveBytes + ); + } + + } + + } else { + + NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = MoveBytes; + + } + + } + break; + + + + + case NdisRequestSetInformation: + + // + // We intercept some calls + // + + switch (NdisRequest->DATA.SET_INFORMATION.Oid) { + + case OID_GEN_CURRENT_PACKET_FILTER: + if (NdisRequest->DATA.SET_INFORMATION.InformationBufferLength + != 4) { + Status = NDIS_STATUS_INVALID_LENGTH; + NdisRequest->DATA.SET_INFORMATION.BytesRead = 0; + NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0; + break; + } + + // + // Now call the filter package to set the packet filter. + // + NdisMoveMemory ((PVOID)&PacketFilter, + NdisRequest->DATA.SET_INFORMATION.InformationBuffer, + sizeof(ULONG) + ); + + if (PacketFilter & ~(Miniport->SupportedPacketFilters)) { + Status = NDIS_STATUS_NOT_SUPPORTED; + NdisRequest->DATA.SET_INFORMATION.BytesRead = 4; + NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0; + break; + } + + switch (Miniport->MediaType) { + case NdisMedium802_3: + Status = EthFilterAdjust( + Miniport->EthDB, + Reserved->Open->FilterHandle, + (PNDIS_REQUEST)NdisRequest, + PacketFilter, + TRUE + ); + + NdisRequest->DATA.SET_INFORMATION.BytesRead = 4; + break; + + case NdisMedium802_5: + Status = TrFilterAdjust( + Miniport->TrDB, + Reserved->Open->FilterHandle, + (PNDIS_REQUEST)NdisRequest, + PacketFilter, + TRUE + ); + + NdisRequest->DATA.SET_INFORMATION.BytesRead = 4; + break; + + case NdisMediumFddi: + Status = FddiFilterAdjust( + Miniport->FddiDB, + Reserved->Open->FilterHandle, + (PNDIS_REQUEST)NdisRequest, + PacketFilter, + TRUE + ); + + NdisRequest->DATA.SET_INFORMATION.BytesRead = 4; + break; + + case NdisMediumArcnet878_2: + + if (Reserved->Open->UsingEthEncapsulation) { + + Status = EthFilterAdjust( + Miniport->EthDB, + Reserved->Open->FilterHandle, + (PNDIS_REQUEST)NdisRequest, + PacketFilter, + TRUE + ); + + } else { + + Status = ArcFilterAdjust( + Miniport->ArcDB, + Reserved->Open->FilterHandle, + (PNDIS_REQUEST)NdisRequest, + PacketFilter, + TRUE + ); + } + + NdisRequest->DATA.SET_INFORMATION.BytesRead = 4; + break; + } + break; + + case OID_GEN_CURRENT_LOOKAHEAD: + // + // Verify length + // + if (NdisRequest->DATA.SET_INFORMATION.InformationBufferLength + != 4) { + Status = NDIS_STATUS_INVALID_LENGTH; + NdisRequest->DATA.SET_INFORMATION.BytesRead = 0; + NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0; + break; + } + + NdisMoveMemory(&Lookahead, + NdisRequest->DATA.SET_INFORMATION.InformationBuffer, + 4 + ); + + if (Lookahead > Miniport->MaximumLookahead) { + + Status = NDIS_STATUS_INVALID_LENGTH; + NdisRequest->DATA.SET_INFORMATION.BytesRead = 0; + NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0; + break; + + } + + Reserved->Open->CurrentLookahead = Lookahead; + Status = MiniportAdjustMaximumLookahead(Miniport); + + // + // Since this routine may submit another request, update our + // pointer to the currently executing request. + // + NdisRequest = Miniport->MiniportRequest; + + break; + + case OID_GEN_PROTOCOL_OPTIONS: + + if (NdisRequest->DATA.SET_INFORMATION.InformationBufferLength + != 4) { + Status = NDIS_STATUS_INVALID_LENGTH; + NdisRequest->DATA.SET_INFORMATION.BytesRead = 0; + NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0; + break; + } + + NdisMoveMemory(&(Reserved->Open->ProtocolOptions), + NdisRequest->DATA.SET_INFORMATION.InformationBuffer, + 4 + ); + + break; + + case OID_802_3_MULTICAST_LIST: + + if ( (NdisRequest->DATA.SET_INFORMATION.InformationBufferLength + % ETH_LENGTH_OF_ADDRESS) != 0) { + + // + // The data must be a multiple of the Ethernet + // address size. + // + + Status = NDIS_STATUS_INVALID_DATA; + break; + + } + + if ((Miniport->MediaType != NdisMedium802_3) && + !((Miniport->MediaType == NdisMediumArcnet878_2) && + (Reserved->Open->UsingEthEncapsulation))) { + Status = NDIS_STATUS_NOT_SUPPORTED; + break; + } + + // + // Now call the filter package to set up the addresses. + // + + Status = EthChangeFilterAddresses( + Miniport->EthDB, + Reserved->Open->FilterHandle, + (PNDIS_REQUEST)NdisRequest, + NdisRequest->DATA.SET_INFORMATION.InformationBufferLength + / ETH_LENGTH_OF_ADDRESS, + NdisRequest->DATA.SET_INFORMATION.InformationBuffer, + TRUE + ); + + NdisRequest->DATA.SET_INFORMATION.BytesRead = + NdisRequest->DATA.SET_INFORMATION.InformationBufferLength; + break; + + case OID_802_5_CURRENT_FUNCTIONAL: + if (Miniport->MediaType != NdisMedium802_5) { + Status = NDIS_STATUS_NOT_SUPPORTED; + break; + } + + if (NdisRequest->DATA.SET_INFORMATION.InformationBufferLength + != 4) { + Status = NDIS_STATUS_INVALID_LENGTH; + NdisRequest->DATA.SET_INFORMATION.BytesRead = 0; + NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0; + break; + } + + Status = TrChangeFunctionalAddress( + Reserved->Open->MiniportHandle->TrDB, + Reserved->Open->FilterHandle, + NdisRequest, + (PUCHAR)(NdisRequest->DATA.SET_INFORMATION.InformationBuffer), + TRUE + ); + break; + + case OID_802_5_CURRENT_GROUP: + if (Miniport->MediaType != NdisMedium802_5) { + Status = NDIS_STATUS_NOT_SUPPORTED; + break; + } + + if (NdisRequest->DATA.SET_INFORMATION.InformationBufferLength + != 4) { + Status = NDIS_STATUS_INVALID_LENGTH; + NdisRequest->DATA.SET_INFORMATION.BytesRead = 0; + NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0; + break; + } + + Status = TrChangeGroupAddress( + Reserved->Open->MiniportHandle->TrDB, + Reserved->Open->FilterHandle, + NdisRequest, + (PUCHAR)(NdisRequest->DATA.SET_INFORMATION.InformationBuffer), + TRUE + ); + break; + + case OID_FDDI_LONG_MULTICAST_LIST: + if (Miniport->MediaType != NdisMediumFddi) { + Status = NDIS_STATUS_NOT_SUPPORTED; + break; + } + + if (NdisRequest->DATA.SET_INFORMATION.InformationBufferLength + % FDDI_LENGTH_OF_LONG_ADDRESS != 0) { + + // + // The data must be a multiple of the Ethernet + // address size. + // + + Status = NDIS_STATUS_INVALID_DATA; + break; + + } + + // + // Now call the filter package to set up the addresses. + // + Status = FddiChangeFilterLongAddresses( + Miniport->FddiDB, + Reserved->Open->FilterHandle, + (PNDIS_REQUEST)NdisRequest, + NdisRequest->DATA.SET_INFORMATION.InformationBufferLength + / FDDI_LENGTH_OF_LONG_ADDRESS, + NdisRequest->DATA.SET_INFORMATION.InformationBuffer, + TRUE + ); + NdisRequest->DATA.SET_INFORMATION.BytesRead = + NdisRequest->DATA.SET_INFORMATION.InformationBufferLength; + break; + + case OID_FDDI_SHORT_MULTICAST_LIST: + if (Miniport->MediaType != NdisMediumFddi) { + Status = NDIS_STATUS_NOT_SUPPORTED; + break; + } + + if (NdisRequest->DATA.SET_INFORMATION.InformationBufferLength + % FDDI_LENGTH_OF_SHORT_ADDRESS != 0) { + + // + // The data must be a multiple of the Ethernet + // address size. + // + + Status = NDIS_STATUS_INVALID_DATA; + break; + + } + + // + // Now call the filter package to set up the addresses. + // + Status = FddiChangeFilterShortAddresses( + Miniport->FddiDB, + Reserved->Open->FilterHandle, + (PNDIS_REQUEST)NdisRequest, + NdisRequest->DATA.SET_INFORMATION.InformationBufferLength + / FDDI_LENGTH_OF_SHORT_ADDRESS, + NdisRequest->DATA.SET_INFORMATION.InformationBuffer, + TRUE + ); + NdisRequest->DATA.SET_INFORMATION.BytesRead = + NdisRequest->DATA.SET_INFORMATION.InformationBufferLength; + break; + + default: + + Status = + (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler)( + Miniport->MiniportAdapterContext, + NdisRequest->DATA.SET_INFORMATION.Oid, + NdisRequest->DATA.SET_INFORMATION.InformationBuffer, + NdisRequest->DATA.SET_INFORMATION.InformationBufferLength, + &(NdisRequest->DATA.SET_INFORMATION.BytesRead), + &(NdisRequest->DATA.SET_INFORMATION.BytesNeeded) + ); + + break; + + } + break; + + } + + if ((Status == NDIS_STATUS_PENDING) && (Miniport->MiniportRequest)) { + + // + // Still outstanding + // + LOUD_DEBUG(DbgPrint("NdisM: Exit do requests\n");) + + Miniport->RunDoRequests = FALSE; + + return; + + } + + // + // Complete request + // + + if (Status != NDIS_STATUS_PENDING) { + + switch (NdisRequest->RequestType) { + + case NdisRequestQueryStatistics: + case NdisRequestQueryInformation: + + NdisMQueryInformationComplete( + (NDIS_HANDLE)Miniport, + Status + ); + break; + + case NdisRequestSetInformation: + + NdisMSetInformationComplete( + (NDIS_HANDLE)Miniport, + Status + ); + break; + } + } + } + } + + if ((Miniport->NeedToUpdateEthAddresses || + Miniport->NeedToUpdatePacketFilter || + Miniport->NeedToUpdateFunctionalAddress || + Miniport->NeedToUpdateGroupAddress || + Miniport->NeedToUpdateFddiLongAddresses || + Miniport->NeedToUpdateFddiShortAddresses || + (Miniport->FirstPendingRequest != NULL)) + && + (Miniport->MiniportRequest == NULL)) + { + Miniport->RunDoRequests = TRUE; + Miniport->ProcessOddDeferredStuff = TRUE; + } + else + { + Miniport->RunDoRequests = FALSE; + } + + LOUD_DEBUG(DbgPrint("NdisM: Exit do requests\n");) + return; + +} + + + +BOOLEAN +FASTCALL +MiniportSendLoopback( + PNDIS_MINIPORT_BLOCK Miniport, + PNDIS_PACKET Packet + ) + +/*++ + +Routine Description: + + Checks if a packet needs to be loopbacked and does so if necessary. + + NOTE: Must be called at DPC_LEVEL with lock HELD! + +Arguments: + + Miniport - Miniport to send to. + + Packet - Packet to loopback. + +Return Value: + + FALSE if the packet should be sent on the net, TRUE if it is + a self-directed packet. + +--*/ + +{ + + BOOLEAN Loopback; + BOOLEAN SelfDirected; + INT FddiAddressCheck; + PNDIS_BUFFER FirstBuffer; + UINT BufferLength; + PUCHAR BufferAddress; + UINT Length; + UINT AddressLength; + + // We should not be here if the driver handles loopback + ASSERT(Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK); + ASSERT(MINIPORT_AT_DPC_LEVEL); + + FirstBuffer = Packet->Private.Head; + BufferAddress = MmGetSystemAddressForMdl(FirstBuffer); + + switch (Miniport->MediaType) { + + case NdisMedium802_3: + + // + // If the card does not do loopback, then we check if + // we need to send it to ourselves, then if that is the + // case we also check for it being self-directed. + // + + EthShouldAddressLoopBackMacro(Miniport->EthDB, BufferAddress, &Loopback, &SelfDirected); + + if (!Loopback) { + ASSERT(!SelfDirected); + return FALSE; + } + break; + + case NdisMedium802_5: + + Loopback = TrShouldAddressLoopBack( + Miniport->TrDB, + BufferAddress + 2, // Skip FC & AC bytes. + BufferAddress + 8 // Destination address. + ); + + if (!Loopback) { + return FALSE; + } + + // + // See if it is self-directed. + // + + if ((*(ULONG UNALIGNED *)&BufferAddress[4] == + *(ULONG UNALIGNED *)&Miniport->TrDB->AdapterAddress[2]) && + (*(USHORT UNALIGNED *)&BufferAddress[2] == + *(USHORT UNALIGNED *)&Miniport->TrDB->AdapterAddress[0])) { + + SelfDirected = TRUE; + Loopback = TRUE; + + } else { + + SelfDirected = FALSE; + } + + break; + + case NdisMediumFddi: + + AddressLength = (BufferAddress[0] & 0x40)? FDDI_LENGTH_OF_LONG_ADDRESS: + FDDI_LENGTH_OF_SHORT_ADDRESS; + + FddiShouldAddressLoopBackMacro(Miniport->FddiDB, + BufferAddress + 1, // Skip FC byte to dest address. + AddressLength, + &Loopback, + &SelfDirected); + + if (!Loopback) { + return FALSE; + } + break; + + case NdisMediumArcnet878_2: + + if ( ARC_PACKET_IS_ENCAPSULATED(Packet) ) { + + // + // The second buffer in the packet is the ethernet + // header so we need to get that one before we can + // proceed. + // + + NdisGetNextBuffer(FirstBuffer, &FirstBuffer); + + BufferAddress = MmGetSystemAddressForMdl(FirstBuffer); + + // Length -= 3; Length is not valid at this point. Do this later when + // we determine that we need to loopback for certain + + // + // Now we can continue as though this were ethernet. + // + + EthShouldAddressLoopBackMacro( + Miniport->EthDB, + BufferAddress, + &Loopback, + &SelfDirected); + + if (!Loopback) { + return FALSE; + } + } else { + + Loopback = ((BufferAddress[0] == BufferAddress[1]) || + ((BufferAddress[1] == 0x00) && + (ARC_QUERY_FILTER_CLASSES(Miniport->ArcDB) | + NDIS_PACKET_TYPE_BROADCAST))); + + if (BufferAddress[0] == BufferAddress[1]) { + SelfDirected = TRUE; + Loopback = TRUE; + } else { + SelfDirected = FALSE; + } + } + + break; + } + + if (Loopback) { + + // + // Get the buffer length + // + + NdisQueryPacket( + Packet, + NULL, + NULL, + NULL, + &Length + ); + + if ((Miniport->MediaType == NdisMediumArcnet878_2) && + ARC_PACKET_IS_ENCAPSULATED(Packet)) + { + Length -= 3; + } + + // + // See if we need to copy the data from the packet + // into the loopback buffer. + // + // We need to copy to the local loopback buffer if + // the first buffer of the packet is less than the + // minimum loopback size AND the first buffer isn't + // the total packet. + // + + BufferLength = MmGetMdlByteCount(FirstBuffer); + + if ((BufferLength < NDIS_M_MAX_LOOKAHEAD) && (BufferLength != Length)) { + + UINT BytesToCopy; + UINT Offset = 0; + + switch( Miniport->MediaType ) { + + case NdisMedium802_3: + case NdisMedium802_5: + + BytesToCopy = 14; + break; + + case NdisMediumFddi: + + BytesToCopy = 1 + (2 * AddressLength); + break; + + case NdisMediumArcnet878_2: + + if ( ARC_PACKET_IS_ENCAPSULATED(Packet) ) { + + BytesToCopy = 14; // Copy encapsulated ethernet header. + Offset = 3; // Skip fake arcnet header. + + } else { + + BytesToCopy = 3; // Copy arcnet header. + } + break; + } + + BytesToCopy += Miniport->CurrentLookahead; + + BufferAddress = Miniport->LookaheadBuffer; + + MiniportCopyFromPacketToBuffer( + Packet, // Packet to copy from. + Offset, // Offset from beginning of packet. + BytesToCopy, // Number of bytes to copy. + BufferAddress, // The destination buffer. + &BufferLength // The number of bytes copied. + ); + } + + Miniport->LoopbackPacket = Packet; + + NDIS_LOG_PACKET(Miniport, Packet, 'L'); + + if (BufferLength >= 14) { + + // + // Not a runt packet + // + // + // Indicate the packet to every open binding + // that could want it. + // + + switch (Miniport->MediaType) { + + case NdisMedium802_3: + + // + // NOTE: Code re-use for 878.2 (arcnet) encapsulated + // ethernet packets. + // + +EthIndicateLoopbackFullPacket: + + Miniport->LoopbackPacketHeaderSize = 14; + + EthFilterDprIndicateReceive( + Miniport->EthDB, + Packet, + ((PCHAR)BufferAddress), + BufferAddress, + 14, + ((PUCHAR)BufferAddress) + 14, + BufferLength - 14, + Length - 14 + ); + + EthFilterDprIndicateReceiveComplete( + Miniport->EthDB + ); + + break; + + case NdisMedium802_5: + + Miniport->LoopbackPacketHeaderSize = 14; + + TrFilterDprIndicateReceive( + Miniport->TrDB, + Packet, + BufferAddress, + 14, + ((PUCHAR)BufferAddress) + 14, + BufferLength - 14, + Length - 14 + ); + + TrFilterDprIndicateReceiveComplete( + Miniport->TrDB + ); + + break; + + case NdisMediumFddi: + + Miniport->LoopbackPacketHeaderSize = 1+(2*AddressLength); + + FddiFilterDprIndicateReceive( + Miniport->FddiDB, + Packet, + ((PCHAR)BufferAddress) + 1, + AddressLength, + BufferAddress, + Miniport->LoopbackPacketHeaderSize, + ((PUCHAR)BufferAddress) + Miniport->LoopbackPacketHeaderSize, + BufferLength - Miniport->LoopbackPacketHeaderSize, + Length - Miniport->LoopbackPacketHeaderSize + ); + + FddiFilterDprIndicateReceiveComplete( + Miniport->FddiDB + ); + + break; + + case NdisMediumArcnet878_2: + + if ( ARC_PACKET_IS_ENCAPSULATED(Packet) ) { + + goto EthIndicateLoopbackFullPacket; + + } else { + + PUCHAR PlaceInBuffer; + PUCHAR ArcDataBuffer; + UINT ArcDataLength; + UINT PacketDataOffset; + UCHAR FrameCount; + UCHAR i; + UINT IndicateDataLength; + // + // Calculate how many frames we will need. + // + + ArcDataLength = Length - 3; + PacketDataOffset = 3; + + FrameCount = (UCHAR) (ArcDataLength / ARC_MAX_FRAME_SIZE); + + if ( (ArcDataLength % ARC_MAX_FRAME_SIZE) != 0) { + + FrameCount++; + } + + for (i = 0; i < FrameCount; ++i) { + + PlaceInBuffer = Miniport->LookaheadBuffer; + + // + // Point data buffer to start of 'data' + // + + ArcDataBuffer = Miniport->LookaheadBuffer + 2; + + // + // Copy Header (SrcId/DestId/ProtId) + // + + MiniportCopyFromPacketToBuffer( + Packet, + 0, + 3, + PlaceInBuffer, + &BufferLength + ); + + PlaceInBuffer += 3; + + // + // Put in split flag + // + + if ( FrameCount > 1 ) { + + // + // Multi-frame indication... + // + + if ( i == 0 ) { + + // + // first frame + // + + // *PlaceInBuffer = ( (FrameCount - 2) * 2 ) + 1; + + *PlaceInBuffer = 2 * FrameCount - 3; + } else { + + // + // Subsequent frame + // + *PlaceInBuffer = ( i * 2 ); + } + + } else { + + // + // Only frame in the indication + // + + *PlaceInBuffer = 0; + } + + // + // Skip split flag + // + + PlaceInBuffer++; + + // + // Put in packet number. + // + + *PlaceInBuffer++ = 0; + *PlaceInBuffer++ = 0; + + // + // Copy data + // + + if ( ArcDataLength > ARC_MAX_FRAME_SIZE ) { + + IndicateDataLength = ARC_MAX_FRAME_SIZE; + } else { + + IndicateDataLength = ArcDataLength; + } + + MiniportCopyFromPacketToBuffer( + Packet, + PacketDataOffset, + IndicateDataLength, + PlaceInBuffer, + &BufferLength + ); + + ArcFilterDprIndicateReceive( + Miniport->ArcDB, + Miniport->LookaheadBuffer, + ArcDataBuffer, + IndicateDataLength + 4 + ); + + ArcDataLength -= ARC_MAX_FRAME_SIZE; + PacketDataOffset += ARC_MAX_FRAME_SIZE; + } + } + + ArcFilterDprIndicateReceiveComplete( + Miniport->ArcDB + ); + + break; + + } + + } else { + + // + // A runt packet + // + // + // Indicate the packet to every open binding + // that could want it. + // + + Miniport->LoopbackPacketHeaderSize = BufferLength; + + switch (Miniport->MediaType) { + case NdisMedium802_3: + + // + // NOTE: Code re-use for 878.2 (arcnet) encapsulated + // ethernet packets. + // + +EthIndicateLoopbackRuntPacket: + + EthFilterDprIndicateReceive( + Miniport->EthDB, + Packet, + ((PCHAR)BufferAddress), + BufferAddress, + BufferLength, + NULL, + 0, + 0 + ); + + EthFilterDprIndicateReceiveComplete( + Miniport->EthDB + ); + + break; + + case NdisMedium802_5: + + TrFilterDprIndicateReceive( + Miniport->TrDB, + Packet, + BufferAddress, + BufferLength, + NULL, + 0, + 0 + ); + + TrFilterDprIndicateReceiveComplete( + Miniport->TrDB + ); + + break; + + case NdisMediumFddi: + + FddiFilterDprIndicateReceive( + Miniport->FddiDB, + Packet, + ((PCHAR)BufferAddress) + 1, + 0, + BufferAddress, + BufferLength, + NULL, + 0, + 0 + ); + + FddiFilterDprIndicateReceiveComplete( + Miniport->FddiDB + ); + + break; + + case NdisMediumArcnet878_2: + + + if ( ARC_PACKET_IS_ENCAPSULATED(Packet) ) { + + goto EthIndicateLoopbackRuntPacket; + + } else { + + ArcFilterDprIndicateReceive( + Miniport->ArcDB, + BufferAddress, + ((PCHAR)BufferAddress) + Miniport->LoopbackPacketHeaderSize, + Length - Miniport->LoopbackPacketHeaderSize + ); + + ArcFilterDprIndicateReceiveComplete( + Miniport->ArcDB + ); + } + + break; + + } + + } + + Miniport->LoopbackPacket = NULL; + + } + + return SelfDirected; + +} + +VOID +MiniportFreeArcnetHeader( + IN PNDIS_MINIPORT_BLOCK Miniport, + IN PNDIS_PACKET Packet + ) +/*++ + +Routine Description: + + This function strips off the arcnet header appended to + ethernet encapsulated packets + +Arguments: + + MiniportAdapterHandle - points to the adapter block. + + Packet - Ndis packet. + +Return Value: + + None. + +--*/ +{ + PNDIS_M_OPEN_BLOCK Open; + PARC_BUFFER_LIST Buffer, TmpBuffer; + PNDIS_BUFFER NdisBuffer; + PVOID BufferVa; + UINT Length; + + Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Open; + + if ( Open->UsingEthEncapsulation ) { + + NdisUnchainBufferAtFront( + Packet, + &NdisBuffer + ); + + NdisQueryBuffer(NdisBuffer, + (PVOID *) &BufferVa, + &Length + ); + + NdisFreeBuffer(NdisBuffer); + + Buffer = Miniport->ArcnetUsedBufferList; + + if (Buffer->Buffer == BufferVa) { + + Miniport->ArcnetUsedBufferList = Buffer->Next; + + } else { + + while (Buffer->Next->Buffer != BufferVa) { + + Buffer = Buffer->Next; + } + + TmpBuffer = Buffer->Next; + Buffer->Next = Buffer->Next->Next; + Buffer = TmpBuffer; + + } + + Buffer->Next = Miniport->ArcnetFreeBufferList; + Miniport->ArcnetFreeBufferList = Buffer; + } +} + + +VOID +FASTCALL +MiniportStartSends( + PNDIS_MINIPORT_BLOCK Miniport + ) + +/*++ + +Routine Description: + + Submits as many sends as possible to the mini-port. + +Arguments: + + Miniport - Miniport to send to. + +Return Value: + + None. + +--*/ + +{ + PARC_BUFFER_LIST Buffer; + PNDIS_BUFFER NdisBuffer; + PNDIS_BUFFER TmpBuffer; + PNDIS_PACKET Packet; + PNDIS_PACKET PrevPacket; + NDIS_STATUS Status; + PNDIS_PACKET_RESERVED Reserved; + PNDIS_M_OPEN_BLOCK Open; + UINT Flags; + PUCHAR Address; + + ASSERT(MINIPORT_AT_DPC_LEVEL); + ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport)); + + LOUD_DEBUG(DbgPrint("NdisM: Enter sends\n");) + + LOG('s'); + + Miniport->SendCompleteCalled = FALSE; + + do { + Packet = Miniport->FirstPendingPacket; + Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet); + Open = Reserved->Open; + + NDIS_LOG_PACKET(Miniport, Packet, 's'); + + if (Miniport->MediaType == NdisMediumArcnet878_2) { + + goto BuildArcnetHeader; + + } + +DoneBuildingArcnetHeader: + + // + // Remove from Queue + // + Miniport->FirstPendingPacket = Reserved->Next; + + // + // Put on finish queue + // + + PrevPacket = Miniport->LastMiniportPacket; + Miniport->LastMiniportPacket = Packet; + + // + // Indicate the packet loopback if necessary. + // + + if ((Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) && + (!Miniport->AlreadyLoopedBack) && + MiniportSendLoopback(Miniport, Packet) + ) + { + + LOUD_DEBUG(DbgPrint("NdisM: Not sending packet 0x%x\n", Packet);) + + LOG('l'); + NDIS_LOG_PACKET(Miniport, Packet, 'l'); + + Status = NDIS_STATUS_SUCCESS; + goto NoCardSend; + } + + // + // Submit to card + // + + LOUD_DEBUG(DbgPrint("NdisM: Sending packet 0x%x\n", Packet);) + + REMOVE_RESOURCE(Miniport, 'S'); + + NdisQuerySendFlags(Packet, &Flags); + + LOG('M'); + + NDIS_LOG_PACKET(Miniport, Packet, 'M'); + + Status = (Open->SendHandler)( + Open->MiniportAdapterContext, + Packet, + Flags + ); + if (Status == NDIS_STATUS_PENDING) + { + LOG('p'); + NDIS_LOG_PACKET(Miniport, Packet, 'p'); + + LOUD_DEBUG(DbgPrint("NdisM: Complete is pending\n");) + + // + // We need to clear the loop back flag here also. + // + Miniport->AlreadyLoopedBack = FALSE; + + continue; + + } + +NoCardSend: + + if (Miniport->MediaType == NdisMediumArcnet878_2) { + + MiniportFreeArcnetHeader(Miniport, Packet); + } + + if (Status != NDIS_STATUS_RESOURCES) + { + if (Status != NDIS_STATUS_SUCCESS) + { + ADD_RESOURCE(Miniport, 'F'); + + LOG('F'); + NDIS_LOG_PACKET(Miniport, Packet, 'F'); + } + + // + // Remove from finish queue + // + + LOUD_DEBUG(DbgPrint("NdisM: Completed 0x%x\n", Status);) + + // + // If send complete was called from the miniport's send handler + // then our local PrevPacket pointer may no longer be valid. + // + + if ( Miniport->SendCompleteCalled ) + { + Miniport->SendCompleteCalled = FALSE; + MiniportFindPacket(Miniport, Packet, &PrevPacket); + } + + Miniport->LastMiniportPacket = PrevPacket; + + if ( PrevPacket == NULL ) { + + Miniport->FirstPacket = Reserved->Next; + Miniport->DeadPacket = NULL; + + } else { + + PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = Reserved->Next; + + // + // If we just unlinked the last packet then we need to update + // our last packet pointer. + // + + if ( Packet == Miniport->LastPacket ) { + + Miniport->LastPacket = PrevPacket; + } + } + + // + // Reset for the next packet in the pending queue. + // + Miniport->AlreadyLoopedBack = FALSE; + + // + // Indicate the completion to the protocol. + // + NDIS_LOG_PACKET(Miniport, Packet, 'C'); + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + + (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler) ( + Open->ProtocolBindingContext, + Packet, + Status + ); + + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + Open->References--; + + if (Open->References == 0) { + + FinishClose(Miniport, Open); + } + + } else { + + LOUD_DEBUG(DbgPrint("NdisM: Deferring send\n");) + + // + // If send complete was called from the miniport's send handler + // then our local PrevPacket pointer may no longer be valid. + // + + if ( Miniport->SendCompleteCalled ) { + + Miniport->SendCompleteCalled = FALSE; + MiniportFindPacket(Miniport, Packet, &PrevPacket); + } + + // + // Remove from finish queue + // + Miniport->LastMiniportPacket = PrevPacket; + + // + // Put on pending queue + // + Miniport->FirstPendingPacket = Packet; + + // + // Mark the packet at the head of the pending queue as having + // been looped back. + // + Miniport->AlreadyLoopedBack = TRUE; + + LOG('o'); + NDIS_LOG_PACKET(Miniport, Packet, 'o'); + + // + // Set flag + // + CLEAR_RESOURCE(Miniport, 'S'); + } + + } while ((Miniport->SendResourcesAvailable != 0) && (Miniport->FirstPendingPacket)); + + LOG('S'); + + LOUD_DEBUG(DbgPrint("NdisM: Exit sends\n");) + + return; + +BuildArcnetHeader: + + if (Open->UsingEthEncapsulation) { + + if (Miniport->ArcnetFreeBufferList == NULL) { + + // + // Set flag + // + CLEAR_RESOURCE(Miniport, 'S'); + return; + + } + + NdisQueryPacket(Packet, + NULL, + NULL, + &TmpBuffer, + NULL + ); + + NdisQueryBuffer(TmpBuffer, &Address, &Flags); + + Buffer = Miniport->ArcnetFreeBufferList; + Miniport->ArcnetFreeBufferList = Buffer->Next; + + NdisAllocateBuffer( + &Status, + &NdisBuffer, + Miniport->ArcnetBufferPool, + Buffer->Buffer, + 3 + ); + + if (Status != NDIS_STATUS_SUCCESS) { + + Buffer->Next = Miniport->ArcnetFreeBufferList; + Miniport->ArcnetFreeBufferList = Buffer; + CLEAR_RESOURCE(Miniport, 'S'); + return; + + } + + Buffer->Next = Miniport->ArcnetUsedBufferList; + Miniport->ArcnetUsedBufferList = Buffer; + + NdisChainBufferAtFront(Packet, NdisBuffer); + + ((PUCHAR)Buffer->Buffer)[0] = Miniport->ArcnetAddress; + + if (Address[0] & 0x01) { + + // + // Broadcast + // + ((PUCHAR)Buffer->Buffer)[1] = 0x00; + + } else { + + ((PUCHAR)Buffer->Buffer)[1] = Address[5]; + + } + + ((PUCHAR) Buffer->Buffer)[2] = 0xE8; + + } + + goto DoneBuildingArcnetHeader; +} + + + +VOID +AbortMiniportPacketsAndPending( + PNDIS_MINIPORT_BLOCK Miniport + ) + +/*++ + +Routine Description: + + Aborts all outstanding requests on a mini-port. + + CALLED WITH THE LOCK HELD!! + +Arguments: + + Miniport - Miniport to abort. + +Return Value: + + None. + +--*/ +{ + PNDIS_PACKET Packet; + PNDIS_PACKET TmpPacket; + PNDIS_REQUEST Request; + PNDIS_REQUEST TmpRequest; + PNDIS_M_OPEN_BLOCK Open; + PNDIS_PACKET ArcnetLimitPacket; + + LOUD_DEBUG(DbgPrint("NdisM: Enter abort packets and pending\n");) + + ASSERT(MINIPORT_AT_DPC_LEVEL); + + Miniport->Timeout = FALSE; + + // + // Abort Packets + // + + Packet = Miniport->FirstPacket; + ArcnetLimitPacket = Miniport->FirstPendingPacket; + + Miniport->LastMiniportPacket = NULL; + Miniport->FirstPendingPacket = NULL; + Miniport->FirstPacket = NULL; + Miniport->LastPacket = NULL; + Miniport->DeadPacket = NULL; + + NDIS_LOG_PACKET(Miniport, NULL, 'a'); + + while (Packet != NULL) { + + TmpPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next; + + Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Open; + + // + // Set flag that we've reached the packets that are + // not on the mini-port. + // + + if ( Packet == ArcnetLimitPacket ) { + + ArcnetLimitPacket = NULL; + } + + // + // Now free the arcnet header. + // + + if ( Miniport->MediaType == NdisMediumArcnet878_2 && ArcnetLimitPacket ) { + + MiniportFreeArcnetHeader(Miniport, Packet); + } + + NDIS_LOG_PACKET(Miniport, Packet, 'C'); + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + + (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler) ( + Open->ProtocolBindingContext, + Packet, + NDIS_STATUS_REQUEST_ABORTED + ); + + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + Open->References--; + + if (Open->References == 0) { + + FinishClose(Miniport,Open); + } + + Packet = TmpPacket; + } + + NDIS_LOG_PACKET(Miniport, NULL, 'A'); + + // + // Abort Requests + // + Request = Miniport->MiniportRequest; + Miniport->MiniportRequest = NULL; + + if (Request != NULL) { + + Open = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open; + + if (Request != &(Miniport->InternalRequest)) { + + if (Request->RequestType == NdisRequestQueryStatistics) { + + AbortQueryStatisticsRequest( Request, NDIS_STATUS_REQUEST_ABORTED ); + + } else { + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + + (Open->ProtocolHandle->ProtocolCharacteristics.RequestCompleteHandler) ( + Open->ProtocolBindingContext, + Request, + NDIS_STATUS_REQUEST_ABORTED + ); + + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + Open->References--; + + if (Open->References == 0) { + + FinishClose(Miniport,Open); + + } + + } + + } else { + + if (Request->RequestType == NdisRequestSetInformation) { + + NdisMSetInformationComplete( + (NDIS_HANDLE)Miniport, + NDIS_STATUS_FAILURE + ); + + } else { + + NdisMQueryInformationComplete( + (NDIS_HANDLE)Miniport, + NDIS_STATUS_FAILURE + ); + + } + + } + + } + + Request = Miniport->FirstPendingRequest; + Miniport->FirstPendingRequest = NULL; + Miniport->LastPendingRequest = NULL; + Miniport->PendingRequestTimeout = FALSE; + + while (Request != NULL) { + + TmpRequest = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Next; + + Open = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open; + + if (Request->RequestType == NdisRequestQueryStatistics) { + + AbortQueryStatisticsRequest( Request, NDIS_STATUS_REQUEST_ABORTED ); + + } else { + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + + (Open->ProtocolHandle->ProtocolCharacteristics.RequestCompleteHandler) ( + Open->ProtocolBindingContext, + Request, + NDIS_STATUS_REQUEST_ABORTED + ); + + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + Open->References--; + + if (Open->References == 0) { + + FinishClose(Miniport,Open); + + } + + } + + Request = TmpRequest; + + } + + LOUD_DEBUG(DbgPrint("NdisM: Exit abort packets and pending\n");) + +} + +VOID +AbortQueryStatisticsRequest( + PNDIS_REQUEST Request, + NDIS_STATUS Status + ) +{ + PNDIS_QUERY_GLOBAL_REQUEST GlobalRequest; + PNDIS_QUERY_ALL_REQUEST AllRequest; + PNDIS_QUERY_OPEN_REQUEST OpenRequest; + PIRP Irp; + PIO_STACK_LOCATION IrpSp; + + GlobalRequest = CONTAINING_RECORD (Request, + NDIS_QUERY_GLOBAL_REQUEST, + Request + ); + Irp = GlobalRequest->Irp; + IrpSp = IoGetCurrentIrpStackLocation (Irp); + + switch (IrpSp->MajorFunction) { + + case IRP_MJ_CREATE: + + // + // This request is one of the ones made during an open, + // while we are trying to determine the OID list. We + // set the event we are waiting for, the open code + // takes care of the rest. + // + + OpenRequest = (PNDIS_QUERY_OPEN_REQUEST)GlobalRequest; + + OpenRequest->NdisStatus = Status; + KeSetEvent( + &OpenRequest->Event, + 0L, + FALSE); + + break; + + case IRP_MJ_DEVICE_CONTROL: + + // + // This is a real user request, process it as such. + // + + switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) { + + case IOCTL_NDIS_QUERY_GLOBAL_STATS: + + // + // A single query, complete the IRP. + // + + Irp->IoStatus.Information = + Request->DATA.QUERY_INFORMATION.BytesWritten; + + if (Status == NDIS_STATUS_SUCCESS) { + Irp->IoStatus.Status = STATUS_SUCCESS; + } else if (Status == NDIS_STATUS_INVALID_LENGTH) { + Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; + } else { + Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; // what else + } + + IoCompleteRequest (Irp, IO_NETWORK_INCREMENT); + + ExFreePool (GlobalRequest); + break; + + case IOCTL_NDIS_QUERY_ALL_STATS: + + // + // An "all" query. + // + + AllRequest = (PNDIS_QUERY_ALL_REQUEST)GlobalRequest; + + AllRequest->NdisStatus = Status; + KeSetEvent( + &AllRequest->Event, + 0L, + FALSE); + + break; + + } + + break; + + } + + return; + +} // AbortQueryStatisticsRequest + + +VOID +FASTCALL +MiniportProcessDeferred( + PNDIS_MINIPORT_BLOCK Miniport + ) + +/*++ + +Routine Description: + + Processes all outstanding operations. + + CALLED WITH THE LOCK HELD!! + +Arguments: + + Miniport - Miniport to send to. + +Return Value: + + None. + +--*/ + +{ + BOOLEAN DoneSomething; + + ASSERT(MINIPORT_AT_DPC_LEVEL); + + VERY_LOUD_DEBUG(DbgPrint("NdisM: Enter processing deferred \n");) + + Miniport->ProcessingDeferred = TRUE; + + do + { + DoneSomething = FALSE; + + // + // Check for outstanding timers and dpcs first. + // + if (Miniport->ProcessOddDeferredStuff) + { + Miniport->ProcessOddDeferredStuff = FALSE; + + if (Miniport->HaltingMiniport && Miniport->ResetInProgress == NULL) + { + // + // Do nothing + // + Miniport->ProcessingDeferred = FALSE; + Miniport->ProcessOddDeferredStuff = TRUE; + + VERY_LOUD_DEBUG(DbgPrint("NdisM: Exit processing deferred\n");) + + return; + } + + if (Miniport->RunDpc && Miniport->ResetInProgress == NULL) + { + VERY_LOUD_DEBUG(DbgPrint("NdisM: queuing dpc timer\n");) + Miniport->RunDpc = FALSE; + Miniport->ProcessingDeferred = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 0); + + if (Miniport->RunTimer || + Miniport->HaltingMiniport || + Miniport->ResetRequested || + Miniport->RunDoRequests) { + + Miniport->ProcessOddDeferredStuff = TRUE; + } + + return; + } + + if (Miniport->RunTimer != NULL) + { + PNDIS_MINIPORT_TIMER MiniportTimer; + + VERY_LOUD_DEBUG(DbgPrint("NdisM: queueing timer timer\n");) + + MiniportTimer = Miniport->RunTimer; + Miniport->RunTimer = MiniportTimer->NextDeferredTimer; + Miniport->ProcessingDeferred = FALSE; + + NdisMSetTimer(MiniportTimer, 0); + + if (Miniport->RunTimer || + Miniport->HaltingMiniport || + Miniport->ResetRequested || + Miniport->RunDoRequests) { + + Miniport->ProcessOddDeferredStuff = TRUE; + } + + return; + } + + // + // If we have a reset in progress then bail now. + // + + if ( Miniport->ResetInProgress != NULL ) { + + Miniport->ProcessOddDeferredStuff = TRUE; + return; + } + + // + // If we have any pending opens, complete them now. + // + + if ( Miniport->FirstPendingOpen != NULL ) + { + MiniportFinishPendingOpens(Miniport); + } + + // + // Do we need to reset? + // + + if (Miniport->ResetRequested != NULL) + { + NDIS_STATUS Status; + BOOLEAN AddressingReset; + PNDIS_M_OPEN_BLOCK Open = Miniport->ResetRequested; + + VERY_LOUD_DEBUG(DbgPrint("NdisM: Reset requested \n");) + + if (Open != (PNDIS_M_OPEN_BLOCK)(Miniport)) { + + // + // Real reset. Wait for card to go slow + // + + if ((Miniport->LastMiniportPacket != NULL) || + (Miniport->MiniportRequest != NULL)) { + + // + // Wait for send/request to complete + // + + VERY_LOUD_DEBUG(DbgPrint("NdisM: Card is busy\n");) + VERY_LOUD_DEBUG(DbgPrint("NdisM: Exit do deferred\n");) + + Miniport->ProcessingDeferred = FALSE; + + if (Miniport->RunTimer || + Miniport->HaltingMiniport || + Miniport->ResetRequested || + Miniport->RunDoRequests) { + + Miniport->ProcessOddDeferredStuff = TRUE; + } + + return; + } + + } + + // + // Start Miniport reset. + // + + DoneSomething = TRUE; + + Miniport->ResetInProgress = Miniport->ResetRequested; + Miniport->ResetRequested = NULL; + + // + // Indicate status to protocols + // + + NdisMIndicateStatus(Miniport, + NDIS_STATUS_RESET_START, + NULL, + 0 + ); + + NdisMIndicateStatusComplete(Miniport); + + VERY_LOUD_DEBUG(DbgPrint("NdisM: calling mini-port reset\n");) + + Status = + (Miniport->DriverHandle->MiniportCharacteristics.ResetHandler)( + &AddressingReset, + Miniport->MiniportAdapterContext + ); + + if (Status != NDIS_STATUS_PENDING) { + + AbortMiniportPacketsAndPending(Miniport); + + VERY_LOUD_DEBUG(DbgPrint("NdisM: Reset completed\n");) + + // + // Check if we are going to have to reset the + // adapter again. This happens when we are doing + // the reset because of a ring failure. + // + if (Miniport->TrResetRing == 1) { + + if (Status == NDIS_STATUS_SUCCESS) { + + Miniport->TrResetRing = 0; + + } else { + + Miniport->TrResetRing = NDIS_MINIPORT_TR_RESET_TIMEOUT; + + } + + } + + // + // Finish off reset + // + + Miniport->ResetInProgress = NULL; + + NdisMIndicateStatus(Miniport, + NDIS_STATUS_RESET_END, + &Status, + sizeof(Status) + ); + + NdisMIndicateStatusComplete(Miniport); + + if (Open != (PNDIS_M_OPEN_BLOCK)(Miniport)) { + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + + (Open->ProtocolHandle->ProtocolCharacteristics.ResetCompleteHandler)( + Open->ProtocolBindingContext, + Status + ); + + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + Open->References--; + + if (Open->References == 0) { + + FinishClose(Miniport, Open); + + } + + } + + if (AddressingReset && + (Status == NDIS_STATUS_SUCCESS) && + ((Miniport->EthDB != NULL) || + (Miniport->TrDB != NULL) || + (Miniport->FddiDB != NULL) || + (Miniport->ArcDB != NULL))) { + + Miniport->NeedToUpdatePacketFilter = TRUE; + switch (Miniport->MediaType) { + case NdisMedium802_3: + Miniport->NeedToUpdateEthAddresses = TRUE; + break; + case NdisMedium802_5: + Miniport->NeedToUpdateFunctionalAddress = TRUE; + Miniport->NeedToUpdateGroupAddress = TRUE; + break; + case NdisMediumFddi: + Miniport->NeedToUpdateFddiLongAddresses = TRUE; + Miniport->NeedToUpdateFddiShortAddresses = TRUE; + break; + case NdisMediumArcnet878_2: + break; + } + + Miniport->RunDoRequests = TRUE; + + } + + if (Miniport->RunTimer || + Miniport->HaltingMiniport || + Miniport->ResetRequested || + Miniport->RunDoRequests) { + + Miniport->ProcessOddDeferredStuff = TRUE; + } + } + else + { + VERY_LOUD_DEBUG(DbgPrint("NdisM: Reset is pending\n");) + VERY_LOUD_DEBUG(DbgPrint("NdisM: Exit do deferred\n");) + + // + // Lock everything else out while processing + // + Miniport->ProcessingDeferred = FALSE; + + if (Miniport->RunDpc) + { + Miniport->RunDpc = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 0); + } + + if (Miniport->RunTimer || + Miniport->HaltingMiniport || + Miniport->ResetRequested || + Miniport->RunDoRequests) { + + Miniport->ProcessOddDeferredStuff = TRUE; + } + + return; + } + } + + if ((Miniport->RunDoRequests) && + (Miniport->ResetInProgress == NULL) + ) + { + MiniportDoRequests(Miniport); + DoneSomething = TRUE; + } + } + + if ((Miniport->FirstPendingPacket != NULL) && + (Miniport->SendResourcesAvailable != 0) && + (Miniport->ResetInProgress == NULL) + ) + { + MiniportStartSends(Miniport); + DoneSomething = TRUE; + } + + } while ( DoneSomething ); + + Miniport->ProcessingDeferred = FALSE; + + VERY_LOUD_DEBUG(DbgPrint("NdisM: Exit do deferred\n");) + +} + +// +// Timers +// + + +VOID +NdisMTimerDpc( + PKDPC Dpc, + PVOID Context, + PVOID SystemContext1, + PVOID SystemContext2 + ) +/*++ + +Routine Description: + + This function services all mini-port timer interrupts. It then calls the + appropriate function that mini-port consumers have registered in the + call to NdisMInitializeTimer. + +Arguments: + + Dpc - Not used. + + Context - A pointer to the NDIS_MINIPORT_TIMER which is bound to this DPC. + + SystemContext1,2 - not used. + +Return Value: + + None. + +--*/ +{ + PNDIS_MINIPORT_TIMER MiniportTimer = (PNDIS_MINIPORT_TIMER)(Context); + PNDIS_TIMER_FUNCTION TimerFunction; + PNDIS_MINIPORT_BLOCK Miniport = MiniportTimer->Miniport; + BOOLEAN LocalLock; + + UNREFERENCED_PARAMETER(Dpc); + UNREFERENCED_PARAMETER(SystemContext1); + UNREFERENCED_PARAMETER(SystemContext2); + + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + if (Miniport->HaltingMiniport) { + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + return; + + } + + if ((Miniport->LockAcquired) || (Miniport->InInitialize)) { + + PNDIS_MINIPORT_TIMER TmpTimer; + + // + // Make sure it is not already on the list + // + TmpTimer = Miniport->RunTimer; + + while (TmpTimer != NULL) { + + if (TmpTimer == MiniportTimer) { + + Miniport->ProcessOddDeferredStuff = TRUE; + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + + return; + + } + + TmpTimer = TmpTimer->NextDeferredTimer; + } + + // + // A DPC or timer is already running, queue this for later. + // + + MiniportTimer->NextDeferredTimer = Miniport->RunTimer; + Miniport->RunTimer = MiniportTimer; + + Miniport->ProcessOddDeferredStuff = TRUE; + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + + return; + + } + + LOCK_MINIPORT(Miniport, LocalLock); + + // + // Call Miniport timer function + // + + TimerFunction = MiniportTimer->MiniportTimerFunction; + + (*TimerFunction)(NULL, MiniportTimer->MiniportTimerContext, NULL, NULL); + + if (!Miniport->ProcessingDeferred) { + + MiniportProcessDeferred(Miniport); + + } + + UNLOCK_MINIPORT(Miniport, LocalLock); + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + +} + + +VOID +NdisMInitializeTimer( + IN OUT PNDIS_MINIPORT_TIMER MiniportTimer, + IN NDIS_HANDLE MiniportAdapterHandle, + IN PNDIS_TIMER_FUNCTION TimerFunction, + IN PVOID FunctionContext + ) +/*++ + +Routine Description: + + Sets up an Miniport Timer object, initializing the DPC in the timer to + the function and context. + +Arguments: + + MiniportTimer - the timer object. + MiniportAdapterHandle - pointer to the mini-port block; + TimerFunction - Routine to start. + FunctionContext - Context of TimerFunction. + +Return Value: + + None. + +--*/ +{ + KeInitializeTimer(&(MiniportTimer->Timer)); + + MiniportTimer->Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle; + MiniportTimer->MiniportTimerFunction = TimerFunction; + MiniportTimer->MiniportTimerContext = FunctionContext; + + // + // Initialize our dpc. If Dpc was previously initialized, this will + // reinitialize it. + // + + KeInitializeDpc( + &(MiniportTimer->Dpc), + (PKDEFERRED_ROUTINE) NdisMTimerDpc, + (PVOID)MiniportTimer + ); +} + + + + +VOID +NdisMWakeUpDpc( + PKDPC Dpc, + PVOID Context, + PVOID SystemContext1, + PVOID SystemContext2 + ) +/*++ + +Routine Description: + + This function services all mini-port. It checks to see if a mini-port is + ever stalled. + +Arguments: + + Dpc - Not used. + + Context - A pointer to the NDIS_TIMER which is bound to this DPC. + + SystemContext1,2 - not used. + +Return Value: + + None. + +--*/ +{ + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(Context); + BOOLEAN Hung = FALSE; + BOOLEAN LocalLock; + + UNREFERENCED_PARAMETER(Dpc); + UNREFERENCED_PARAMETER(SystemContext1); + UNREFERENCED_PARAMETER(SystemContext2); + + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + if (Miniport->HaltingMiniport) + { + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + + return; + } + + // + // Slam the window open + // + Miniport->SendResourcesAvailable = 0xffffff; + + if (Miniport->LockAcquired) + { + // + // A DPC or timer is already running, assume that means things are fine. + // + + NdisSetTimer(&Miniport->WakeUpDpcTimer, NDIS_MINIPORT_WAKEUP_TIMEOUT); + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + + return; + } + + LOCK_MINIPORT(Miniport, LocalLock); + + // + // Call Miniport stall checker. + // + if (Miniport->DriverHandle->MiniportCharacteristics.CheckForHangHandler != NULL) + { + Hung = (Miniport->DriverHandle->MiniportCharacteristics.CheckForHangHandler)( + Miniport->MiniportAdapterContext + ); + } + + // + // Did a request pend to long? + // + if (Miniport->MiniportRequest != NULL) + { + if (Miniport->Timeout) + Hung = TRUE; + else + Miniport->Timeout = TRUE; + } + + // + // Did a packet send pend to long? + // + if (Miniport->FirstPacket != NULL) + { + if ((Miniport->Timeout) && + (Miniport->FirstPacket == Miniport->DeadPacket) + ) + { + Hung = TRUE; + } + else + { + Miniport->Timeout = TRUE; + Miniport->DeadPacket = Miniport->FirstPacket; + } + } + + if ((Miniport->TrResetRing == 1) && (Miniport->ResetRequested == NULL)) + { + Hung = TRUE; + } + else if (Miniport->TrResetRing > 1) + { + Miniport->TrResetRing--; + } + + // + // Check to see if we have a request that is pending to long. + // + if (Miniport->FirstPendingRequest != NULL) + { + if (Miniport->PendingRequestTimeout) + { + Hung = TRUE; + } + else + { + Miniport->PendingRequestTimeout = TRUE; + } + } + + if (Hung) + { + if (Miniport->InAddDriver) + { + // + // Just abort everything + // + AbortMiniportPacketsAndPending(Miniport); + } + else + { + PNDIS_M_OPEN_BLOCK Open = Miniport->ResetRequested; + + LOUD_DEBUG(DbgPrint("NdisM: WakeUpDpc is resetting mini-port\n");) + + if ((Open != NULL) && (Open != (PNDIS_M_OPEN_BLOCK)Miniport)) + { + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + + (Open->ProtocolHandle->ProtocolCharacteristics.ResetCompleteHandler)( + Open->ProtocolBindingContext, + NDIS_STATUS_REQUEST_ABORTED + ); + + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + } + + // + // If there isn't already a reset in progress, issue a + // reset, otherwise let the current reset complete. + // + + if ( !Miniport->ResetInProgress ) + { + Miniport->ResetRequested = (PNDIS_M_OPEN_BLOCK)Miniport; + Miniport->ProcessOddDeferredStuff = TRUE; + + if (!Miniport->ProcessingDeferred) + { + MiniportProcessDeferred(Miniport); + } + } + } + } + else + { + // + // Process any changes that may have occured. + // + if (!Miniport->ProcessingDeferred) + { + MiniportProcessDeferred(Miniport); + } + } + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisSetTimer(&Miniport->WakeUpDpcTimer, NDIS_MINIPORT_WAKEUP_TIMEOUT); + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); +} + +// +// Dma operations +// + +extern +IO_ALLOCATION_ACTION +NdisDmaExecutionRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID MapRegisterBase, + IN PVOID Context + ); + + +// +// Map Registers +// + +extern +IO_ALLOCATION_ACTION +NdisAllocationExecutionRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID MapRegisterBase, + IN PVOID Context + ); + + +NDIS_STATUS +NdisMAllocateMapRegisters( + IN NDIS_HANDLE MiniportAdapterHandle, + IN UINT DmaChannel, + IN BOOLEAN Dma32BitAddresses, + IN ULONG PhysicalMapRegistersNeeded, + IN ULONG MaximumPhysicalMapping + ) + +/*++ + +Routine Description: + + Allocates map registers for bus mastering devices. + +Arguments: + + MiniportAdapterHandle - Handle passed to MiniportInitialize. + + PhysicalMapRegistersNeeded - The maximum number of map registers needed + by the Miniport at any one time. + + MaximumPhysicalMapping - Maximum length of a buffer that will have to be mapped. + +Return Value: + + None. + +--*/ + +{ + // + // Convert the handle to our internal structure. + // + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportAdapterHandle; + + // + // This is needed by HalGetAdapter. + // + DEVICE_DESCRIPTION DeviceDescription; + + // + // Returned by HalGetAdapter. + // + ULONG MapRegistersAllowed; + + // + // Returned by HalGetAdapter. + // + PADAPTER_OBJECT AdapterObject; + + // + // Map registers needed per channel. + // + ULONG MapRegistersPerChannel; + + NTSTATUS NtStatus; + + KIRQL OldIrql; + + UINT i; + + LARGE_INTEGER TimeoutValue; + + // + // If the device is a busmaster, we get an adapter + // object for it. + // If map registers are needed, we loop, allocating an + // adapter channel for each map register needed. + // + + if ((Miniport->Master) && + (Miniport->BusType != (NDIS_INTERFACE_TYPE)-1) && + (Miniport->BusNumber != (ULONG)-1)) { + + TimeoutValue.QuadPart = Int32x32To64(2 * 1000, -10000); + + Miniport->PhysicalMapRegistersNeeded = PhysicalMapRegistersNeeded; + Miniport->MaximumPhysicalMapping = MaximumPhysicalMapping; + + // + // Allocate storage for holding the appropriate + // information for each map register. + // + + Miniport->MapRegisters = (PMAP_REGISTER_ENTRY) + ExAllocatePool( + NonPagedPool, + sizeof(MAP_REGISTER_ENTRY) * PhysicalMapRegistersNeeded + ); + + if (Miniport->MapRegisters == (PMAP_REGISTER_ENTRY)NULL) { + + // + // Error out + // + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 1, + 0xFFFFFFFF + ); + + return (NDIS_STATUS_RESOURCES); + + } + + // + // Use this event to tell us when NdisAllocationExecutionRoutine + // has been called. + // + + KeInitializeEvent( + &Miniport->AllocationEvent, + NotificationEvent, + FALSE + ); + + + // + // Set up the device description; zero it out in case its + // size changes. + // + + RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION)); + + DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION; + DeviceDescription.Master = TRUE; + DeviceDescription.ScatterGather = TRUE; + + DeviceDescription.BusNumber = Miniport->BusNumber; + DeviceDescription.DmaChannel = DmaChannel; + DeviceDescription.InterfaceType = Miniport->AdapterType; + + if (DeviceDescription.InterfaceType == NdisInterfaceIsa) { + + // + // For ISA devices, the width is based on the DMA channel: + // 0-3 == 8 bits, 5-7 == 16 bits. Timing is compatibility + // mode. + // + + if (DmaChannel > 4) { + DeviceDescription.DmaWidth = Width16Bits; + } else { + DeviceDescription.DmaWidth = Width8Bits; + } + DeviceDescription.DmaSpeed = Compatible; + + } else if ((DeviceDescription.InterfaceType == NdisInterfaceEisa) || + (DeviceDescription.InterfaceType == NdisInterfacePci) || + (DeviceDescription.InterfaceType == NdisInterfaceMca)) { + + DeviceDescription.Dma32BitAddresses = Dma32BitAddresses; + } + + DeviceDescription.MaximumLength = MaximumPhysicalMapping; + + // + // Get the adapter object. + // + + AdapterObject = HalGetAdapter (&DeviceDescription, &MapRegistersAllowed); + + if (AdapterObject == NULL) { + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 1, + 0xFFFFFFFF + ); + + ExFreePool(Miniport->MapRegisters); + Miniport->MapRegisters = NULL; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + return(NDIS_STATUS_RESOURCES); + + } + + // + // We save this to call IoFreeMapRegisters later. + // + + Miniport->SystemAdapterObject = AdapterObject; + + // + // Determine how many map registers we need per channel. + // + + MapRegistersPerChannel = ((MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2; + + ASSERT (MapRegistersAllowed >= MapRegistersPerChannel); + + // + // Now loop, allocating an adapter channel each time, then + // freeing everything but the map registers. + // + + for (i=0; i<Miniport->PhysicalMapRegistersNeeded; i++) { + + Miniport->CurrentMapRegister = i; + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NtStatus = IoAllocateAdapterChannel( + AdapterObject, + Miniport->DeviceObject, + MapRegistersPerChannel, + NdisAllocationExecutionRoutine, + (PVOID)Miniport + ); + + KeLowerIrql(OldIrql); + + if (!NT_SUCCESS(NtStatus)) { + + NdisPrint2("AllocateAdapterChannel: %lx\n", NtStatus); + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + for (; i != 0; i--) { + IoFreeMapRegisters( + Miniport->SystemAdapterObject, + Miniport->MapRegisters[i-1].MapRegister, + MapRegistersPerChannel + ); + } + + KeLowerIrql(OldIrql); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 1, + 0xFFFFFFFF + ); + + ExFreePool(Miniport->MapRegisters); + Miniport->MapRegisters = NULL; + return NDIS_STATUS_RESOURCES; + } + + TimeoutValue.QuadPart = Int32x32To64(2 * 1000, -10000); + + // + // NdisAllocationExecutionRoutine will set this event + // when it has gotten FirstTranslationEntry. + // + + NtStatus = KeWaitForSingleObject( + &Miniport->AllocationEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + NdisPrint2("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus); + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + for (; i != 0; i--) { + IoFreeMapRegisters( + Miniport->SystemAdapterObject, + Miniport->MapRegisters[i-1].MapRegister, + MapRegistersPerChannel + ); + } + + KeLowerIrql(OldIrql); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 1, + 0xFFFFFFFF + ); + + ExFreePool(Miniport->MapRegisters); + Miniport->MapRegisters = NULL; + return NDIS_STATUS_RESOURCES; + + } + + KeResetEvent( + &Miniport->AllocationEvent + ); + + } + + } + + return(NDIS_STATUS_SUCCESS); +} + + +VOID +NdisMFreeMapRegisters( + IN NDIS_HANDLE MiniportAdapterHandle + ) + +/*++ + +Routine Description: + + Releases allocated map registers + +Arguments: + + MiniportAdapterHandle - Handle passed to MiniportInitialize. + +Return Value: + + None. + +--*/ + +{ + // + // Convert the handle to our internal structure. + // + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportAdapterHandle; + + KIRQL OldIrql; + + ULONG i; + + if (Miniport->Master && (Miniport->MapRegisters != NULL)) { + + ULONG MapRegistersPerChannel = + ((Miniport->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2; + + for (i=0; i<Miniport->PhysicalMapRegistersNeeded; i++) { + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + IoFreeMapRegisters( + Miniport->SystemAdapterObject, + Miniport->MapRegisters[i].MapRegister, + MapRegistersPerChannel + ); + + KeLowerIrql(OldIrql); + } + + ExFreePool(Miniport->MapRegisters); + + Miniport->MapRegisters = NULL; + + } + +} + + + + +// +// Interrupt stuff +// + + +BOOLEAN +NdisMIsr( + IN PKINTERRUPT KInterrupt, + IN PVOID Context + ) +/*++ + +Routine Description: + + Handles ALL Miniport interrupts, calling the appropriate Miniport ISR and DPC + depending on the context. + +Arguments: + + Interrupt - Interrupt object for the Mac. + + Context - Really a pointer to the interrupt. + +Return Value: + + None. + +--*/ +{ + // + // Get adapter from context. + // + + PNDIS_MINIPORT_INTERRUPT Interrupt = (PNDIS_MINIPORT_INTERRUPT)Context; + PNDIS_MINIPORT_BLOCK Miniport = Interrupt->Miniport; + + BOOLEAN InterruptRecognized; + BOOLEAN QueueDpc; + + if (Miniport->NormalInterrupts) { + + // + // Call to disable the interrupt + // + + ASSERT(Miniport->DriverHandle->MiniportCharacteristics.DisableInterruptHandler != NULL); + + MINIPORT_DISABLE_INTERRUPT(Miniport); + + InterruptRecognized = TRUE; + +queue_dpc: + + Increment((PLONG)&Interrupt->DpcCount,&Interrupt->DpcCountLock); + + if (KeInsertQueueDpc(&Interrupt->InterruptDpc,NULL,NULL)) { + return InterruptRecognized; + } + + // + // The DPC was already queued, so we have an extra reference (we + // do it this way to ensure that the reference is added *before* + // the DPC is queued). + // + + Decrement((PLONG)&Interrupt->DpcCount,&Interrupt->DpcCountLock); + + if (Miniport->HaltingMiniport && (Interrupt->DpcCount==0)) { + + // + // We need to queue a DPC to set the event because we + // can't do it from the ISR. We know that the interrupt + // DPC won't fire because the refcount is 0, so we reuse it. + // + + KeInitializeDpc( + &Interrupt->InterruptDpc, + NdisLastCountRemovedFunction, + (PVOID)&Interrupt->DpcsCompletedEvent + ); + + // + // When NdisLastCountRemovedFunction runs it will set + // the event. + // + + KeInsertQueueDpc(&Interrupt->InterruptDpc, NULL, NULL); + + } + + return InterruptRecognized; + + } + + if (!Miniport->HaltingMiniport) { + + // + // Call MiniportIsr + // + + Interrupt->MiniportIsr(&InterruptRecognized, + &QueueDpc, + Miniport->MiniportAdapterContext + ); + if (QueueDpc) goto queue_dpc; + return InterruptRecognized; + + } + + if (!Interrupt->SharedInterrupt && + !Interrupt->IsrRequested && + !Miniport->InInitialize) { + + // + // Call to disable the interrupt + // + + ASSERT(Miniport->DriverHandle->MiniportCharacteristics.DisableInterruptHandler != NULL); + + MINIPORT_DISABLE_INTERRUPT(Miniport); + return TRUE; + + } + + // + // Call MiniportIsr, but don't queue a DPC. + // + + Interrupt->MiniportIsr(&InterruptRecognized, + &QueueDpc, + Miniport->MiniportAdapterContext + ); + return InterruptRecognized; + +} + + +VOID +NdisMDpc( + IN PVOID SystemSpecific1, + IN PVOID InterruptContext, + IN PVOID SystemSpecific2, + IN PVOID SystemSpecific3 + ) +/*++ + +Routine Description: + + Handles ALL Miniport interrupt DPCs, calling the appropriate Miniport DPC + depending on the context. + +Arguments: + + Interrupt - Interrupt object for the Mac. + + Context - Really a pointer to the Interrupt. + +Return Value: + + None. + +--*/ +{ + // + // Get adapter from context. + // + + PNDIS_MINIPORT_INTERRUPT Interrupt = (PNDIS_MINIPORT_INTERRUPT)(InterruptContext); + PNDIS_MINIPORT_BLOCK Miniport = Interrupt->Miniport; + BOOLEAN LocalLock; + + W_HANDLE_INTERRUPT_HANDLER MiniportDpc = Interrupt->MiniportDpc; + + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + LOG('d'); + + if (Miniport->HaltingMiniport) { + + Decrement((PLONG)&Interrupt->DpcCount,&Interrupt->DpcCountLock); + + if (Interrupt->DpcCount==0) { + + KeSetEvent( + &Interrupt->DpcsCompletedEvent, + 0L, + FALSE + ); + + } + + LOG('h'); + LOG('D'); + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + return; + } + + if (Miniport->LockAcquired) { + + // + // A DPC is already running, queue this for later. + // + + Miniport->RunDpc = TRUE; + Miniport->ProcessOddDeferredStuff = TRUE; + + Decrement((PLONG)&Interrupt->DpcCount,&Interrupt->DpcCountLock); + + LOG('L'); + LOG('D'); + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + + return; + + } + + LOCK_MINIPORT(Miniport, LocalLock); + + // + // Call MiniportDpc + // + + (*MiniportDpc)(Miniport->MiniportAdapterContext); + + Decrement((PLONG)&Interrupt->DpcCount,&Interrupt->DpcCountLock); + + if (!Miniport->HaltingMiniport) { + + // + // Enable interrupts + // + + MINIPORT_SYNC_ENABLE_INTERRUPT(Miniport); + + if (!Miniport->ProcessingDeferred) { + + MiniportProcessDeferred(Miniport); + + } + + } else { + + if (Interrupt->DpcCount == 0) { + + KeSetEvent( + &Interrupt->DpcsCompletedEvent, + 0L, + FALSE + ); + + } + + } + + UNLOCK_MINIPORT(Miniport, LocalLock); + + LOG('D'); + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + +} + + +VOID +NdisMDpcTimer( + IN PVOID SystemSpecific1, + IN PVOID InterruptContext, + IN PVOID SystemSpecific2, + IN PVOID SystemSpecific3 + ) +/*++ + +Routine Description: + + Handles a deferred interrupt dpc. + +Arguments: + + Context - Really a pointer to the Miniport block. + +Return Value: + + None. + +--*/ +{ + // + // Get adapter from context. + // + + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(InterruptContext); + BOOLEAN LocalLock; + + W_HANDLE_INTERRUPT_HANDLER MiniportDpc = + Miniport->DriverHandle->MiniportCharacteristics.HandleInterruptHandler; + + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + if ((Miniport->HaltingMiniport) || + (Miniport->InInitialize)) { + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + return; + } + + if (Miniport->LockAcquired) { + + // + // A DPC is already running, queue this for later. + // + + Miniport->RunDpc = TRUE; + Miniport->ProcessOddDeferredStuff = TRUE; + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + + return; + + } + + LOCK_MINIPORT(Miniport, LocalLock); + + MINIPORT_SYNC_DISABLE_INTERRUPT(Miniport); + + // + // Call MiniportDpc + // + + if (MiniportDpc != NULL) { + + (*MiniportDpc)(Miniport->MiniportAdapterContext); + + } + + // + // Enable interrupts + // + MINIPORT_SYNC_ENABLE_INTERRUPT(Miniport); + + // + // Check if we need to shutdown. + // + if (!Miniport->HaltingMiniport) { + + if (!Miniport->ProcessingDeferred) { + + MiniportProcessDeferred(Miniport); + + } + } + + UNLOCK_MINIPORT(Miniport, LocalLock); + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + return; + +} + +// +// Io Port stuff +// + + +NDIS_STATUS +NdisMRegisterIoPortRange( + OUT PVOID *PortOffset, + IN NDIS_HANDLE MiniportAdapterHandle, + IN UINT InitialPort, + IN UINT NumberOfPorts + ) + +/*++ + +Routine Description: + + Sets up an IO port for operations. + +Arguments: + + PortOffset - The mapped port address the Miniport uses for NdisRaw functions. + + MiniportAdapterHandle - Handle passed to Miniport Initialize. + + InitialPort - Physical address of the starting port number. + + NumberOfPorts - Number of ports to map. + +Return Value: + + None. + +--*/ +{ + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(MiniportAdapterHandle); + PHYSICAL_ADDRESS PortAddress; + PHYSICAL_ADDRESS InitialPortAddress; + ULONG addressSpace; + ULONG NumberOfElements; + + BOOLEAN Conflict; + PCM_RESOURCE_LIST Resources; + NDIS_STATUS Status; + + // + // First check if any bus access is allowed + // + + if ((Miniport->BusType == (NDIS_INTERFACE_TYPE)-1) || + (Miniport->BusNumber == (ULONG)-1)) { + + return NDIS_STATUS_FAILURE; + + } + + // + // First check for resource conflict by expanding current resource list, + // adding in the mapped space, and then re-submitting the resource list. + // + + if (Miniport->Resources != NULL) { + + NumberOfElements = Miniport->Resources->List[0].PartialResourceList.Count + 1; + + } else { + + NumberOfElements = 1; + } + + Resources = (PCM_RESOURCE_LIST)ExAllocatePool( + NonPagedPool, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + NumberOfElements + ); + + if (Resources == NULL) { + + return NDIS_STATUS_RESOURCES; + + } + + if (Miniport->Resources != NULL) { + + RtlMoveMemory (Resources, + Miniport->Resources, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + Miniport->Resources->List[0].PartialResourceList.Count + ); + + } else { + + // + // Setup initial resource info + // + Resources->Count = 1; + Resources->List[0].InterfaceType = Miniport->AdapterType; + Resources->List[0].BusNumber = Miniport->BusNumber; + Resources->List[0].PartialResourceList.Version = 0; + Resources->List[0].PartialResourceList.Revision = 0; + Resources->List[0].PartialResourceList.Count = 0; + + } + + // + // Setup port + // + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type = + CmResourceTypePort; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition = + CmResourceShareDeviceExclusive; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags = + (Miniport->AdapterType == NdisInterfaceInternal)? + CM_RESOURCE_PORT_MEMORY : CM_RESOURCE_PORT_IO; +#if !defined(BUILD_FOR_3_1) + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Port.Start.QuadPart = + (ULONG)InitialPort; +#else + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Port.Start = + RtlConvertUlongToLargeInteger((ULONG)(InitialPort)); +#endif + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Port.Length = + NumberOfPorts; + Resources->List[0].PartialResourceList.Count++; + + // + // Make the call + // + + Status = IoReportResourceUsage( + NULL, + Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver, + NULL, + 0, + Miniport->DeviceObject, + Resources, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + Resources->List[0].PartialResourceList.Count, + TRUE, + &Conflict + ); + + if (Miniport->Resources != NULL) { + ExFreePool(Miniport->Resources); + } + + Miniport->Resources = Resources; + + // + // Check for conflict. + // + + if (Conflict || (Status != STATUS_SUCCESS)) { + + + if (Conflict) { + + + // + // Log an error + // + + PIO_ERROR_LOG_PACKET errorLogEntry; + ULONG i; + ULONG StringSize; + PUCHAR Place; + PWCH baseFileName; + + baseFileName = Miniport->MiniportName.Buffer; + + // + // Parse out the path name, leaving only the device name. + // + + for ( i = 0; i < Miniport->MiniportName.Length / sizeof(WCHAR); i++ ) { + + // + // If s points to a directory separator, set baseFileName to + // the character after the separator. + // + + if ( Miniport->MiniportName.Buffer[i] == OBJ_NAME_PATH_SEPARATOR ) { + baseFileName = &(Miniport->MiniportName.Buffer[++i]); + } + + } + + StringSize = Miniport->MiniportName.MaximumLength - + (((ULONG)baseFileName) - ((ULONG)Miniport->MiniportName.Buffer)) ; + + errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( + Miniport->DeviceObject, + (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) + + StringSize + + 6) // wstrlen("99") * sizeof(WHCAR) + sizeof(UNICODE_NULL) + ); + + if (errorLogEntry != NULL) { + + errorLogEntry->ErrorCode = EVENT_NDIS_IO_PORT_CONFLICT; + + // + // store the time + // + + errorLogEntry->MajorFunctionCode = 0; + errorLogEntry->RetryCount = 0; + errorLogEntry->UniqueErrorValue = 0; + errorLogEntry->FinalStatus = 0; + errorLogEntry->SequenceNumber = 0; + errorLogEntry->IoControlCode = 0; + + // + // Set string information + // + + if (StringSize != 0) { + + errorLogEntry->NumberOfStrings = 1; + errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET); + + RtlMoveMemory ( + ((PUCHAR)errorLogEntry) + + sizeof(IO_ERROR_LOG_PACKET), + (PVOID)baseFileName, + StringSize + ); + + Place = ((PUCHAR)errorLogEntry) + + sizeof(IO_ERROR_LOG_PACKET) + + StringSize; + + } else { + + Place = ((PUCHAR)errorLogEntry) + + sizeof(IO_ERROR_LOG_PACKET); + + errorLogEntry->NumberOfStrings = 0; + + } + + // + // write it out + // + + IoWriteErrorLogEntry(errorLogEntry); + + } + + return NDIS_STATUS_RESOURCE_CONFLICT; + + } + + return NDIS_STATUS_FAILURE; + + } + + // + // Now Map the ports + // + + + + // + // Get the system physical address for this card. The card uses + // I/O space, except for "internal" Jazz devices which use + // memory space. + // + + addressSpace = (Miniport->AdapterType == NdisInterfaceInternal) ? 0 : 1; + + InitialPortAddress.LowPart = InitialPort; + InitialPortAddress.HighPart = 0; + + if ( !HalTranslateBusAddress( + Miniport->BusType, // InterfaceType + Miniport->BusNumber, // BusNumber + InitialPortAddress, // Bus Address + &addressSpace, // AddressSpace + &PortAddress // Translated address + ) ) { + + // + // It would be nice to return a better status here, but we only get + // TRUE/FALSE back from HalTranslateBusAddress. + // + + return NDIS_STATUS_FAILURE; + } + + if (addressSpace == 0) { + + // + // memory space + // + + *(PortOffset) = (PULONG)MmMapIoSpace( + PortAddress, + NumberOfPorts, + FALSE + ); + + if (*(PortOffset) == (PULONG)NULL) { + + return NDIS_STATUS_RESOURCES; + + } + + } else { + + // + // I/O space + // + + *(PortOffset) = (PULONG)PortAddress.LowPart; + + } + + return NDIS_STATUS_SUCCESS; + +} + + + +VOID +NdisMDeregisterIoPortRange( + IN NDIS_HANDLE MiniportAdapterHandle, + IN UINT InitialPort, + IN UINT NumberOfPorts, + IN PVOID PortOffset + ) + +/*++ + +Routine Description: + + Sets up an IO port for operations. + +Arguments: + + MiniportAdapterHandle - Handle passed to Miniport Initialize. + + InitialPort - Physical address of the starting port number. + + NumberOfPorts - Number of ports to map. + + PortOffset - The mapped port address the Miniport uses for NdisRaw functions. + +Return Value: + + None. + +--*/ +{ + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(MiniportAdapterHandle); + PHYSICAL_ADDRESS PortAddress; + PHYSICAL_ADDRESS InitialPortAddress; + ULONG addressSpace; + + // + // Get the system physical address for this card. The card uses + // I/O space, except for "internal" Jazz devices which use + // memory space. + // + + addressSpace = (Miniport->AdapterType == NdisInterfaceInternal) ? 0 : 1; + + InitialPortAddress.LowPart = InitialPort; + InitialPortAddress.HighPart = 0; + + if ( !HalTranslateBusAddress( + Miniport->BusType, // InterfaceType + Miniport->BusNumber, // BusNumber + InitialPortAddress, // Bus Address + &addressSpace, // AddressSpace + &PortAddress // Translated address + ) ) { + + // + // It would be nice to return a better status here, but we only get + // TRUE/FALSE back from HalTranslateBusAddress. + // + + return; + } + + if (addressSpace == 0) { + + // + // memory space + // + + MmUnmapIoSpace( + PortOffset, + NumberOfPorts + ); + + } else { + + // + // I/O space + // + + } + +} + + +// +// Attribute functions +// + + +VOID +NdisMSetAttributes( + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_HANDLE MiniportAdapterContext, + IN BOOLEAN BusMaster, + IN NDIS_INTERFACE_TYPE AdapterType + ) +/*++ + +Routine Description: + + This function sets specific information about an adapter. + +Arguments: + + MiniportAdapterHandle - points to the adapter block. + + MiniportAdapterContext - Context to pass to all Miniport driver functions. + + BusMaster - TRUE if a bus mastering adapter. + + AdapterType - Eisa, Isa, Mca or Internal. + +Return Value: + + None. + + +--*/ +{ + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle; + + Miniport->MiniportAdapterContext = MiniportAdapterContext; + Miniport->Master = BusMaster; + Miniport->AdapterType = AdapterType; + + MiniportReferencePackage(); +} + + + +// +// Interface functions +// + + + +VOID +NdisMIndicateStatus( + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_STATUS GeneralStatus, + IN PVOID StatusBuffer, + IN UINT StatusBufferSize + ) +/*++ + +Routine Description: + + This function indicates a new status of the media/mini-port. + +Arguments: + + MiniportAdapterHandle - points to the adapter block. + + GeneralStatus - The status to indicate. + + StatusBuffer - Additional information. + + StatusBufferSize - Length of the buffer. + +Return Value: + + None. + + +--*/ +{ + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle; + PNDIS_M_OPEN_BLOCK Open; + NDIS_STATUS Status; + + ASSERT(MINIPORT_AT_DPC_LEVEL); + ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport)); + + if ((GeneralStatus == NDIS_STATUS_RING_STATUS) && + (StatusBufferSize == sizeof(NDIS_STATUS))) { + + Status = *((PNDIS_STATUS)StatusBuffer); + + if (Status & (NDIS_RING_LOBE_WIRE_FAULT | + NDIS_RING_HARD_ERROR | + NDIS_RING_SIGNAL_LOSS)) { + + Miniport->TrResetRing = NDIS_MINIPORT_TR_RESET_TIMEOUT; + + } + + } + + Open = Miniport->OpenQueue; + + while (Open != NULL) { + + // + // Call Protocol to indicate status + // + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + + (Open->ProtocolHandle->ProtocolCharacteristics.StatusHandler) ( + Open->ProtocolBindingContext, + GeneralStatus, + StatusBuffer, + StatusBufferSize + ); + + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + Open = Open->MiniportNextOpen; + + } + +} + + + +VOID +NdisMIndicateStatusComplete( + IN NDIS_HANDLE MiniportAdapterHandle + ) +/*++ + +Routine Description: + + This function indicates the status is complete. + +Arguments: + + MiniportAdapterHandle - points to the adapter block. + +Return Value: + + None. + + +--*/ +{ + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle; + PNDIS_M_OPEN_BLOCK Open; + + ASSERT(MINIPORT_AT_DPC_LEVEL); + ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport)); + + Open = Miniport->OpenQueue; + + while (Open != NULL) { + + // + // Call Protocol to indicate status + // + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + + (Open->ProtocolHandle->ProtocolCharacteristics.StatusCompleteHandler) ( + Open->ProtocolBindingContext + ); + + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + Open = Open->MiniportNextOpen; + + } + +} + + +VOID +NdisMSendComplete( + IN NDIS_HANDLE MiniportAdapterHandle, + IN PNDIS_PACKET Packet, + IN NDIS_STATUS Status + ) +/*++ + +Routine Description: + + This function indicates the completion of a send. + +Arguments: + + MiniportAdapterHandle - points to the adapter block. + +Return Value: + + None. + +--*/ +{ + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle; + PNDIS_M_OPEN_BLOCK Open; + PNDIS_PACKET_RESERVED Reserved; + + ASSERT(MINIPORT_AT_DPC_LEVEL); + ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport)); + + LOUD_DEBUG(DbgPrint("NdisM: Enter send complete\n");) + LOUD_DEBUG(DbgPrint("NdisM: packet 0x%x\n", Packet);) + + Miniport->SendCompleteCalled = TRUE; + + // + // If the packet is not equal to the first packet then we have to find + // it because it may have completed out of order. + // + + Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet); + + if ( Miniport->FirstPacket == Packet ) + { + Miniport->FirstPacket = Reserved->Next; + Miniport->DeadPacket = NULL; + + if ( Miniport->LastMiniportPacket == Packet ) + { + Miniport->LastMiniportPacket = NULL; + } + } + else + { + PNDIS_PACKET PrevPacket; + + // + // Search for the packet. + // + MiniportFindPacket(Miniport, Packet, &PrevPacket); + + ASSERT( PrevPacket != NULL ); + + // + // If we just completed the last packet then + // we need to update our last packet pointer. + // + if (Packet != Miniport->LastPacket) + { + PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = Reserved->Next; + } + else + { + Miniport->LastPacket = PrevPacket; + } + + // + // If we just completed the last miniport packet then + // last miniport packet is the previous packet. + // + + if ( Miniport->LastMiniportPacket == Packet ) + { + Miniport->LastMiniportPacket = PrevPacket; + } + } + + // + // Indicate to Protocol; + // + + Open = Reserved->Open; + + Miniport->Timeout = FALSE; + + // + // If this is arcnet, then free the appended header. + // + if ( Miniport->MediaType == NdisMediumArcnet878_2 ) + { + MiniportFreeArcnetHeader(Miniport, Packet); + } + + LOG('C'); + NDIS_LOG_PACKET(Miniport, Packet, 'C'); + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + + (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)( + Open->ProtocolBindingContext, + Packet, + Status + ); + + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + ADD_RESOURCE(Miniport, 'P'); + + Open->References--; + + if (Open->References == 0) + { + FinishClose(Miniport,Open); + } + + if (!Miniport->ProcessingDeferred) + MiniportProcessDeferred(Miniport); + + LOUD_DEBUG(DbgPrint("NdisM: Exit send complete\n");) +} + + +VOID +NdisMWanSendComplete( + IN NDIS_HANDLE MiniportAdapterHandle, + IN PNDIS_PACKET Packet, + IN NDIS_STATUS Status + ) + +/*++ + +Routine Description: + + This function indicates the status is complete. + +Arguments: + + MiniportAdapterHandle - points to the adapter block. + +Return Value: + + None. + + +--*/ +{ + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle; + PNDIS_M_OPEN_BLOCK Open; + + ASSERT(MINIPORT_AT_DPC_LEVEL); + ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport)); + + Open = Miniport->OpenQueue; + + while (Open != NULL) { + + // + // Call Protocol to indicate status + // + + NDIS_LOG_PACKET(Miniport, Packet, 'C'); + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + + (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler) ( + Open->ProtocolBindingContext, + Packet, + Status + ); + + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + Open = Open->MiniportNextOpen; + + } + +} + + + +typedef +NDIS_STATUS +(*WAN_RECEIVE_HANDLER) ( + IN NDIS_HANDLE NdisLinkContext, + IN PUCHAR Packet, + IN ULONG PacketSize + ); + +VOID +NdisMWanIndicateReceive( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_HANDLE NdisLinkContext, + IN PUCHAR Packet, + IN ULONG PacketSize + ) +/*++ + +Routine Description: + + This function indicates the status is complete. + +Arguments: + + MiniportAdapterHandle - points to the adapter block. + +Return Value: + + None. + + +--*/ +{ + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle; + PNDIS_M_OPEN_BLOCK Open; + + ASSERT(MINIPORT_AT_DPC_LEVEL); + ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport)); + + Open = Miniport->OpenQueue; + + while (Open != NULL) { + + // + // Call Protocol to indicate status + // + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + + *Status = + ((WAN_RECEIVE_HANDLER)(Open->ProtocolHandle->ProtocolCharacteristics.ReceiveHandler)) ( + NdisLinkContext, + Packet, + PacketSize); + + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + Open = Open->MiniportNextOpen; + + } +} + + + +VOID +NdisMWanIndicateReceiveComplete( + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_HANDLE NdisLinkContext + ) +/*++ + +Routine Description: + + This function indicates the status is complete. + +Arguments: + + MiniportAdapterHandle - points to the adapter block. + +Return Value: + + None. + + +--*/ +{ + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle; + PNDIS_M_OPEN_BLOCK Open; + + ASSERT(MINIPORT_AT_DPC_LEVEL); + ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport)); + + Open = Miniport->OpenQueue; + + while (Open != NULL) { + + // + // Call Protocol to indicate status + // + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + + (Open->ProtocolHandle->ProtocolCharacteristics.ReceiveCompleteHandler) ( + NdisLinkContext); + + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + Open = Open->MiniportNextOpen; + + } +} + + +VOID +NdisMSendResourcesAvailable( + IN NDIS_HANDLE MiniportAdapterHandle + ) +/*++ + +Routine Description: + + This function indicates that some send resources are available and are free for + processing more sends. + +Arguments: + + MiniportAdapterHandle - points to the adapter block. + +Return Value: + + None. + + +--*/ +{ + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle; + + ASSERT(MINIPORT_AT_DPC_LEVEL); + + LOG('a'); + + ADD_RESOURCE(Miniport, 'V'); + + Miniport->Timeout = FALSE; + + if (!Miniport->ProcessingDeferred) { + + MiniportProcessDeferred(Miniport); + } +} + + +VOID +NdisMSetInformationComplete( + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_STATUS Status + ) +/*++ + +Routine Description: + + This function indicates the completion of a set information operation. + +Arguments: + + MiniportAdapterHandle - points to the adapter block. + + Status - Status of the operation + +Return Value: + + None. + + +--*/ +{ + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle; + PNDIS_REQUEST Request; + PNDIS_M_OPEN_BLOCK Open; + + ASSERT(MINIPORT_AT_DPC_LEVEL); + ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport)); + LOUD_DEBUG(DbgPrint("NdisM: Enter set information complete\n");) + + // + // Remove request. + // + + Miniport->Timeout = FALSE; + + if (Miniport->MiniportRequest == NULL) { + + // + // Assume this is a complete that was aborted due to the wake up dpc + // + return; + + } + + Request = Miniport->MiniportRequest; + Miniport->MiniportRequest = NULL; + + LOUD_DEBUG(DbgPrint("NdisM: Request 0x%x\n", Request);) + + Open = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request)->Open; + + if (Request != &(Miniport->InternalRequest)) { + + // + // Indicate to Protocol; + // + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + + (Open->ProtocolHandle->ProtocolCharacteristics.RequestCompleteHandler) ( + Open->ProtocolBindingContext, + Request, + Status + ); + + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + Open->References--; + + if (Open->References == 0) { + + FinishClose(Miniport,Open); + + } + + } else if (Request->RequestType == NdisRequestQueryStatistics) { + + // + // Flag meaning that we need to set the request event + // + Miniport->RequestStatus = Status; + KeSetEvent( + &Miniport->RequestEvent, + 0L, + FALSE + ); + + } else if ((Open != NULL) && (Open->Closing)) { + + Open->References--; + + if (Open->References == 0) { + + FinishClose(Miniport,Open); + + } + + } else { + + // + // Internal request, check if we need to do more work now. + // + if ((Miniport->NeedToUpdateEthAddresses || + Miniport->NeedToUpdatePacketFilter || + Miniport->NeedToUpdateFunctionalAddress || + Miniport->NeedToUpdateGroupAddress || + Miniport->NeedToUpdateFddiLongAddresses || + Miniport->NeedToUpdateFddiShortAddresses || + (Miniport->FirstPendingRequest != NULL)) + && + (Miniport->MiniportRequest == NULL)) { + Miniport->RunDoRequests = TRUE; + Miniport->ProcessOddDeferredStuff = TRUE; + } else { + Miniport->RunDoRequests = FALSE; + } + + + } + + if (!Miniport->ProcessingDeferred) { + + MiniportProcessDeferred(Miniport); + + } + LOUD_DEBUG(DbgPrint("NdisM: Exit set information complete\n");) + +} + + +VOID +NdisMResetComplete( + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_STATUS Status, + IN BOOLEAN AddressingReset + ) +/*++ + +Routine Description: + + This function indicates the completion of a reset. + +Arguments: + + MiniportAdapterHandle - points to the adapter block. + + Status - Status of the reset. + + AddressingReset - Do we have to submit a request to reload the address + information. This includes packet filter, and multicast/functional addresses. + +Return Value: + + None. + + +--*/ +{ + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle; + PNDIS_M_OPEN_BLOCK Open; + + ASSERT(MINIPORT_AT_DPC_LEVEL); + ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport)); + + // + // Destroy all outstanding packets and requests. + // + AbortMiniportPacketsAndPending(Miniport); + + // + // Check if we are going to have to reset the + // adapter again. This happens when we are doing + // the reset because of a ring failure. + // + if (Miniport->TrResetRing == 1) { + + if (Status == NDIS_STATUS_SUCCESS) { + + Miniport->TrResetRing = 0; + + } else { + + Miniport->TrResetRing = NDIS_MINIPORT_TR_RESET_TIMEOUT; + + } + + } + + // + // Indicate to Protocols the reset is complete + // + + LOUD_DEBUG(DbgPrint("NdisM: Enter reset complete\n");) + + Open = Miniport->ResetInProgress; + Miniport->ResetInProgress = NULL; + Miniport->ProcessingDeferred = FALSE; + + NdisMIndicateStatus(Miniport, + NDIS_STATUS_RESET_END, + &Status, + sizeof(Status) + ); + + NdisMIndicateStatusComplete(Miniport); + + if ( Open != (PNDIS_M_OPEN_BLOCK) Miniport && Open != NULL ) { + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + + (Open->ProtocolHandle->ProtocolCharacteristics.ResetCompleteHandler) ( + Open->ProtocolBindingContext, + Status + ); + + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + Open->References--; + + if (Open->References == 0) { + + FinishClose(Miniport,Open); + } + } + + if (AddressingReset && + (Status == NDIS_STATUS_SUCCESS) && + ((Miniport->EthDB != NULL) || + (Miniport->TrDB != NULL) || + (Miniport->FddiDB != NULL) || + (Miniport->ArcDB != NULL))) { + + + Miniport->NeedToUpdatePacketFilter = TRUE; + switch (Miniport->MediaType) { + case NdisMedium802_3: + Miniport->NeedToUpdateEthAddresses = TRUE; + break; + case NdisMedium802_5: + Miniport->NeedToUpdateFunctionalAddress = TRUE; + Miniport->NeedToUpdateGroupAddress = TRUE; + break; + case NdisMediumFddi: + Miniport->NeedToUpdateFddiLongAddresses = TRUE; + Miniport->NeedToUpdateFddiShortAddresses = TRUE; + break; + case NdisMediumArcnet878_2: + break; + } + + Miniport->RunDoRequests = TRUE; + Miniport->ProcessOddDeferredStuff = TRUE; + + } + + if (!Miniport->ProcessingDeferred) { + + MiniportProcessDeferred(Miniport); + + } + LOUD_DEBUG(DbgPrint("NdisM: Exit reset complete\n");) + +} + + + +VOID +NdisMTransferDataComplete( + IN NDIS_HANDLE MiniportAdapterHandle, + IN PNDIS_PACKET Packet, + IN NDIS_STATUS Status, + IN UINT BytesTransferred + ) +/*++ + +Routine Description: + + This function indicates the completion of a transfer data request. + +Arguments: + + MiniportAdapterHandle - points to the adapter block. + + Packet - The packet the data was copied into. + + Status - Status of the operation. + + BytesTransferred - Total number of bytes transferred. + +Return Value: + + None. + + +--*/ +{ + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle; + PNDIS_M_OPEN_BLOCK Open; + PNDIS_PACKET PrevPacket; + + ASSERT(MINIPORT_AT_DPC_LEVEL); + ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport)); + ASSERT(Miniport->FirstTDPacket != NULL); + + // + // Find the packet + // + + if (Packet == Miniport->FirstTDPacket) { + + Miniport->FirstTDPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next; + + } else { + + PrevPacket = Miniport->FirstTDPacket; + + while (PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next != Packet) { + + PrevPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next; + + ASSERT(PrevPacket != NULL); + } + + PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = + PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next; + + if (Packet == Miniport->LastTDPacket) { + + Miniport->LastTDPacket = PrevPacket; + + } + + } + + // + // Indicate to Protocol; + // + + Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Open; + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + + (Open->ProtocolHandle->ProtocolCharacteristics.TransferDataCompleteHandler) ( + Open->ProtocolBindingContext, + Packet, + Status, + BytesTransferred + ); + + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + +} + + + +VOID +NdisMQueryInformationComplete( + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_STATUS Status + ) +/*++ + +Routine Description: + + This function indicates the completion of a query information operation. + +Arguments: + + MiniportAdapterHandle - points to the adapter block. + + Status - Status of the operation + +Return Value: + + None. + + +--*/ +{ + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle; + PNDIS_REQUEST Request; + PNDIS_M_OPEN_BLOCK Open; + PNDIS_REQUEST_RESERVED Reserved; + + ASSERT(MINIPORT_AT_DPC_LEVEL); + ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport)); + LOUD_DEBUG(DbgPrint("NdisM: Enter query information complete\n");) + + // + // Check for global statistics request + // + Miniport->Timeout = FALSE; + + if (Miniport->MiniportRequest == NULL) + { + // + // Assume this is a complete that was aborted due to the wake up dpc + // + return; + } + + // + // Get the request that was completed. + // + Request = Miniport->MiniportRequest; + Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request); + Miniport->MiniportRequest = NULL; + + if (Request->RequestType == NdisRequestQueryStatistics) + { + PNDIS_QUERY_GLOBAL_REQUEST GlobalRequest; + PNDIS_QUERY_ALL_REQUEST AllRequest; + PNDIS_QUERY_OPEN_REQUEST OpenRequest; + PIRP Irp; + PIO_STACK_LOCATION IrpSp; + + GlobalRequest = CONTAINING_RECORD (Request, + NDIS_QUERY_GLOBAL_REQUEST, + Request + ); + Irp = GlobalRequest->Irp; + IrpSp = IoGetCurrentIrpStackLocation (Irp); + + switch (IrpSp->MajorFunction) { + + case IRP_MJ_CREATE: + + // + // This request is one of the ones made during an open, + // while we are trying to determine the OID list. We + // set the event we are waiting for, the open code + // takes care of the rest. + // + + OpenRequest = (PNDIS_QUERY_OPEN_REQUEST)GlobalRequest; + + OpenRequest->NdisStatus = Status; + KeSetEvent( + &OpenRequest->Event, + 0L, + FALSE); + + break; + + case IRP_MJ_DEVICE_CONTROL: + + // + // This is a real user request, process it as such. + // + + switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) { + + case IOCTL_NDIS_QUERY_GLOBAL_STATS: + + // + // A single query, complete the IRP. + // + + Irp->IoStatus.Information = + Request->DATA.QUERY_INFORMATION.BytesWritten; + + if (Status == NDIS_STATUS_SUCCESS) { + Irp->IoStatus.Status = STATUS_SUCCESS; + } else if (Status == NDIS_STATUS_INVALID_LENGTH) { + Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; + } else { + Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; // BUGBUG + } + + IoCompleteRequest (Irp, IO_NETWORK_INCREMENT); + + ExFreePool (GlobalRequest); + break; + + case IOCTL_NDIS_QUERY_ALL_STATS: + + // + // An "all" query. + // + + AllRequest = (PNDIS_QUERY_ALL_REQUEST)GlobalRequest; + + AllRequest->NdisStatus = Status; + KeSetEvent( + &AllRequest->Event, + 0L, + FALSE); + + break; + + } + + break; + + } + + if (!Miniport->ProcessingDeferred) { + + MiniportProcessDeferred(Miniport); + + } + LOUD_DEBUG(DbgPrint("NdisM: Exit qeury information complete\n");) + return; + + } + + // + // Remove request. + // + LOUD_DEBUG(DbgPrint("NdisM: Request 0x%x\n", Request);) + + // + // Was this an internal request? + // + if (Request == &(Miniport->InternalRequest)) + { + Miniport->RequestStatus = Status; + KeSetEvent( + &Miniport->RequestEvent, + 0L, + FALSE + ); + + LOUD_DEBUG(DbgPrint("NdisM: Exit qeury information complete\n");) + return; + } + + // + // If the request is OID_GEN_SUPPORTED_LIST + // + if (OID_GEN_SUPPORTED_LIST == Request->DATA.QUERY_INFORMATION.Oid) + { + ULONG cbDestination; + PNDIS_REQUEST pFakeRequest; + PNDIS_REQUEST_RESERVED pFakeReserved; + + // + // Restore the original request. + // + pFakeRequest = Request; + pFakeReserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(pFakeRequest); + Request = pFakeReserved->Next; + Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(Request); + + // + // If the request succeeded then filter out the statistics oids. + // Otherwise pass the relevant information back to the protocol. + // + if (NDIS_STATUS_SUCCESS != Status) + { + // + // There was an error.... + // + Request->DATA.QUERY_INFORMATION.BytesWritten = + pFakeRequest->DATA.QUERY_INFORMATION.BytesWritten; + Request->DATA.QUERY_INFORMATION.BytesNeeded = + pFakeRequest->DATA.QUERY_INFORMATION.BytesNeeded; + } + else + { + // + // Size of the request originators buffer. + // + cbDestination = + Request->DATA.QUERY_INFORMATION.InformationBufferLength; + + // + // Do the OID fix ups. + // + Status = FilterOutOidStatistics( + Miniport, + Request, + Request->DATA.QUERY_INFORMATION.InformationBuffer, + &cbDestination, + pFakeRequest->DATA.QUERY_INFORMATION.InformationBuffer, + pFakeRequest->DATA.QUERY_INFORMATION.BytesWritten + ); + if (NDIS_STATUS_BUFFER_TOO_SHORT == Status) + { + // + // Save the size needed with the original request. + // + Request->DATA.QUERY_INFORMATION.BytesNeeded = cbDestination; + Request->DATA.QUERY_INFORMATION.BytesWritten = 0; + } + else + { + // + // Save the bytes written with the original request. + // + Request->DATA.QUERY_INFORMATION.BytesNeeded = 0; + Request->DATA.QUERY_INFORMATION.BytesWritten = cbDestination; + } + + // + // Free the allocated resources. + // + ExFreePool(pFakeRequest->DATA.QUERY_INFORMATION.InformationBuffer); + ExFreePool(pFakeRequest); + } + + // + // Fall through to protocol indication. + // + } + + // + // Indicate to Protocol; + // + Open = Reserved->Open; + + LOUD_DEBUG(DbgPrint("NdisM: Open 0x%x\n", Open);) + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + + (Open->ProtocolHandle->ProtocolCharacteristics.RequestCompleteHandler)( + Open->ProtocolBindingContext, + Request, + Status + ); + + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + Open->References--; + + if (Open->References == 0) + { + FinishClose(Miniport,Open); + } + + if (!Miniport->ProcessingDeferred) + { + MiniportProcessDeferred(Miniport); + } + + LOUD_DEBUG(DbgPrint("NdisM: Exit query information complete\n");) +} + +NDIS_STATUS +NdisMRegisterMiniport( + IN NDIS_HANDLE NdisWrapperHandle, + IN PNDIS_MINIPORT_CHARACTERISTICS MiniportCharacteristics, + IN UINT CharacteristicsLength + ) + +/*++ + +Routine Description: + + Used to register a Miniport driver with the wrapper. + +Arguments: + + Status - Status of the operation. + + NdisWrapperHandle - Handle returned by NdisWInitializeWrapper. + + MiniportCharacteritics - The NDIS_MINIPORT_CHARACTERISTICS table. + + CharacteristicsLength - The length of MiniportCharacteristics. + +Return Value: + + None. + +--*/ + +{ + PNDIS_M_DRIVER_BLOCK WDriver; + PNDIS_WRAPPER_HANDLE DriverInfo = (PNDIS_WRAPPER_HANDLE)(NdisWrapperHandle); + UINT MemNeeded; + UINT charLength; + NDIS_STATUS Status; + + // + // Do any initial initialization that may be necessary. Note: this + // routine will notice if this is the second or later call to it. + // + Status = NdisInitialInit( DriverInfo->NdisWrapperDriver ); + if (!NT_SUCCESS(Status)) { + return Status; + } + + LOUD_DEBUG(DbgPrint("NdisM: Enter mini-port register\n");) + + if (DriverInfo == NULL) { + + return NDIS_STATUS_FAILURE; + + + } + + if (MiniportCharacteristics->MajorNdisVersion != 3 || + MiniportCharacteristics->MinorNdisVersion != 0) { + + return NDIS_STATUS_BAD_VERSION; + } + + // + // Check that CharacteristicsLength is enough. + // + + charLength = sizeof(NDIS_MINIPORT_CHARACTERISTICS); + if (CharacteristicsLength < charLength) { + return NDIS_STATUS_BAD_CHARACTERISTICS; + } + + // + // Allocate memory for the NDIS MINIPORT block. + // + MemNeeded = sizeof(NDIS_M_DRIVER_BLOCK); + + WDriver = (PNDIS_M_DRIVER_BLOCK)ExAllocatePool(NonPagedPool, MemNeeded); + + if (WDriver == (PNDIS_M_DRIVER_BLOCK)NULL) { + return NDIS_STATUS_RESOURCES; + } + + NdisZeroMemory(WDriver, MemNeeded); + + WDriver->Length = MemNeeded; + + + // + // Copy over the characteristics table. + // + + RtlMoveMemory((PVOID)&WDriver->MiniportCharacteristics, + (PVOID)MiniportCharacteristics, charLength); + + // + // No adapters yet registered for this Miniport. + // + + WDriver->MiniportQueue = (PNDIS_MINIPORT_BLOCK)NULL; + + // + // Set up unload handler + // + + DriverInfo->NdisWrapperDriver->DriverUnload = NdisMUnload; + + // + // Set up shutdown handler + // + DriverInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_SHUTDOWN] = NdisMShutdown; + + // + // Set up the handlers for this driver (they all do nothing). + // + + DriverInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CREATE] = NdisCreateIrpHandler; + DriverInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NdisDeviceControlIrpHandler; + DriverInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CLEANUP] = NdisSuccessIrpHandler; + DriverInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CLOSE] = NdisCloseIrpHandler; + + // + // Put Driver on global list. + // + + ACQUIRE_SPIN_LOCK(&NdisDriverListLock); + + WDriver->NextDriver = NdisDriverList; + NdisDriverList = WDriver; + + RELEASE_SPIN_LOCK(&NdisDriverListLock); + + // + // Use this event to tell us when all adapters are removed from the mac + // during an unload + // + + KeInitializeEvent( + &WDriver->MiniportsRemovedEvent, + NotificationEvent, + FALSE + ); + + WDriver->Unloading = FALSE; + WDriver->NdisDriverInfo = DriverInfo; + WDriver->MiniportIdField = (NDIS_HANDLE)0x1; + + NdisInitializeRef(&WDriver->Ref); + NdisInitReferencePackage(); + + LOUD_DEBUG(DbgPrint("NdisM: Exit mini-port register\n");) + + if (DriverInfo->NdisWrapperConfigurationHandle) { + + if (NdisCallDriverAddAdapter((PNDIS_MAC_BLOCK)WDriver) == NDIS_STATUS_SUCCESS) { + + NdisInitDereferencePackage(); + return NDIS_STATUS_SUCCESS; + } else { + NdisDereferenceDriver(WDriver); + NdisInitDereferencePackage(); + return NDIS_STATUS_FAILURE; + } + } else { + NdisInitDereferencePackage(); + return NDIS_STATUS_FAILURE; + } + +} + +// +// Protocol entry points +// +NDIS_STATUS FASTCALL MiniportSyncSend( + PNDIS_MINIPORT_BLOCK Miniport, + PNDIS_PACKET Packet +) + +/*++ + +Routine Description: + + Submits an immediate send to a miniport. The miniport has + the send on the pending queue, and it is the only element on the send + queue. This routine is also called with the lock held. + +Arguments: + + Miniport - Miniport to send to. + +Return Value: + + None. + +--*/ + +{ + PARC_BUFFER_LIST Buffer; + PARC_BUFFER_LIST ArcTmpBuffer; + PNDIS_BUFFER NdisBuffer; + PNDIS_BUFFER TmpBuffer; + PNDIS_PACKET PrevPacket; + NDIS_STATUS Status; + PNDIS_PACKET_RESERVED Reserved; + PNDIS_M_OPEN_BLOCK Open; + UINT Flags; + PVOID BufferVa; + PUCHAR Address; + + ASSERT(MINIPORT_AT_DPC_LEVEL); + ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport)); + + LOUD_DEBUG(DbgPrint("NdisM: Enter Sync send.\n");) + + LOG('+'); + NDIS_LOG_PACKET(Miniport, Packet, '+'); + + Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet); + Open = Reserved->Open; + + if (Miniport->MediaType == NdisMediumArcnet878_2) + goto BuildArcnetHeader; + +DoneBuildingArcnetHeader: + + // + // Remove from Queue + // + Miniport->FirstPendingPacket = Reserved->Next; + + // + // Put on finish queue + // + PrevPacket = Miniport->LastMiniportPacket; + Miniport->LastMiniportPacket = Packet; + Miniport->SendCompleteCalled = FALSE; + + // + // Indicate the packet loopback if necessary. + // + if ((Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) && + MiniportSendLoopback(Miniport, Packet) + ) + { + LOUD_DEBUG(DbgPrint("NdisM: Not sending packet 0x%x\n", Packet);) + + LOG('l'); + NDIS_LOG_PACKET(Miniport, Packet, 'l'); + + Status = NDIS_STATUS_SUCCESS; + goto SyncNoCardSend; + } + + // + // Submit to card + // + LOUD_DEBUG(DbgPrint("NdisM: Sending packet 0x%x\n", Packet);) + + REMOVE_RESOURCE(Miniport, 'S'); + + NdisQuerySendFlags(Packet, &Flags); + + LOG('M'); + + NDIS_LOG_PACKET(Miniport, Packet, 'M'); + + Status = (Open->SendHandler)( + Open->MiniportAdapterContext, + Packet, + Flags + ); + if (Status == NDIS_STATUS_PENDING) + { + LOG('p'); + NDIS_LOG_PACKET(Miniport, Packet, 'p'); + + LOUD_DEBUG(DbgPrint("NdisM: Complete sync send is pending\n");) + + return(Status); + } + +SyncNoCardSend: + + if (Miniport->MediaType == NdisMediumArcnet878_2) + MiniportFreeArcnetHeader(Miniport, Packet); + + if (Status != NDIS_STATUS_RESOURCES) + { + if (Status != NDIS_STATUS_SUCCESS) + { + ADD_RESOURCE(Miniport, 'F'); + + LOG('F'); + NDIS_LOG_PACKET(Miniport, Packet, 'F'); + } + + // + // Remove from finish queue + // + LOUD_DEBUG(DbgPrint("NdisM: Completed 0x%x\n", Status);) + + // + // If send complete was called from the miniport's send handler + // then our local PrevPacket pointer may no longer be valid.... + // + MiniportFindPacket(Miniport, Packet, &PrevPacket); + + Miniport->LastMiniportPacket = PrevPacket; + + if (PrevPacket == NULL) + { + Miniport->FirstPacket = Reserved->Next; + Miniport->DeadPacket = NULL; + } + else + { + PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = Reserved->Next; + + if ( Packet == Miniport->LastPacket ) { + + Miniport->LastPacket = PrevPacket; + } + } + + Open->References--; + + if (Open->References == 0) + FinishClose(Miniport, Open); + + NDIS_LOG_PACKET(Miniport, Packet, 'C'); + return(Status); + } + + // Status == NDIS_STATUS_RESOURCES!!!! + + LOUD_DEBUG(DbgPrint("NdisM: Deferring send\n");) + + // + // If send complete was called from the miniport's send handler + // then our local PrevPacket pointer may no longer be valid. + // + MiniportFindPacket(Miniport, Packet, &PrevPacket); + + // + // Remove from finish queue + // + Miniport->LastMiniportPacket = PrevPacket; + + // + // Put on pending queue + // + Miniport->FirstPendingPacket = Packet; + + // + // Mark the packet at the head of the pending queue as having + // been looped back. + // + Miniport->AlreadyLoopedBack = TRUE; + + LOG('o'); + NDIS_LOG_PACKET(Miniport, Packet, 'o'); + + // + // Set flag + // + CLEAR_RESOURCE(Miniport, 'S'); + + return(NDIS_STATUS_PENDING); + +BuildArcnetHeader: + + if (Open->UsingEthEncapsulation) + { + if (Miniport->ArcnetFreeBufferList == NULL) + { + // + // Set flag + // + CLEAR_RESOURCE(Miniport, 'S'); + return(NDIS_STATUS_PENDING); + } + + NdisQueryPacket(Packet, NULL, NULL, &TmpBuffer, NULL); + NdisQueryBuffer(TmpBuffer, &Address, &Flags); + + Buffer = Miniport->ArcnetFreeBufferList; + Miniport->ArcnetFreeBufferList = Buffer->Next; + + NdisAllocateBuffer( + &Status, + &NdisBuffer, + Miniport->ArcnetBufferPool, + Buffer->Buffer, + 3 + ); + + if (Status != NDIS_STATUS_SUCCESS) + { + Buffer->Next = Miniport->ArcnetFreeBufferList; + Miniport->ArcnetFreeBufferList = Buffer; + CLEAR_RESOURCE(Miniport, 'S'); + return(NDIS_STATUS_PENDING); + } + + Buffer->Next = Miniport->ArcnetUsedBufferList; + Miniport->ArcnetUsedBufferList = Buffer; + + NdisChainBufferAtFront(Packet, NdisBuffer); + + ((PUCHAR)Buffer->Buffer)[0] = Miniport->ArcnetAddress; + + if (Address[0] & 0x01) + { + // + // Broadcast + // + ((PUCHAR)Buffer->Buffer)[1] = 0x00; + } + else + { + ((PUCHAR)Buffer->Buffer)[1] = Address[5]; + } + + ((PUCHAR)Buffer->Buffer)[2] = 0xE8; + } + + goto DoneBuildingArcnetHeader; +} + + + +NDIS_STATUS NdisMSend( + IN NDIS_HANDLE NdisBindingHandle, + IN PNDIS_PACKET Packet +) +{ + PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle; + PNDIS_PACKET_RESERVED Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet); + BOOLEAN LocalLock; + KIRQL OldIrql; + BOOLEAN FirstSend = FALSE; + NDIS_STATUS StatusToReturn = NDIS_STATUS_PENDING; + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + ASSERT(MINIPORT_AT_DPC_LEVEL); + LOCK_MINIPORT(Miniport, LocalLock); + + if (!Miniport->HaltingMiniport) + { + NDIS_LOG_PACKET(Miniport, Packet, 'w'); + + ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++; + + // + // Handle protocol requests + // + Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet); + Reserved->Next = NULL; + Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle; + + if ( Miniport->FirstPacket == NULL ) + { + Miniport->FirstPacket = Packet; + Miniport->DeadPacket = NULL; + } + else + { +#if DBG + { + PNDIS_PACKET p; + + for (p = Miniport->FirstPacket; p != NULL; p = PNDIS_RESERVED_FROM_PNDIS_PACKET(p)->Next) + { + if (Packet == p) + { + DbgBreakPoint(); + } + } + } +#endif + + PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = Packet; + } + + Miniport->LastPacket = Packet; + + // + // Initialize some variables. + // + FirstSend = FALSE; + StatusToReturn = NDIS_STATUS_PENDING; + + if (Miniport->FirstPendingPacket == NULL) + { + FirstSend = TRUE; + Miniport->FirstPendingPacket = Packet; + Miniport->AlreadyLoopedBack = FALSE; + } + + if (LocalLock) + { + // + // If we did not lock down the mini-port, then some other routine will + // do this processing for us. Otherwise we need to do this processing. + // + if (!Miniport->ProcessingDeferred) + { + Miniport->ProcessingDeferred = TRUE; + + if (FirstSend && + !(Miniport->RunTimer || + Miniport->HaltingMiniport || + Miniport->ResetRequested || + Miniport->ResetInProgress || + Miniport->RunDoRequests || + Miniport->ProcessOddDeferredStuff) + ) + { + // + // There aren't any pending sends, we are not processing + // odd deferred stuff (i.e. we are obeying the priority + // in processdeferred, and we have the lock. If all is + // not perfect we will defer and try again later.) + // + StatusToReturn = MiniportSyncSend(Miniport, Packet); + Miniport->ProcessingDeferred = FALSE; + } + else + { + MiniportProcessDeferred(Miniport); + } + } + } + + NDIS_LOG_PACKET(Miniport, Packet, 'W'); + + UNLOCK_MINIPORT(Miniport, LocalLock); + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + KeLowerIrql(OldIrql); + + return(StatusToReturn); + } + else + { + NDIS_LOG_PACKET(Miniport, Packet, 'F'); + NDIS_LOG_PACKET(Miniport, Packet, 'W'); + + UNLOCK_MINIPORT(Miniport, LocalLock); + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + KeLowerIrql(OldIrql); + + return(NDIS_STATUS_FAILURE); + } +} + +typedef +NDIS_STATUS +(*PNDIS_M_WAN_SEND) ( + IN NDIS_HANDLE NdisBindingHandle, + IN NDIS_HANDLE NdisLinkHandle, + IN PVOID Packet + ); + +// +// Protocol entry point for WAN miniport +// + +NDIS_STATUS +NdisMWanSend( + IN NDIS_HANDLE NdisBindingHandle, + IN NDIS_HANDLE NdisLinkHandle, + IN PVOID Packet + ) +{ + PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle; + BOOLEAN LocalLock; + KIRQL OldIrql; + NDIS_STATUS Status; + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + ASSERT(MINIPORT_AT_DPC_LEVEL); + LOCK_MINIPORT(Miniport, LocalLock); + + // + // Call MAC to send WAN packet + // + + Status= + ((PNDIS_M_WAN_SEND)(Miniport->DriverHandle->MiniportCharacteristics.SendHandler)) ( + Miniport->MiniportAdapterContext, + NdisLinkHandle, + Packet); + + if (LocalLock) { + + // + // Process any changes that may have occured. + // + + if (!Miniport->ProcessingDeferred) { + MiniportProcessDeferred(Miniport); + } + } + + UNLOCK_MINIPORT(Miniport, LocalLock); + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + KeLowerIrql(OldIrql); + return(Status); +} + + +NDIS_STATUS +NdisMTransferDataSync( + IN NDIS_HANDLE NdisBindingHandle, + IN NDIS_HANDLE MacReceiveContext, + IN UINT ByteOffset, + IN UINT BytesToTransfer, + IN OUT PNDIS_PACKET Packet, + OUT PUINT BytesTransferred + ) +{ + PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle; + PNDIS_PACKET_RESERVED Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet); + NDIS_STATUS Status; + KIRQL OldIrql; + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + ASSERT(MINIPORT_AT_DPC_LEVEL); + ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport)); + ASSERT((Miniport->MacOptions & NDIS_MAC_OPTION_TRANSFERS_NOT_PEND) != 0); + + // + // Handle non-loopback as the default case. + // + + if (Miniport->LoopbackPacket == NULL) { + + Reserved->Next = NULL; + Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle; + + // + // Call Miniport. + // + + Status = + (Reserved->Open->TransferDataHandler)( + Packet, + BytesTransferred, + Reserved->Open->MiniportAdapterContext, + MacReceiveContext, + ByteOffset, + BytesToTransfer + ); + + // + // This miniport better not pend this send. + // + + ASSERT(Status != NDIS_STATUS_PENDING); + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + KeLowerIrql(OldIrql); + + return Status; + } + + // + // This packet is a loopback packet! + // + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + KeLowerIrql(OldIrql); + + NdisCopyFromPacketToPacket( + Packet, + 0, + BytesToTransfer, + Miniport->LoopbackPacket, + ByteOffset + Miniport->LoopbackPacketHeaderSize, + BytesTransferred + ); + + if ( *BytesTransferred == BytesToTransfer ) { + + return NDIS_STATUS_SUCCESS; + } + + return NDIS_STATUS_FAILURE; +} + +NDIS_STATUS +NdisMTransferData( + IN NDIS_HANDLE NdisBindingHandle, + IN NDIS_HANDLE MacReceiveContext, + IN UINT ByteOffset, + IN UINT BytesToTransfer, + IN OUT PNDIS_PACKET Packet, + OUT PUINT BytesTransferred + ) +{ + PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle; + PNDIS_PACKET_RESERVED Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet); + PNDIS_PACKET PrevLast; + NDIS_STATUS Status; + KIRQL OldIrql; + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + ASSERT(MINIPORT_AT_DPC_LEVEL); + ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport)); + + // + // Handle non-loopback as the default case. + // + + if (Miniport->LoopbackPacket == NULL) { + + Reserved->Next = NULL; + Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle; + + // + // Put this guy on the transfer data queue. + // + + PrevLast = Miniport->LastTDPacket; + + if (Miniport->FirstTDPacket == NULL) { + + Miniport->FirstTDPacket = Packet; + + } else { + + PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastTDPacket)->Next = Packet; + } + + Miniport->LastTDPacket = Packet; + + // + // Call Miniport + // + + Status = + (Reserved->Open->TransferDataHandler)( + Packet, + BytesTransferred, + Reserved->Open->MiniportAdapterContext, + MacReceiveContext, + ByteOffset, + BytesToTransfer + ); + + // + // If it didn't pend then we won't get a transfer data complte call + // so we need to remove this guy now. + // + + if ( Status != NDIS_STATUS_PENDING ) { + + // + // Remove from queue + // + + if (Miniport->FirstTDPacket != Packet) { + + PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevLast)->Next = NULL; + Miniport->LastTDPacket = PrevLast; + + } else { + + Miniport->FirstTDPacket = NULL; + Miniport->LastTDPacket = NULL; + + } + } + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + KeLowerIrql(OldIrql); + + return Status; + } + + // + // This packet is a loopback packet! + // + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + KeLowerIrql(OldIrql); + + NdisCopyFromPacketToPacket( + Packet, + 0, + BytesToTransfer, + Miniport->LoopbackPacket, + ByteOffset + Miniport->LoopbackPacketHeaderSize, + BytesTransferred + ); + + if ( *BytesTransferred == BytesToTransfer ) { + + return NDIS_STATUS_SUCCESS; + } + + return NDIS_STATUS_FAILURE; +} + +NDIS_STATUS +NdisMReset( + IN NDIS_HANDLE NdisBindingHandle + ) +{ + PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle; + BOOLEAN LocalLock; + KIRQL OldIrql; + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + ASSERT(MINIPORT_AT_DPC_LEVEL); + LOCK_MINIPORT(Miniport, LocalLock); + + if (Miniport->HaltingMiniport) { + + UNLOCK_MINIPORT(Miniport, LocalLock); + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + KeLowerIrql(OldIrql); + + return(NDIS_STATUS_FAILURE); + + } + + Miniport->ResetRequested = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle; + Miniport->ProcessOddDeferredStuff = TRUE; + + ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++; + + if (LocalLock) { + + // + // If we did not lock down the mini-port, then some other routine will + // do this processing for us. Otherwise we need to do this processing. + // + if (!Miniport->ProcessingDeferred) { + + MiniportProcessDeferred(Miniport); + + } + + } + + UNLOCK_MINIPORT(Miniport, LocalLock); + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + KeLowerIrql(OldIrql); + + return(NDIS_STATUS_PENDING); +} + + +NDIS_STATUS +NdisMRequest( + IN NDIS_HANDLE NdisBindingHandle, + IN PNDIS_REQUEST NdisRequest + ) +{ + PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle; + PNDIS_REQUEST_RESERVED Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(NdisRequest); + BOOLEAN LocalLock; + KIRQL OldIrql; + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + ASSERT(MINIPORT_AT_DPC_LEVEL); + LOCK_MINIPORT(Miniport, LocalLock); + + if (Miniport->HaltingMiniport) { + + UNLOCK_MINIPORT(Miniport, LocalLock); + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + KeLowerIrql(OldIrql); + + return(NDIS_STATUS_FAILURE); + + } + + LOUD_DEBUG(DbgPrint("NdisM: Got request 0x%x\n",NdisRequest);) + + // + // Handle protocol requests + // + + Reserved->Next = NULL; + Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle; + ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++; + + if (Miniport->FirstPendingRequest == NULL) { + + Miniport->FirstPendingRequest = NdisRequest; + + } else { + + PNDIS_RESERVED_FROM_PNDIS_REQUEST(Miniport->LastPendingRequest)->Next = NdisRequest; + + } + + Miniport->LastPendingRequest = NdisRequest; + + if (Miniport->MiniportRequest == NULL) + { + Miniport->RunDoRequests = TRUE; + Miniport->ProcessOddDeferredStuff = TRUE; + } + + if (LocalLock) + { + // + // If we did not lock down the mini-port, then some other routine will + // do this processing for us. Otherwise we need to do this processing. + // + if (!Miniport->ProcessingDeferred) { + + MiniportProcessDeferred(Miniport); + + } + + } + + UNLOCK_MINIPORT(Miniport, LocalLock); + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + KeLowerIrql(OldIrql); + + return (NDIS_STATUS_PENDING); +} + + +NDIS_STATUS +NdisMMapIoSpace( + OUT PVOID * VirtualAddress, + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_PHYSICAL_ADDRESS PhysicalAddress, + IN UINT Length + ) +{ + NDIS_STATUS Status; + NdisMapIoSpace(&Status, + VirtualAddress, + MiniportAdapterHandle, + PhysicalAddress, + Length + ); + return(Status); +} + + +VOID +NdisMUnmapIoSpace( + IN NDIS_HANDLE MiniportAdapterHandle, + IN PVOID VirtualAddress, + IN UINT Length + ) +{ + +#ifdef _ALPHA_ + +#else + MmUnmapIoSpace(VirtualAddress, Length); +#endif + +} + + +NDIS_STATUS +NdisMRegisterInterrupt( + OUT PNDIS_MINIPORT_INTERRUPT Interrupt, + IN NDIS_HANDLE MiniportAdapterHandle, + IN UINT InterruptVector, + IN UINT InterruptLevel, + IN BOOLEAN RequestIsr, + IN BOOLEAN SharedInterrupt, + IN NDIS_INTERRUPT_MODE InterruptMode + ) +{ + NDIS_STATUS Status; + NdisInitializeInterrupt(&Status, + (PNDIS_INTERRUPT)Interrupt, + MiniportAdapterHandle, + NULL, + NULL, + (PNDIS_DEFERRED_PROCESSING)RequestIsr, + InterruptVector, + InterruptLevel, + SharedInterrupt, + InterruptMode + ); + + return(Status); +} + + +VOID +NdisMDeregisterInterrupt( + IN PNDIS_MINIPORT_INTERRUPT Interrupt + ) +{ + NdisRemoveInterrupt((PNDIS_INTERRUPT)Interrupt); +} + + +BOOLEAN +NdisMSynchronizeWithInterrupt( + IN PNDIS_MINIPORT_INTERRUPT Interrupt, + IN PVOID SynchronizeFunction, + IN PVOID SynchronizeContext + ) +{ + return (KeSynchronizeExecution( + (Interrupt)->InterruptObject, + (PKSYNCHRONIZE_ROUTINE)SynchronizeFunction, + SynchronizeContext + ) + ); +} + + + +VOID +NdisMAllocateSharedMemory( + IN NDIS_HANDLE MiniportAdapterHandle, + IN ULONG Length, + IN BOOLEAN Cached, + OUT PVOID *VirtualAddress, + OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress + ) +{ + // + // Convert the handle to our internal structure. + // + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportAdapterHandle; + + if (Miniport->SystemAdapterObject == NULL) { + + *VirtualAddress = NULL; + return; + + } + + NdisAllocateSharedMemory(MiniportAdapterHandle, + Length, + Cached, + VirtualAddress, + PhysicalAddress + ); +} + +VOID +NdisMFreeSharedMemory( + IN NDIS_HANDLE MiniportAdapterHandle, + IN ULONG Length, + IN BOOLEAN Cached, + IN PVOID VirtualAddress, + IN NDIS_PHYSICAL_ADDRESS PhysicalAddress + ) +{ + NdisFreeSharedMemory(MiniportAdapterHandle, + Length, + Cached, + VirtualAddress, + PhysicalAddress); +} + + + +NDIS_STATUS +NdisMRegisterDmaChannel( + OUT PNDIS_HANDLE MiniportDmaHandle, + IN NDIS_HANDLE MiniportAdapterHandle, + IN UINT DmaChannel, + IN BOOLEAN Dma32BitAddresses, + IN PNDIS_DMA_DESCRIPTION DmaDescription, + IN ULONG MaximumLength + ) +{ + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(MiniportAdapterHandle); + NDIS_STATUS Status; + Miniport->ChannelNumber = (DmaChannel); + Miniport->Dma32BitAddresses = (Dma32BitAddresses); + NdisAllocateDmaChannel(&Status, + MiniportDmaHandle, + (NDIS_HANDLE)Miniport, + DmaDescription, + MaximumLength + ); + return(Status); +} + + + +VOID +NdisMDeregisterDmaChannel( + IN PNDIS_HANDLE MiniportDmaHandle + ) +{ + NdisFreeDmaChannel(MiniportDmaHandle); +} + + +VOID +HaltOneMiniport( + PNDIS_MINIPORT_BLOCK Miniport + ) + +/*++ + +Routine Description: + + Does all the clean up for a mini-port. + +Arguments: + + Miniport - pointer to the mini-port to halt + +Return Value: + + None. + +--*/ + +{ + BOOLEAN LocalLock; + BOOLEAN Canceled; + KIRQL OldIrql; + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + while (Miniport->LockAcquired) { + + // + // This can only happen on an MP system. We must now + // wait for the other processor to exit the mini-port. + // + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + KeLowerIrql(OldIrql); + + NdisStallExecution(1000); + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + } + + // + // Lock mini-port so that nothing will enter it. + // + LOCK_MINIPORT(Miniport, LocalLock); + + // + // We can now release safely + // + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + KeLowerIrql(OldIrql); + + NdisCancelTimer(&Miniport->WakeUpDpcTimer, &Canceled); + + if (!Canceled) { + + NdisStallExecution(500000); + } + + Miniport->ProcessOddDeferredStuff = TRUE; + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler)( + Miniport->MiniportAdapterContext + ); + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + AbortMiniportPacketsAndPending(Miniport); + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + KeLowerIrql(OldIrql); + + // + // If a shutdown handler was registered then deregister it. + // + + NdisMDeregisterAdapterShutdownHandler(Miniport); + + NdisDereferenceMiniport(Miniport); + MiniportDereferencePackage(); + + return; + +} + +// +// Arcnet support routines +// + +VOID +NdisMArcIndicateEthEncapsulatedReceive( + IN PNDIS_MINIPORT_BLOCK Miniport, + IN PVOID HeaderBuffer, + IN PVOID DataBuffer, + IN UINT Length + ) +/*++ + + HeaderBuffer - This is the 878.2 header. + DataBuffer - This is the 802.3 header. + Length - This is the length of the ethernet frame. + +--*/ + +{ + ULONG MacReceiveContext[2]; + + // + // Indicate the packet. + // + + MacReceiveContext[0] = (ULONG) DataBuffer; + MacReceiveContext[1] = (ULONG) Length; + + if (Length > 14) { + + NdisMEthIndicateReceive( + (NDIS_HANDLE) Miniport, // miniport handle. + (NDIS_HANDLE) MacReceiveContext, // receive context. + DataBuffer, // ethernet header. + 14, // ethernet header length. + (PUCHAR)DataBuffer + 14, // ethernet data. + Length - 14, // ethernet data length. + Length - 14 // ethernet data length. + ); + + } else { + + NdisMEthIndicateReceive( + (NDIS_HANDLE) Miniport, // miniport handle. + (NDIS_HANDLE) MacReceiveContext, // receive context. + DataBuffer, // ethernet header. + Length, // ethernet header length. + NULL, // ethernet data. + 0, // ethernet data length. + 0 // ethernet data length. + ); + } +} + + +NDIS_STATUS +NdisMArcTransferData( + IN NDIS_HANDLE NdisBindingHandle, + IN NDIS_HANDLE MacReceiveContext, + IN UINT ByteOffset, + IN UINT BytesToTransfer, + IN OUT PNDIS_PACKET DstPacket, + OUT PUINT BytesTransferred + ) +/*++ + +Routine Description: + + This routine handles the transfer data calls to arcnet mini-port. + +Arguments: + + NdisBindingHandle - Pointer to open block. + + MacReceiveContext - Context given for the indication + + ByteOffset - Offset to start transfer at. + + BytesToTransfer - Number of bytes to transfer + + Packet - Packet to transfer into + + BytesTransferred - the number of actual bytes copied + +Return values: + + NDIS_STATUS_SUCCESS, if successful, else NDIS_STATUS_FAILURE. + +--*/ +{ + PNDIS_MINIPORT_BLOCK Miniport; + PNDIS_M_OPEN_BLOCK MiniportOpen; + KIRQL OldIrql; + PNDIS_PACKET SrcPacket; + PNDIS_BUFFER NdisBuffer; + NDIS_STATUS Status; + NDIS_PACKET TempPacket; + + MiniportOpen = (PNDIS_M_OPEN_BLOCK) NdisBindingHandle; + Miniport = MiniportOpen->MiniportHandle; + NdisBuffer = NULL; + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + ASSERT(MINIPORT_AT_DPC_LEVEL); + ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport)); + + // + // If this is encapsulated ethernet then we don't currently + // have the source packet from which to copy from. + // + + if ( MiniportOpen->UsingEthEncapsulation ) { + + // + // If this is not loopback then we need to create a + // temp NDIS_PACKET for the packet-to-packet copy. + // + + if ( !Miniport->LoopbackPacket ) { + + PUCHAR DataBuffer = (PUCHAR) ((PULONG) MacReceiveContext)[0]; + UINT DataLength = (UINT) ((PULONG) MacReceiveContext)[1]; + + // + // We'll always be in the scope of this function so we + // can use local stack space rather than allocating dynamic + // memory. + // + + SrcPacket = &TempPacket; // Use the local stack for packet store. + + NdisZeroMemory( + SrcPacket, + sizeof(NDIS_PACKET) + ); + + NdisAllocateBuffer( + &Status, // Status code. + &NdisBuffer, // NDIS buffer to chain onto the packet. + NULL, // On NT, this parameter is ignored. + DataBuffer, // The ethernet frame. + DataLength // The ethernet frame length. + ); + + NdisChainBufferAtFront(SrcPacket, NdisBuffer); + + } else { + + SrcPacket = Miniport->LoopbackPacket; + + ByteOffset += 3; // Skip fake arcnet header. + } + + // + // Skip the ethernet header. + // + + ByteOffset += 14; + + } else { + + SrcPacket = (PNDIS_PACKET) MacReceiveContext; + } + + // + // Now we can simply copy from the source packet to the + // destination packet. + // + + NdisCopyFromPacketToPacket( + DstPacket, // destination packet. + 0, // destination offset. + BytesToTransfer, // bytes to copy. + SrcPacket, // source packet. + ByteOffset, // source offset. + BytesTransferred // bytes copied. + ); + + // + // If we allocated an NDIS_BUFFER then we need to free it. We don't + // need to unchain the buffer from the packet since the packet is + // a local stack variable the will just get trashed anyway. + // + + if ( NdisBuffer != NULL ) { + + NdisFreeBuffer(NdisBuffer); + } + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + KeLowerIrql(OldIrql); + + return NDIS_STATUS_SUCCESS; +} + + +VOID +MiniportArcCopyFromBufferToPacket( + IN PCHAR Buffer, + IN UINT BytesToCopy, + IN PNDIS_PACKET Packet, + IN UINT Offset, + OUT PUINT BytesCopied + ) + +/*++ + +Routine Description: + + Copy from a buffer into an ndis packet. + +Arguments: + + Buffer - The packet to copy from. + + Offset - The offset from which to start the copy. + + BytesToCopy - The number of bytes to copy from the buffer. + + Packet - The destination of the copy. + + BytesCopied - The number of bytes actually copied. Will be less + than BytesToCopy if the packet is not large enough. + +Return Value: + + None + +--*/ + +{ + // + // Holds the count of the number of ndis buffers comprising the + // destination packet. + // + UINT DestinationBufferCount; + + // + // Points to the buffer into which we are putting data. + // + PNDIS_BUFFER DestinationCurrentBuffer; + + // + // Points to the location in Buffer from which we are extracting data. + // + PUCHAR SourceCurrentAddress; + + // + // Holds the virtual address of the current destination buffer. + // + PVOID DestinationVirtualAddress; + + // + // Holds the length of the current destination buffer. + // + UINT DestinationCurrentLength; + + // + // Keep a local variable of BytesCopied so we aren't referencing + // through a pointer. + // + UINT LocalBytesCopied = 0; + + + // + // Take care of boundary condition of zero length copy. + // + + *BytesCopied = 0; + if (!BytesToCopy) return; + + // + // Get the first buffer of the destination. + // + + NdisQueryPacket( + Packet, + NULL, + &DestinationBufferCount, + &DestinationCurrentBuffer, + NULL + ); + + // + // Could have a null packet. + // + + if (!DestinationBufferCount) return; + + NdisQueryBuffer( + DestinationCurrentBuffer, + &DestinationVirtualAddress, + &DestinationCurrentLength + ); + + // + // Set up the source address. + // + + SourceCurrentAddress = Buffer; + + + while (LocalBytesCopied < BytesToCopy) { + + // + // Check to see whether we've exhausted the current destination + // buffer. If so, move onto the next one. + // + + if (!DestinationCurrentLength) { + + NdisGetNextBuffer( + DestinationCurrentBuffer, + &DestinationCurrentBuffer + ); + + if (!DestinationCurrentBuffer) { + + // + // We've reached the end of the packet. We return + // with what we've done so far. (Which must be shorter + // than requested.) + // + + break; + + } + + NdisQueryBuffer( + DestinationCurrentBuffer, + &DestinationVirtualAddress, + &DestinationCurrentLength + ); + + continue; + + } + + // + // Try to get us up to the point to start the copy. + // + + if (Offset) { + + if (Offset > DestinationCurrentLength) { + + // + // What we want isn't in this buffer. + // + + Offset -= DestinationCurrentLength; + DestinationCurrentLength = 0; + continue; + + } else { + + DestinationVirtualAddress = (PCHAR)DestinationVirtualAddress + + Offset; + DestinationCurrentLength -= Offset; + Offset = 0; + + } + + } + + + // + // Copy the data. + // + + { + + // + // Holds the amount of data to move. + // + UINT AmountToMove; + + // + // Holds the amount desired remaining. + // + UINT Remaining = BytesToCopy - LocalBytesCopied; + + + AmountToMove = DestinationCurrentLength; + + AmountToMove = ((Remaining < AmountToMove)? + (Remaining):(AmountToMove)); + + NdisMoveFromMappedMemory( + DestinationVirtualAddress, + SourceCurrentAddress, + AmountToMove + ); + + SourceCurrentAddress += AmountToMove; + LocalBytesCopied += AmountToMove; + DestinationCurrentLength -= AmountToMove; + + } + + } + + *BytesCopied = LocalBytesCopied; + + +} + + +VOID +NdisMCancelTimer( + IN PNDIS_MINIPORT_TIMER Timer, + OUT PBOOLEAN TimerCancelled + ) +/*++ + +Routine Description: + + Cancels a timer. + +Arguments: + + Timer - The timer to cancel. + + TimerCancelled - TRUE if the timer was canceled, else FALSE. + +Return Value: + + None + +--*/ +{ + *TimerCancelled = KeCancelTimer(&((((PNDIS_TIMER)(Timer))->Timer))); +} + + +ULONG +NdisMReadDmaCounter( + IN NDIS_HANDLE MiniportDmaHandle + ) +/*++ + +Routine Description: + + Reads the current value of the dma counter + +Arguments: + + MiniportDmaHandle - Handle for the DMA transfer. + +Return Value: + + None + +--*/ + +{ + return HalReadDmaCounter(((PNDIS_DMA_BLOCK)(MiniportDmaHandle))->SystemAdapterObject); +} + + +#if !defined(BUILD_FOR_3_1) +VOID +NdisBugcheckHandler( + IN PNDIS_WRAPPER_CONTEXT WrapperContext, + IN ULONG Size + ) +/*++ + +Routine Description: + + This routine is called when a bugcheck occurs in the system. + +Arguments: + + Buffer -- Ndis wrapper context. + + Size -- Size of wrapper context + +Return Value: + + Void. + +--*/ +{ + if ( Size == sizeof(NDIS_WRAPPER_CONTEXT) ) { + + if ( WrapperContext->ShutdownHandler != NULL ) { + + WrapperContext->ShutdownHandler(WrapperContext->ShutdownContext); + } + } +} +#endif + +VOID +NdisMRegisterAdapterShutdownHandler( + IN NDIS_HANDLE MiniportHandle, + IN PVOID ShutdownContext, + IN ADAPTER_SHUTDOWN_HANDLER ShutdownHandler + ) +/*++ + +Routine Description: + + Deregisters an NDIS adapter. + +Arguments: + + MiniportHandle - The miniport. + + ShutdownHandler - The Handler for the Adapter, to be called on shutdown. + +Return Value: + + none. + +--*/ +{ + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportHandle; + PNDIS_WRAPPER_CONTEXT WrapperContext = Miniport->WrapperContext; + + if (WrapperContext->ShutdownHandler == NULL) { + + // + // Store information + // + + WrapperContext->ShutdownHandler = ShutdownHandler; + WrapperContext->ShutdownContext = ShutdownContext; + +#if !defined(BUILD_FOR_3_1) + // + // Register our shutdown handler for a bugcheck. (Note that we are + // already registered for shutdown notification.) + // + + KeInitializeCallbackRecord(&WrapperContext->BugcheckCallbackRecord); + + KeRegisterBugCheckCallback( + &WrapperContext->BugcheckCallbackRecord, // callback record. + (PVOID) NdisBugcheckHandler, // callback routine. + (PVOID) WrapperContext, // free form buffer. + sizeof(NDIS_WRAPPER_CONTEXT), // buffer size. + "Ndis miniport" // component id. + ); +#endif + } +} + + +VOID +NdisMDeregisterAdapterShutdownHandler( + IN NDIS_HANDLE MiniportHandle + ) +/*++ + +Routine Description: + +Arguments: + + MiniportHandle - The miniport. + +Return Value: + + None. + +--*/ +{ + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportHandle; + PNDIS_WRAPPER_CONTEXT WrapperContext = Miniport->WrapperContext; + + // + // Clear information + // + + if ( WrapperContext->ShutdownHandler != NULL ) { + +#if !defined(BUILD_FOR_3_1) + KeDeregisterBugCheckCallback(&WrapperContext->BugcheckCallbackRecord); +#endif + + WrapperContext->ShutdownHandler = NULL; + } +} + +#if !defined(BUILD_FOR_3_1) + +NDIS_STATUS +NdisMPciAssignResources( + IN NDIS_HANDLE MiniportHandle, + IN ULONG SlotNumber, + OUT PNDIS_RESOURCE_LIST *AssignedResources + ) +/*++ + +Routine Description: + + This routine uses the Hal to assign a set of resources to a PCI + device. + +Arguments: + + MiniportHandle - The miniport. + + SlotNumber - Slot number of the device. + + AssignedResources - The returned resources. + +Return Value: + + Status of the operation + +--*/ +{ + NTSTATUS NtStatus; + PCM_RESOURCE_LIST AllocatedResources = NULL; + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportHandle; + + NtStatus = HalAssignSlotResources ( + (PUNICODE_STRING)(Miniport->DriverHandle->NdisDriverInfo->NdisWrapperConfigurationHandle), + NULL, + Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver, + Miniport->DeviceObject, + Miniport->BusType, + Miniport->BusNumber, + SlotNumber, + &AllocatedResources + ); + + if (NtStatus != STATUS_SUCCESS) { + *AssignedResources = NULL; + return(NDIS_STATUS_FAILURE); + } + + // + // Store resources into the driver wide block + // + ((PNDIS_WRAPPER_CONTEXT)Miniport->WrapperContext)->AssignedSlotResources = AllocatedResources; + + *AssignedResources = &(AllocatedResources->List[0].PartialResourceList); + + return(NDIS_STATUS_SUCCESS); + +} + +#else // !defined(BUILD_FOR_3_1) + +NDIS_STATUS +NdisMPciAssignResources( + IN NDIS_HANDLE MiniportHandle, + IN ULONG SlotNumber, + OUT PNDIS_RESOURCE_LIST *AssignedResources + ) +{ + return NDIS_STATUS_FAILURE; +} + +#endif // else !defined(BUILD_FOR_3_1) + +NDIS_STATUS +NdisMQueryAdapterResources( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE WrapperConfigurationContext, + OUT PNDIS_RESOURCE_LIST ResourceList, + IN OUT PUINT BufferSize + ) +{ + return NDIS_STATUS_NOT_SUPPORTED; +} + diff --git a/private/ntos/ndis/ndis30/minisub.c b/private/ntos/ndis/ndis30/minisub.c new file mode 100644 index 000000000..4454cd129 --- /dev/null +++ b/private/ntos/ndis/ndis30/minisub.c @@ -0,0 +1,280 @@ +/*++ +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + miniport.c + +Abstract: + + NDIS wrapper functions + +Author: + + Sean Selitrennikoff (SeanSe) 05-Oct-93 + +Environment: + + Kernel mode, FSD + +Revision History: + +--*/ + +#include "precomp.h" +#pragma hdrstop + +#undef NdisAllocateSpinLock +#undef NdisFreeSpinLock +#undef NdisAcquireSpinLock +#undef NdisReleaseSpinLock +#undef NdisDprAcquireSpinLock +#undef NdisDprReleaseSpinLock +#undef NdisFreeBuffer +#undef NdisQueryBuffer +#undef NdisQueryBufferOffset +#undef NDIS_BUFFER_TO_SPAN_PAGES +#undef NdisGetBufferPhysicalArraySize +#undef NdisEqualString +#undef NdisMStartBufferPhysicalMapping +#undef NdisMCompleteBufferPhysicalMapping + +VOID +NdisAllocateSpinLock( + IN PNDIS_SPIN_LOCK SpinLock + ); + +VOID +NdisFreeSpinLock( + IN PNDIS_SPIN_LOCK SpinLock + ); + +VOID +NdisAcquireSpinLock( + IN PNDIS_SPIN_LOCK SpinLock + ); + +VOID +NdisReleaseSpinLock( + IN PNDIS_SPIN_LOCK SpinLock + ); + +VOID +NdisDprAcquireSpinLock( + IN PNDIS_SPIN_LOCK SpinLock + ); + +VOID +NdisDprReleaseSpinLock( + IN PNDIS_SPIN_LOCK SpinLock + ); + +VOID +NdisFreeBuffer( + IN PNDIS_BUFFER Buffer + ); + +VOID +NdisQueryBuffer( + IN PNDIS_BUFFER Buffer, + OUT PVOID *VirtualAddress OPTIONAL, + OUT PUINT Length + ); + +VOID +NdisQueryBufferOffset( + IN PNDIS_BUFFER Buffer, + OUT PUINT Offset, + OUT PUINT Length + ); + +ULONG +NDIS_BUFFER_TO_SPAN_PAGES( + IN PNDIS_BUFFER Buffer + ); + +VOID +NdisGetBufferPhysicalArraySize( + IN PNDIS_BUFFER Buffer, + OUT PUINT ArraySize + ); + +BOOLEAN +NdisEqualString( + IN PNDIS_STRING String1, + IN PNDIS_STRING String2, + IN BOOLEAN CaseInsensitive + ); + +VOID +NdisMStartBufferPhysicalMapping( + IN NDIS_HANDLE MiniportAdapterHandle, + IN PNDIS_BUFFER Buffer, + IN ULONG PhysicalMapRegister, + IN BOOLEAN WriteToDevice, + OUT PNDIS_PHYSICAL_ADDRESS_UNIT PhysicalAddressArray, + OUT PUINT ArraySize + ); + +VOID +NdisMCompleteBufferPhysicalMapping( + IN NDIS_HANDLE MiniportAdapterHandle, + IN PNDIS_BUFFER Buffer, + IN ULONG PhysicalMapRegister + ); + + +VOID +NdisAllocateSpinLock( + IN PNDIS_SPIN_LOCK SpinLock + ) +{ + KeInitializeSpinLock(&SpinLock->SpinLock); +} + +VOID +NdisFreeSpinLock( + IN PNDIS_SPIN_LOCK SpinLock + ) +{ + UNREFERENCED_PARAMETER (SpinLock); +} + +VOID +NdisAcquireSpinLock( + IN PNDIS_SPIN_LOCK SpinLock + ) +{ + KeAcquireSpinLock(&SpinLock->SpinLock, &SpinLock->OldIrql); +} + +VOID +NdisReleaseSpinLock( + IN PNDIS_SPIN_LOCK SpinLock + ) +{ + KeReleaseSpinLock(&SpinLock->SpinLock, SpinLock->OldIrql); +} + +VOID +NdisDprAcquireSpinLock( + IN PNDIS_SPIN_LOCK SpinLock + ) +{ + KeAcquireSpinLockAtDpcLevel(&SpinLock->SpinLock); + SpinLock->OldIrql = DISPATCH_LEVEL; +} + +VOID +NdisDprReleaseSpinLock( + IN PNDIS_SPIN_LOCK SpinLock + ) +{ + KeReleaseSpinLockFromDpcLevel(&SpinLock->SpinLock); +} +VOID +NdisFreeBuffer( + IN PNDIS_BUFFER Buffer + ) +{ + IoFreeMdl(Buffer); +} + +VOID +NdisQueryBuffer( + IN PNDIS_BUFFER Buffer, + OUT PVOID *VirtualAddress OPTIONAL, + OUT PUINT Length + ) +{ + if ( ARGUMENT_PRESENT(VirtualAddress) ) { + *VirtualAddress = MmGetSystemAddressForMdl(Buffer); + } + *Length = MmGetMdlByteCount(Buffer); +} + +VOID +NdisQueryBufferOffset( + IN PNDIS_BUFFER Buffer, + OUT PUINT Offset, + OUT PUINT Length + ) +{ + *Offset = MmGetMdlByteOffset(Buffer); + *Length = MmGetMdlByteCount(Buffer); +} + +ULONG +NDIS_BUFFER_TO_SPAN_PAGES( + IN PNDIS_BUFFER Buffer + ) +{ + if (MmGetMdlByteCount(Buffer) == 0) { + return 1; + } + return COMPUTE_PAGES_SPANNED( + MmGetMdlVirtualAddress(Buffer), + MmGetMdlByteCount(Buffer) + ); +} + +VOID +NdisGetBufferPhysicalArraySize( + IN PNDIS_BUFFER Buffer, + OUT PUINT ArraySize + ) +{ + if (MmGetMdlByteCount(Buffer) == 0) { + *ArraySize = 1; + } else { + *ArraySize = COMPUTE_PAGES_SPANNED( + MmGetMdlVirtualAddress(Buffer), + MmGetMdlByteCount(Buffer) + ); + } +} + +BOOLEAN +NdisEqualString( + IN PNDIS_STRING String1, + IN PNDIS_STRING String2, + IN BOOLEAN CaseInsensitive + ) +{ + return RtlEqualUnicodeString(String1, String2, CaseInsensitive); +} + +VOID +NdisMStartBufferPhysicalMapping( + IN NDIS_HANDLE MiniportAdapterHandle, + IN PNDIS_BUFFER Buffer, + IN ULONG PhysicalMapRegister, + IN BOOLEAN WriteToDevice, + OUT PNDIS_PHYSICAL_ADDRESS_UNIT PhysicalAddressArray, + OUT PUINT ArraySize + ) +{ + NdisMStartBufferPhysicalMappingMacro( + MiniportAdapterHandle, + Buffer, + PhysicalMapRegister, + WriteToDevice, + PhysicalAddressArray, + ArraySize + ); +} + +VOID +NdisMCompleteBufferPhysicalMapping( + IN NDIS_HANDLE MiniportAdapterHandle, + IN PNDIS_BUFFER Buffer, + IN ULONG PhysicalMapRegister + ) +{ + NdisMCompleteBufferPhysicalMappingMacro( + MiniportAdapterHandle, + Buffer, + PhysicalMapRegister + ); +} + diff --git a/private/ntos/ndis/ndis30/ndis.prf b/private/ntos/ndis/ndis30/ndis.prf new file mode 100644 index 000000000..cf7a25416 --- /dev/null +++ b/private/ntos/ndis/ndis30/ndis.prf @@ -0,0 +1,102 @@ +NdisMTimerDpc@16 +NDIS_BUFFER_TO_SPAN_PAGES@4 +NdisMSendComplete@12 +NdisMSend@8 +NdisMIsr@8 +NdisSetTimer@8 +EthFilterDprIndicateReceiveComplete@4 +@MiniportProcessDeferred@4 +EthFilterDprIndicateReceive@32 +NdisMDpc@16 +@MiniportStartSends@4 +NdisMWakeUpDpc@16 +NdisMCompleteBufferPhysicalMapping@12 +NdisMStartBufferPhysicalMapping@24 +NdisQueryBuffer@12 +@InterlockedIncrement@4 +@MiniportSyncSend@8 +@InterlockedDecrement@4 +_allmul +NdisMSendResourcesAvailable@4 +NdisAllocateBuffer@20 +NdisUnchainBufferAtFront@8 +NdisMTransferDataSync@24 +MiniportDereferencePackage@0 +NdisMRegisterMiniport@12 +NdisMacDereferencePackage@0 +EthDereferencePackage@0 +NdisMacInitializePackage@0 +NdisInitDereferencePackage@0 +NdisInitializeTimer@12 +NdisAllocateSharedMemory@20 +NdisInitReferencePackage@0 +EthInitializePackage@0 +NdisInitInitializePackage@0 +EthReferencePackage@0 +MiniportReferencePackage@0 +NdisUnmapFile@4 +WrapperCheckRoute@24 +NdisOpenFile@24 +NdisCloseFile@4 +NdisMapFile@12 +NdisAllocateBufferPool@12 +FddiDeleteFilter@4 +FddiDereferencePackage@0 +FddiReferencePackage@0 +FddiInitializePackage@0 +TrDeleteFilter@4 +TrDereferencePackage@0 +TrReferencePackage@0 +ArcDeleteFilter@4 +ArcInitializePackage@0 +ArcReferencePackage@0 +ArcDereferencePackage@0 +NdisAllocateMemory@20 +NdisFreeMemory@12 +NdisInitialInit@4 +MiniportOpenAdapter@48 +NdisRegisterProtocol@16 +NdisOpenAdapter@44 +NdisFreeBufferPool@4 +TrInitializePackage@0 +NdisAllocationExecutionRoutine@16 +NdisMacReferencePackage@0 +MiniportInitializePackage@0 +EthDeleteFilter@4 +NdisReferenceRef@4 +NdisInitializeRef@4 +memmove +NdisQueueOpenOnProtocol@8 +NdisCreateIrpHandler@8 +NdisSuccessIrpHandler@8 +WrapperSaveLinkage@24 +NdisMRegisterAdapterShutdownHandler@12 +EthNoteFilterOpenAdapter@16 +EthFilterAdjust@20 +NdisMAllocateSharedMemory@20 +NdisMAllocateMapRegisters@20 +NdisInitializeWrapper@16 +NdisCloseConfiguration@4 +NdisReadConfiguration@20 +NdisMSetAttributes@16 +NdisInitializeInterrupt@40 +NdisOpenConfiguration@12 +NdisReadNetworkAddress@16 +NdisCallDriverAddAdapter@4 +WrapperSaveParameters@24 +NdisMRegisterInterrupt@28 +MiniportDoRequests@4 +ArcCreateFilter@24 +NdisMQueryInformationComplete@8 +NdisMSetInformationComplete@8 +NdisMRequest@8 +NdisMChangeClass@20 +NdisMInitializeTimer@16 +MiniportAdjustMaximumLookahead@4 +NdisMDpcTimer@16 +NdisQueueMiniportOnDriver@8 +FddiCreateFilter@36 +TrCreateFilter@28 +EthCreateFilter@28 +NdisMRegisterIoPortRange@16 +NdisReadEisaSlotInformation@16 diff --git a/private/ntos/ndis/ndis30/ndis.rc b/private/ntos/ndis/ndis30/ndis.rc new file mode 100644 index 000000000..3d5b057d2 --- /dev/null +++ b/private/ntos/ndis/ndis30/ndis.rc @@ -0,0 +1,39 @@ +#include <windows.h> +#include <ntverp.h> + +/*-----------------------------------------------*/ +/* the following lines are specific to this file */ +/*-----------------------------------------------*/ + +/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR + * and VER_INTERNALNAME_STR must be defined before including COMMON.VER + * The strings don't need a '\0', since common.ver has them. + */ +#define VER_FILETYPE VFT_DRV +/* possible values: VFT_UNKNOWN + VFT_APP + VFT_DLL + VFT_DRV + VFT_FONT + VFT_VXD + VFT_STATIC_LIB +*/ +#define VER_FILESUBTYPE VFT2_DRV_NETWORK +/* possible values VFT2_UNKNOWN + VFT2_DRV_PRINTER + VFT2_DRV_KEYBOARD + VFT2_DRV_LANGUAGE + VFT2_DRV_DISPLAY + VFT2_DRV_MOUSE + VFT2_DRV_NETWORK + VFT2_DRV_SYSTEM + VFT2_DRV_INSTALLABLE + VFT2_DRV_SOUND + VFT2_DRV_COMM +*/ +#define VER_FILEDESCRIPTION_STR "NDIS 3.0 wrapper driver" +#define VER_INTERNALNAME_STR "NDIS.SYS" +#define VER_ORIGINALFILENAME_STR "NDIS.SYS" + +#include "common.ver" + diff --git a/private/ntos/ndis/ndis30/ndis.src b/private/ntos/ndis/ndis30/ndis.src new file mode 100644 index 000000000..bdbfdff44 --- /dev/null +++ b/private/ntos/ndis/ndis30/ndis.src @@ -0,0 +1,185 @@ +NAME NDIS.SYS + +DESCRIPTION 'NDIS.SYS' + +EXPORTS + ArcFilterDprIndicateReceive + ArcFilterDprIndicateReceiveComplete + EthChangeFilterAddresses + EthCreateFilter + EthDeleteFilter + EthDeleteFilterOpenAdapter + EthFilterAdjust + EthFilterDprIndicateReceive + EthFilterDprIndicateReceiveComplete + EthFilterIndicateReceive + EthFilterIndicateReceiveComplete + EthNoteFilterOpenAdapter + EthNumberOfOpenFilterAddresses + EthQueryGlobalFilterAddresses + EthQueryOpenFilterAddresses + EthShouldAddressLoopBack + FddiChangeFilterLongAddresses + FddiChangeFilterShortAddresses + FddiCreateFilter + FddiDeleteFilter + FddiDeleteFilterOpenAdapter + FddiFilterAdjust + FddiFilterDprIndicateReceive + FddiFilterDprIndicateReceiveComplete + FddiFilterIndicateReceive + FddiFilterIndicateReceiveComplete + FddiNoteFilterOpenAdapter + FddiNumberOfOpenFilterLongAddresses + FddiNumberOfOpenFilterShortAddresses + FddiQueryGlobalFilterLongAddresses + FddiQueryGlobalFilterShortAddresses + FddiQueryOpenFilterLongAddresses + FddiQueryOpenFilterShortAddresses + FddiShouldAddressLoopBack + NdisAllocateBuffer + NdisAllocateBufferPool + NdisAllocateDmaChannel + NdisAllocateMemory + NdisAllocatePacket + NdisAllocatePacketPool + NdisAllocateSharedMemory + NdisCloseAdapter + NdisCloseConfiguration + NdisCloseFile + NdisCloseRef + NdisCompleteCloseAdapter + NdisCompleteDmaTransfer + NdisCompleteOpenAdapter + NdisCompleteQueryStatistics + NdisCopyBuffer + NdisCopyFromPacketToPacket + NdisDereferenceRef +#if ALPHA + NdisCreateLookaheadBufferFromSharedMemory + NdisDestroyLookaheadBufferFromSharedMemory +#endif + NdisDeregisterAdapter + NdisDeregisterAdapterShutdownHandler + NdisDeregisterMac + NdisDeregisterProtocol + NdisFinishOpen + NdisFreeBufferPool + NdisFreeDmaChannel + NdisFreeMemory + NdisFreeSharedMemory + NdisImmediateReadPciSlotInformation + NdisImmediateReadPortUchar + NdisImmediateReadPortUshort + NdisImmediateReadPortUlong + NdisImmediateReadSharedMemory + NdisImmediateWritePciSlotInformation + NdisImmediateWritePortUchar + NdisImmediateWritePortUshort + NdisImmediateWritePortUlong + NdisImmediateWriteSharedMemory + NdisInitializeInterrupt + NdisInitializePacketPool + NdisInitializeRef + NdisInitializeTimer + NdisInitializeWrapper + NdisMapFile + NdisMapIoSpace + NdisOpenAdapter + NdisOpenConfiguration + NdisOpenFile + NdisPciAssignResources + NdisReadConfiguration + NdisReadBindingInformation + NdisReadEisaSlotInformation + NdisReadEisaSlotInformationEx + NdisReadMcaPosInformation + NdisReadNetworkAddress + NdisReadPciSlotInformation + NdisReferenceRef + NdisRegisterAdapter + NdisRegisterAdapterShutdownHandler + NdisRegisterMac + NdisRegisterProtocol + NdisReleaseAdapterResources + NdisRemoveInterrupt + NdisSetTimer + NdisSetupDmaTransfer + NdisTerminateWrapper + NdisUnchainBufferAtFront + NdisUnchainBufferAtBack + NdisUnmapFile + NdisUpdateSharedMemory + NdisWriteErrorLogEntry + NdisWritePciSlotInformation + + NdisMAllocateMapRegisters + NdisMCancelTimer + NdisMDeregisterIoPortRange + NdisMFreeMapRegisters + NdisMIndicateStatus + NdisMIndicateStatusComplete + NdisMInitializeTimer + NdisMQueryInformationComplete + NdisMRegisterIoPortRange + NdisMRegisterMiniport + NdisMResetComplete + NdisMSendComplete + NdisMSendResourcesAvailable + NdisMSetAttributes + NdisMSetInformationComplete + NdisMTransferDataComplete + + NdisAllocateSpinLock + NdisFreeSpinLock + NdisAcquireSpinLock + NdisReleaseSpinLock + NdisDprAcquireSpinLock + NdisDprReleaseSpinLock + NdisFreeBuffer + NdisQueryBuffer + NdisQueryBufferOffset + NDIS_BUFFER_TO_SPAN_PAGES + NdisGetBufferPhysicalArraySize + NdisEqualString + + NdisMMapIoSpace + NdisMUnmapIoSpace + NdisMRegisterInterrupt + NdisMDeregisterInterrupt + NdisMSynchronizeWithInterrupt + NdisMAllocateSharedMemory + NdisMFreeSharedMemory + NdisMRegisterDmaChannel + NdisMDeregisterDmaChannel + NdisMReadDmaCounter + + TrChangeFunctionalAddress + TrChangeGroupAddress + TrCreateFilter + TrDeleteFilter + TrDeleteFilterOpenAdapter + TrFilterAdjust + TrFilterDprIndicateReceive + TrFilterDprIndicateReceiveComplete + TrFilterIndicateReceive + TrFilterIndicateReceiveComplete + TrNoteFilterOpenAdapter + TrShouldAddressLoopBack + + NdisMWanSendComplete + NdisMWanIndicateReceive + NdisMWanIndicateReceiveComplete + + NdisMStartBufferPhysicalMapping + NdisMCompleteBufferPhysicalMapping + NdisSystemProcessorCount + NdisWriteConfiguration + + NdisMRegisterAdapterShutdownHandler + NdisMDeregisterAdapterShutdownHandler + + NdisMPciAssignResources + NdisOverrideBusNumber + + NdisMQueryAdapterResources diff --git a/private/ntos/ndis/ndis30/ndismac.h b/private/ntos/ndis/ndis30/ndismac.h new file mode 100644 index 000000000..a5395883a --- /dev/null +++ b/private/ntos/ndis/ndis30/ndismac.h @@ -0,0 +1,1218 @@ +typedef +BOOLEAN +(*PNDIS_INTERRUPT_SERVICE) ( + IN PVOID InterruptContext + ); + +typedef +VOID +(*PNDIS_DEFERRED_PROCESSING) ( + IN PVOID SystemSpecific1, + IN PVOID InterruptContext, + IN PVOID SystemSpecific2, + IN PVOID SystemSpecific3 + ); + + +typedef struct _NDIS_INTERRUPT { + PKINTERRUPT InterruptObject; + KSPIN_LOCK DpcCountLock; + PNDIS_INTERRUPT_SERVICE MacIsr; // Pointer to Mac ISR routine + PNDIS_DEFERRED_PROCESSING MacDpc; // Pointer to Mac DPC routine + KDPC InterruptDpc; + PVOID InterruptContext; // Pointer to context for calling + // adapters ISR and DPC. + UCHAR DpcCount; + BOOLEAN Removing; // TRUE if removing interrupt + + // + // This is used to tell when all the Dpcs for the adapter are completed. + // + KEVENT DpcsCompletedEvent; + +} NDIS_INTERRUPT, *PNDIS_INTERRUPT; + +// +// Ndis Adapter Information +// + +typedef +NDIS_STATUS +(*PNDIS_ACTIVATE_CALLBACK) ( + IN NDIS_HANDLE NdisAdatperHandle, + IN NDIS_HANDLE MacAdapterContext, + IN ULONG DmaChannel + ); + +typedef struct _NDIS_PORT_DESCRIPTOR { + ULONG InitialPort; + ULONG NumberOfPorts; + PVOID *PortOffset; +} NDIS_PORT_DESCRIPTOR, *PNDIS_PORT_DESCRIPTOR; + +typedef struct _NDIS_ADAPTER_INFORMATION { + ULONG DmaChannel; + BOOLEAN Master; + BOOLEAN Dma32BitAddresses; + PNDIS_ACTIVATE_CALLBACK ActivateCallback; + NDIS_INTERFACE_TYPE AdapterType; + ULONG PhysicalMapRegistersNeeded; + ULONG MaximumPhysicalMapping; + ULONG NumberOfPortDescriptors; + NDIS_PORT_DESCRIPTOR PortDescriptors[1]; // as many as needed +} NDIS_ADAPTER_INFORMATION, *PNDIS_ADAPTER_INFORMATION; + +// +// Function types for NDIS_MAC_CHARACTERISTICS +// + +typedef +NDIS_STATUS +(*OPEN_ADAPTER_HANDLER) ( + OUT PNDIS_STATUS OpenErrorStatus, + OUT NDIS_HANDLE *MacBindingHandle, + OUT PUINT SelectedMediumIndex, + IN PNDIS_MEDIUM MediumArray, + IN UINT MediumArraySize, + IN NDIS_HANDLE NdisBindingContext, + IN NDIS_HANDLE MacAdapterContext, + IN UINT OpenOptions, + IN PSTRING AddressingInformation OPTIONAL + ); + +typedef +NDIS_STATUS +(*CLOSE_ADAPTER_HANDLER) ( + IN NDIS_HANDLE MacBindingHandle + ); + +typedef +NDIS_STATUS +(*SEND_HANDLER) ( + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_PACKET Packet + ); + +typedef +NDIS_STATUS +(*TRANSFER_DATA_HANDLER) ( + IN NDIS_HANDLE MacBindingHandle, + IN NDIS_HANDLE MacReceiveContext, + IN UINT ByteOffset, + IN UINT BytesToTransfer, + OUT PNDIS_PACKET Packet, + OUT PUINT BytesTransferred + ); + +typedef +NDIS_STATUS +(*RESET_HANDLER) ( + IN NDIS_HANDLE MacBindingHandle + ); + +typedef +NDIS_STATUS +(*REQUEST_HANDLER) ( + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest + ); + +typedef +NDIS_STATUS +(*QUERY_GLOBAL_STATISTICS_HANDLER) ( + IN NDIS_HANDLE MacAdapterContext, + IN PNDIS_REQUEST NdisRequest + ); + +typedef +VOID +(*UNLOAD_MAC_HANDLER) ( + IN NDIS_HANDLE MacMacContext + ); + +typedef +NDIS_STATUS +(*ADD_ADAPTER_HANDLER) ( + IN NDIS_HANDLE MacMacContext, + IN NDIS_HANDLE WrapperConfigurationContext, + IN PNDIS_STRING AdapterName + ); + +typedef +VOID +(*REMOVE_ADAPTER_HANDLER) ( + IN NDIS_HANDLE MacAdapterContext + ); + + +typedef struct _NDIS_MAC_CHARACTERISTICS { + UCHAR MajorNdisVersion; + UCHAR MinorNdisVersion; + UINT Reserved; + OPEN_ADAPTER_HANDLER OpenAdapterHandler; + CLOSE_ADAPTER_HANDLER CloseAdapterHandler; + SEND_HANDLER SendHandler; + TRANSFER_DATA_HANDLER TransferDataHandler; + RESET_HANDLER ResetHandler; + REQUEST_HANDLER RequestHandler; + QUERY_GLOBAL_STATISTICS_HANDLER QueryGlobalStatisticsHandler; + UNLOAD_MAC_HANDLER UnloadMacHandler; + ADD_ADAPTER_HANDLER AddAdapterHandler; + REMOVE_ADAPTER_HANDLER RemoveAdapterHandler; + NDIS_STRING Name; +} NDIS_MAC_CHARACTERISTICS, *PNDIS_MAC_CHARACTERISTICS; + + +// +// Function types for NDIS_PROTOCOL_CHARACTERISTICS +// +// + +typedef +VOID +(*OPEN_ADAPTER_COMPLETE_HANDLER) ( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_STATUS Status, + IN NDIS_STATUS OpenErrorStatus + ); + +typedef +VOID +(*CLOSE_ADAPTER_COMPLETE_HANDLER) ( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_STATUS Status + ); + +typedef +VOID +(*RESET_COMPLETE_HANDLER) ( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_STATUS Status + ); + +typedef +VOID +(*REQUEST_COMPLETE_HANDLER) ( + IN NDIS_HANDLE ProtocolBindingContext, + IN PNDIS_REQUEST NdisRequest, + IN NDIS_STATUS Status + ); + +typedef +VOID +(*STATUS_HANDLER) ( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_STATUS GeneralStatus, + IN PVOID StatusBuffer, + IN UINT StatusBufferSize + ); + +typedef +VOID +(*STATUS_COMPLETE_HANDLER) ( + IN NDIS_HANDLE ProtocolBindingContext + ); + +typedef struct _NDIS_PROTOCOL_CHARACTERISTICS { + UCHAR MajorNdisVersion; + UCHAR MinorNdisVersion; + UINT Reserved; + OPEN_ADAPTER_COMPLETE_HANDLER OpenAdapterCompleteHandler; + CLOSE_ADAPTER_COMPLETE_HANDLER CloseAdapterCompleteHandler; + SEND_COMPLETE_HANDLER SendCompleteHandler; + TRANSFER_DATA_COMPLETE_HANDLER TransferDataCompleteHandler; + RESET_COMPLETE_HANDLER ResetCompleteHandler; + REQUEST_COMPLETE_HANDLER RequestCompleteHandler; + RECEIVE_HANDLER ReceiveHandler; + RECEIVE_COMPLETE_HANDLER ReceiveCompleteHandler; + STATUS_HANDLER StatusHandler; + STATUS_COMPLETE_HANDLER StatusCompleteHandler; + NDIS_STRING Name; +} NDIS_PROTOCOL_CHARACTERISTICS, *PNDIS_PROTOCOL_CHARACTERISTICS; + +// +// MAC specific considerations. +// + +struct _NDIS_WRAPPER_HANDLE { + + // + // These store the PDRIVER_OBJECT that + // the MAC passes to NdisInitializeWrapper until it can be + // used by NdisRegisterMac and NdisTerminateWrapper. + // + + PDRIVER_OBJECT NdisWrapperDriver; + + HANDLE NdisWrapperConfigurationHandle; + +}; + + + + +// +// one of these per MAC +// + +struct _NDIS_MAC_BLOCK { + PNDIS_ADAPTER_BLOCK AdapterQueue; // queue of adapters for this MAC + NDIS_HANDLE MacMacContext; // Context for calling MACUnload and + // MACAddAdapter. + + REFERENCE Ref; // contains spinlock for AdapterQueue + UINT Length; // of this NDIS_MAC_BLOCK structure + NDIS_MAC_CHARACTERISTICS MacCharacteristics; // handler addresses + PNDIS_WRAPPER_HANDLE NdisMacInfo; // Mac information. + PNDIS_MAC_BLOCK NextMac; + KEVENT AdaptersRemovedEvent; // used to find when all adapters are gone. + BOOLEAN Unloading; // TRUE if unloading + + // + // Extensions added for NT 3.5 support + // + PCM_RESOURCE_LIST PciAssignedResources; +}; + +// +// one of these per adapter registered on a MAC +// + +struct _NDIS_ADAPTER_BLOCK { + PDEVICE_OBJECT DeviceObject; // created by NdisRegisterAdapter + PNDIS_MAC_BLOCK MacHandle; // pointer to our MAC block + NDIS_HANDLE MacAdapterContext; // context when calling MacOpenAdapter + NDIS_STRING AdapterName; // how NdisOpenAdapter refers to us + PNDIS_OPEN_BLOCK OpenQueue; // queue of opens for this adapter + PNDIS_ADAPTER_BLOCK NextAdapter; // used by MAC's AdapterQueue + REFERENCE Ref; // contains spinlock for OpenQueue + BOOLEAN BeingRemoved; // TRUE if adapter is being removed + + // + // Resource information + // + PCM_RESOURCE_LIST Resources; + + // + // Obsolete field. + // + ULONG NotUsed; + + // + // Wrapper context. + // + PVOID WrapperContext; + + // + // contains adapter information + // + ULONG BusNumber; + NDIS_INTERFACE_TYPE BusType; + ULONG ChannelNumber; + NDIS_INTERFACE_TYPE AdapterType; + BOOLEAN Master; + ULONG PhysicalMapRegistersNeeded; + ULONG MaximumPhysicalMapping; + ULONG InitialPort; + ULONG NumberOfPorts; + + // + // Holds the mapping for ports, if needed. + // + PUCHAR InitialPortMapping; + + // + // TRUE if InitialPortMapping was mapped with NdisMapIoSpace. + // + BOOLEAN InitialPortMapped; + + // + // This is the offset added to the port passed to NdisXXXPort to + // get to the real value to be passed to the NDIS_XXX_PORT macros. + // It equals InitialPortMapping - InitialPort; that is, the + // mapped "address" of port 0, even if we didn't actually + // map port 0. + // + PUCHAR PortOffset; + + // + // Holds the map registers for this adapter. + // + PMAP_REGISTER_ENTRY MapRegisters; + + // + // These two are used temporarily while allocating + // the map registers. + // + KEVENT AllocationEvent; + UINT CurrentMapRegister; + PADAPTER_OBJECT SystemAdapterObject; +}; + +// +// one of these per protocol registered +// + +struct _NDIS_PROTOCOL_BLOCK { + PNDIS_OPEN_BLOCK OpenQueue; // queue of opens for this protocol + REFERENCE Ref; // contains spinlock for OpenQueue + UINT Length; // of this NDIS_PROTOCOL_BLOCK struct + NDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics; // handler addresses +}; + +// +// one of these per open on an adapter/protocol +// + +struct _NDIS_OPEN_BLOCK { + PNDIS_MAC_BLOCK MacHandle; // pointer to our MAC + NDIS_HANDLE MacBindingHandle; // context when calling MacXX funcs + PNDIS_ADAPTER_BLOCK AdapterHandle; // pointer to our adapter + PNDIS_PROTOCOL_BLOCK ProtocolHandle; // pointer to our protocol + NDIS_HANDLE ProtocolBindingContext; // context when calling ProtXX funcs + PNDIS_OPEN_BLOCK AdapterNextOpen; // used by adapter's OpenQueue + PNDIS_OPEN_BLOCK ProtocolNextOpen; // used by protocol's OpenQueue + PFILE_OBJECT FileObject; // created by operating system + BOOLEAN Closing; // TRUE when removing this struct + NDIS_HANDLE CloseRequestHandle; // 0 indicates an internal close + NDIS_SPIN_LOCK SpinLock; // guards Closing + + // + // These are optimizations for getting to MAC routines. They are not + // necessary, but are here to save a dereference through the MAC block. + // + + SEND_HANDLER SendHandler; + TRANSFER_DATA_HANDLER TransferDataHandler; + + // + // These are optimizations for getting to PROTOCOL routines. They are not + // necessary, but are here to save a dereference through the PROTOCOL block. + // + + SEND_COMPLETE_HANDLER SendCompleteHandler; + TRANSFER_DATA_COMPLETE_HANDLER TransferDataCompleteHandler; + RECEIVE_HANDLER ReceiveHandler; + RECEIVE_COMPLETE_HANDLER ReceiveCompleteHandler; + + // + // Extentions to the OPEN_BLOCK since Product 1. + // + RECEIVE_HANDLER PostNt31ReceiveHandler; + RECEIVE_COMPLETE_HANDLER PostNt31ReceiveCompleteHandler; + PNDIS_OPEN_BLOCK NextGlobalOpen; + +}; + +// +// Routines to access packet flags +// + +/*++ + +VOID +NdisSetSendFlags( + IN PNDIS_PACKET Packet, + IN UINT Flags + ); + +--*/ + +#define NdisSetSendFlags(_Packet,_Flags) \ + (_Packet)->Private.Flags = (_Flags) + +/*++ + +VOID +NdisQuerySendFlags( + IN PNDIS_PACKET Packet, + OUT PUINT Flags + ); + +--*/ + +#define NdisQuerySendFlags(_Packet,_Flags) \ + *(_Flags) = (_Packet)->Private.Flags + + +// +// Packet Pool +// + +EXPORT +VOID +NdisAllocatePacketPool( + OUT PNDIS_STATUS Status, + OUT PNDIS_HANDLE PoolHandle, + IN UINT NumberOfDescriptors, + IN UINT ProtocolReservedLength + ); + +// VOID +// NdisFreePacketPool( +// IN NDIS_HANDLE PoolHandle +// ); +#define NdisFreePacketPool(PoolHandle) {\ + NdisFreeSpinLock(&((PNDIS_PACKET_POOL)PoolHandle)->SpinLock);\ + ExFreePool(PoolHandle); \ +} + +EXPORT +VOID +NdisAllocatePacket( + OUT PNDIS_STATUS Status, + OUT PNDIS_PACKET * Packet, + IN NDIS_HANDLE PoolHandle + ); + +// VOID +// NdisFreePacket( +// IN PNDIS_PACKET Packet +// ); +#define NdisFreePacket(Packet) {\ + NdisAcquireSpinLock(&(Packet)->Private.Pool->SpinLock); \ + (Packet)->Private.Head = (PNDIS_BUFFER)(Packet)->Private.Pool->FreeList; \ + (Packet)->Private.Pool->FreeList = (Packet); \ + NdisReleaseSpinLock(&(Packet)->Private.Pool->SpinLock); \ +} + + +// VOID +// NdisReinitializePacket( +// IN OUT PNDIS_PACKET Packet +// ); +#define NdisReinitializePacket(Packet) { \ + (Packet)->Private.Head = (PNDIS_BUFFER)NULL; \ + (Packet)->Private.ValidCounts = FALSE; \ +} + + +EXPORT +VOID +NdisInitializeTimer( + IN OUT PNDIS_TIMER Timer, + IN PNDIS_TIMER_FUNCTION TimerFunction, + IN PVOID FunctionContext + ); + +/*++ +VOID +NdisCancelTimer( + IN PNDIS_TIMER Timer, + OUT PBOOLEAN TimerCancelled + ) +--*/ +#define NdisCancelTimer(NdisTimer,TimerCancelled) \ + (*(TimerCancelled) = KeCancelTimer(&((NdisTimer)->Timer))) + +// +// Shared memory +// + +EXPORT +VOID +NdisAllocateSharedMemory( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG Length, + IN BOOLEAN Cached, + OUT PVOID *VirtualAddress, + OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress + ); + +EXPORT +VOID +NdisFreeSharedMemory( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG Length, + IN BOOLEAN Cached, + IN PVOID VirtualAddress, + IN NDIS_PHYSICAL_ADDRESS PhysicalAddress + ); + + +// +// Requests used by Protocol Modules +// + +EXPORT +VOID +NdisRegisterProtocol( + OUT PNDIS_STATUS Status, + OUT PNDIS_HANDLE NdisProtocolHandle, + IN PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics, + IN UINT CharacteristicsLength + ); + +EXPORT +VOID +NdisDeregisterProtocol( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE NdisProtocolHandle + ); + + +EXPORT +VOID +NdisOpenAdapter( + OUT PNDIS_STATUS Status, + OUT PNDIS_STATUS OpenErrorStatus, + OUT PNDIS_HANDLE NdisBindingHandle, + OUT PUINT SelectedMediumIndex, + IN PNDIS_MEDIUM MediumArray, + IN UINT MediumArraySize, + IN NDIS_HANDLE NdisProtocolHandle, + IN NDIS_HANDLE ProtocolBindingContext, + IN PNDIS_STRING AdapterName, + IN UINT OpenOptions, + IN PSTRING AddressingInformation OPTIONAL + ); + + +EXPORT +VOID +NdisCloseAdapter( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE NdisBindingHandle + ); + + +// VOID +// NdisSend( +// OUT PNDIS_STATUS Status, +// IN NDIS_HANDLE NdisBindingHandle, +// IN PNDIS_PACKET Packet +// ); +#define NdisSend(Status, \ + NdisBindingHandle, \ + Packet \ + ) \ +{\ + *(Status) = \ + (((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->SendHandler) ( \ + ((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->MacBindingHandle, \ + (Packet)); \ +} + + +// VOID +// NdisTransferData( +// OUT PNDIS_STATUS Status, +// IN NDIS_HANDLE NdisBindingHandle, +// IN NDIS_HANDLE MacReceiveContext, +// IN UINT ByteOffset, +// IN UINT BytesToTransfer, +// IN OUT PNDIS_PACKET Packet, +// OUT PUINT BytesTransferred +// ); +#define NdisTransferData( \ + Status, \ + NdisBindingHandle, \ + MacReceiveContext, \ + ByteOffset, \ + BytesToTransfer, \ + Packet, \ + BytesTransferred \ + ) \ +{\ + *(Status) = \ + (((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->TransferDataHandler) ( \ + ((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->MacBindingHandle, \ + (MacReceiveContext), \ + (ByteOffset), \ + (BytesToTransfer), \ + (Packet), \ + (BytesTransferred)); \ +} + + +// VOID +// NdisReset( +// OUT PNDIS_STATUS Status, +// IN NDIS_HANDLE NdisBindingHandle +// ); +#define NdisReset( \ + Status, \ + NdisBindingHandle \ + ) \ +{ \ + *(Status) = \ + (((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->MacHandle->MacCharacteristics.ResetHandler) ( \ + ((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->MacBindingHandle); \ +} + +// VOID +// NdisRequest( +// OUT PNDIS_STATUS Status, +// IN NDIS_HANDLE NdisBindingHandle, +// IN PNDIS_REQUEST NdisRequest +// ); +#define NdisRequest( \ + Status,\ + NdisBindingHandle, \ + NdisRequest \ + ) \ +{ \ + *(Status) = \ + (((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->MacHandle->MacCharacteristics.RequestHandler) ( \ + ((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->MacBindingHandle, \ + (NdisRequest)); \ +} + +// +// DMA operations. +// + +EXPORT +VOID +NdisAllocateDmaChannel( + OUT PNDIS_STATUS Status, + OUT PNDIS_HANDLE NdisDmaHandle, + IN NDIS_HANDLE NdisAdapterHandle, + IN PNDIS_DMA_DESCRIPTION DmaDescription, + IN ULONG MaximumLength + ); + +EXPORT +VOID +NdisFreeDmaChannel( + IN PNDIS_HANDLE NdisDmaHandle + ); + +EXPORT +VOID +NdisSetupDmaTransfer( + OUT PNDIS_STATUS Status, + IN PNDIS_HANDLE NdisDmaHandle, + IN PNDIS_BUFFER Buffer, + IN ULONG Offset, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ); + +EXPORT +VOID +NdisCompleteDmaTransfer( + OUT PNDIS_STATUS Status, + IN PNDIS_HANDLE NdisDmaHandle, + IN PNDIS_BUFFER Buffer, + IN ULONG Offset, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ); + +/*++ +ULONG +NdisReadDmaCounter( + IN NDIS_HANDLE NdisDmaHandle + ) +--*/ + +#define NdisReadDmaCounter(_NdisDmaHandle) \ + HalReadDmaCounter(((PNDIS_DMA_BLOCK)(_NdisDmaHandle))->SystemAdapterObject) + +// +// Requests Used by MAC Drivers +// + +EXPORT +VOID +NdisRegisterMac( + OUT PNDIS_STATUS Status, + OUT PNDIS_HANDLE NdisMacHandle, + IN NDIS_HANDLE NdisWrapperHandle, + IN NDIS_HANDLE MacMacContext, + IN PNDIS_MAC_CHARACTERISTICS MacCharacteristics, + IN UINT CharacteristicsLength + ); + +EXPORT +VOID +NdisDeregisterMac( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE NdisMacHandle + ); + + +EXPORT +NDIS_STATUS +NdisRegisterAdapter( + OUT PNDIS_HANDLE NdisAdapterHandle, + IN NDIS_HANDLE NdisMacHandle, + IN NDIS_HANDLE MacAdapterContext, + IN NDIS_HANDLE WrapperConfigurationContext, + IN PNDIS_STRING AdapterName, + IN PVOID AdapterInformation + ); + +EXPORT +NDIS_STATUS +NdisDeregisterAdapter( + IN NDIS_HANDLE NdisAdapterHandle + ); + +EXPORT +VOID +NdisRegisterAdapterShutdownHandler( + IN NDIS_HANDLE NdisAdapterHandle, + IN PVOID ShutdownContext, + IN ADAPTER_SHUTDOWN_HANDLER ShutdownHandler + ); + +EXPORT +VOID +NdisDeregisterAdapterShutdownHandler( + IN NDIS_HANDLE NdisAdapterHandle + ); + +EXPORT +VOID +NdisReleaseAdapterResources( + IN NDIS_HANDLE NdisAdapterHandle + ); + +EXPORT +VOID +NdisCompleteOpenAdapter( + IN NDIS_HANDLE NdisBindingContext, + IN NDIS_STATUS Status, + IN NDIS_STATUS OpenErrorStatus + ); + + +EXPORT +VOID +NdisCompleteCloseAdapter( + IN NDIS_HANDLE NdisBindingContext, + IN NDIS_STATUS Status + ); + + +// VOID +// NdisCompleteSend( +// IN NDIS_HANDLE NdisBindingContext, +// IN PNDIS_PACKET Packet, +// IN NDIS_STATUS Status +// ); +#define NdisCompleteSend( \ + NdisBindingContext, \ + Packet, \ + Status \ + ) \ +{\ + (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->SendCompleteHandler) ( \ + ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext, \ + (Packet), \ + (Status)); \ +} + + +// VOID +// NdisCompleteTransferData( +// IN NDIS_HANDLE NdisBindingContext, +// IN PNDIS_PACKET Packet, +// IN NDIS_STATUS Status, +// IN UINT BytesTransferred +// ); +#define NdisCompleteTransferData( \ + NdisBindingContext, \ + Packet, \ + Status, \ + BytesTransferred \ + ) \ +{\ + (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->TransferDataCompleteHandler) ( \ + ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext, \ + (Packet), \ + (Status), \ + (BytesTransferred)); \ +} + +// VOID +// NdisCompleteReset( +// IN NDIS_HANDLE NdisBindingContext, +// IN NDIS_STATUS Status +// ); +#define NdisCompleteReset( \ + NdisBindingContext, \ + Status \ + ) \ +{ \ + (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolHandle->ProtocolCharacteristics.ResetCompleteHandler) ( \ + ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext, \ + Status); \ +} + + +// VOID +// NdisCompleteRequest( +// IN NDIS_HANDLE NdisBindingContext, +// IN PNDIS_REQUEST NdisRequest, +// IN NDIS_STATUS Status +// ); +#define NdisCompleteRequest( \ + NdisBindingContext, \ + NdisRequest, \ + Status) \ +{ \ + (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolHandle->ProtocolCharacteristics.RequestCompleteHandler) ( \ + ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext, \ + NdisRequest, \ + Status); \ +} + +// VOID +// NdisIndicateReceive( +// OUT PNDIS_STATUS Status, +// IN NDIS_HANDLE NdisBindingContext, +// IN NDIS_HANDLE MacReceiveContext, +// IN PVOID HeaderBuffer, +// IN UINT HeaderBufferSize, +// IN PVOID LookaheadBuffer, +// IN UINT LookaheadBufferSize, +// IN UINT PacketSize +// ); +#define NdisIndicateReceive( \ + Status, \ + NdisBindingContext, \ + MacReceiveContext, \ + HeaderBuffer, \ + HeaderBufferSize, \ + LookaheadBuffer, \ + LookaheadBufferSize, \ + PacketSize \ + ) \ +{\ + KIRQL oldIrql;\ + KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );\ + *(Status) = \ + (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->PostNt31ReceiveHandler) ( \ + ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext, \ + (MacReceiveContext), \ + (HeaderBuffer), \ + (HeaderBufferSize), \ + (LookaheadBuffer), \ + (LookaheadBufferSize), \ + (PacketSize)); \ + KeLowerIrql( oldIrql );\ +} + +// +// Used by the filter packages for indicating receives +// + +#define FilterIndicateReceive( \ + Status, \ + NdisBindingContext, \ + MacReceiveContext, \ + HeaderBuffer, \ + HeaderBufferSize, \ + LookaheadBuffer, \ + LookaheadBufferSize, \ + PacketSize \ + ) \ +{\ + *(Status) = \ + (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->PostNt31ReceiveHandler) ( \ + ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext, \ + (MacReceiveContext), \ + (HeaderBuffer), \ + (HeaderBufferSize), \ + (LookaheadBuffer), \ + (LookaheadBufferSize), \ + (PacketSize)); \ +} + + +// VOID +// NdisIndicateReceiveComplete( +// IN NDIS_HANDLE NdisBindingContext +// ); +#define NdisIndicateReceiveComplete(NdisBindingContext) \ +{\ + KIRQL oldIrql;\ + KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );\ + (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->PostNt31ReceiveCompleteHandler) ( \ + ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext);\ + KeLowerIrql( oldIrql );\ +} + +// +// Used by the filter packages for indicating receive completion +// + +#define FilterIndicateReceiveComplete(NdisBindingContext) \ +{\ + (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->PostNt31ReceiveCompleteHandler) ( \ + ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext);\ +} + +// VOID +// NdisIndicateStatus( +// IN NDIS_HANDLE NdisBindingContext, +// IN NDIS_STATUS GeneralStatus, +// IN PVOID StatusBuffer, +// IN UINT StatusBufferSize +// ); +#define NdisIndicateStatus( \ + NdisBindingContext, \ + GeneralStatus, \ + StatusBuffer, \ + StatusBufferSize \ + ) \ +{\ + (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolHandle->ProtocolCharacteristics.StatusHandler) ( \ + ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext, \ + (GeneralStatus), \ + (StatusBuffer), \ + (StatusBufferSize)); \ +} + + +// VOID +// NdisIndicateStatusComplete( +// IN NDIS_HANDLE NdisBindingContext +// ); +#define NdisIndicateStatusComplete( \ + NdisBindingContext \ + ) \ +{ \ + (((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolHandle->ProtocolCharacteristics.StatusCompleteHandler) ( \ + ((PNDIS_OPEN_BLOCK)(NdisBindingContext))->ProtocolBindingContext); \ +} + +EXPORT +VOID +NdisCompleteQueryStatistics( + IN NDIS_HANDLE NdisAdapterHandle, + IN PNDIS_REQUEST NdisRequest, + IN NDIS_STATUS Status + ); + +// +// Interlocked support functions +// + +/*++ + +VOID +NdisInterlockedAddUlong( + IN PULONG Addend, + IN ULONG Increment, + IN PNDIS_SPIN_LOCK SpinLock + ); + +--*/ + +#define NdisInterlockedAddUlong(_Addend, _Increment, _SpinLock) \ + ExInterlockedAddUlong(_Addend, _Increment, &(_SpinLock)->SpinLock) + +/*++ + +PLIST_ENTRY +NdisInterlockedInsertHeadList( + IN PLIST_ENTRY ListHead, + IN PLIST_ENTRY ListEntry, + IN PNDIS_SPIN_LOCK SpinLock + ); + +--*/ + +#define NdisInterlockedInsertHeadList(_ListHead, _ListEntry, _SpinLock) \ + ExInterlockedInsertHeadList(_ListHead, _ListEntry, &(_SpinLock)->SpinLock) + +/*++ + +PLIST_ENTRY +NdisInterlockedInsertTailList( + IN PLIST_ENTRY ListHead, + IN PLIST_ENTRY ListEntry, + IN PNDIS_SPIN_LOCK SpinLock + ); + +--*/ + +#define NdisInterlockedInsertTailList(_ListHead, _ListEntry, _SpinLock) \ + ExInterlockedInsertTailList(_ListHead, _ListEntry, &(_SpinLock)->SpinLock) + +/*++ + +PLIST_ENTRY +NdisInterlockedRemoveHeadList( + IN PLIST_ENTRY ListHead, + IN PNDIS_SPIN_LOCK SpinLock + ); + +--*/ + +#define NdisInterlockedRemoveHeadList(_ListHead, _SpinLock) \ + ExInterlockedRemoveHeadList(_ListHead, &(_SpinLock)->SpinLock) + +/*++ + +VOID +NdisAdjustBufferLength( + IN PNDIS_BUFFER Buffer, + IN UINT Length + ); + +--*/ + +#define NdisAdjustBufferLength(Buffer, Length) \ + (((Buffer)->ByteCount) = (Length)) + +// +// Operating System Requests +// + +EXPORT +VOID +NdisMapIoSpace( + OUT PNDIS_STATUS Status, + OUT PVOID * VirtualAddress, + IN NDIS_HANDLE NdisAdapterHandle, + IN NDIS_PHYSICAL_ADDRESS PhysicalAddress, + IN UINT Length + ); + +#if defined(_ALPHA_) + +/*++ +VOID +NdisUnmapIoSpace( + IN NDIS_HANDLE NdisAdapterHandle, + IN PVOID VirtualAddress, + IN UINT Length + ) +--*/ +#define NdisUnmapIoSpace(Handle,VirtualAddress,Length) {} + +#else + +/*++ +VOID +NdisUnmapIoSpace( + IN NDIS_HANDLE NdisAdapterHandle, + IN PVOID VirtualAddress, + IN UINT Length + ) +--*/ +#define NdisUnmapIoSpace(Handle,VirtualAddress,Length) \ + MmUnmapIoSpace((VirtualAddress), (Length)); + +#endif + +EXPORT +VOID +NdisInitializeInterrupt( + OUT PNDIS_STATUS Status, + IN OUT PNDIS_INTERRUPT Interrupt, + IN NDIS_HANDLE NdisAdapterHandle, + IN PNDIS_INTERRUPT_SERVICE InterruptServiceRoutine, + IN PVOID InterruptContext, + IN PNDIS_DEFERRED_PROCESSING DeferredProcessingRoutine, + IN UINT InterruptVector, + IN UINT InterruptLevel, + IN BOOLEAN SharedInterrupt, + IN NDIS_INTERRUPT_MODE InterruptMode + ); + +EXPORT +VOID +NdisRemoveInterrupt( + IN PNDIS_INTERRUPT Interrupt + ); + +/*++ +BOOLEAN +NdisSynchronizeWithInterrupt( + IN PNDIS_INTERRUPT Interrupt, + IN PVOID SynchronizeFunction, + IN PVOID SynchronizeContext + ) +--*/ + +#define NdisSynchronizeWithInterrupt(Interrupt,Function,Context) \ + KeSynchronizeExecution( \ + (Interrupt)->InterruptObject,\ + (PKSYNCHRONIZE_ROUTINE)Function,\ + Context \ + ) + +// +// Physical Mapping +// + +// +// VOID +// NdisStartBufferPhysicalMapping( +// IN NDIS_HANDLE NdisAdapterHandle, +// IN PNDIS_BUFFER Buffer, +// IN ULONG PhysicalMapRegister, +// IN BOOLEAN WriteToDevice, +// OUT PNDIS_PHYSICAL_ADDRESS_UNIT PhysicalAddressArray, +// OUT PUINT ArraySize +// ); +// + +#define NdisStartBufferPhysicalMapping( \ + _NdisAdapterHandle, \ + _Buffer, \ + _PhysicalMapRegister, \ + _Write, \ + _PhysicalAddressArray, \ + _ArraySize \ + ) \ +{ \ + PNDIS_ADAPTER_BLOCK _AdaptP = (PNDIS_ADAPTER_BLOCK)(_NdisAdapterHandle); \ + PHYSICAL_ADDRESS _LogicalAddress; \ + PUCHAR _VirtualAddress; \ + ULONG _LengthRemaining; \ + ULONG _LengthMapped; \ + UINT _CurrentArrayLocation; \ + _VirtualAddress = MmGetMdlVirtualAddress(_Buffer); \ + _LengthRemaining = MmGetMdlByteCount(_Buffer); \ + _CurrentArrayLocation = 0; \ + while (_LengthRemaining > 0) { \ + _LengthMapped = _LengthRemaining; \ + _LogicalAddress = IoMapTransfer( \ + NULL, \ + _Buffer, \ + _AdaptP->MapRegisters[_PhysicalMapRegister].MapRegister, \ + _VirtualAddress, \ + &_LengthMapped, \ + _Write); \ + _PhysicalAddressArray[_CurrentArrayLocation].PhysicalAddress = _LogicalAddress; \ + _PhysicalAddressArray[_CurrentArrayLocation].Length = _LengthMapped; \ + _LengthRemaining -= _LengthMapped; \ + _VirtualAddress += _LengthMapped; \ + ++_CurrentArrayLocation; \ + } \ + _AdaptP->MapRegisters[_PhysicalMapRegister].WriteToDevice = _Write; \ + *(_ArraySize) = _CurrentArrayLocation; \ +} + + +// +// VOID +// NdisCompleteBufferPhysicalMapping( +// IN NDIS_HANDLE NdisAdapterHandle, +// IN PNDIS_BUFFER Buffer, +// IN ULONG PhysicalMapRegister +// ); +// + +#define NdisCompleteBufferPhysicalMapping( \ + NdisAdapterHandle, \ + Buffer, \ + PhysicalMapRegister \ + ) \ +{ \ + PNDIS_ADAPTER_BLOCK _AdaptP = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle; \ + IoFlushAdapterBuffers( \ + NULL, \ + Buffer, \ + _AdaptP->MapRegisters[PhysicalMapRegister].MapRegister, \ + MmGetMdlVirtualAddress(Buffer), \ + MmGetMdlByteCount(Buffer), \ + _AdaptP->MapRegisters[PhysicalMapRegister].WriteToDevice); \ +} diff --git a/private/ntos/ndis/ndis30/ndismain.h b/private/ntos/ndis/ndis30/ndismain.h new file mode 100644 index 000000000..b96557a19 --- /dev/null +++ b/private/ntos/ndis/ndis30/ndismain.h @@ -0,0 +1,1976 @@ +// +// Indicate that we're building for NT. NDIS_NT is always used for +// miniport builds. +// + +#define NDIS_NT 1 + +#if defined(NDIS_DOS) +#undef NDIS_DOS +#endif + + +// +// Define status codes and event log codes. +// + +#include <ntstatus.h> +#include <netevent.h> + +// +// Define a couple of extra types. +// + +#if !defined(_WINDEF_) // these are defined in windows.h too +typedef signed int INT, *PINT; +typedef unsigned int UINT, *PUINT; +#endif + +typedef UNICODE_STRING NDIS_STRING, *PNDIS_STRING; + + +// +// Portability extentions +// + +#define NDIS_INIT_FUNCTION(_F) alloc_text(INIT,_F) +#define NDIS_PAGABLE_FUNCTION(_F) + + +// +// This file contains the definition of an NDIS_OID as +// well as #defines for all the current OID values. +// + +#include <ntddndis.h> + + +// +// Ndis defines for configuration manager data structures +// + +typedef CM_MCA_POS_DATA NDIS_MCA_POS_DATA, *PNDIS_MCA_POS_DATA; +typedef CM_EISA_SLOT_INFORMATION NDIS_EISA_SLOT_INFORMATION, + *PNDIS_EISA_SLOT_INFORMATION; +typedef CM_EISA_FUNCTION_INFORMATION NDIS_EISA_FUNCTION_INFORMATION, + *PNDIS_EISA_FUNCTION_INFORMATION; + +// +// Define an exported function. +// +#if defined(NDIS_WRAPPER) +#define EXPORT +#else +#define EXPORT DECLSPEC_IMPORT +#endif + +// +// Memory manipulation functions. +// + +#define NdisMoveMemory(Destination,Source,Length) RtlCopyMemory(Destination,Source,Length) +#define NdisZeroMemory(Destination,Length) RtlZeroMemory(Destination,Length) +#define NdisRetrieveUlong(Destination,Source) RtlRetrieveUlong(Destination,Source) +#define NdisStoreUlong(Destination,Value) RtlStoreUlong(Destination,Value) + +#define NDIS_STRING_CONST(x) {sizeof(L##x)-2, sizeof(L##x), L##x} + +// +// On a MIPS machine, I/O mapped memory can't be accessed with +// the Rtl routines. +// + +#if defined(_M_IX86) + +#define NdisMoveMappedMemory(Destination,Source,Length) RtlCopyMemory(Destination,Source,Length) +#define NdisZeroMappedMemory(Destination,Length) RtlZeroMemory(Destination,Length) + +#elif defined(_M_MRX000) + +#define NdisMoveMappedMemory(Destination,Source,Length) \ +{ \ + PUCHAR _Src = (Source); \ + PUCHAR _Dest = (Destination); \ + PUCHAR _End = _Dest + (Length); \ + while (_Dest < _End) { \ + *_Dest++ = *_Src++; \ + } \ +} +#define NdisZeroMappedMemory(Destination,Length) \ +{ \ + PUCHAR _Dest = (Destination); \ + PUCHAR _End = _Dest + (Length); \ + while (_Dest < _End) { \ + *_Dest++ = 0; \ + } \ +} + +#elif defined(_PPC_) + +#define NdisMoveMappedMemory(Destination,Source,Length) RtlCopyMemory32( Destination, Source, Length ); +#define NdisZeroMappedMemory(Destination,Length) \ +{ \ + PUCHAR _Dest = (Destination); \ + PUCHAR _End = _Dest + (Length); \ + while (_Dest < _End) { \ + *_Dest++ = 0; \ + } \ +} + +#elif defined(_ALPHA_) + +#define NdisMoveMappedMemory(Destination,Source,Length) \ +{ \ + PUCHAR _Src = (Source); \ + PUCHAR _Dest = (Destination); \ + PUCHAR _End = _Dest + (Length); \ + while (_Dest < _End) \ + { \ + NdisReadRegisterUchar(_Src, _Dest); \ + _Src++; \ + _Dest++; \ + } \ +} +#define NdisZeroMappedMemory(Destination,Length) \ +{ \ + PUCHAR _Dest = (Destination); \ + PUCHAR _End = _Dest + (Length); \ + while (_Dest < _End) { \ + NdisWriteRegisterUchar(_Dest,0); \ + _Dest++; \ + } \ +} + +#endif + + +// +// On Mips and Intel systems, these are the same. On Alpha, they are different. +// + +#if defined(_ALPHA_) + +#define NdisMoveToMappedMemory(Destination,Source,Length) WRITE_REGISTER_BUFFER_UCHAR(Destination,Source,Length) +#define NdisMoveFromMappedMemory(Destination,Source,Length) READ_REGISTER_BUFFER_UCHAR(Source,Destination,Length) + +#else + +#define NdisMoveToMappedMemory(Destination,Source,Length) NdisMoveMappedMemory(Destination,Source,Length) +#define NdisMoveFromMappedMemory(Destination,Source,Length) NdisMoveMappedMemory(Destination,Source,Length) + +#endif + + +// +// definition of the basic spin lock structure +// + +typedef struct _NDIS_SPIN_LOCK { + KSPIN_LOCK SpinLock; + KIRQL OldIrql; +} NDIS_SPIN_LOCK, * PNDIS_SPIN_LOCK; + + +typedef PVOID NDIS_HANDLE, *PNDIS_HANDLE; + +typedef int NDIS_STATUS, *PNDIS_STATUS; // note default size + +#define NdisInterruptLatched Latched +#define NdisInterruptLevelSensitive LevelSensitive +typedef KINTERRUPT_MODE NDIS_INTERRUPT_MODE, *PNDIS_INTERRUPT_MODE; + +// +// Configuration definitions +// + +// +// Possible data types +// + +typedef enum _NDIS_PARAMETER_TYPE { + NdisParameterInteger, + NdisParameterHexInteger, + NdisParameterString, + NdisParameterMultiString +} NDIS_PARAMETER_TYPE, *PNDIS_PARAMETER_TYPE; + +// +// To store configuration information +// +typedef struct _NDIS_CONFIGURATION_PARAMETER { + NDIS_PARAMETER_TYPE ParameterType; + union { + ULONG IntegerData; + NDIS_STRING StringData; + } ParameterData; +} NDIS_CONFIGURATION_PARAMETER, *PNDIS_CONFIGURATION_PARAMETER; + + +// +// Definitions for the "ProcessorType" keyword +// +typedef enum _NDIS_PROCESSOR_TYPE { + NdisProcessorX86, + NdisProcessorMips, + NdisProcessorAlpha, + NdisProcessorPpc +} NDIS_PROCESSOR_TYPE, *PNDIS_PROCESSOR_TYPE; + +// +// Definitions for the "Environment" keyword +// +typedef enum _NDIS_ENVIRONMENT_TYPE { + NdisEnvironmentWindows, + NdisEnvironmentWindowsNt +} NDIS_ENVIRONMENT_TYPE, *PNDIS_ENVIRONMENT_TYPE; + + +// +// Possible Hardware Architecture. Define these to +// match the HAL INTERFACE_TYPE enum. +// +typedef enum _NDIS_INTERFACE_TYPE { + NdisInterfaceInternal = Internal, + NdisInterfaceIsa = Isa, + NdisInterfaceEisa = Eisa, + NdisInterfaceMca = MicroChannel, + NdisInterfaceTurboChannel = TurboChannel, + NdisInterfacePci = PCIBus, + NdisInterfacePcMcia = PCMCIABus +} NDIS_INTERFACE_TYPE, *PNDIS_INTERFACE_TYPE; + +// +// Definition for shutdown handler +// + +typedef +VOID +(*ADAPTER_SHUTDOWN_HANDLER) ( + IN PVOID ShutdownContext + ); + +// +// Stuff for PCI configuring +// + +typedef CM_PARTIAL_RESOURCE_LIST NDIS_RESOURCE_LIST, *PNDIS_RESOURCE_LIST; + + +// +// The structure passed up on a WAN_LINE_UP indication +// + +typedef struct _NDIS_WAN_LINE_UP { + ULONG LinkSpeed; // 100 bps units + ULONG MaximumTotalSize; // suggested max for send packets + NDIS_WAN_QUALITY Quality; + USHORT SendWindow; // suggested by the MAC + UCHAR Address[1]; // variable length, depends on address type +} NDIS_WAN_LINE_UP, *PNDIS_WAN_LINE_UP; + +// +// The structure passed up on a WAN_LINE_DOWN indication +// + +typedef struct _NDIS_WAN_LINE_DOWN { + UCHAR Address[1]; // variable length, depends on address type +} NDIS_WAN_LINE_DOWN, *PNDIS_WAN_LINE_DOWN; + +// +// The structure passed up on a WAN_FRAGMENT indication +// + +typedef struct _NDIS_WAN_FRAGMENT { + UCHAR Address[1]; // variable length, depends on address type +} NDIS_WAN_FRAGMENT, *PNDIS_WAN_FRAGMENT; + + +// +// DMA Channel information +// +typedef struct _NDIS_DMA_DESCRIPTION { + BOOLEAN DemandMode; + BOOLEAN AutoInitialize; + BOOLEAN DmaChannelSpecified; + DMA_WIDTH DmaWidth; + DMA_SPEED DmaSpeed; + ULONG DmaPort; + ULONG DmaChannel; +} NDIS_DMA_DESCRIPTION, *PNDIS_DMA_DESCRIPTION; + +// +// Internal structure representing an NDIS DMA channel +// +typedef struct _NDIS_DMA_BLOCK { + PVOID MapRegisterBase; + KEVENT AllocationEvent; + PADAPTER_OBJECT SystemAdapterObject; + BOOLEAN InProgress; +} NDIS_DMA_BLOCK, *PNDIS_DMA_BLOCK; + + +// +// Ndis Buffer is actually an Mdl +// +typedef MDL NDIS_BUFFER, * PNDIS_BUFFER; + +// +// Include an incomplete type for NDIS_PACKET structure so that +// function types can refer to a type to be defined later. +// +struct _NDIS_PACKET; + +// +// packet pool definition +// +typedef struct _NDIS_PACKET_POOL { + NDIS_SPIN_LOCK SpinLock; + struct _NDIS_PACKET *FreeList; // linked list of free slots in pool + UINT PacketLength; // amount needed in each packet + UCHAR Buffer[1]; // actual pool memory +} NDIS_PACKET_POOL, * PNDIS_PACKET_POOL; + + +// +// wrapper-specific part of a packet +// + +typedef struct _NDIS_PACKET_PRIVATE { + UINT PhysicalCount; // number of physical pages in packet. + UINT TotalLength; // Total amount of data in the packet. + PNDIS_BUFFER Head; // first buffer in the chain + PNDIS_BUFFER Tail; // last buffer in the chain + + // if Head is NULL the chain is empty; Tail doesn't have to be NULL also + + PNDIS_PACKET_POOL Pool; // so we know where to free it back to + UINT Count; + ULONG Flags; + BOOLEAN ValidCounts; +} NDIS_PACKET_PRIVATE, * PNDIS_PACKET_PRIVATE; + + +// +// packet definition +// + +typedef struct _NDIS_PACKET { + NDIS_PACKET_PRIVATE Private; + + union { + + struct { + UCHAR MiniportReserved[8]; + UCHAR WrapperReserved[8]; + }; + + struct { + UCHAR MacReserved[16]; + }; + + }; + + UCHAR ProtocolReserved[1]; + +} NDIS_PACKET, * PNDIS_PACKET; + +// +// Request types used by NdisRequest; constants are added for +// all entry points in the MAC, for those that want to create +// their own internal requests. +// + +typedef enum _NDIS_REQUEST_TYPE { + NdisRequestQueryInformation, + NdisRequestSetInformation, + NdisRequestQueryStatistics, + NdisRequestOpen, + NdisRequestClose, + NdisRequestSend, + NdisRequestTransferData, + NdisRequestReset, + NdisRequestGeneric1, + NdisRequestGeneric2, + NdisRequestGeneric3, + NdisRequestGeneric4 +} NDIS_REQUEST_TYPE, *PNDIS_REQUEST_TYPE; + + +// +// Structure of requests sent via NdisRequest +// + +typedef struct _NDIS_REQUEST { + UCHAR MacReserved[16]; + NDIS_REQUEST_TYPE RequestType; + union _DATA { + + struct _QUERY_INFORMATION { + NDIS_OID Oid; + PVOID InformationBuffer; + UINT InformationBufferLength; + UINT BytesWritten; + UINT BytesNeeded; + } QUERY_INFORMATION; + + struct _SET_INFORMATION { + NDIS_OID Oid; + PVOID InformationBuffer; + UINT InformationBufferLength; + UINT BytesRead; + UINT BytesNeeded; + } SET_INFORMATION; + + } DATA; + +} NDIS_REQUEST, *PNDIS_REQUEST; + +// +// Definitions for physical address. +// + +typedef PHYSICAL_ADDRESS NDIS_PHYSICAL_ADDRESS, *PNDIS_PHYSICAL_ADDRESS; +typedef struct _NDIS_PHYSICAL_ADDRESS_UNIT { + NDIS_PHYSICAL_ADDRESS PhysicalAddress; + UINT Length; +} NDIS_PHYSICAL_ADDRESS_UNIT, *PNDIS_PHYSICAL_ADDRESS_UNIT; + + +/*++ + +ULONG +NdisGetPhysicalAddressHigh( + IN NDIS_PHYSICAL_ADDRESS PhysicalAddress + ); + +--*/ + +#define NdisGetPhysicalAddressHigh(_PhysicalAddress)\ + ((_PhysicalAddress).HighPart) + +/*++ + +VOID +NdisSetPhysicalAddressHigh( + IN NDIS_PHYSICAL_ADDRESS PhysicalAddress, + IN ULONG Value + ); + +--*/ + +#define NdisSetPhysicalAddressHigh(_PhysicalAddress, _Value)\ + ((_PhysicalAddress).HighPart) = (_Value) + + +/*++ + +ULONG +NdisGetPhysicalAddressLow( + IN NDIS_PHYSICAL_ADDRESS PhysicalAddress + ); + +--*/ + +#define NdisGetPhysicalAddressLow(_PhysicalAddress) \ + ((_PhysicalAddress).LowPart) + + +/*++ + +VOID +NdisSetPhysicalAddressLow( + IN NDIS_PHYSICAL_ADDRESS PhysicalAddress, + IN ULONG Value + ); + +--*/ + +#define NdisSetPhysicalAddressLow(_PhysicalAddress, _Value) \ + ((_PhysicalAddress).LowPart) = (_Value) + +// +// Macro to initialize an NDIS_PHYSICAL_ADDRESS constant +// + +#define NDIS_PHYSICAL_ADDRESS_CONST(_Low, _High) \ + { (ULONG)(_Low), (LONG)(_High) } + + +// +// block used for references... +// + +typedef struct _REFERENCE { + NDIS_SPIN_LOCK SpinLock; + USHORT ReferenceCount; + BOOLEAN Closing; +} REFERENCE, * PREFERENCE; + + +// +// This holds a map register entry. +// + +typedef struct _MAP_REGISTER_ENTRY { + PVOID MapRegister; + BOOLEAN WriteToDevice; +} MAP_REGISTER_ENTRY, * PMAP_REGISTER_ENTRY; + +// +// Types of Memory (not mutually exclusive) +// + +#define NDIS_MEMORY_CONTIGUOUS 0x00000001 +#define NDIS_MEMORY_NONCACHED 0x00000002 + +// +// Open options +// +#define NDIS_OPEN_RECEIVE_NOT_REENTRANT 0x00000001 + +// +// NDIS_STATUS values +// + +#define NDIS_STATUS_SUCCESS ((NDIS_STATUS) STATUS_SUCCESS) +#define NDIS_STATUS_PENDING ((NDIS_STATUS) STATUS_PENDING) +#define NDIS_STATUS_NOT_RECOGNIZED ((NDIS_STATUS)0x00010001L) +#define NDIS_STATUS_NOT_COPIED ((NDIS_STATUS)0x00010002L) +#define NDIS_STATUS_NOT_ACCEPTED ((NDIS_STATUS)0x00010003L) + +#define NDIS_STATUS_ONLINE ((NDIS_STATUS)0x40010003L) +#define NDIS_STATUS_RESET_START ((NDIS_STATUS)0x40010004L) +#define NDIS_STATUS_RESET_END ((NDIS_STATUS)0x40010005L) +#define NDIS_STATUS_RING_STATUS ((NDIS_STATUS)0x40010006L) +#define NDIS_STATUS_CLOSED ((NDIS_STATUS)0x40010007L) +#define NDIS_STATUS_WAN_LINE_UP ((NDIS_STATUS)0x40010008L) +#define NDIS_STATUS_WAN_LINE_DOWN ((NDIS_STATUS)0x40010009L) +#define NDIS_STATUS_WAN_FRAGMENT ((NDIS_STATUS)0x4001000AL) + +#define NDIS_STATUS_NOT_RESETTABLE ((NDIS_STATUS)0x80010001L) +#define NDIS_STATUS_SOFT_ERRORS ((NDIS_STATUS)0x80010003L) +#define NDIS_STATUS_HARD_ERRORS ((NDIS_STATUS)0x80010004L) + +#define NDIS_STATUS_FAILURE ((NDIS_STATUS) STATUS_UNSUCCESSFUL) +#define NDIS_STATUS_RESOURCES ((NDIS_STATUS) \ + STATUS_INSUFFICIENT_RESOURCES) +#define NDIS_STATUS_CLOSING ((NDIS_STATUS)0xC0010002L) +#define NDIS_STATUS_BAD_VERSION ((NDIS_STATUS)0xC0010004L) +#define NDIS_STATUS_BAD_CHARACTERISTICS ((NDIS_STATUS)0xC0010005L) +#define NDIS_STATUS_ADAPTER_NOT_FOUND ((NDIS_STATUS)0xC0010006L) +#define NDIS_STATUS_OPEN_FAILED ((NDIS_STATUS)0xC0010007L) +#define NDIS_STATUS_DEVICE_FAILED ((NDIS_STATUS)0xC0010008L) +#define NDIS_STATUS_MULTICAST_FULL ((NDIS_STATUS)0xC0010009L) +#define NDIS_STATUS_MULTICAST_EXISTS ((NDIS_STATUS)0xC001000AL) +#define NDIS_STATUS_MULTICAST_NOT_FOUND ((NDIS_STATUS)0xC001000BL) +#define NDIS_STATUS_REQUEST_ABORTED ((NDIS_STATUS)0xC001000CL) +#define NDIS_STATUS_RESET_IN_PROGRESS ((NDIS_STATUS)0xC001000DL) +#define NDIS_STATUS_CLOSING_INDICATING ((NDIS_STATUS)0xC001000EL) +#define NDIS_STATUS_NOT_SUPPORTED ((NDIS_STATUS)STATUS_NOT_SUPPORTED) +#define NDIS_STATUS_INVALID_PACKET ((NDIS_STATUS)0xC001000FL) +#define NDIS_STATUS_OPEN_LIST_FULL ((NDIS_STATUS)0xC0010010L) +#define NDIS_STATUS_ADAPTER_NOT_READY ((NDIS_STATUS)0xC0010011L) +#define NDIS_STATUS_ADAPTER_NOT_OPEN ((NDIS_STATUS)0xC0010012L) +#define NDIS_STATUS_NOT_INDICATING ((NDIS_STATUS)0xC0010013L) +#define NDIS_STATUS_INVALID_LENGTH ((NDIS_STATUS)0xC0010014L) +#define NDIS_STATUS_INVALID_DATA ((NDIS_STATUS)0xC0010015L) +#define NDIS_STATUS_BUFFER_TOO_SHORT ((NDIS_STATUS)0xC0010016L) +#define NDIS_STATUS_INVALID_OID ((NDIS_STATUS)0xC0010017L) +#define NDIS_STATUS_ADAPTER_REMOVED ((NDIS_STATUS)0xC0010018L) +#define NDIS_STATUS_UNSUPPORTED_MEDIA ((NDIS_STATUS)0xC0010019L) +#define NDIS_STATUS_GROUP_ADDRESS_IN_USE ((NDIS_STATUS)0xC001001AL) +#define NDIS_STATUS_FILE_NOT_FOUND ((NDIS_STATUS)0xC001001BL) +#define NDIS_STATUS_ERROR_READING_FILE ((NDIS_STATUS)0xC001001CL) +#define NDIS_STATUS_ALREADY_MAPPED ((NDIS_STATUS)0xC001001DL) +#define NDIS_STATUS_RESOURCE_CONFLICT ((NDIS_STATUS)0xC001001EL) +#define NDIS_STATUS_NO_CABLE ((NDIS_STATUS)0xC001001FL) + +#define NDIS_STATUS_TOKEN_RING_OPEN_ERROR ((NDIS_STATUS)0xC0011000L) + + +// +// used in error logging +// + +#define NDIS_ERROR_CODE ULONG + +#define NDIS_ERROR_CODE_RESOURCE_CONFLICT EVENT_NDIS_RESOURCE_CONFLICT +#define NDIS_ERROR_CODE_OUT_OF_RESOURCES EVENT_NDIS_OUT_OF_RESOURCE +#define NDIS_ERROR_CODE_HARDWARE_FAILURE EVENT_NDIS_HARDWARE_FAILURE +#define NDIS_ERROR_CODE_ADAPTER_NOT_FOUND EVENT_NDIS_ADAPTER_NOT_FOUND +#define NDIS_ERROR_CODE_INTERRUPT_CONNECT EVENT_NDIS_INTERRUPT_CONNECT +#define NDIS_ERROR_CODE_DRIVER_FAILURE EVENT_NDIS_DRIVER_FAILURE +#define NDIS_ERROR_CODE_BAD_VERSION EVENT_NDIS_BAD_VERSION +#define NDIS_ERROR_CODE_TIMEOUT EVENT_NDIS_TIMEOUT +#define NDIS_ERROR_CODE_NETWORK_ADDRESS EVENT_NDIS_NETWORK_ADDRESS +#define NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION EVENT_NDIS_UNSUPPORTED_CONFIGURATION +#define NDIS_ERROR_CODE_INVALID_VALUE_FROM_ADAPTER EVENT_NDIS_INVALID_VALUE_FROM_ADAPTER +#define NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER EVENT_NDIS_MISSING_CONFIGURATION_PARAMETER +#define NDIS_ERROR_CODE_BAD_IO_BASE_ADDRESS EVENT_NDIS_BAD_IO_BASE_ADDRESS +#define NDIS_ERROR_CODE_RECEIVE_SPACE_SMALL EVENT_NDIS_RECEIVE_SPACE_SMALL +#define NDIS_ERROR_CODE_ADAPTER_DISABLED EVENT_NDIS_ADAPTER_DISABLED + + +// +// Ndis Spin Locks +// + +#if BINARY_COMPATIBLE + +EXPORT +VOID +NdisAllocateSpinLock( + IN PNDIS_SPIN_LOCK SpinLock + ); + +EXPORT +VOID +NdisFreeSpinLock( + IN PNDIS_SPIN_LOCK SpinLock + ); + +EXPORT +VOID +NdisAcquireSpinLock( + IN PNDIS_SPIN_LOCK SpinLock + ); + +EXPORT +VOID +NdisReleaseSpinLock( + IN PNDIS_SPIN_LOCK SpinLock + ); + +EXPORT +VOID +NdisDprAcquireSpinLock( + IN PNDIS_SPIN_LOCK SpinLock + ); + +EXPORT +VOID +NdisDprReleaseSpinLock( + IN PNDIS_SPIN_LOCK SpinLock + ); + +#else + +#define NdisAllocateSpinLock(_SpinLock) \ + KeInitializeSpinLock(&(_SpinLock)->SpinLock) + +#define NdisFreeSpinLock(_SpinLock) + +#define NdisAcquireSpinLock(_SpinLock) \ + KeAcquireSpinLock(&(_SpinLock)->SpinLock, &(_SpinLock)->OldIrql) + +#define NdisReleaseSpinLock(_SpinLock) \ + KeReleaseSpinLock(&(_SpinLock)->SpinLock,(_SpinLock)->OldIrql) + +#define NdisDprAcquireSpinLock(_SpinLock) { \ + KeAcquireSpinLockAtDpcLevel(&(_SpinLock)->SpinLock); \ + (_SpinLock)->OldIrql = DISPATCH_LEVEL; \ +} + +#define NdisDprReleaseSpinLock(_SpinLock) \ + KeReleaseSpinLockFromDpcLevel(&(_SpinLock)->SpinLock) + +#endif + +// +// List manipulation +// + +/*++ + +VOID +NdisInitializeListHead( + IN PLIST_ENTRY ListHead + ); + +--*/ +#define NdisInitializeListHead(_ListHead) InitializeListHead(_ListHead) + + + +// +// Configuration Requests +// + +EXPORT +VOID +NdisOpenConfiguration( + OUT PNDIS_STATUS Status, + OUT PNDIS_HANDLE ConfigurationHandle, + IN NDIS_HANDLE WrapperConfigurationContext + ); + +EXPORT +VOID +NdisReadConfiguration( + OUT PNDIS_STATUS Status, + OUT PNDIS_CONFIGURATION_PARAMETER *ParameterValue, + IN NDIS_HANDLE ConfigurationHandle, + IN PNDIS_STRING Keyword, + IN NDIS_PARAMETER_TYPE ParameterType + ); + +EXPORT +VOID +NdisWriteConfiguration( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE WrapperConfigurationContext, + IN PNDIS_STRING Keyword, + IN PNDIS_CONFIGURATION_PARAMETER ParameterValue + ); + +EXPORT +VOID +NdisCloseConfiguration( + IN NDIS_HANDLE ConfigurationHandle + ); + +EXPORT +VOID +NdisReadNetworkAddress( + OUT PNDIS_STATUS Status, + OUT PVOID * NetworkAddress, + OUT PUINT NetworkAddressLength, + IN NDIS_HANDLE ConfigurationHandle + ); + +EXPORT +VOID +NdisReadBindingInformation( + OUT PNDIS_STATUS Status, + OUT PNDIS_STRING * Binding, + IN NDIS_HANDLE ConfigurationHandle + ); + + +EXPORT +VOID +NdisReadEisaSlotInformation( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE WrapperConfigurationContext, + OUT PUINT SlotNumber, + OUT PNDIS_EISA_FUNCTION_INFORMATION EisaData + ); + +EXPORT +VOID +NdisReadEisaSlotInformationEx( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE WrapperConfigurationContext, + OUT PUINT SlotNumber, + OUT PNDIS_EISA_FUNCTION_INFORMATION *EisaData, + OUT PUINT NumberOfFunctions + ); + +EXPORT +VOID +NdisReadMcaPosInformation( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE WrapperConfigurationContext, + IN PUINT ChannelNumber, + OUT PNDIS_MCA_POS_DATA McaData + ); + +EXPORT +ULONG +NdisReadPciSlotInformation( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG SlotNumber, + IN ULONG Offset, + IN PVOID Buffer, + IN ULONG Length + ); + +EXPORT +ULONG +NdisWritePciSlotInformation( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG SlotNumber, + IN ULONG Offset, + IN PVOID Buffer, + IN ULONG Length + ); + +EXPORT +NDIS_STATUS +NdisPciAssignResources( + IN NDIS_HANDLE NdisMacHandle, + IN NDIS_HANDLE NdisWrapperHandle, + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG SlotNumber, + OUT PNDIS_RESOURCE_LIST *AssignedResources + ); + +// +// Buffer Pool +// + +EXPORT +VOID +NdisAllocateBufferPool( + OUT PNDIS_STATUS Status, + OUT PNDIS_HANDLE PoolHandle, + IN UINT NumberOfDescriptors + ); + +EXPORT +VOID +NdisFreeBufferPool( + IN NDIS_HANDLE PoolHandle + ); + +EXPORT +VOID +NdisAllocateBuffer( + OUT PNDIS_STATUS Status, + OUT PNDIS_BUFFER * Buffer, + IN NDIS_HANDLE PoolHandle, + IN PVOID VirtualAddress, + IN UINT Length + ); + +EXPORT +VOID +NdisCopyBuffer( + OUT PNDIS_STATUS Status, + OUT PNDIS_BUFFER * Buffer, + IN NDIS_HANDLE PoolHandle, + IN PVOID MemoryDescriptor, + IN UINT Offset, + IN UINT Length + ); + + +#if BINARY_COMPATIBLE + +EXPORT +VOID +NdisFreeBuffer( + IN PNDIS_BUFFER Buffer + ); + +EXPORT +VOID +NdisQueryBuffer( + IN PNDIS_BUFFER Buffer, + OUT PVOID *VirtualAddress OPTIONAL, + OUT PUINT Length + ); + +EXPORT +VOID +NdisQueryBufferOffset( + IN PNDIS_BUFFER Buffer, + OUT PUINT Offset, + OUT PUINT Length + ); + +#else + +#define NdisFreeBuffer(Buffer) IoFreeMdl(Buffer) + +#define NdisQueryBuffer(_Buffer, _VirtualAddress, _Length) \ +{ \ + if ( ARGUMENT_PRESENT(_VirtualAddress) ) { \ + *(PVOID *)(_VirtualAddress) = MmGetSystemAddressForMdl(_Buffer); \ + } \ + *(_Length) = MmGetMdlByteCount(_Buffer); \ +} + +#define NdisQueryBufferOffset(_Buffer, _Offset, _Length) \ +{ \ + *(_Offset) = MmGetMdlByteOffset(_Buffer); \ + *(_Length) = MmGetMdlByteCount(_Buffer); \ +} + +#endif + + +// +// This macro is used to determine how many physical pieces +// an NDIS_BUFFER will take up when mapped. +// + +#if BINARY_COMPATIBLE + +EXPORT +ULONG +NDIS_BUFFER_TO_SPAN_PAGES( + IN PNDIS_BUFFER Buffer + ); + +EXPORT +VOID +NdisGetBufferPhysicalArraySize( + IN PNDIS_BUFFER Buffer, + OUT PUINT ArraySize + ); + +#else + +#define NDIS_BUFFER_TO_SPAN_PAGES(_Buffer) \ + (MmGetMdlByteCount(_Buffer)==0 ? \ + 1 : \ + (COMPUTE_PAGES_SPANNED(\ + MmGetMdlVirtualAddress(_Buffer), \ + MmGetMdlByteCount(_Buffer)))) + +#define NdisGetBufferPhysicalArraySize(Buffer, ArraySize) \ + (*(ArraySize) = NDIS_BUFFER_TO_SPAN_PAGES(Buffer)) + +#endif + +/*++ +VOID +NdisBufferGetSystemSpecific( + IN PNDIS_BUFFER Buffer, + OUT PVOID * SystemSpecific + ); +--*/ + +#define NdisBufferGetSystemSpecific(Buffer, SystemSpecific) \ + *(SystemSpecific) = (Buffer) + + +/*++ + +NDIS_BUFFER_LINKAGE( + IN PNDIS_BUFFER Buffer + ); + +--*/ + +#define NDIS_BUFFER_LINKAGE(Buffer) \ + ((Buffer)->Next) + + +/*++ + +VOID +NdisRecalculatePacketCounts( + IN OUT PNDIS_PACKET Packet + ); + +--*/ + +#define NdisRecalculatePacketCounts(Packet) { \ + { \ + PNDIS_BUFFER TmpBuffer = (Packet)->Private.Head; \ + if (TmpBuffer) { \ + while (TmpBuffer->Next) { \ + TmpBuffer = TmpBuffer->Next; \ + } \ + (Packet)->Private.Tail = TmpBuffer; \ + } \ + (Packet)->Private.ValidCounts = FALSE; \ + } \ +} + + +/*++ + +VOID +NdisChainBufferAtFront( + IN OUT PNDIS_PACKET Packet, + IN OUT PNDIS_BUFFER Buffer + ); + +--*/ + +#define NdisChainBufferAtFront(Packet, Buffer) { \ + PNDIS_BUFFER TmpBuffer = (Buffer); \ +\ + for (;;) { \ + if (TmpBuffer->Next == (PNDIS_BUFFER)NULL) \ + break; \ + TmpBuffer = TmpBuffer->Next; \ + } \ + if ((Packet)->Private.Head == (PNDIS_BUFFER)NULL) { \ + (Packet)->Private.Tail = TmpBuffer; \ + } \ + TmpBuffer->Next = (Packet)->Private.Head; \ + (Packet)->Private.Head = (Buffer); \ + (Packet)->Private.ValidCounts = FALSE; \ +} + +/*++ + +VOID +NdisChainBufferAtBack( + IN OUT PNDIS_PACKET Packet, + IN OUT PNDIS_BUFFER Buffer + ); + +--*/ + +#define NdisChainBufferAtBack(Packet, Buffer) { \ + PNDIS_BUFFER TmpBuffer = (Buffer); \ +\ + for (;;) { \ + if (TmpBuffer->Next == (PNDIS_BUFFER)NULL) \ + break; \ + TmpBuffer = TmpBuffer->Next; \ + } \ + if ((Packet)->Private.Head != (PNDIS_BUFFER)NULL) { \ + (Packet)->Private.Tail->Next = (Buffer); \ + } else { \ + (Packet)->Private.Head = (Buffer); \ + } \ + (Packet)->Private.Tail = TmpBuffer; \ + TmpBuffer->Next = (PNDIS_BUFFER)NULL; \ + (Packet)->Private.ValidCounts = FALSE; \ +} + +EXPORT +VOID +NdisUnchainBufferAtFront( + IN OUT PNDIS_PACKET Packet, + OUT PNDIS_BUFFER * Buffer + ); + +EXPORT +VOID +NdisUnchainBufferAtBack( + IN OUT PNDIS_PACKET Packet, + OUT PNDIS_BUFFER * Buffer + ); + + +/*++ + +VOID +NdisQueryPacket( + IN PNDIS_PACKET _Packet, + OUT PUINT _PhysicalBufferCount OPTIONAL, + OUT PUINT _BufferCount OPTIONAL, + OUT PNDIS_BUFFER * _FirstBuffer OPTIONAL, + OUT PUINT _TotalPacketLength OPTIONAL + ); + +--*/ + +#define NdisQueryPacket(_Packet, _PhysicalBufferCount, _BufferCount, _FirstBuffer, _TotalPacketLength) \ +{ \ + \ + if ((_FirstBuffer) != NULL) \ + { \ + PNDIS_BUFFER * __FirstBuffer = (_FirstBuffer); \ + *(__FirstBuffer) = (_Packet)->Private.Head; \ + } \ + if ((_PhysicalBufferCount) || (_BufferCount) || (_TotalPacketLength)) { \ + if (!(_Packet)->Private.ValidCounts) { \ + PNDIS_BUFFER TmpBuffer = (_Packet)->Private.Head; \ + UINT PTotalLength = 0, PPhysicalCount = 0, PAddedCount = 0; \ + UINT PacketLength; \ + \ + while (TmpBuffer != (PNDIS_BUFFER)NULL) { \ + NdisQueryBuffer(TmpBuffer, NULL, &PacketLength); \ + PTotalLength += PacketLength; \ + PPhysicalCount += NDIS_BUFFER_TO_SPAN_PAGES(TmpBuffer); \ + ++PAddedCount; \ + TmpBuffer = TmpBuffer->Next; \ + } \ + (_Packet)->Private.Count = PAddedCount; \ + (_Packet)->Private.TotalLength = PTotalLength; \ + (_Packet)->Private.PhysicalCount = PPhysicalCount; \ + (_Packet)->Private.ValidCounts = TRUE; \ + } \ + if (_PhysicalBufferCount) \ + { \ + PUINT __PhysicalBufferCount = (_PhysicalBufferCount); \ + *(__PhysicalBufferCount) = (_Packet)->Private.PhysicalCount; \ + } \ + if (_BufferCount) \ + { \ + PUINT __BufferCount = (_BufferCount); \ + *(__BufferCount) = (_Packet)->Private.Count; \ + } \ + if (_TotalPacketLength) \ + { \ + PUINT __TotalPacketLength = (_TotalPacketLength); \ + *(__TotalPacketLength) = (_Packet)->Private.TotalLength; \ + } \ + } \ +} + + +/*++ + +VOID +NdisGetNextBuffer( + IN PNDIS_BUFFER CurrentBuffer, + OUT PNDIS_BUFFER * NextBuffer + ); + +--*/ + +#define NdisGetNextBuffer(CurrentBuffer, NextBuffer) {\ + *(NextBuffer) = (CurrentBuffer)->Next; \ +} + + +EXPORT +VOID +NdisCopyFromPacketToPacket( + IN PNDIS_PACKET Destination, + IN UINT DestinationOffset, + IN UINT BytesToCopy, + IN PNDIS_PACKET Source, + IN UINT SourceOffset, + OUT PUINT BytesCopied + ); + + +EXPORT +NDIS_STATUS +NdisAllocateMemory( + OUT PVOID *VirtualAddress, + IN UINT Length, + IN UINT MemoryFlags, + IN NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress + ); + +EXPORT +VOID +NdisFreeMemory( + IN PVOID VirtualAddress, + IN UINT Length, + IN UINT MemoryFlags + ); + + +/*++ +VOID +NdisStallExecution( + IN UINT MicrosecondsToStall + ) +--*/ + +#define NdisStallExecution(MicroSecondsToStall) \ + KeStallExecutionProcessor(MicroSecondsToStall) + + +// +// Simple I/O support +// + +EXPORT +VOID +NdisOpenFile( + OUT PNDIS_STATUS Status, + OUT PNDIS_HANDLE FileHandle, + OUT PUINT FileLength, + IN PNDIS_STRING FileName, + IN NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress + ); + +EXPORT +VOID +NdisCloseFile( + IN NDIS_HANDLE FileHandle + ); + +EXPORT +VOID +NdisMapFile( + OUT PNDIS_STATUS Status, + OUT PVOID * MappedBuffer, + IN NDIS_HANDLE FileHandle + ); + +EXPORT +VOID +NdisUnmapFile( + IN NDIS_HANDLE FileHandle + ); + + +// +// Portability extensions +// + +/*++ +VOID +NdisFlushBuffer( + IN PNDIS_BUFFER Buffer, + IN BOOLEAN WriteToDevice + ) +--*/ + +#define NdisFlushBuffer(Buffer,WriteToDevice) \ + KeFlushIoBuffers((Buffer),!(WriteToDevice), TRUE) + +/*++ +ULONG +NdisGetCacheFillSize( + ) +--*/ +#define NdisGetCacheFillSize() \ + HalGetDmaAlignmentRequirement() + +// +// This macro is used to convert a port number as the caller +// thinks of it, to a port number as it should be passed to +// READ/WRITE_PORT. +// + +#define NDIS_PORT_TO_PORT(Handle,Port) (((PNDIS_ADAPTER_BLOCK)(Handle))->PortOffset + (Port)) + + +// +// Write Port +// + +/*++ +VOID +NdisWritePortUchar( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG Port, + IN UCHAR Data + ) +--*/ +#define NdisWritePortUchar(Handle,Port,Data) \ + WRITE_PORT_UCHAR((PUCHAR)(NDIS_PORT_TO_PORT(Handle,Port)),(UCHAR)(Data)) + +/*++ +VOID +NdisWritePortUshort( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG Port, + IN USHORT Data + ) +--*/ +#define NdisWritePortUshort(Handle,Port,Data) \ + WRITE_PORT_USHORT((PUSHORT)(NDIS_PORT_TO_PORT(Handle,Port)),(USHORT)(Data)) + + +/*++ +VOID +NdisWritePortUlong( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG Port, + IN ULONG Data + ) +--*/ +#define NdisWritePortUlong(Handle,Port,Data) \ + WRITE_PORT_ULONG((PULONG)(NDIS_PORT_TO_PORT(Handle,Port)),(ULONG)(Data)) + + +// +// Write Port Buffers +// + +/*++ +VOID +NdisWritePortBufferUchar( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG Port, + IN PUCHAR Buffer, + IN ULONG Length + ) +--*/ +#define NdisWritePortBufferUchar(Handle,Port,Buffer,Length) \ + NdisRawWritePortBufferUchar(NDIS_PORT_TO_PORT((Handle),(Port)),(Buffer),(Length)) + +/*++ +VOID +NdisWritePortBufferUshort( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG Port, + IN PUSHORT Buffer, + IN ULONG Length + ) +--*/ +#define NdisWritePortBufferUshort(Handle,Port,Buffer,Length) \ + NdisRawWritePortBufferUshort(NDIS_PORT_TO_PORT((Handle),(Port)),(Buffer),(Length)) + + +/*++ +VOID +NdisWritePortBufferUlong( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG Port, + IN PULONG Buffer, + IN ULONG Length + ) +--*/ +#define NdisWritePortBufferUlong(Handle,Port,Buffer,Length) \ + NdisRawWritePortBufferUlong(NDIS_PORT_TO_PORT((Handle),(Port)),(Buffer),(Length)) + + +// +// Read Ports +// + +/*++ +VOID +NdisReadPortUchar( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG Port, + OUT PUCHAR Data + ) +--*/ +#define NdisReadPortUchar(Handle,Port, Data) \ + NdisRawReadPortUchar(NDIS_PORT_TO_PORT((Handle),(Port)),(Data)) + +/*++ +VOID +NdisReadPortUshort( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG Port, + OUT PUSHORT Data + ) +--*/ +#define NdisReadPortUshort(Handle,Port,Data) \ + NdisRawReadPortUshort(NDIS_PORT_TO_PORT((Handle),(Port)),(Data)) + + +/*++ +VOID +NdisReadPortUlong( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG Port, + OUT PULONG Data + ) +--*/ +#define NdisReadPortUlong(Handle,Port,Data) \ + NdisRawReadPortUlong(NDIS_PORT_TO_PORT((Handle),(Port)),(Data)) + +// +// Read Buffer Ports +// + +/*++ +VOID +NdisReadPortBufferUchar( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG Port, + OUT PUCHAR Buffer, + IN ULONG Length + ) +--*/ +#define NdisReadPortBufferUchar(Handle,Port,Buffer,Length) \ + NdisRawReadPortBufferUchar(NDIS_PORT_TO_PORT((Handle),(Port)),(Buffer),(Length)) + +/*++ +VOID +NdisReadPortBufferUshort( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG Port, + OUT PUSHORT Buffer, + IN ULONG Length + ) +--*/ +#define NdisReadPortBufferUshort(Handle,Port,Buffer,Length) \ + NdisRawReadPortBufferUshort(NDIS_PORT_TO_PORT((Handle),(Port)),(Buffer),(Length)) + +/*++ +VOID +NdisReadPortBufferUlong( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG Port, + OUT PULONG Buffer, + IN ULONG Length + ) +--*/ +#define NdisReadPortBufferUlong(Handle,Port,Buffer) \ + NdisRawReadPortBufferUlong(NDIS_PORT_TO_PORT((Handle),(Port)),(Buffer),(Length)) + +// +// Raw Routines +// + +// +// Write Port Raw +// + +/*++ +VOID +NdisRawWritePortUchar( + IN ULONG Port, + IN UCHAR Data + ) +--*/ +#define NdisRawWritePortUchar(Port,Data) \ + WRITE_PORT_UCHAR((PUCHAR)(Port),(UCHAR)(Data)) + +/*++ +VOID +NdisRawWritePortUshort( + IN ULONG Port, + IN USHORT Data + ) +--*/ +#define NdisRawWritePortUshort(Port,Data) \ + WRITE_PORT_USHORT((PUSHORT)(Port),(USHORT)(Data)) + +/*++ +VOID +NdisRawWritePortUlong( + IN ULONG Port, + IN ULONG Data + ) +--*/ +#define NdisRawWritePortUlong(Port,Data) \ + WRITE_PORT_ULONG((PULONG)(Port),(ULONG)(Data)) + + +// +// Raw Write Port Buffers +// + +/*++ +VOID +NdisRawWritePortBufferUchar( + IN ULONG Port, + IN PUCHAR Buffer, + IN ULONG Length + ) +--*/ +#define NdisRawWritePortBufferUchar(Port,Buffer,Length) \ + WRITE_PORT_BUFFER_UCHAR((PUCHAR)(Port),(PUCHAR)(Buffer),(Length)) + +/*++ +VOID +NdisRawWritePortBufferUshort( + IN ULONG Port, + IN PUSHORT Buffer, + IN ULONG Length + ) +--*/ +#if defined(_M_IX86) +#define NdisRawWritePortBufferUshort(Port,Buffer,Length) \ + WRITE_PORT_BUFFER_USHORT((PUSHORT)(Port),(PUSHORT)(Buffer),(Length)) +#else +#define NdisRawWritePortBufferUshort(Port,Buffer,Length) \ +{ \ + ULONG _Port = (ULONG)(Port); \ + PUSHORT _Current = (Buffer); \ + PUSHORT _End = _Current + (Length); \ + for ( ; _Current < _End; ++_Current) { \ + WRITE_PORT_USHORT((PUSHORT)_Port,*(UNALIGNED USHORT *)_Current); \ + } \ +} +#endif + + +/*++ +VOID +NdisRawWritePortBufferUlong( + IN ULONG Port, + IN PULONG Buffer, + IN ULONG Length + ) +--*/ +#if defined(_M_IX86) +#define NdisRawWritePortBufferUlong(Port,Buffer,Length) \ + WRITE_PORT_BUFFER_ULONG((PULONG)(Port),(PULONG)(Buffer),(Length)) +#else +#define NdisRawWritePortBufferUlong(Port,Buffer,Length) \ +{ \ + ULONG _Port = (ULONG)(Port); \ + PULONG _Current = (Buffer); \ + PULONG _End = _Current + (Length); \ + for ( ; _Current < _End; ++_Current) { \ + WRITE_PORT_ULONG((PULONG)_Port,*(UNALIGNED ULONG *)_Current); \ + } \ +} +#endif + + +// +// Raw Read Ports +// + +/*++ +VOID +NdisRawReadPortUchar( + IN ULONG Port, + OUT PUCHAR Data + ) +--*/ +#define NdisRawReadPortUchar(Port, Data) \ + *(Data) = READ_PORT_UCHAR((PUCHAR)(Port)) + +/*++ +VOID +NdisRawReadPortUshort( + IN ULONG Port, + OUT PUSHORT Data + ) +--*/ +#define NdisRawReadPortUshort(Port,Data) \ + *(Data) = READ_PORT_USHORT((PUSHORT)(Port)) + +/*++ +VOID +NdisRawReadPortUlong( + IN ULONG Port, + OUT PULONG Data + ) +--*/ +#define NdisRawReadPortUlong(Port,Data) \ + *(Data) = READ_PORT_ULONG((PULONG)(Port)) + + +// +// Raw Read Buffer Ports +// + +/*++ +VOID +NdisRawReadPortBufferUchar( + IN ULONG Port, + OUT PUCHAR Buffer, + IN ULONG Length + ) +--*/ +#define NdisRawReadPortBufferUchar(Port,Buffer,Length) \ + READ_PORT_BUFFER_UCHAR((PUCHAR)(Port),(PUCHAR)(Buffer),(Length)) + + +/*++ +VOID +NdisRawReadPortBufferUshort( + IN ULONG Port, + OUT PUSHORT Buffer, + IN ULONG Length + ) +--*/ +#if defined(_M_IX86) +#define NdisRawReadPortBufferUshort(Port,Buffer,Length) \ + READ_PORT_BUFFER_USHORT((PUSHORT)(Port),(PUSHORT)(Buffer),(Length)) +#else +#define NdisRawReadPortBufferUshort(Port,Buffer,Length) \ +{ \ + ULONG _Port = (ULONG)(Port); \ + PUSHORT _Current = (Buffer); \ + PUSHORT _End = _Current + (Length); \ + for ( ; _Current < _End; ++_Current) { \ + *(UNALIGNED USHORT *)_Current = READ_PORT_USHORT((PUSHORT)_Port); \ + } \ +} +#endif + + +/*++ +VOID +NdisRawReadPortBufferUlong( + IN ULONG Port, + OUT PULONG Buffer, + IN ULONG Length + ) +--*/ +#if defined(_M_IX86) +#define NdisRawReadPortBufferUlong(Port,Buffer,Length) \ + READ_PORT_BUFFER_ULONG((PULONG)(Port),(PULONG)(Buffer),(Length)) +#else +#define NdisRawReadPortBufferUlong(Port,Buffer,Length) \ +{ \ + ULONG _Port = (ULONG)(Port); \ + PULONG _Current = (Buffer); \ + PULONG _End = _Current + (Length); \ + for ( ; _Current < _End; ++_Current) { \ + *(UNALIGNED ULONG *)_Current = READ_PORT_ULONG((PULONG)_Port); \ + } \ +} +#endif + + +// +// Write Registers +// + +/*++ +VOID +NdisWriteRegisterUchar( + IN PUCHAR Register, + IN UCHAR Data + ) +--*/ + +#if defined(_M_IX86) +#define NdisWriteRegisterUchar(Register,Data) \ + WRITE_REGISTER_UCHAR((Register),(Data)) +#else +#define NdisWriteRegisterUchar(Register,Data) { \ + WRITE_REGISTER_UCHAR((Register),(Data)); \ + READ_REGISTER_UCHAR(Register); \ + } +#endif + +/*++ +VOID +NdisWriteRegisterUshort( + IN PUSHORT Register, + IN USHORT Data + ) +--*/ + +#if defined(_M_IX86) +#define NdisWriteRegisterUshort(Register,Data) \ + WRITE_REGISTER_USHORT((Register),(Data)) +#else +#define NdisWriteRegisterUshort(Register,Data) { \ + WRITE_REGISTER_USHORT((Register),(Data)); \ + READ_REGISTER_USHORT(Register); \ + } +#endif + +/*++ +VOID +NdisWriteRegisterUlong( + IN PULONG Register, + IN ULONG Data + ) +--*/ + +#if defined(_M_IX86) +#define NdisWriteRegisterUlong(Register,Data) \ + WRITE_REGISTER_ULONG((Register),(Data)) +#else +#define NdisWriteRegisterUlong(Register,Data) { \ + WRITE_REGISTER_ULONG((Register),(Data)); \ + READ_REGISTER_ULONG(Register); \ + } +#endif + +/*++ +VOID +NdisReadRegisterUchar( + IN PUCHAR Register, + OUT PUCHAR Data + ) +--*/ +#if defined(_M_IX86) +#define NdisReadRegisterUchar(Register,Data) \ + *((PUCHAR)(Data)) = *(Register) +#else +#define NdisReadRegisterUchar(Register,Data) \ + *(Data) = READ_REGISTER_UCHAR((PUCHAR)(Register)) +#endif + +/*++ +VOID +NdisReadRegisterUshort( + IN PUSHORT Register, + OUT PUSHORT Data + ) +--*/ +#if defined(_M_IX86) +#define NdisReadRegisterUshort(Register,Data) \ + *((PUSHORT)(Data)) = *(Register) +#else +#define NdisReadRegisterUshort(Register,Data) \ + *(Data) = READ_REGISTER_USHORT((PUSHORT)(Register)) +#endif + +/*++ +VOID +NdisReadRegisterUlong( + IN PULONG Register, + OUT PULONG Data + ) +--*/ +#if defined(_M_IX86) +#define NdisReadRegisterUlong(Register,Data) \ + *((PULONG)(Data)) = *(Register) +#else +#define NdisReadRegisterUlong(Register,Data) \ + *(Data) = READ_REGISTER_ULONG((PULONG)(Register)) +#endif + +#if BINARY_COMPATIBLE + +EXPORT +BOOLEAN +NdisEqualString( + IN PNDIS_STRING String1, + IN PNDIS_STRING String2, + IN BOOLEAN CaseInsensitive + ); + +#else + +#define NdisEqualString(_String1,_String2,CaseInsensitive) \ + RtlEqualUnicodeString((_String1), (_String2), CaseInsensitive) + +#endif + +EXPORT +VOID +NdisWriteErrorLogEntry( + IN NDIS_HANDLE NdisAdapterHandle, + IN NDIS_ERROR_CODE ErrorCode, + IN ULONG NumberOfErrorValues, + ... + ); + +#define NdisInitializeString(Destination,Source) \ +{\ + PNDIS_STRING _D = (Destination);\ + UCHAR *_S = (Source);\ + WCHAR *_P;\ + _D->Length = (strlen(_S)) * sizeof(WCHAR);\ + _D->MaximumLength = _D->Length + sizeof(WCHAR);\ + NdisAllocateMemory((PVOID *)&(_D->Buffer), _D->MaximumLength, 0, (-1));\ + _P = _D->Buffer;\ + while(*_S != '\0'){\ + *_P = (WCHAR)(*_S);\ + _S++;\ + _P++;\ + }\ + *_P = UNICODE_NULL;\ +} + +#define NdisFreeString(String) NdisFreeMemory((String).Buffer, (String).MaximumLength, 0) + +#define NdisPrintString(String) DbgPrint("%ls",(String).Buffer) + + +#if !defined(_ALPHA_) +/*++ + + VOID + NdisCreateLookaheadBufferFromSharedMemory( + IN PVOID pSharedMemory, + IN UINT LookaheadLength, + OUT PVOID *pLookaheadBuffer + ); + +--*/ + +#define NdisCreateLookaheadBufferFromSharedMemory(_S, _L, _B) \ + ((*(_B)) = (_S)) + +/*++ + + VOID + NdisDestroyLookaheadBufferFromSharedMemory( + IN PVOID pLookaheadBuffer + ); + +--*/ + +#define NdisDestroyLookaheadBufferFromSharedMemory(_B) + +#else // Alpha + +EXPORT +VOID +NdisCreateLookaheadBufferFromSharedMemory( + IN PVOID pSharedMemory, + IN UINT LookaheadLength, + OUT PVOID *pLookaheadBuffer + ); + +EXPORT +VOID +NdisDestroyLookaheadBufferFromSharedMemory( + IN PVOID pLookaheadBuffer + ); + +#endif + + +// +// The following declarations are shared between ndismac.h and ndismini.h. They +// are meant to be for internal use only. They should not be used directly by +// miniport drivers. +// + +// +// declare these first since they point to each other +// + +typedef struct _NDIS_WRAPPER_HANDLE NDIS_WRAPPER_HANDLE, * PNDIS_WRAPPER_HANDLE; +typedef struct _NDIS_MAC_BLOCK NDIS_MAC_BLOCK, * PNDIS_MAC_BLOCK; +typedef struct _NDIS_ADAPTER_BLOCK NDIS_ADAPTER_BLOCK, * PNDIS_ADAPTER_BLOCK; +typedef struct _NDIS_PROTOCOL_BLOCK NDIS_PROTOCOL_BLOCK, * PNDIS_PROTOCOL_BLOCK; +typedef struct _NDIS_OPEN_BLOCK NDIS_OPEN_BLOCK, * PNDIS_OPEN_BLOCK; + +// +// Timers. +// + +typedef +VOID +(*PNDIS_TIMER_FUNCTION) ( + IN PVOID SystemSpecific1, + IN PVOID FunctionContext, + IN PVOID SystemSpecific2, + IN PVOID SystemSpecific3 + ); + +typedef struct _NDIS_TIMER { + KTIMER Timer; + KDPC Dpc; +} NDIS_TIMER, *PNDIS_TIMER; + +EXPORT +VOID +NdisSetTimer( + IN PNDIS_TIMER Timer, + IN UINT MillisecondsToDelay + ); + +// +// Function types for NDIS_PROTOCOL_CHARACTERISTICS +// + +typedef +VOID +(*SEND_COMPLETE_HANDLER) ( + IN NDIS_HANDLE ProtocolBindingContext, + IN PNDIS_PACKET Packet, + IN NDIS_STATUS Status + ); + +typedef +VOID +(*TRANSFER_DATA_COMPLETE_HANDLER) ( + IN NDIS_HANDLE ProtocolBindingContext, + IN PNDIS_PACKET Packet, + IN NDIS_STATUS Status, + IN UINT BytesTransferred + ); + +typedef +NDIS_STATUS +(*RECEIVE_HANDLER) ( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_HANDLE MacReceiveContext, + IN PVOID HeaderBuffer, + IN UINT HeaderBufferSize, + IN PVOID LookAheadBuffer, + IN UINT LookaheadBufferSize, + IN UINT PacketSize + ); + +typedef +VOID +(*RECEIVE_COMPLETE_HANDLER) ( + IN NDIS_HANDLE ProtocolBindingContext + ); + +// +// Wrapper initialization and termination. +// + +EXPORT +VOID +NdisInitializeWrapper( + OUT PNDIS_HANDLE NdisWrapperHandle, + IN PVOID SystemSpecific1, + IN PVOID SystemSpecific2, + IN PVOID SystemSpecific3 + ); + +EXPORT +VOID +NdisTerminateWrapper( + IN NDIS_HANDLE NdisWrapperHandle, + IN PVOID SystemSpecific + ); + +// +// Shared memory +// + +#define NdisUpdateSharedMemory(_H, _L, _V, _P) + +// +// System processor count +// + +EXPORT +CCHAR +NdisSystemProcessorCount( + VOID + ); + +// +// Override bus number +// + +EXPORT +VOID +NdisOverrideBusNumber( + IN NDIS_HANDLE WrapperConfigurationContext, + IN NDIS_HANDLE MiniportAdapterHandle OPTIONAL, + IN ULONG BusNumber + ); + + +EXPORT +VOID +NdisImmediateReadPortUchar( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG Port, + OUT PUCHAR Data + ); + +EXPORT +VOID +NdisImmediateReadPortUshort( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG Port, + OUT PUSHORT Data + ); + +EXPORT +VOID +NdisImmediateReadPortUlong( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG Port, + OUT PULONG Data + ); + +EXPORT +VOID +NdisImmediateWritePortUchar( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG Port, + IN UCHAR Data + ); + +EXPORT +VOID +NdisImmediateWritePortUshort( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG Port, + IN USHORT Data + ); + +EXPORT +VOID +NdisImmediateWritePortUlong( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG Port, + IN ULONG Data + ); + +EXPORT +ULONG +NdisImmediateReadPciSlotInformation( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG SlotNumber, + IN ULONG Offset, + IN PVOID Buffer, + IN ULONG Length + ); + +EXPORT +ULONG +NdisImmediateWritePciSlotInformation( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG SlotNumber, + IN ULONG Offset, + IN PVOID Buffer, + IN ULONG Length + ); + diff --git a/private/ntos/ndis/ndis30/ndismini.h b/private/ntos/ndis/ndis30/ndismini.h new file mode 100644 index 000000000..38892897d --- /dev/null +++ b/private/ntos/ndis/ndis30/ndismini.h @@ -0,0 +1,1216 @@ +#include <afilter.h> +#include <efilter.h> +#include <tfilter.h> +#include <ffilter.h> + +#define NDIS_M_MAX_MULTI_LIST 32 +#define NDIS_M_MAX_LOOKAHEAD 526 + +// +// declare these first since they point to each other +// + +typedef struct _NDIS_M_DRIVER_BLOCK NDIS_M_DRIVER_BLOCK, * PNDIS_M_DRIVER_BLOCK; +typedef struct _NDIS_MINIPORT_BLOCK NDIS_MINIPORT_BLOCK, * PNDIS_MINIPORT_BLOCK; +typedef struct _NDIS_M_PROTOCOL_BLOCK NDIS_M_PROTOCOL_BLOCK, * PNDIS_M_PROTOCOL_BLOCK; +typedef struct _NDIS_M_OPEN_BLOCK NDIS_M_OPEN_BLOCK, * PNDIS_M_OPEN_BLOCK; + + +// +// Function types for NDIS_MINIPORT_CHARACTERISTICS +// + + +typedef +BOOLEAN +(*W_CHECK_FOR_HANG_HANDLER) ( + IN NDIS_HANDLE MiniportAdapterContext + ); + +typedef +VOID +(*W_DISABLE_INTERRUPT_HANDLER) ( + IN NDIS_HANDLE MiniportAdapterContext + ); + +typedef +VOID +(*W_ENABLE_INTERRUPT_HANDLER) ( + IN NDIS_HANDLE MiniportAdapterContext + ); + +typedef +VOID +(*W_HALT_HANDLER) ( + IN NDIS_HANDLE MiniportAdapterContext + ); + +typedef +VOID +(*W_HANDLE_INTERRUPT_HANDLER) ( + IN NDIS_HANDLE MiniportAdapterContext + ); + +typedef +NDIS_STATUS +(*W_INITIALIZE_HANDLER) ( + OUT PNDIS_STATUS OpenErrorStatus, + OUT PUINT SelectedMediumIndex, + IN PNDIS_MEDIUM MediumArray, + IN UINT MediumArraySize, + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_HANDLE WrapperConfigurationContext + ); + +typedef +VOID +(*W_ISR_HANDLER) ( + OUT PBOOLEAN InterruptRecognized, + OUT PBOOLEAN QueueMiniportHandleInterrupt, + IN NDIS_HANDLE MiniportAdapterContext + ); + +typedef +NDIS_STATUS +(*W_QUERY_INFORMATION_HANDLER) ( + IN NDIS_HANDLE MiniportAdapterContext, + IN NDIS_OID Oid, + IN PVOID InformationBuffer, + IN ULONG InformationBufferLength, + OUT PULONG BytesWritten, + OUT PULONG BytesNeeded + ); + +typedef +NDIS_STATUS +(*W_RECONFIGURE_HANDLER) ( + OUT PNDIS_STATUS OpenErrorStatus, + IN NDIS_HANDLE MiniportAdapterContext, + IN NDIS_HANDLE WrapperConfigurationContext + ); + +typedef +NDIS_STATUS +(*W_RESET_HANDLER) ( + OUT PBOOLEAN AddressingReset, + IN NDIS_HANDLE MiniportAdapterContext + ); + +typedef +NDIS_STATUS +(*W_SEND_HANDLER) ( + IN NDIS_HANDLE MiniportAdapterContext, + IN PNDIS_PACKET Packet, + IN UINT Flags + ); + +typedef +NDIS_STATUS +(*W_SET_INFORMATION_HANDLER) ( + IN NDIS_HANDLE MiniportAdapterContext, + IN NDIS_OID Oid, + IN PVOID InformationBuffer, + IN ULONG InformationBufferLength, + OUT PULONG BytesRead, + OUT PULONG BytesNeeded + ); + +typedef +NDIS_STATUS +(*W_TRANSFER_DATA_HANDLER) ( + OUT PNDIS_PACKET Packet, + OUT PUINT BytesTransferred, + IN NDIS_HANDLE MiniportAdapterContext, + IN NDIS_HANDLE MiniportReceiveContext, + IN UINT ByteOffset, + IN UINT BytesToTransfer + ); + +typedef struct _NDIS_MINIPORT_CHARACTERISTICS { + UCHAR MajorNdisVersion; + UCHAR MinorNdisVersion; + UINT Reserved; + W_CHECK_FOR_HANG_HANDLER CheckForHangHandler; + W_DISABLE_INTERRUPT_HANDLER DisableInterruptHandler; + W_ENABLE_INTERRUPT_HANDLER EnableInterruptHandler; + W_HALT_HANDLER HaltHandler; + W_HANDLE_INTERRUPT_HANDLER HandleInterruptHandler; + W_INITIALIZE_HANDLER InitializeHandler; + W_ISR_HANDLER ISRHandler; + W_QUERY_INFORMATION_HANDLER QueryInformationHandler; + W_RECONFIGURE_HANDLER ReconfigureHandler; + W_RESET_HANDLER ResetHandler; + W_SEND_HANDLER SendHandler; + W_SET_INFORMATION_HANDLER SetInformationHandler; + W_TRANSFER_DATA_HANDLER TransferDataHandler; +} NDIS_MINIPORT_CHARACTERISTICS, *PNDIS_MINIPORT_CHARACTERISTICS; + +// +// one of these per Driver +// + +struct _NDIS_M_DRIVER_BLOCK { + PNDIS_MINIPORT_BLOCK MiniportQueue; // queue of mini-ports for this driver + NDIS_HANDLE MiniportIdField; + + REFERENCE Ref; // contains spinlock for MiniportQueue + UINT Length; // of this NDIS_DRIVER_BLOCK structure + NDIS_MINIPORT_CHARACTERISTICS MiniportCharacteristics; // handler addresses + PNDIS_WRAPPER_HANDLE NdisDriverInfo; // Driver information. + PNDIS_M_DRIVER_BLOCK NextDriver; + PNDIS_MAC_BLOCK FakeMac; + KEVENT MiniportsRemovedEvent; // used to find when all mini-ports are gone. + BOOLEAN Unloading; // TRUE if unloading + +}; + +typedef struct _NDIS_MINIPORT_INTERRUPT { + PKINTERRUPT InterruptObject; + KSPIN_LOCK DpcCountLock; + PVOID MiniportIdField; + W_ISR_HANDLER MiniportIsr; + W_HANDLE_INTERRUPT_HANDLER MiniportDpc; + KDPC InterruptDpc; + PNDIS_MINIPORT_BLOCK Miniport; + UCHAR DpcCount; + BOOLEAN Filler1; + + // + // This is used to tell when all the Dpcs for the adapter are completed. + // + + KEVENT DpcsCompletedEvent; + + BOOLEAN SharedInterrupt; + BOOLEAN IsrRequested; + +} NDIS_MINIPORT_INTERRUPT, *PNDIS_MINIPORT_INTERRUPT; + + +typedef struct _NDIS_MINIPORT_TIMER { + KTIMER Timer; + KDPC Dpc; + PNDIS_TIMER_FUNCTION MiniportTimerFunction; + PVOID MiniportTimerContext; + PNDIS_MINIPORT_BLOCK Miniport; + struct _NDIS_MINIPORT_TIMER *NextDeferredTimer; +} NDIS_MINIPORT_TIMER, *PNDIS_MINIPORT_TIMER; + +// +// Pending NdisOpenAdapter() structure (for miniports only). +// + +typedef struct _MINIPORT_PENDING_OPEN *PMINIPORT_PENDING_OPEN; + +typedef struct _MINIPORT_PENDING_OPEN { + + PMINIPORT_PENDING_OPEN NextPendingOpen; + PNDIS_HANDLE NdisBindingHandle; + PNDIS_MINIPORT_BLOCK Miniport; + PVOID NewOpenP; + PVOID FileObject; + NDIS_HANDLE NdisProtocolHandle; + NDIS_HANDLE ProtocolBindingContext; + PNDIS_STRING AdapterName; + UINT OpenOptions; + PSTRING AddressingInformation; + BOOLEAN UsingEncapsulation; +} MINIPORT_PENDING_OPEN; + + +// +// one of these per mini-port registered on a Driver +// + +struct _NDIS_MINIPORT_BLOCK { + ULONG Flags; // used to distinquish between MACs and mini-ports + PDEVICE_OBJECT DeviceObject; // created by the wrapper + PNDIS_M_DRIVER_BLOCK DriverHandle; // pointer to our Driver block + NDIS_HANDLE MiniportAdapterContext; // context when calling mini-port functions + NDIS_STRING MiniportName; // how mini-port refers to us + PNDIS_M_OPEN_BLOCK OpenQueue; // queue of opens for this mini-port + PNDIS_MINIPORT_BLOCK NextMiniport; // used by driver's MiniportQueue + REFERENCE Ref; // contains spinlock for OpenQueue + BOOLEAN NormalInterrupts; + BOOLEAN ProcessingDeferred; // TRUE if processing deferred operations + + // + // Synchronization stuff. + // + // The boolean is used to lock out several DPCs from running at the + // same time. The difficultly is if DPC A releases the spin lock + // and DPC B tries to run, we want to defer B until after A has + // exited. + // + BOOLEAN LockAcquired; + NDIS_SPIN_LOCK Lock; + PNDIS_MINIPORT_INTERRUPT Interrupt; + + // + // Stuff that got deferred. + // + BOOLEAN RunDpc; + BOOLEAN Timeout; + BOOLEAN InAddDriver; + BOOLEAN InInitialize; + PNDIS_MINIPORT_TIMER RunTimer; + NDIS_TIMER DpcTimer; + NDIS_TIMER WakeUpDpcTimer; + + // + // Holds media specific information + // + PETH_FILTER EthDB; + PTR_FILTER TrDB; + PFDDI_FILTER FddiDB; + PARC_FILTER ArcDB; + NDIS_MEDIUM MediaType; + + UCHAR TrResetRing; + UCHAR ArcnetAddress; + BOOLEAN ArcnetBroadcastSet; + BOOLEAN SendCompleteCalled; + + PVOID WrapperContext; + + NDIS_HANDLE ArcnetBufferPool; + PARC_BUFFER_LIST ArcnetFreeBufferList; + PARC_BUFFER_LIST ArcnetUsedBufferList; + + // + // Resource information + // + PCM_RESOURCE_LIST Resources; + + // + // contains mini-port information + // + ULONG BusNumber; + NDIS_INTERFACE_TYPE BusType; + NDIS_INTERFACE_TYPE AdapterType; + BOOLEAN Master; + + // + // Holds the map registers for this mini-port. + // + BOOLEAN Dma32BitAddresses; + PMAP_REGISTER_ENTRY MapRegisters; + ULONG PhysicalMapRegistersNeeded; + ULONG MaximumPhysicalMapping; + + // + // These two are used temporarily while allocating + // the map registers. + // + KEVENT AllocationEvent; + UINT CurrentMapRegister; + PADAPTER_OBJECT SystemAdapterObject; + + // + // Send information + // + PNDIS_PACKET FirstPacket; // This pointer serves two purposes; + // it is the head of the queue of ALL + // packets that have been sent to + // the miniport, it is also the head + // of the packets that have been sent + // down to the miniport by the wrapper. + PNDIS_PACKET LastPacket; // This is tail pointer for the global + // packet queue and this is the tail + // pointer to the queue of packets + // waiting to be sent to the miniport. + PNDIS_PACKET FirstPendingPacket; // This is head of the queue of packets + // waiting to be sent to miniport. + PNDIS_PACKET LastMiniportPacket; // This is the tail pointer of the + // queue of packets that have been + // sent to the miniport by the wrapper. + ULONG SendResourcesAvailable; + PNDIS_PACKET DeadPacket; // This pointer is used by the wake-up + // dpc to make sure that a packet that + // was sent to the miniport has been + // completed with-in a decent amount + // of time. + BOOLEAN AlreadyLoopedBack; // This flag is set if a packet that + // is waiting to be sent to the + // miniport has already been looped- + // back; + + + // + // Transfer data information + // + PNDIS_PACKET FirstTDPacket; + PNDIS_PACKET LastTDPacket; + PNDIS_PACKET LoopbackPacket; + UINT LoopbackPacketHeaderSize; + + // + // Reset information + // + PNDIS_M_OPEN_BLOCK ResetRequested; + PNDIS_M_OPEN_BLOCK ResetInProgress; + + // + // RequestInformation + // + KEVENT RequestEvent; + PNDIS_REQUEST FirstPendingRequest; + PNDIS_REQUEST LastPendingRequest; + PNDIS_REQUEST MiniportRequest; + NDIS_REQUEST InternalRequest; + NDIS_STATUS RequestStatus; + UINT MaximumLongAddresses; + UINT MaximumShortAddresses; + UINT CurrentLookahead; + UINT MaximumLookahead; + UINT MacOptions; + ULONG SupportedPacketFilters; + BOOLEAN NeedToUpdateEthAddresses; + BOOLEAN NeedToUpdatePacketFilter; + BOOLEAN NeedToUpdateFunctionalAddress; + BOOLEAN NeedToUpdateGroupAddress; + BOOLEAN NeedToUpdateFddiLongAddresses; + BOOLEAN NeedToUpdateFddiShortAddresses; + BOOLEAN RunDoRequests; + BOOLEAN ProcessOddDeferredStuff; + UCHAR MulticastBuffer[NDIS_M_MAX_MULTI_LIST][6]; + UCHAR LookaheadBuffer[NDIS_M_MAX_LOOKAHEAD]; + + BOOLEAN BeingRemoved; // TRUE if mini-port is being removed + BOOLEAN HaltingMiniport; // TRUE if mini-port halt handler needs to be called + + // + // Temp stuff for using the old NDIS functions + // + ULONG ChannelNumber; + + PMINIPORT_PENDING_OPEN FirstPendingOpen; + PMINIPORT_PENDING_OPEN LastPendingOpen; + BOOLEAN PendingRequestTimeout; +}; + +#define MINIPORT_LOCK_ACQUIRED(_Miniport) ((_Miniport)->LockAcquired) + + +// +// one of these per open on an mini-port/protocol +// + +struct _NDIS_M_OPEN_BLOCK { + PNDIS_M_DRIVER_BLOCK DriverHandle; // pointer to our driver + PNDIS_MINIPORT_BLOCK MiniportHandle; // pointer to our mini-port + PNDIS_PROTOCOL_BLOCK ProtocolHandle; // pointer to our protocol + PNDIS_OPEN_BLOCK FakeOpen; // Pointer to fake open block + NDIS_HANDLE ProtocolBindingContext; // context when calling ProtXX funcs + NDIS_HANDLE MiniportAdapterContext; // context when calling MiniportXX funcs + PNDIS_M_OPEN_BLOCK MiniportNextOpen; // used by mini-port's OpenQueue + PFILE_OBJECT FileObject; // created by operating system + BOOLEAN Closing; // TRUE when removing this struct + BOOLEAN UsingEthEncapsulation; // TRUE if running 802.3 on 878.2 + NDIS_HANDLE CloseRequestHandle; // 0 indicates an internal close + NDIS_HANDLE FilterHandle; + NDIS_SPIN_LOCK SpinLock; // guards Closing + ULONG References; + UINT CurrentLookahead; + ULONG ProtocolOptions; + + // + // These are optimizations for getting to driver routines. They are not + // necessary, but are here to save a dereference through the Driver block. + // + + W_SEND_HANDLER SendHandler; + W_TRANSFER_DATA_HANDLER TransferDataHandler; + + // + // These are optimizations for getting to PROTOCOL routines. They are not + // necessary, but are here to save a dereference through the PROTOCOL block. + // + + SEND_COMPLETE_HANDLER SendCompleteHandler; + TRANSFER_DATA_COMPLETE_HANDLER TransferDataCompleteHandler; + RECEIVE_HANDLER ReceiveHandler; + RECEIVE_COMPLETE_HANDLER ReceiveCompleteHandler; + +}; + +// +// NOTE: THIS STRUCTURE MUST, MUST, MUST ALIGN WITH THE +// NDIS_USER_OPEN_CONTEXT STRUCTURE defined in the wrapper. +// +typedef struct _NDIS_M_USER_OPEN_CONTEXT { + PDEVICE_OBJECT DeviceObject; + PNDIS_MINIPORT_BLOCK MiniportBlock; + ULONG OidCount; + PNDIS_OID OidArray; +} NDIS_M_USER_OPEN_CONTEXT, *PNDIS_M_USER_OPEN_CONTEXT; + + +typedef struct _NDIS_REQUEST_RESERVED { + PNDIS_REQUEST Next; + struct _NDIS_M_OPEN_BLOCK * Open; +} NDIS_REQUEST_RESERVED, *PNDIS_REQUEST_RESERVED; + +#define PNDIS_RESERVED_FROM_PNDIS_REQUEST(_request) \ + ((PNDIS_REQUEST_RESERVED)((_request)->MacReserved)) + + +BOOLEAN +NdisMIsr( + IN PKINTERRUPT KInterrupt, + IN PVOID Context + ); + +VOID +NdisMDpc( + IN PVOID SystemSpecific1, + IN PVOID InterruptContext, + IN PVOID SystemSpecific2, + IN PVOID SystemSpecific3 + ); + +VOID +NdisMDpcTimer( + IN PVOID SystemSpecific1, + IN PVOID InterruptContext, + IN PVOID SystemSpecific2, + IN PVOID SystemSpecific3 + ); + +VOID +NdisMWakeUpDpc( + PKDPC Dpc, + PVOID Context, + PVOID SystemContext1, + PVOID SystemContext2 + ); + +NDIS_STATUS +NdisMChangeEthAddresses( + IN UINT OldAddressCount, + IN CHAR OldAddresses[][6], + IN UINT NewAddressCount, + IN CHAR NewAddresses[][6], + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest, + IN BOOLEAN Set + ); + +NDIS_STATUS +NdisMChangeClass( + IN UINT OldFilterClasses, + IN UINT NewFilterClasses, + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest, + IN BOOLEAN Set + ); + +VOID +NdisMCloseAction( + IN NDIS_HANDLE MacBindingHandle + ); + +NDIS_STATUS +NdisMChangeFunctionalAddress( + IN TR_FUNCTIONAL_ADDRESS OldFunctionalAddress, + IN TR_FUNCTIONAL_ADDRESS NewFunctionalAddress, + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest, + IN BOOLEAN Set + ); + +NDIS_STATUS +NdisMChangeGroupAddress( + IN TR_FUNCTIONAL_ADDRESS OldGroupAddress, + IN TR_FUNCTIONAL_ADDRESS NewGroupAddress, + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest, + IN BOOLEAN Set + ); + +NDIS_STATUS +NdisMChangeFddiAddresses( + IN UINT oldLongAddressCount, + IN CHAR oldLongAddresses[][6], + IN UINT newLongAddressCount, + IN CHAR newLongAddresses[][6], + IN UINT oldShortAddressCount, + IN CHAR oldShortAddresses[][2], + IN UINT newShortAddressCount, + IN CHAR newShortAddresses[][2], + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest, + IN BOOLEAN Set + ); + +NDIS_STATUS +NdisMSend( + IN NDIS_HANDLE NdisBindingHandle, + IN PNDIS_PACKET Packet + ); + +NDIS_STATUS +NdisMTransferData( + IN NDIS_HANDLE NdisBindingHandle, + IN NDIS_HANDLE MacReceiveContext, + IN UINT ByteOffset, + IN UINT BytesToTransfer, + IN OUT PNDIS_PACKET Packet, + OUT PUINT BytesTransferred + ); + +NDIS_STATUS +NdisMArcTransferData( + IN NDIS_HANDLE NdisBindingHandle, + IN NDIS_HANDLE MacReceiveContext, + IN UINT ByteOffset, + IN UINT BytesToTransfer, + IN OUT PNDIS_PACKET Packet, + OUT PUINT BytesTransferred + ); + +NDIS_STATUS +NdisMReset( + IN NDIS_HANDLE NdisBindingHandle + ); + +NDIS_STATUS +NdisMRequest( + IN NDIS_HANDLE NdisBindingHandle, + IN PNDIS_REQUEST NdisRequest + ); + + +// +// Operating System Requests +// + +EXPORT +NDIS_STATUS +NdisMAllocateMapRegisters( + IN NDIS_HANDLE MiniportAdapterHandle, + IN UINT DmaChannel, + IN BOOLEAN Dma32BitAddresses, + IN ULONG PhysicalMapRegistersNeeded, + IN ULONG MaximumPhysicalMapping + ); + +EXPORT +VOID +NdisMFreeMapRegisters( + IN NDIS_HANDLE MiniportAdapterHandle + ); + +EXPORT +NDIS_STATUS +NdisMRegisterIoPortRange( + OUT PVOID *PortOffset, + IN NDIS_HANDLE MiniportAdapterHandle, + IN UINT InitialPort, + IN UINT NumberOfPorts + ); + +EXPORT +VOID +NdisMDeregisterIoPortRange( + IN NDIS_HANDLE MiniportAdapterHandle, + IN UINT InitialPort, + IN UINT NumberOfPorts, + IN PVOID PortOffset + ); + +EXPORT +NDIS_STATUS +NdisMMapIoSpace( + OUT PVOID * VirtualAddress, + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_PHYSICAL_ADDRESS PhysicalAddress, + IN UINT Length + ); + +EXPORT +VOID +NdisMUnmapIoSpace( + IN NDIS_HANDLE MiniportAdapterHandle, + IN PVOID VirtualAddress, + IN UINT Length + ); + +EXPORT +NDIS_STATUS +NdisMRegisterInterrupt( + OUT PNDIS_MINIPORT_INTERRUPT Interrupt, + IN NDIS_HANDLE MiniportAdapterHandle, + IN UINT InterruptVector, + IN UINT InterruptLevel, + IN BOOLEAN RequestIsr, + IN BOOLEAN SharedInterrupt, + IN NDIS_INTERRUPT_MODE InterruptMode + ); + +EXPORT +VOID +NdisMDeregisterInterrupt( + IN PNDIS_MINIPORT_INTERRUPT Interrupt + ); + +EXPORT +BOOLEAN +NdisMSynchronizeWithInterrupt( + IN PNDIS_MINIPORT_INTERRUPT Interrupt, + IN PVOID SynchronizeFunction, + IN PVOID SynchronizeContext + ); + + +EXPORT +NDIS_STATUS +NdisMQueryAdapterResources( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE WrapperConfigurationContext, + OUT PNDIS_RESOURCE_LIST ResourceList, + IN OUT PUINT BufferSize + ); + +// +// Timers +// + +/*++ +VOID +NdisMSetTimer( + IN PNDIS_MINIPORT_TIMER Timer, + IN UINT MillisecondsToDelay + ); +--*/ +#define NdisMSetTimer(_Timer, _Delay) NdisSetTimer((PNDIS_TIMER)(_Timer), _Delay) + +EXPORT +VOID +NdisMInitializeTimer( + IN OUT PNDIS_MINIPORT_TIMER Timer, + IN NDIS_HANDLE MiniportAdapterHandle, + IN PNDIS_TIMER_FUNCTION TimerFunction, + IN PVOID FunctionContext + ); + +EXPORT +VOID +NdisMCancelTimer( + IN PNDIS_MINIPORT_TIMER Timer, + OUT PBOOLEAN TimerCancelled + ); + +// +// Physical Mapping +// + +#define NdisMStartBufferPhysicalMappingMacro( \ + _MiniportAdapterHandle, \ + _Buffer, \ + _PhysicalMapRegister, \ + _Write, \ + _PhysicalAddressArray, \ + _ArraySize \ + ) \ +{ \ + PNDIS_MINIPORT_BLOCK _Miniport = (PNDIS_MINIPORT_BLOCK)(_MiniportAdapterHandle); \ + PHYSICAL_ADDRESS _LogicalAddress; \ + PUCHAR _VirtualAddress; \ + ULONG _LengthRemaining; \ + ULONG _LengthMapped; \ + UINT _CurrentArrayLocation; \ + _VirtualAddress = MmGetMdlVirtualAddress(_Buffer); \ + _LengthRemaining = MmGetMdlByteCount(_Buffer); \ + _CurrentArrayLocation = 0; \ + while (_LengthRemaining > 0) { \ + _LengthMapped = _LengthRemaining; \ + _LogicalAddress = \ + IoMapTransfer( \ + NULL, \ + (_Buffer), \ + _Miniport->MapRegisters[_PhysicalMapRegister].MapRegister, \ + _VirtualAddress, \ + &_LengthMapped, \ + (_Write)); \ + (_PhysicalAddressArray)[_CurrentArrayLocation].PhysicalAddress = _LogicalAddress; \ + (_PhysicalAddressArray)[_CurrentArrayLocation].Length = _LengthMapped; \ + _LengthRemaining -= _LengthMapped; \ + _VirtualAddress += _LengthMapped; \ + ++_CurrentArrayLocation; \ + } \ + _Miniport->MapRegisters[_PhysicalMapRegister].WriteToDevice = (_Write); \ + *(_ArraySize) = _CurrentArrayLocation; \ +} + +#if BINARY_COMPATIBLE + +EXPORT +VOID +NdisMStartBufferPhysicalMapping( + IN NDIS_HANDLE MiniportAdapterHandle, + IN PNDIS_BUFFER Buffer, + IN ULONG PhysicalMapRegister, + IN BOOLEAN WriteToDevice, + OUT PNDIS_PHYSICAL_ADDRESS_UNIT PhysicalAddressArray, + OUT PUINT ArraySize + ); + +#else + +#define NdisMStartBufferPhysicalMapping( \ + _MiniportAdapterHandle, \ + _Buffer, \ + _PhysicalMapRegister, \ + _Write, \ + _PhysicalAddressArray, \ + _ArraySize \ + ) \ + NdisMStartBufferPhysicalMappingMacro( \ + (_MiniportAdapterHandle), \ + (_Buffer), \ + (_PhysicalMapRegister), \ + (_Write), \ + (_PhysicalAddressArray), \ + (_ArraySize) \ + ) + +#endif + +#define NdisMCompleteBufferPhysicalMappingMacro( \ + _MiniportAdapterHandle, \ + _Buffer, \ + _PhysicalMapRegister \ + ) { \ + PNDIS_MINIPORT_BLOCK _Miniport = (PNDIS_MINIPORT_BLOCK)(_MiniportAdapterHandle); \ + IoFlushAdapterBuffers( \ + NULL, \ + _Buffer, \ + _Miniport->MapRegisters[_PhysicalMapRegister].MapRegister, \ + MmGetMdlVirtualAddress(_Buffer), \ + MmGetMdlByteCount(_Buffer), \ + _Miniport->MapRegisters[_PhysicalMapRegister].WriteToDevice); \ +} + +#if BINARY_COMPATIBLE + +EXPORT +VOID +NdisMCompleteBufferPhysicalMapping( + IN NDIS_HANDLE MiniportAdapterHandle, + IN PNDIS_BUFFER Buffer, + IN ULONG PhysicalMapRegister + ); + +#else + +#define NdisMCompleteBufferPhysicalMapping( \ + _MiniportAdapterHandle, \ + _Buffer, \ + _PhysicalMapRegister \ + ) \ + NdisMCompleteBufferPhysicalMappingMacro( \ + (_MiniportAdapterHandle), \ + (_Buffer), \ + (_PhysicalMapRegister) \ + ) + +#endif + +// +// Shared memory +// + +EXPORT +VOID +NdisMAllocateSharedMemory( + IN NDIS_HANDLE MiniportAdapterHandle, + IN ULONG Length, + IN BOOLEAN Cached, + OUT PVOID *VirtualAddress, + OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress + ); + +/*++ +VOID +NdisMUpdateSharedMemory( + IN NDIS_HANDLE MiniportAdapterHandle, + IN ULONG Length, + IN PVOID VirtualAddress, + IN NDIS_PHYSICAL_ADDRESS PhysicalAddress + ) +--*/ +#define NdisMUpdateSharedMemory(_H, _L, _V, _P) NdisUpdateSharedMemory(_H, _L, _V, _P) + + +EXPORT +VOID +NdisMFreeSharedMemory( + IN NDIS_HANDLE MiniportAdapterHandle, + IN ULONG Length, + IN BOOLEAN Cached, + IN PVOID VirtualAddress, + IN NDIS_PHYSICAL_ADDRESS PhysicalAddress + ); + + +// +// DMA operations. +// + +EXPORT +NDIS_STATUS +NdisMRegisterDmaChannel( + OUT PNDIS_HANDLE MiniportDmaHandle, + IN NDIS_HANDLE MiniportAdapterHandle, + IN UINT DmaChannel, + IN BOOLEAN Dma32BitAddresses, + IN PNDIS_DMA_DESCRIPTION DmaDescription, + IN ULONG MaximumLength + ); + + +EXPORT +VOID +NdisMDeregisterDmaChannel( + IN PNDIS_HANDLE MiniportDmaHandle + ); + +/*++ +VOID +NdisMSetupDmaTransfer( + OUT PNDIS_STATUS Status, + IN PNDIS_HANDLE MiniportDmaHandle, + IN PNDIS_BUFFER Buffer, + IN ULONG Offset, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ) +--*/ +#define NdisMSetupDmaTransfer(_S, _H, _B, _O, _L, _M_) \ + NdisSetupDmaTransfer(_S, _H, _B, _O, _L, _M_) + +/*++ +VOID +NdisMCompleteDmaTransfer( + OUT PNDIS_STATUS Status, + IN PNDIS_HANDLE MiniportDmaHandle, + IN PNDIS_BUFFER Buffer, + IN ULONG Offset, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ) +--*/ +#define NdisMCompleteDmaTransfer(_S, _H, _B, _O, _L, _M_) \ + NdisCompleteDmaTransfer(_S, _H, _B, _O, _L, _M_) + +EXPORT +ULONG +NdisMReadDmaCounter( + IN NDIS_HANDLE MiniportDmaHandle + ); + + +// +// Requests Used by Miniport Drivers +// + + +#define NdisMInitializeWrapper(_a,_b,_c,_d) NdisInitializeWrapper((_a),(_b),(_c),(_d)) + +EXPORT +NDIS_STATUS +NdisMRegisterMiniport( + IN NDIS_HANDLE NdisWrapperHandle, + IN PNDIS_MINIPORT_CHARACTERISTICS MiniportCharacteristics, + IN UINT CharacteristicsLength + ); + +EXPORT +VOID +NdisMSetAttributes( + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_HANDLE MiniportAdapterContext, + IN BOOLEAN BusMaster, + IN NDIS_INTERFACE_TYPE AdapterType + ); + +EXPORT +VOID +NdisMSendComplete( + IN NDIS_HANDLE MiniportAdapterHandle, + IN PNDIS_PACKET Packet, + IN NDIS_STATUS Status + ); + +EXPORT +VOID +NdisMSendResourcesAvailable( + IN NDIS_HANDLE MiniportAdapterHandle + ); + +EXPORT +VOID +NdisMTransferDataComplete( + IN NDIS_HANDLE MiniportAdapterHandle, + IN PNDIS_PACKET Packet, + IN NDIS_STATUS Status, + IN UINT BytesTransferred + ); + +EXPORT +VOID +NdisMResetComplete( + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_STATUS Status, + IN BOOLEAN AddressingReset + ); + +EXPORT +VOID +NdisMSetInformationComplete( + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_STATUS Status + ); + +EXPORT +VOID +NdisMQueryInformationComplete( + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_STATUS Status + ); + + +/*++ + +VOID +NdisMEthIndicateReceive( + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_HANDLE MiniportReceiveContext, + IN PVOID HeaderBuffer, + IN UINT HeaderBufferSize, + IN PVOID LookaheadBuffer, + IN UINT LookaheadBufferSize, + IN UINT PacketSize + ) + +--*/ +#define NdisMEthIndicateReceive( _H, _C, _B, _SZ, _L, _LSZ, _PSZ ) \ +{ \ + ASSERT(MINIPORT_LOCK_ACQUIRED((PNDIS_MINIPORT_BLOCK)(_H))); \ + EthFilterDprIndicateReceive( \ + ((PNDIS_MINIPORT_BLOCK)(_H))->EthDB, \ + _C, \ + _B, \ + _B, \ + _SZ, \ + _L, \ + _LSZ, \ + _PSZ \ + ); \ +} + +/*++ + +VOID +NdisMTrIndicateReceive( + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_HANDLE MiniportReceiveContext, + IN PVOID HeaderBuffer, + IN UINT HeaderBufferSize, + IN PVOID LookaheadBuffer, + IN UINT LookaheadBufferSize, + IN UINT PacketSize + ) + +--*/ +#define NdisMTrIndicateReceive( _H, _C, _B, _SZ, _L, _LSZ, _PSZ ) \ +{ \ + ASSERT(MINIPORT_LOCK_ACQUIRED((PNDIS_MINIPORT_BLOCK)(_H))); \ + TrFilterDprIndicateReceive( \ + ((PNDIS_MINIPORT_BLOCK)(_H))->TrDB, \ + _C, \ + _B, \ + _SZ, \ + _L, \ + _LSZ, \ + _PSZ \ + ); \ +} + +/*++ + +VOID +NdisMFddiIndicateReceive( + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_HANDLE MiniportReceiveContext, + IN PVOID HeaderBuffer, + IN UINT HeaderBufferSize, + IN PVOID LookaheadBuffer, + IN UINT LookaheadBufferSize, + IN UINT PacketSize + ) + +--*/ + +#define NdisMFddiIndicateReceive( _H, _C, _B, _SZ, _L, _LSZ, _PSZ ) \ +{ \ + ASSERT(MINIPORT_LOCK_ACQUIRED((PNDIS_MINIPORT_BLOCK)(_H))); \ + \ + FddiFilterDprIndicateReceive( \ + ((PNDIS_MINIPORT_BLOCK)(_H))->FddiDB, \ + _C, \ + (PUCHAR)_B + 1, \ + ((((PUCHAR)_B)[0] & 0x40) ? FDDI_LENGTH_OF_LONG_ADDRESS \ + : FDDI_LENGTH_OF_SHORT_ADDRESS), \ + _B, \ + _SZ, \ + _L, \ + _LSZ, \ + _PSZ \ + ); \ +} + +/*++ + +VOID +NdisMArcIndicateReceive( + IN NDIS_HANDLE MiniportAdapterHandle, + IN PUCHAR pRawHeader, // Pointer to Arcnet frame header + IN PUCHAR pData, // Pointer to data portion of Arcnet frame + IN UINT Length // Data Length + ) + +--*/ +#define NdisMArcIndicateReceive( _H, _HD, _D, _SZ) \ +{ \ + ASSERT(MINIPORT_LOCK_ACQUIRED((PNDIS_MINIPORT_BLOCK)(_H))); \ + ArcFilterDprIndicateReceive( \ + ((PNDIS_MINIPORT_BLOCK)(_H))->ArcDB, \ + _HD, \ + _D, \ + _SZ \ + ); \ +} + +// +// Used only internally by the wrapper and filter package. +// +VOID +NdisMArcIndicateEthEncapsulatedReceive( + IN PNDIS_MINIPORT_BLOCK Miniport, + IN PVOID HeaderBuffer, + IN PVOID DataBuffer, + IN UINT Length + ); + + + + +/*++ + +VOID +NdisMEthIndicateReceiveComplete( + IN NDIS_HANDLE MiniportAdapterHandle + ); + +--*/ + +#define NdisMEthIndicateReceiveComplete( _H ) \ +{ \ + PNDIS_MINIPORT_BLOCK _M_ = (PNDIS_MINIPORT_BLOCK)_H; \ + ASSERT(MINIPORT_LOCK_ACQUIRED(_M_)); \ + EthFilterDprIndicateReceiveComplete(_M_->EthDB); \ +} + +/*++ + +VOID +NdisMTrIndicateReceiveComplete( + IN NDIS_HANDLE MiniportAdapterHandle + ); + +--*/ + +#define NdisMTrIndicateReceiveComplete( _H ) \ +{ \ + PNDIS_MINIPORT_BLOCK _M_ = (PNDIS_MINIPORT_BLOCK)_H; \ + ASSERT(MINIPORT_LOCK_ACQUIRED(_M_)); \ + TrFilterDprIndicateReceiveComplete(_M_->TrDB); \ +} + +/*++ + +VOID +NdisMFddiIndicateReceiveComplete( + IN NDIS_HANDLE MiniportAdapterHandle + ); + +--*/ + +#define NdisMFddiIndicateReceiveComplete( _H ) \ +{ \ + PNDIS_MINIPORT_BLOCK _M_ = (PNDIS_MINIPORT_BLOCK)_H; \ + ASSERT(MINIPORT_LOCK_ACQUIRED(_M_)); \ + FddiFilterDprIndicateReceiveComplete(_M_->FddiDB); \ +} + +/*++ + +VOID +NdisMArcIndicateReceiveComplete( + IN NDIS_HANDLE MiniportAdapterHandle + ); + +--*/ + +#define NdisMArcIndicateReceiveComplete( _H ) \ +{ \ + PNDIS_MINIPORT_BLOCK _M_ = (PNDIS_MINIPORT_BLOCK)_H; \ + ASSERT(MINIPORT_LOCK_ACQUIRED(_M_)); \ + \ + if ( _M_->EthDB ) { \ + EthFilterDprIndicateReceiveComplete(_M_->EthDB); \ + } \ + \ + ArcFilterDprIndicateReceiveComplete(_M_->ArcDB); \ +} + +EXPORT +VOID +NdisMIndicateStatus( + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_STATUS GeneralStatus, + IN PVOID StatusBuffer, + IN UINT StatusBufferSize + ); + +EXPORT +VOID +NdisMIndicateStatusComplete( + IN NDIS_HANDLE MiniportAdapterHandle + ); + +EXPORT +VOID +NdisMRegisterAdapterShutdownHandler( + IN NDIS_HANDLE MiniportHandle, + IN PVOID ShutdownContext, + IN ADAPTER_SHUTDOWN_HANDLER ShutdownHandler + ); + +EXPORT +VOID +NdisMDeregisterAdapterShutdownHandler( + IN NDIS_HANDLE MiniportHandle + ); + +EXPORT +NDIS_STATUS +NdisMPciAssignResources( + IN NDIS_HANDLE MiniportHandle, + IN ULONG SlotNumber, + IN PNDIS_RESOURCE_LIST *AssignedResources + ); + + diff --git a/private/ntos/ndis/ndis30/precomp.h b/private/ntos/ndis/ndis30/precomp.h new file mode 100644 index 000000000..9521fc237 --- /dev/null +++ b/private/ntos/ndis/ndis30/precomp.h @@ -0,0 +1,6 @@ +#include "wrapper.h" + +#include <afilter.h> +#include <efilter.h> +#include <ffilter.h> +#include <tfilter.h> diff --git a/private/ntos/ndis/ndis30/sources b/private/ntos/ndis/ndis30/sources new file mode 100644 index 000000000..1d31c6f72 --- /dev/null +++ b/private/ntos/ndis/ndis30/sources @@ -0,0 +1,59 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + Steve Wood (stevewo) 12-Apr-1990 + +NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl + +!ENDIF + +MAJORCOMP=ntos +MINORCOMP=ndis + +NT_UP=0 + +TARGETNAME=ndis +TARGETPATH=\nt\public\sdk\lib +TARGETTYPE=EXPORT_DRIVER + +MSC_WARNING_LEVEL=/W3 /WX + +INCLUDES=..\..\inc +C_DEFINES= $(C_DEFINES) -DNDIS_WRAPPER -D_NTDRIVER_ + +NTPROFILEINPUT=yes + + +SOURCES= \ + miniport.c \ + wrapper.c \ + minisub.c \ + afilter.c \ + efilter.c \ + tfilter.c \ + ffilter.c \ + ndis.rc + +PRECOMPILED_INCLUDE=precomp.h +PRECOMPILED_PCH=precomp.pch +PRECOMPILED_OBJ=precomp.obj + +DLLDEF=obj\*\ndis.def + +NTTARGETFILE0=obj\$(TARGET_DIRECTORY)\ndis.def + diff --git a/private/ntos/ndis/ndis30/tfilter.c b/private/ntos/ndis/ndis30/tfilter.c new file mode 100644 index 000000000..6d0b98a82 --- /dev/null +++ b/private/ntos/ndis/ndis30/tfilter.c @@ -0,0 +1,2119 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + tfilter.c + +Abstract: + + This module implements a set of library routines to handle packet + filtering for NDIS MAC drivers. + +Author: + + Anthony V. Ercolano (Tonye) 03-Aug-1990 + +Environment: + + Kernel Mode - Or whatever is the equivalent on OS/2 and DOS. + +Revision History: + + Adam Barr (adamba) 19-Mar-1991 + + - Modified for Token-Ring + +--*/ + +#include <precomp.h> +#pragma hdrstop + +// +// This constant is used for places where NdisAllocateMemory +// needs to be called and the HighestAcceptableAddress does +// not matter. +// + +static const NDIS_PHYSICAL_ADDRESS HighestAcceptableMax = + NDIS_PHYSICAL_ADDRESS_CONST(-1,-1); + +// +// ZZZ NonPortable definitions. +// +#define AllocPhys(s, l) NdisAllocateMemory((PVOID *)(s), (l), 0, HighestAcceptableMax) +#define FreePhys(s, l) NdisFreeMemory((PVOID)(s), (l), 0) + +#define RetrieveUlong(Destination, Source)\ +{\ + PUCHAR _S = (Source);\ + *(Destination) = ((ULONG)(*_S) << 24) | \ + ((ULONG)(*(_S+1)) << 16) | \ + ((ULONG)(*(_S+2)) << 8) | \ + ((ULONG)(*(_S+3)));\ +} + +#ifdef NDIS_NT +#define MoveMemory(Destination,Source,Length) RtlMoveMemory(Destination,Source,Length) +#define ZeroMemory(Destination,Length) RtlZeroMemory(Destination,Length) +#endif + +#ifdef NDIS_DOS +#define MoveMemory(Destination,Source,Length) \ +{\ + int _i = Length;\ + while( _i--) ((PUCHAR)(Destination))[_i] = ((PUCHAR)(Source))[_i]; \ +} + +#define ZeroMemory(Destination,Length) \ +{\ + int _i = Length;\ + while (_i--) ((PUCHAR)(Destination))[_i] = 0;\ +} +#endif + +// +// Used in case we have to call TrChangeFunctionalAddress or +// TrChangeGroupAddress with a NULL address. +// +static CHAR NullFunctionalAddress[4] = { 0x00 }; + + +// +// Maximum number of supported opens +// +#define TR_FILTER_MAX_OPENS 32 + + + +#if DBG +extern BOOLEAN NdisCheckBadDrivers; +#endif + +//VOID +//CLEAR_BIT_IN_MASK( +// IN UINT Offset, +// IN OUT PULONG MaskToClear +// ) +// +///*++ +// +//Routine Description: +// +// Clear a bit in the bitmask pointed to by the parameter. +// +//Arguments: +// +// Offset - The offset (from 0) of the bit to altered. +// +// MaskToClear - Pointer to the mask to be adjusted. +// +//Return Value: +// +// None. +// +//--*/ +// +#define CLEAR_BIT_IN_MASK(Offset,MaskToClear) *MaskToClear &= (~(1 << Offset)) + +//VOID +//SET_BIT_IN_MASK( +// IN UINT Offset, +// IN OUT PULONG MaskToSet +// ) +// +///*++ +// +//Routine Description: +// +// Set a bit in the bitmask pointed to by the parameter. +// +//Arguments: +// +// Offset - The offset (from 0) of the bit to altered. +// +// MaskToSet - Pointer to the mask to be adjusted. +// +//Return Value: +// +// None. +// +//--*/ +#define SET_BIT_IN_MASK(Offset,MaskToSet) *MaskToSet |= (1 << Offset) + +//BOOLEAN +//IS_BIT_SET_IN_MASK( +// IN UINT Offset, +// IN ULONG MaskToTest +// ) +// +///*++ +// +//Routine Description: +// +// Tests if a particular bit in the bitmask pointed to by the parameter is +// set. +// +//Arguments: +// +// Offset - The offset (from 0) of the bit to test. +// +// MaskToTest - The mask to be tested. +// +//Return Value: +// +// Returns TRUE if the bit is set. +// +//--*/ +#define IS_BIT_SET_IN_MASK(Offset,MaskToTest) \ +((MaskToTest & (1 << Offset))?(TRUE):(FALSE)) + +// +// VOID +// TR_FILTER_ALLOC_OPEN( +// IN PTR_FILTER Filter, +// OUT PUINT FilterIndex +// ) +// +///*++ +// +//Routine Description: +// +// Allocates an open block. This only allocate the index, not memory for +// the open block. +// +//Arguments: +// +// Filter - DB from which to allocate the space +// +// FilterIndex - pointer to place to store the index. +// +//Return Value: +// +// FilterIndex of the new open +// +//--*/ +#define TR_FILTER_ALLOC_OPEN(Filter, FilterIndex)\ +{\ + UINT i; \ + for (i=0; i < TR_FILTER_MAX_OPENS; i++) { \ + if (IS_BIT_SET_IN_MASK(i,(Filter)->FreeBindingMask)) { \ + *(FilterIndex) = i; \ + CLEAR_BIT_IN_MASK(i, &((Filter)->FreeBindingMask)); \ + break; \ + } \ + } \ +} + +// +// VOID +// TR_FILTER_FREE_OPEN( +// IN PTR_FILTER Filter, +// IN PTR_BINDING_INFO LocalOpen +// ) +// +///*++ +// +//Routine Description: +// +// Frees an open block. Also frees the memory associated with the open. +// +//Arguments: +// +// Filter - DB from which to allocate the space +// +// FilterIndex - Index to free +// +//Return Value: +// +// FilterIndex of the new open +// +//--*/ +#define TR_FILTER_FREE_OPEN(Filter, LocalOpen)\ +{\ + SET_BIT_IN_MASK(((LocalOpen)->FilterIndex), &((Filter)->FreeBindingMask)); \ + FreePhys((LocalOpen), sizeof(TR_BINDING_INFO));\ +} + +NDIS_SPIN_LOCK TrReferenceLock = {0}; +KEVENT TrPagedInEvent = {0}; +ULONG TrReferenceCount = 0; +PVOID TrImageHandle = {0}; + +VOID +TrInitializePackage(VOID) +{ + NdisAllocateSpinLock(&TrReferenceLock); + KeInitializeEvent( + &TrPagedInEvent, + NotificationEvent, + FALSE + ); +} + +VOID +TrReferencePackage(VOID) +{ + + ACQUIRE_SPIN_LOCK(&TrReferenceLock); + + TrReferenceCount++; + + if (TrReferenceCount == 1) { + + KeResetEvent( + &TrPagedInEvent + ); + + RELEASE_SPIN_LOCK(&TrReferenceLock); + + // + // Page in all the functions + // + TrImageHandle = MmLockPagableCodeSection(TrCreateFilter); + + // + // Signal to everyone to go + // + KeSetEvent( + &TrPagedInEvent, + 0L, + FALSE + ); + + } else { + + RELEASE_SPIN_LOCK(&TrReferenceLock); + + // + // Wait for everything to be paged in + // + KeWaitForSingleObject( + &TrPagedInEvent, + Executive, + KernelMode, + TRUE, + NULL + ); + + } + +} + +VOID +TrDereferencePackage(VOID) +{ + ACQUIRE_SPIN_LOCK(&TrReferenceLock); + + TrReferenceCount--; + + if (TrReferenceCount == 0) { + + RELEASE_SPIN_LOCK(&TrReferenceLock); + + // + // Page out all the functions + // + MmUnlockPagableImageSection(TrImageHandle); + + } else { + + RELEASE_SPIN_LOCK(&TrReferenceLock); + + } + +} + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGENDST, TrShouldAddressLoopBack) +#pragma alloc_text(PAGENDST, TrFilterDprIndicateReceiveComplete) +#pragma alloc_text(PAGENDST, TrFilterIndicateReceiveComplete) +#pragma alloc_text(PAGENDST, TrFilterDprIndicateReceive) +#pragma alloc_text(PAGENDST, TrFilterIndicateReceive) +#pragma alloc_text(PAGENDST, TrFilterAdjust) +#pragma alloc_text(PAGENDST, TrChangeGroupAddress) +#pragma alloc_text(PAGENDST, TrChangeFunctionalAddress) +#pragma alloc_text(PAGENDST, TrDeleteFilterOpenAdapter) +#pragma alloc_text(PAGENDST, TrNoteFilterOpenAdapter) +#pragma alloc_text(PAGENDST, TrCreateFilter) + +#endif + + + + +BOOLEAN +TrCreateFilter( + IN TR_ADDRESS_CHANGE AddressChangeAction, + IN TR_GROUP_CHANGE GroupChangeAction, + IN TR_FILTER_CHANGE FilterChangeAction, + IN TR_DEFERRED_CLOSE CloseAction, + IN PUCHAR AdapterAddress, + IN PNDIS_SPIN_LOCK Lock, + OUT PTR_FILTER *Filter + ) + +/*++ + +Routine Description: + + This routine is used to create and initialize the filter database. + +Arguments: + + AddressChangeAction - Action routine to call when the ORing together + of the functional address desired by all the bindings had changed. + + GroupChangeAction - Action routine to call when the group address + desired by all the bindings had changed. + + FilterChangeAction - Action routine to call when a binding sets or clears + a particular filter class and it is the first or only binding using + the filter class. + + CloseAction - This routine is called if a binding closes while + it is being indicated to via NdisIndicateReceive. It will be + called upon return from NdisIndicateReceive. + + AdapterAddress - the address of the adapter associated with this filter + database. + + Lock - Pointer to the lock that should be held when mutual exclusion + is required. + + Filter - A pointer to a TR_FILTER. This is what is allocated and + created by this routine. + +Return Value: + + If the function returns false then one of the parameters exceeded + what the filter was willing to support. + +--*/ + +{ + + PTR_FILTER LocalFilter; + NDIS_STATUS AllocStatus; + + + // + // Allocate the database and it's associated arrays. + // + + AllocStatus = AllocPhys(&LocalFilter, sizeof(TR_FILTER)); + *Filter = LocalFilter; + + if (AllocStatus != NDIS_STATUS_SUCCESS) { + return FALSE; + } + + TrReferencePackage(); + + ZeroMemory( + LocalFilter, + sizeof(TR_FILTER) + ); + + + LocalFilter->GroupReferences = 0; + LocalFilter->GroupAddress = 0; + LocalFilter->OpenList = NULL; + LocalFilter->FreeBindingMask = (ULONG)-1; + + LocalFilter->Lock = Lock; + + TR_COPY_NETWORK_ADDRESS(LocalFilter->AdapterAddress, AdapterAddress); + LocalFilter->AddressChangeAction = AddressChangeAction; + LocalFilter->GroupChangeAction = GroupChangeAction; + LocalFilter->FilterChangeAction = FilterChangeAction; + LocalFilter->CloseAction = CloseAction; + + return TRUE; +} + +// +// NOTE : THIS ROUTINE CANNOT BE PAGEABLE +// + +VOID +TrDeleteFilter( + IN PTR_FILTER Filter + ) + +/*++ + +Routine Description: + + This routine is used to delete the memory associated with a filter + database. Note that this routines *ASSUMES* that the database + has been cleared of any active filters. + +Arguments: + + Filter - A pointer to a TR_FILTER to be deleted. + +Return Value: + + None. + +--*/ + +{ + + ASSERT(Filter->OpenList == NULL); + + FreePhys(Filter, sizeof(TR_FILTER)); + + TrDereferencePackage(); + +} + + +BOOLEAN +TrNoteFilterOpenAdapter( + IN PTR_FILTER Filter, + IN NDIS_HANDLE MacBindingHandle, + IN NDIS_HANDLE NdisBindingContext, + OUT PNDIS_HANDLE NdisFilterHandle + ) + +/*++ + +Routine Description: + + This routine is used to add a new binding to the filter database. + + NOTE: THIS ROUTINE ASSUMES THAT THE DATABASE IS LOCKED WHEN + IT IS CALLED. + +Arguments: + + Filter - A pointer to the previously created and initialized filter + database. + + MacBindingHandle - The MAC supplied value to the protocol in response + to a call to MacOpenAdapter. + + NdisBindingContext - An NDIS supplied value to the call to MacOpenAdapter. + + NdisFilterHandle - A pointer to the open block. + +Return Value: + + Will return false if creating a new filter index will cause the maximum + number of filter indexes to be exceeded. + +--*/ + +{ + NDIS_STATUS AllocStatus; + + // + // Will hold the value of the filter index so that we + // need not indirectly address through pointer parameter. + // + UINT LocalIndex; + + // + // This new open + // + PTR_BINDING_INFO LocalOpen; + + PNDIS_OPEN_BLOCK NdisOpen = (PNDIS_OPEN_BLOCK)NdisBindingContext; + + if (Filter->FreeBindingMask == 0) { + + return FALSE; + + } + + AllocStatus = AllocPhys( + &LocalOpen, + sizeof(TR_BINDING_INFO) + ); + + if (AllocStatus != NDIS_STATUS_SUCCESS) { + + return FALSE; + + } + + // + // Get place for the open and insert it. + // + + TR_FILTER_ALLOC_OPEN(Filter, &LocalIndex); + + LocalOpen->NextOpen = Filter->OpenList; + + if (Filter->OpenList != NULL) { + Filter->OpenList->PrevOpen = LocalOpen; + } + + LocalOpen->PrevOpen = NULL; + + Filter->OpenList = LocalOpen; + + LocalOpen->References = 1; + LocalOpen->FilterIndex = (UCHAR)LocalIndex; + LocalOpen->MacBindingHandle = MacBindingHandle; + LocalOpen->NdisBindingContext = NdisBindingContext; + LocalOpen->UsingGroupAddress = FALSE; + LocalOpen->PacketFilters = 0; + LocalOpen->ReceivedAPacket = FALSE; + + LocalOpen->FunctionalAddress = (TR_FUNCTIONAL_ADDRESS)0; + + *NdisFilterHandle = (PTR_BINDING_INFO)LocalOpen; + + return TRUE; + +} + + +NDIS_STATUS +TrDeleteFilterOpenAdapter( + IN PTR_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest + ) + +/*++ + +Routine Description: + + When an adapter is being closed this routine should + be called to delete knowledge of the adapter from + the filter database. This routine is likely to call + action routines associated with clearing filter classes + and addresses. + + NOTE: THIS ROUTINE SHOULD ****NOT**** BE CALLED IF THE ACTION + ROUTINES FOR DELETING THE FILTER CLASSES OR THE FUNCTIONAL ADDRESSES + HAVE ANY POSSIBILITY OF RETURNING A STATUS OTHER THAN NDIS_STATUS_PENDING + OR NDIS_STATUS_SUCCESS. WHILE THESE ROUTINES WILL NOT BUGCHECK IF + SUCH A THING IS DONE, THE CALLER WILL PROBABLY FIND IT DIFFICULT + TO CODE A CLOSE ROUTINE! + + NOTE: THIS ROUTINE ASSUMES THAT IT IS CALLED WITH THE LOCK HELD. + +Arguments: + + Filter - A pointer to the filter database. + + NdisFilterHandle - A pointer to the open. + + NdisRequest - If it is necessary to call the action routines, + this will be passed to it. + +Return Value: + + If action routines are called by the various address and filtering + routines the this routine will likely return the status returned + by those routines. The exception to this rule is noted below. + + Given that the filter and address deletion routines return a status + NDIS_STATUS_PENDING or NDIS_STATUS_SUCCESS this routine will then + try to return the filter index to the freelist. If the routine + detects that this binding is currently being indicated to via + NdisIndicateReceive, this routine will return a status of + NDIS_STATUS_CLOSING_INDICATING. + +--*/ + +{ + + // + // Holds the status returned from the packet filter and address + // deletion routines. Will be used to return the status to + // the caller of this routine. + // + NDIS_STATUS StatusToReturn; + + PTR_BINDING_INFO LocalOpen = (PTR_BINDING_INFO)NdisFilterHandle; + + StatusToReturn = TrFilterAdjust( + Filter, + NdisFilterHandle, + NdisRequest, + (UINT)0, + FALSE + ); + + + if (StatusToReturn == NDIS_STATUS_SUCCESS || + StatusToReturn == NDIS_STATUS_PENDING) { + + NDIS_STATUS StatusToReturn2; + + StatusToReturn2 = TrChangeFunctionalAddress( + Filter, + NdisFilterHandle, + NdisRequest, + NullFunctionalAddress, + FALSE + ); + + if (StatusToReturn2 != NDIS_STATUS_SUCCESS) { + + StatusToReturn = StatusToReturn2; + + + } + + } + + if (((StatusToReturn == NDIS_STATUS_SUCCESS) || + (StatusToReturn == NDIS_STATUS_PENDING)) && + (LocalOpen->UsingGroupAddress)) { + + Filter->GroupReferences--; + + LocalOpen->UsingGroupAddress = FALSE; + + if (Filter->GroupReferences == 0) { + + NDIS_STATUS StatusToReturn2; + + StatusToReturn2 = TrChangeGroupAddress( + Filter, + NdisFilterHandle, + NdisRequest, + NullFunctionalAddress, + FALSE + ); + + if (StatusToReturn2 != NDIS_STATUS_SUCCESS) { + + StatusToReturn = StatusToReturn2; + + } + + } + + } + + if ((StatusToReturn == NDIS_STATUS_SUCCESS) || + (StatusToReturn == NDIS_STATUS_PENDING)) { + + // + // If this is the last reference to the open - remove it. + // + + if ((--(LocalOpen->References)) == 0) { + + // + // Remove it from the list of opens. + // + + if (LocalOpen->NextOpen != NULL) { + + LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen; + + } + + if (LocalOpen->PrevOpen != NULL) { + + LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen; + + } else { + + Filter->OpenList = LocalOpen->NextOpen; + + } + + // + // Check if we need to clean up an IndicateReceiveComplete + // + + if (LocalOpen->ReceivedAPacket) { + + RELEASE_SPIN_LOCK_DPC(Filter->Lock); + + FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext); + + ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + + } + + // + // Destroy it. + // + + TR_FILTER_FREE_OPEN(Filter, LocalOpen); + + } else { + + // + // Let the caller know that this "reference" to the open + // is still "active". The close action routine will be + // called upon return from NdisIndicateReceive. + // + + StatusToReturn = NDIS_STATUS_CLOSING_INDICATING; + + } + + } + + return StatusToReturn; + +} + + +NDIS_STATUS +TrChangeFunctionalAddress( + IN PTR_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest, + IN CHAR FunctionalAddressArray[TR_LENGTH_OF_FUNCTIONAL], + IN BOOLEAN Set + ) + +/*++ + +Routine Description: + + The ChangeFunctionalAddress routine will call an action + routine when the overall functional address for the adapter + has changed. + + If the action routine returns a value other than pending or + success then this routine has no effect on the functional address + for the open or for the adapter as a whole. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + +Arguments: + + Filter - A pointer to the filter database. + + NdisFilterHandle - A pointer to the open + + NdisRequest - If it is necessary to call the action routine, + this will be passed to it. + + FunctionalAddress - The new functional address for this binding. + + Set - A boolean that determines whether the filter classes + are being adjusted due to a set or because of a close. (The filtering + routines don't care, the MAC might.) + +Return Value: + + If it calls the action routine then it will return the + status returned by the action routine. If the status + returned by the action routine is anything other than + NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database + will be returned to the state it was in upon entrance to this + routine. + + If the action routine is not called this routine will return + the following statum: + + NDIS_STATUS_SUCCESS - If the new packet filters doesn't change + the combined mask of all bindings packet filters. + +--*/ + +{ + // + // Holds the functional address as a longword. + // + TR_FUNCTIONAL_ADDRESS FunctionalAddress; + + // + // Contains the value of the combined functional address before + // it is adjusted. + // + UINT OldCombined = Filter->CombinedFunctionalAddress; + + // + // Pointer to the open. + // + PTR_BINDING_INFO LocalOpen = (PTR_BINDING_INFO)NdisFilterHandle; + + // + // Contains the value of the particlar open's packet filters + // prior to the change. We save this in case the action + // routine (if called) returns an "error" status. + // + UINT OldFunctionalAddress = + LocalOpen->FunctionalAddress; + + // + // Holds the status returned to the user of this routine, if the + // action routine is not called then the status will be success, + // otherwise, it is whatever the action routine returns. + // + NDIS_STATUS StatusOfAdjust; + + // + // Simple iteration variable. + // + PTR_BINDING_INFO OpenList; + + + // + // Convert the 32 bits of the address to a longword. + // + RetrieveUlong(&FunctionalAddress, FunctionalAddressArray); + + // + // Set the new filter information for the open. + // + + LocalOpen->FunctionalAddress = FunctionalAddress; + + // + // We always have to reform the compbined filter since + // this filter index may have been the only filter index + // to use a particular bit. + // + + for ( + OpenList = Filter->OpenList,Filter->CombinedFunctionalAddress = 0; + OpenList != NULL; + OpenList = OpenList->NextOpen + ) { + + Filter->CombinedFunctionalAddress |= + OpenList->FunctionalAddress; + + } + + if (OldCombined != Filter->CombinedFunctionalAddress) { + + StatusOfAdjust = Filter->AddressChangeAction( + OldCombined, + Filter->CombinedFunctionalAddress, + LocalOpen->MacBindingHandle, + NdisRequest, + Set + ); + + if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) && + (StatusOfAdjust != NDIS_STATUS_PENDING)) { + + // + // The user returned a bad status. Put things back as + // they were. + // + + LocalOpen->FunctionalAddress = OldFunctionalAddress; + Filter->CombinedFunctionalAddress = OldCombined; + + } + + } else { + + StatusOfAdjust = NDIS_STATUS_SUCCESS; + + } + + return StatusOfAdjust; + +} + + +NDIS_STATUS +TrChangeGroupAddress( + IN PTR_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest, + IN CHAR GroupAddressArray[TR_LENGTH_OF_FUNCTIONAL], + IN BOOLEAN Set + ) + +/*++ + +Routine Description: + + The ChangeGroupAddress routine will call an action + routine when the overall group address for the adapter + has changed. + + If the action routine returns a value other than pending or + success then this routine has no effect on the group address + for the open or for the adapter as a whole. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + +Arguments: + + Filter - A pointer to the filter database. + + NdisFilterHandle - A pointer to the open. + + NdisRequest - If it is necessary to call the action routine, + this will be passed to it. + + GroupAddressArray - The new group address for this binding. + + Set - A boolean that determines whether the filter classes + are being adjusted due to a set or because of a close. (The filtering + routines don't care, the MAC might.) + +Return Value: + + If it calls the action routine then it will return the + status returned by the action routine. If the status + returned by the action routine is anything other than + NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database + will be returned to the state it was in upon entrance to this + routine. + + If the action routine is not called this routine will return + the following statum: + + NDIS_STATUS_SUCCESS - If the new packet filters doesn't change + the combined mask of all bindings packet filters. + +--*/ + +{ + // + // Holds the Group address as a longword. + // + TR_FUNCTIONAL_ADDRESS GroupAddress; + + PTR_BINDING_INFO LocalOpen = (PTR_BINDING_INFO)NdisFilterHandle; + + UINT OldGroupAddress = Filter->GroupAddress; + UINT OldReferenceCount = Filter->GroupReferences; + + // + // Holds the status returned to the user of this routine, if the + // action routine is not called then the status will be success, + // otherwise, it is whatever the action routine returns. + // + NDIS_STATUS StatusOfAdjust; + + // + // Convert the 32 bits of the address to a longword. + // + RetrieveUlong(&GroupAddress, GroupAddressArray); + + // + // See if this is a deletion + // + if ((GroupAddressArray[0] == NullFunctionalAddress[0]) && + (GroupAddressArray[1] == NullFunctionalAddress[1]) && + (GroupAddressArray[2] == NullFunctionalAddress[2]) && + (GroupAddressArray[3] == NullFunctionalAddress[3])) { + + if (LocalOpen->UsingGroupAddress) { + + Filter->GroupReferences--; + + LocalOpen->UsingGroupAddress = FALSE; + + if (Filter->GroupReferences != 0) { + + return(NDIS_STATUS_SUCCESS); + + } + + } else if (Filter->GroupReferences != 0) { + + return(NDIS_STATUS_GROUP_ADDRESS_IN_USE); + + } else { + + return(NDIS_STATUS_SUCCESS); + + } + + } else { + + // + // See if this address is already the current address. + // + + if (GroupAddress == Filter->GroupAddress) { + + if (LocalOpen->UsingGroupAddress) { + + return(NDIS_STATUS_SUCCESS); + + } + + if (Filter->GroupReferences != 0) { + + LocalOpen->UsingGroupAddress = TRUE; + + Filter->GroupReferences++; + + return(NDIS_STATUS_SUCCESS); + + } + + } else { + + if (Filter->GroupReferences > 1) { + + return(NDIS_STATUS_GROUP_ADDRESS_IN_USE); + + } + + if ((Filter->GroupReferences == 1) && !(LocalOpen->UsingGroupAddress)) { + + return(NDIS_STATUS_GROUP_ADDRESS_IN_USE); + + } + + if ((Filter->GroupReferences == 1) && (LocalOpen->UsingGroupAddress)) { + + // + // Remove old reference + // + + Filter->GroupReferences--; + LocalOpen->UsingGroupAddress = FALSE; + + } + + } + + } + + // + // Set the new filter information for the open. + // + + Filter->GroupAddress = GroupAddress; + + StatusOfAdjust = Filter->GroupChangeAction( + OldGroupAddress, + Filter->GroupAddress, + LocalOpen->MacBindingHandle, + NdisRequest, + Set + ); + + if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) && + (StatusOfAdjust != NDIS_STATUS_PENDING)) { + + // + // The user returned a bad status. Put things back as + // they were. + // + + Filter->GroupAddress = OldGroupAddress; + Filter->GroupReferences = OldReferenceCount; + + } else if (GroupAddress == 0x00000000) { + + LocalOpen->UsingGroupAddress = FALSE; + Filter->GroupReferences = 0; + + } else { + + LocalOpen->UsingGroupAddress = TRUE; + + Filter->GroupReferences = 1; + + } + + return StatusOfAdjust; + +} + + +NDIS_STATUS +TrFilterAdjust( + IN PTR_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest, + IN UINT FilterClasses, + IN BOOLEAN Set + ) + +/*++ + +Routine Description: + + The FilterAdjust routine will call an action routine when a + particular filter class is changes from not being used by any + binding to being used by at least one binding or vice versa. + + If the action routine returns a value other than pending or + success then this routine has no effect on the packet filters + for the open or for the adapter as a whole. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + +Arguments: + + Filter - A pointer to the filter database. + + NdisFilterHandle - A pointer to the open. + + NdisRequest - If it is necessary to call the action routine, + this will be passed to it. + + FilterClasses - The filter classes that are to be added or + deleted. + + Set - A boolean that determines whether the filter classes + are being adjusted due to a set or because of a close. (The filtering + routines don't care, the MAC might.) + +Return Value: + + If it calls the action routine then it will return the + status returned by the action routine. If the status + returned by the action routine is anything other than + NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database + will be returned to the state it was in upon entrance to this + routine. + + If the action routine is not called this routine will return + the following statum: + + NDIS_STATUS_SUCCESS - If the new packet filters doesn't change + the combined mask of all bindings packet filters. + +--*/ + +{ + // + // Contains the value of the combined filter classes before + // it is adjusted. + // + UINT OldCombined = Filter->CombinedPacketFilter; + + // + // Pointer to the open + // + PTR_BINDING_INFO LocalOpen = (PTR_BINDING_INFO)NdisFilterHandle; + + // + // Contains the value of the particlar opens packet filters + // prior to the change. We save this incase the action + // routine (if called) returns an "error" status. + // + UINT OldOpenFilters = LocalOpen->PacketFilters; + + // + // Holds the status returned to the user of this routine, if the + // action routine is not called then the status will be success, + // otherwise, it is whatever the action routine returns. + // + NDIS_STATUS StatusOfAdjust; + + // + // Simple iteration variable. + // + PTR_BINDING_INFO OpenList; + + // + // Set the new filter information for the open. + // + + LocalOpen->PacketFilters = FilterClasses; + + // + // We always have to reform the compbined filter since + // this filter index may have been the only filter index + // to use a particular bit. + // + + for ( + OpenList = Filter->OpenList,Filter->CombinedPacketFilter = 0; + OpenList != NULL; + OpenList = OpenList->NextOpen + ) { + + Filter->CombinedPacketFilter |= + OpenList->PacketFilters; + + } + + if (OldCombined != Filter->CombinedPacketFilter) { + + StatusOfAdjust = Filter->FilterChangeAction( + OldCombined, + Filter->CombinedPacketFilter, + LocalOpen->MacBindingHandle, + NdisRequest, + Set + ); + + if ((StatusOfAdjust != NDIS_STATUS_SUCCESS) && + (StatusOfAdjust != NDIS_STATUS_PENDING)) { + + // + // The user returned a bad status. Put things back as + // they were. + // + + LocalOpen->PacketFilters = OldOpenFilters; + Filter->CombinedPacketFilter = OldCombined; + + } + + } else { + + StatusOfAdjust = NDIS_STATUS_SUCCESS; + + } + + return StatusOfAdjust; + +} + + +VOID +TrFilterIndicateReceive( + IN PTR_FILTER Filter, + IN NDIS_HANDLE MacReceiveContext, + IN PVOID HeaderBuffer, + IN UINT HeaderBufferSize, + IN PVOID LookaheadBuffer, + IN UINT LookaheadBufferSize, + IN UINT PacketSize + ) + +/*++ + +Routine Description: + + This routine is called by the MAC to indicate a packet to + all bindings. The packet will be filtered so that only the + appropriate bindings will receive the packet. + +Arguments: + + Filter - Pointer to the filter database. + + MacReceiveContext - A MAC supplied context value that must be + returned by the protocol if it calls MacTransferData. + + HeaderBuffer - A virtual address of the virtually contiguous + buffer containing the MAC header of the packet. + + HeaderBufferSize - An unsigned integer indicating the size of + the header buffer, in bytes. + + LookaheadBuffer - A virtual address of the virtually contiguous + buffer containing the first LookaheadBufferSize bytes of data + of the packet. The packet buffer is valid only within the current + call to the receive event handler. + + LookaheadBufferSize - An unsigned integer indicating the size of + the lookahead buffer, in bytes. + + PacketSize - An unsigned integer indicating the size of the received + packet, in bytes. This number has nothing to do with the lookahead + buffer, but indicates how large the arrived packet is so that a + subsequent MacTransferData request can be made to transfer the entire + packet as necessary. + +Return Value: + + None. + +--*/ + +{ + KIRQL oldIrql; + KeRaiseIrql( DISPATCH_LEVEL, &oldIrql ); + ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + TrFilterDprIndicateReceive( + Filter, + MacReceiveContext, + HeaderBuffer, + HeaderBufferSize, + LookaheadBuffer, + LookaheadBufferSize, + PacketSize + ); + RELEASE_SPIN_LOCK_DPC(Filter->Lock); + KeLowerIrql( oldIrql ); + return; +} + + +VOID +TrFilterDprIndicateReceive( + IN PTR_FILTER Filter, + IN NDIS_HANDLE MacReceiveContext, + IN PVOID HeaderBuffer, + IN UINT HeaderBufferSize, + IN PVOID LookaheadBuffer, + IN UINT LookaheadBufferSize, + IN UINT PacketSize + ) + +/*++ + +Routine Description: + + This routine is called by the MAC to indicate a packet to + all bindings. The packet will be filtered so that only the + appropriate bindings will receive the packet. + + Called at DPC_LEVEL. + +Arguments: + + Filter - Pointer to the filter database. + + MacReceiveContext - A MAC supplied context value that must be + returned by the protocol if it calls MacTransferData. + + HeaderBuffer - A virtual address of the virtually contiguous + buffer containing the MAC header of the packet. + + HeaderBufferSize - An unsigned integer indicating the size of + the header buffer, in bytes. + + LookaheadBuffer - A virtual address of the virtually contiguous + buffer containing the first LookaheadBufferSize bytes of data + of the packet. The packet buffer is valid only within the current + call to the receive event handler. + + LookaheadBufferSize - An unsigned integer indicating the size of + the lookahead buffer, in bytes. + + PacketSize - An unsigned integer indicating the size of the received + packet, in bytes. This number has nothing to do with the lookahead + buffer, but indicates how large the arrived packet is so that a + subsequent MacTransferData request can be made to transfer the entire + packet as necessary. + +Return Value: + + None. + +--*/ + +{ + // + // The destination address in the lookahead buffer. + // + PCHAR DestinationAddress = (PCHAR)HeaderBuffer + 2; + + // + // The source address in the lookahead buffer. + // + PCHAR SourceAddress = (PCHAR)HeaderBuffer + 8; + + // + // Will hold the type of address that we know we've got. + // + UINT AddressType; + + // + // TRUE if the packet is source routing packet. + // + BOOLEAN IsSourceRouting; + + // + // The functional address as a longword, if the packet + // is addressed to one. + // + TR_FUNCTIONAL_ADDRESS FunctionalAddress; + + // + // Will hold the status of indicating the receive packet. + // ZZZ For now this isn't used. + // + NDIS_STATUS StatusOfReceive; + + // + // Will hold the open being indicated. + // + PTR_BINDING_INFO LocalOpen; + + // + // Will hold the filter classes of the binding being indicated. + // + UINT BindingFilters; + + // + // Holds intersection of open filters and this packet's type + // + UINT IntersectionOfFilters; + + // + // If the packet is a runt packet, then only indicate to PROMISCUOUS + // + + if ( HeaderBufferSize >= 14 && PacketSize != 0 ) { + + // + // Holds the result of address determinations. + // + BOOLEAN ResultOfAddressCheck; + + TR_IS_SOURCE_ROUTING( + SourceAddress, + &IsSourceRouting + ); + + // + // First check if it *at least* has the functional address bit. + // + + TR_IS_NOT_DIRECTED( + DestinationAddress, + &ResultOfAddressCheck + ); + + if (ResultOfAddressCheck) { + + // + // It is at least a functional address. Check to see if + // it is a broadcast address. + // + + TR_IS_BROADCAST( + DestinationAddress, + &ResultOfAddressCheck + ); + + if (ResultOfAddressCheck) { + +#if DBG + +if (NdisCheckBadDrivers) { + + if (!(Filter->CombinedPacketFilter & NDIS_PACKET_TYPE_BROADCAST)) { + + // + // We should never receive directed packets + // to someone else unless in p-mode. + // + DbgPrint("NDIS: Bad driver, indicating broadcast\n"); + DbgPrint("NDIS: packets when not set to.\n"); + DbgBreakPoint(); + + } + +} + +#endif + + AddressType = NDIS_PACKET_TYPE_BROADCAST; + + } else { + + TR_IS_GROUP( + DestinationAddress, + &ResultOfAddressCheck + ); + + if (ResultOfAddressCheck) { + + AddressType = NDIS_PACKET_TYPE_GROUP; + + } else { + + AddressType = NDIS_PACKET_TYPE_FUNCTIONAL; + + } + + RetrieveUlong(&FunctionalAddress, + (DestinationAddress + 2)); + + + } + + } else { + + // + // Verify that the address is directed to the adapter. We + // have to check for this because of the following senario. + // + // Adapter A is in promiscuous mode. + // Adapter B only wants directed packets to this adapter. + // + // The MAC will indicate *all* packets. + // + // The filter package needs to filter directed packets to + // other adapters from ones directed to this adapter. + // + + if (Filter->CombinedPacketFilter & + (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_SOURCE_ROUTING)) { + + // + // The result of comparing an element of the address + // array and the multicast address. + // + // Result < 0 Implies the adapter address is greater. + // Result > 0 Implies the address is greater. + // Result = 0 Implies that the they are equal. + // + INT Result; + + TR_COMPARE_NETWORK_ADDRESSES_EQ( + Filter->AdapterAddress, + DestinationAddress, + &Result + ); + + if (Result == 0) { + + AddressType = NDIS_PACKET_TYPE_DIRECTED; + + } else { + + // + // This will cause binding that only want a specific + // address type to not be indicated. + // + + AddressType = 0; + + } + + } else { + +#if DBG + +if (NdisCheckBadDrivers) { + + // + // The result of comparing an element of the address + // array and the multicast address. + // + // Result < 0 Implies the adapter address is greater. + // Result > 0 Implies the address is greater. + // Result = 0 Implies that the they are equal. + // + INT Result; + + TR_COMPARE_NETWORK_ADDRESSES_EQ( + Filter->AdapterAddress, + DestinationAddress, + &Result + ); + + if (Result != 0) { + + // + // We should never receive directed packets + // to someone else unless in p-mode. + // + DbgPrint("NDIS: Bad driver, indicating packets\n"); + DbgPrint("NDIS: to another station when not in\n"); + DbgPrint("NDIS: promiscuous mode.\n"); + DbgBreakPoint(); + + + } + +} + +#endif + + AddressType = NDIS_PACKET_TYPE_DIRECTED; + + } + + } + + } else { + + // + // Runt Packet + // + + AddressType = NDIS_PACKET_TYPE_PROMISCUOUS; + IsSourceRouting = FALSE; + + } + + // + // We need to aquire the filter exclusively while we're finding + // bindings to indicate to. + // + + LocalOpen = Filter->OpenList; + + while (LocalOpen != NULL) { + + BindingFilters = LocalOpen->PacketFilters; + IntersectionOfFilters = BindingFilters & AddressType; + + // + // Can check directed and broadcast at the same time, just + // mask off all but those two bits in BindingFilters and + // then see if one of them corresponds to AddressType. + // + + if (IntersectionOfFilters & + (NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST)) { + + goto IndicatePacket; + + } + + // + // if the binding wants functional packets and the packet + // is a functional packet and it's in the list of addresses + // it will get the packet. + // + + if (IntersectionOfFilters & NDIS_PACKET_TYPE_FUNCTIONAL) { + + // + // See if the bit from the frame's address is also + // part of this bindings registered functional address. + // + if (FunctionalAddress & + LocalOpen->FunctionalAddress) { + + goto IndicatePacket; + + } + + } + + // + // if the binding wants all functional packets and the packet + // has a functional address it will get the packet + // + + if ((AddressType & NDIS_PACKET_TYPE_FUNCTIONAL) && + (BindingFilters & NDIS_PACKET_TYPE_ALL_FUNCTIONAL)) { + + goto IndicatePacket; + + } + + // + // If the packet is a group packet and the binding is using the + // group address then it will get the packet. + // + + if ((AddressType & NDIS_PACKET_TYPE_GROUP) && + (BindingFilters & NDIS_PACKET_TYPE_GROUP) && + (LocalOpen->UsingGroupAddress)) { + + goto IndicatePacket; + + } + + // + // if this is a source routing packet and the binding + // wants it, indicate it. + // + + if ((BindingFilters & NDIS_PACKET_TYPE_SOURCE_ROUTING) && + IsSourceRouting) { + + goto IndicatePacket; + + } + + // + // if the binding is promiscuous then it will get the packet + // + + if (BindingFilters & NDIS_PACKET_TYPE_PROMISCUOUS) { + + goto IndicatePacket; + + } + + // + // Nothing satisfied, so don't indicate the packet to + // this binding. + // + + goto GetNextBinding; + +IndicatePacket:; + + LocalOpen->References++; + + RELEASE_SPIN_LOCK_DPC(Filter->Lock); + + // + // Indicate the packet to the binding. + // + + FilterIndicateReceive( + &StatusOfReceive, + LocalOpen->NdisBindingContext, + MacReceiveContext, + HeaderBuffer, + HeaderBufferSize, + LookaheadBuffer, + LookaheadBufferSize, + PacketSize + ); + + ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + + LocalOpen->ReceivedAPacket = TRUE; + + if ((--(LocalOpen->References)) == 0) { + + PTR_BINDING_INFO NextOpen = LocalOpen->NextOpen; + + // + // This binding is shutting down. + // + + + // + // Remove it from the list of opens. + // + + if (LocalOpen->NextOpen != NULL) { + + LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen; + + } + + if (LocalOpen->PrevOpen != NULL) { + + LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen; + + } else { + + Filter->OpenList = LocalOpen->NextOpen; + + } + + // + // Call the IndicateComplete routine. + // + + if (LocalOpen->ReceivedAPacket) { + + RELEASE_SPIN_LOCK_DPC(Filter->Lock); + + FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext); + + ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + + } + + // + // Call the macs action routine so that they know we + // are no longer referencing this open binding. + // + + Filter->CloseAction( + LocalOpen->MacBindingHandle + ); + + TR_FILTER_FREE_OPEN(Filter, LocalOpen); + + LocalOpen = NextOpen; + + continue; + + } + +GetNextBinding: + + LocalOpen = LocalOpen->NextOpen; + + } + +} + + +VOID +TrFilterIndicateReceiveComplete( + IN PTR_FILTER Filter + ) + +/*++ + +Routine Description: + + This routine is called by the MAC to indicate that the receive + process is done and to indicate to all protocols which received + a packet that receive is complete. + +Arguments: + + Filter - Pointer to the filter database. + +Return Value: + + None. + +--*/ + +{ + KIRQL oldIrql; + KeRaiseIrql( DISPATCH_LEVEL, &oldIrql ); + ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + TrFilterDprIndicateReceiveComplete( + Filter + ); + RELEASE_SPIN_LOCK_DPC(Filter->Lock); + KeLowerIrql( oldIrql ); + return; +} + + +VOID +TrFilterDprIndicateReceiveComplete( + IN PTR_FILTER Filter + ) + +/*++ + +Routine Description: + + This routine is called by the MAC to indicate that the receive + process is done and to indicate to all protocols which received + a packet that receive is complete. + + Called at DPC_LEVEL. + +Arguments: + + Filter - Pointer to the filter database. + +Return Value: + + None. + +--*/ + +{ + // + // Pointer to currently indicated binding. + // + PTR_BINDING_INFO LocalOpen; + + // + // We need to aquire the filter exclusively while we're finding + // bindings to indicate to. + // + + LocalOpen = Filter->OpenList; + + while (LocalOpen != NULL) { + + LocalOpen->References++; + + if (LocalOpen->ReceivedAPacket) { + + // + // Indicate the binding. + // + + LocalOpen->ReceivedAPacket = FALSE; + + RELEASE_SPIN_LOCK_DPC(Filter->Lock); + + FilterIndicateReceiveComplete(LocalOpen->NdisBindingContext); + + ACQUIRE_SPIN_LOCK_DPC(Filter->Lock); + + } + + if ((--(LocalOpen->References)) == 0) { + + // + // This binding is shutting down. + // + + PTR_BINDING_INFO NextOpen = LocalOpen->NextOpen; + + // + // Remove it from the list. + // + + if (LocalOpen->NextOpen != NULL) { + + LocalOpen->NextOpen->PrevOpen = LocalOpen->PrevOpen; + + } + + if (LocalOpen->PrevOpen != NULL) { + + LocalOpen->PrevOpen->NextOpen = LocalOpen->NextOpen; + + } else { + + Filter->OpenList = LocalOpen->NextOpen; + + } + + // + // Call the macs action routine so that they know we + // are no longer referencing this open binding. + // + + Filter->CloseAction( + LocalOpen->MacBindingHandle + ); + + TR_FILTER_FREE_OPEN(Filter, LocalOpen); + + LocalOpen = NextOpen; + + } else { + + LocalOpen = LocalOpen->NextOpen; + + } + + } + +} + + +BOOLEAN +TrShouldAddressLoopBack( + IN PTR_FILTER Filter, + IN CHAR DestinationAddress[TR_LENGTH_OF_ADDRESS], + IN CHAR SourceAddress[TR_LENGTH_OF_ADDRESS] + ) + +/*++ + +Routine Description: + + Do a quick check to see whether the input address should + loopback. + + NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD. + + NOTE: THIS ROUTINE DOES NOT CHECK THE SPECIAL CASE OF SOURCE + EQUALS DESTINATION. + +Arguments: + + Filter - Pointer to the filter database. + + Address - A network address to check for loopback. + + +Return Value: + + Returns TRUE if the address is *likely* to need loopback. It + will return FALSE if there is *no* chance that the address would + require loopback. + +--*/ +{ + + // + // Holds the result of address determinations. + // + BOOLEAN ResultOfAddressCheck; + + BOOLEAN IsSourceRouting; + + UINT CombinedFilters; + + ULONG GroupAddress; + + // + // Convert the 32 bits of the address to a longword. + // + RetrieveUlong(&GroupAddress, (SourceAddress + 2)); + + // + // Check if the destination is a preexisting group address + // + + TR_IS_GROUP( + SourceAddress, + &ResultOfAddressCheck + ); + + if ((ResultOfAddressCheck) && + (GroupAddress == Filter->GroupAddress) && + (Filter->GroupReferences != 0)) { + + return(TRUE); + + } + + + CombinedFilters = TR_QUERY_FILTER_CLASSES(Filter); + + if ((!CombinedFilters) || (CombinedFilters & NDIS_PACKET_TYPE_PROMISCUOUS)) { + + return FALSE; + + } + + TR_IS_SOURCE_ROUTING( + SourceAddress, + &IsSourceRouting + ); + + if (IsSourceRouting && (CombinedFilters & NDIS_PACKET_TYPE_SOURCE_ROUTING)) { + + return TRUE; + + } + + // + // First check if it *at least* has the functional address bit. + // + + TR_IS_NOT_DIRECTED( + DestinationAddress, + &ResultOfAddressCheck + ); + + if (ResultOfAddressCheck) { + + // + // It is at least a functional address. Check to see if + // it is a broadcast address. + // + + TR_IS_BROADCAST( + DestinationAddress, + &ResultOfAddressCheck + ); + + if (ResultOfAddressCheck) { + + if (CombinedFilters & NDIS_PACKET_TYPE_BROADCAST) { + + return TRUE; + + } else { + + return FALSE; + + } + + } else { + + if (CombinedFilters & + (NDIS_PACKET_TYPE_ALL_FUNCTIONAL | + NDIS_PACKET_TYPE_FUNCTIONAL)) { + + return TRUE; + + } else { + + return FALSE; + + } + + } + + } else { + + // + // Directed address never loops back. + // + + return FALSE; + + } + +} diff --git a/private/ntos/ndis/ndis30/tfilter.h b/private/ntos/ndis/ndis30/tfilter.h new file mode 100644 index 000000000..ea7b0a20d --- /dev/null +++ b/private/ntos/ndis/ndis30/tfilter.h @@ -0,0 +1,558 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + tfilter.h + +Abstract: + + Header file for the address filtering library for NDIS MAC's. + +Author: + + Anthony V. Ercolano (tonye) creation-date 3-Aug-1990 + +Environment: + + Runs in the context of a single MAC driver. + +Notes: + + None. + +Revision History: + + Adam Barr (adamba) 19-Mar-1991 + + - Modified for Token-Ring + +--*/ + +#ifndef _TR_FILTER_DEFS_ +#define _TR_FILTER_DEFS_ + +#define TR_LENGTH_OF_FUNCTIONAL 4 +#define TR_LENGTH_OF_ADDRESS 6 + + +// +// Only the low 32 bits of the functional/group address +// are needed since the upper 16 bits is always c0-00. +// +typedef ULONG TR_FUNCTIONAL_ADDRESS; +typedef ULONG TR_GROUP_ADDRESS; + + + +// +// +#define TR_IS_NOT_DIRECTED(Address, Result) \ +{ \ + PUCHAR _A = Address; \ + PBOOLEAN _R = Result; \ + *_R = (BOOLEAN)(_A[0] & ((UCHAR)0x80));\ +} + +// +// +#define TR_IS_FUNCTIONAL(Address, Result) \ +{ \ + PUCHAR _A = Address; \ + PBOOLEAN _R = Result; \ + *_R = (BOOLEAN)((_A[0] & ((UCHAR)0x80)) &&\ + !(_A[2] & ((UCHAR)0x80))); \ +} + +// +// +#define TR_IS_GROUP(Address, Result) \ +{ \ + PUCHAR _A = Address; \ + PBOOLEAN _R = Result; \ + *_R = (BOOLEAN)(_A[0] & _A[2] & ((UCHAR)0x80)); \ +} + +// +// +#define TR_IS_SOURCE_ROUTING(Address, Result) \ +{ \ + PUCHAR _A = Address; \ + PBOOLEAN _R = Result; \ + *_R = (BOOLEAN)(_A[0] >> 7);\ +} + + +// +// Check whether an address is broadcast. +// +#define TR_IS_BROADCAST(Address, Result) \ +{ \ + PUCHAR _A = Address; \ + PBOOLEAN _R = Result; \ + *_R = (BOOLEAN)((((_A[0] == ((UCHAR)0xff)) && \ + (_A[1] == ((UCHAR)0xff))) || \ + ((_A[0] == ((UCHAR)0xc0)) && \ + (_A[1] == ((UCHAR)0x00)))) && \ + (_A[2] == ((UCHAR)0xff)) && \ + (_A[3] == ((UCHAR)0xff)) && \ + (_A[4] == ((UCHAR)0xff)) && \ + (_A[5] == ((UCHAR)0xff))); \ +} + + +// +// This macro will compare network addresses. +// +// A - Is a network address. +// +// B - Is a network address. +// +// Result - The result of comparing two network address. +// +// Result < 0 Implies the B address is greater. +// Result > 0 Implies the A element is greater. +// Result = 0 Implies equality. +// +// Note that this is an arbitrary ordering. There is not +// defined relation on network addresses. This is ad-hoc! +// +// +#define TR_COMPARE_NETWORK_ADDRESSES(A, B, Result) \ +{ \ + PUCHAR _A = (PUCHAR)(A); \ + PUCHAR _B = (PUCHAR)(B); \ + if ( *(ULONG UNALIGNED *)&_A[2] > \ + *(ULONG UNALIGNED *)&_B[2] ) { \ + *Result = 1; \ + } else if ( *(ULONG UNALIGNED *)&_A[2] < \ + *(ULONG UNALIGNED *)&_B[2] ) { \ + *Result = (UINT)-1; \ + } else if ( *(USHORT UNALIGNED *)_A > \ + *(USHORT UNALIGNED *)_B ) { \ + *Result = 1; \ + } else if ( *(USHORT UNALIGNED *)_A < \ + *(USHORT UNALIGNED *)_B ) { \ + *Result = (UINT)-1; \ + } else { \ + *Result = 0; \ + } \ +} + +// +// This macro will compare network addresses. +// +// A - Is a network address. +// +// B - Is a network address. +// +// Result - The result of comparing two network address. +// +// Result != 0 Implies inequality. +// Result == 0 Implies equality. +// +// +#define TR_COMPARE_NETWORK_ADDRESSES_EQ(A,B,Result) \ +{ \ + PUCHAR _A = (PUCHAR)(A); \ + PUCHAR _B = (PUCHAR)(B); \ + if ( ( *(ULONG UNALIGNED *)&_A[2] == \ + *(ULONG UNALIGNED *)&_B[2] ) && \ + ( *(USHORT UNALIGNED *)_A == \ + *(USHORT UNALIGNED *)_B ) ) { \ + *Result = 0; \ + } else { \ + *Result = 1; \ + } \ +} + + +// +// This macro is used to copy from one network address to +// another. +// +#define TR_COPY_NETWORK_ADDRESS(D, S) \ +{ \ + PCHAR _D = (D); \ + PCHAR _S = (S); \ + _D[0] = _S[0]; \ + _D[1] = _S[1]; \ + _D[2] = _S[2]; \ + _D[3] = _S[3]; \ + _D[4] = _S[4]; \ + _D[5] = _S[5]; \ +} + + +// +//UINT +//TR_QUERY_FILTER_CLASSES( +// IN PTR_FILTER Filter +// ) +// +// This macro returns the currently enabled filter classes. +// +// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD. +// +#define TR_QUERY_FILTER_CLASSES(Filter) ((Filter)->CombinedPacketFilter) + + +// +//UINT +//TR_QUERY_PACKET_FILTER( +// IN PTR_FILTER Filter, +// IN NDIS_HANDLE NdisFilterHandle +// ) +// +// This macro returns the currently enabled filter classes for a specific +// open instance. +// +// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD. +// +#define TR_QUERY_PACKET_FILTER(Filter, NdisFilterHandle) \ + (((PTR_BINDING_INFO)NdisFilterHandle)->PacketFilters) + + + +// +//UINT +//TR_QUERY_FILTER_ADDRESSES( +// IN PTR_FILTER Filter +// ) +// +// This macro returns the currently enabled functional address. +// +// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD. +// +#define TR_QUERY_FILTER_ADDRESSES(Filter) ((Filter)->CombinedFunctionalAddress) + + + +// +//UINT +//TR_QUERY_FILTER_GROUP( +// IN PTR_FILTER Filter +// ) +// +// This macro returns the currently enabled Group address. +// +// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD. +// +#define TR_QUERY_FILTER_Group(Filter) ((Filter)->GroupAddress) +#define TR_QUERY_FILTER_GROUP(Filter) ((Filter)->GroupAddress) + + + +// +//UINT +//TR_QUERY_FILTER_BINDING_ADDRESS( +// IN PTR_FILTER Filter +// IN NDIS_HANDLE NdisFilterHandle, +// ) +// +// This macro returns the currently desired functional addresses +// for the specified binding. +// +// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD. +// +#define TR_QUERY_FILTER_BINDING_ADDRESS(Filter, NdisFilterHandle) \ + (((PTR_BINDING_INFO)NdisFilterHandle)->FunctionalAddress) + + + + +// +//BOOLEAN +//TR_QUERY_FILTER_BINDING_GROUP( +// IN PTR_FILTER Filter +// IN NDIS_HANDLE NdisFilterHandle, +// ) +// +// This macro returns TRUE if the specified binding is using the +// current group address. +// +// NOTE: THIS MACRO ASSUMES THAT THE FILTER LOCK IS HELD. +// +#define TR_QUERY_FILTER_BINDING_GROUP(Filter, NdisFilterHandle) \ + (((PTR_BINDING_INFO)NdisFilterHandle)->UsingGroupAddress) + + +// +// An action routine type. The routines are called +// when a filter type is set for the first time or +// no more bindings require a particular type of filter. +// +// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED. +// +typedef +NDIS_STATUS +(*TR_FILTER_CHANGE)( + IN UINT OldFilterClasses, + IN UINT NewFilterClasses, + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest, + IN BOOLEAN Set + ); + +// +// This action routine is called when the functional address +// for the card has changed. It is passed the old functional +// address as well as the new one. +// +// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED. +// +typedef +NDIS_STATUS +(*TR_ADDRESS_CHANGE)( + IN TR_FUNCTIONAL_ADDRESS OldFunctionalAddress, + IN TR_FUNCTIONAL_ADDRESS NewFunctionalAddress, + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest, + IN BOOLEAN Set + ); + + +// +// This action routine is called when the group address +// for the card has changed. It is passed the old group +// address as well as the new one. +// +// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED. +// +typedef +NDIS_STATUS +(*TR_GROUP_CHANGE)( + IN TR_GROUP_ADDRESS OldGroupAddress, + IN TR_GROUP_ADDRESS NewGroupAddress, + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest, + IN BOOLEAN Set + ); + + + +// +// This action routine is called when the mac requests a close for +// a particular binding *WHILE THE BINDING IS BEING INDICATED TO +// THE PROTOCOL*. The filtering package can't get rid of the open +// right away. So this routine will be called as soon as the +// NdisIndicateReceive returns. +// +// NOTE: THIS ROUTINE SHOULD ASSUME THAT THE LOCK IS ACQUIRED. +// +typedef +VOID +(*TR_DEFERRED_CLOSE)( + IN NDIS_HANDLE MacBindingHandle + ); + + +// +// The binding info is threaded on two lists. When +// the binding is free it is on a single freelist. +// +// When the binding is being used it is on a doubly linked +// index list. +// +typedef struct _TR_BINDING_INFO { + NDIS_HANDLE MacBindingHandle; + NDIS_HANDLE NdisBindingContext; + UINT PacketFilters; + TR_FUNCTIONAL_ADDRESS FunctionalAddress; + struct _TR_BINDING_INFO *NextOpen; + struct _TR_BINDING_INFO *PrevOpen; + UINT References; + UCHAR FilterIndex; + BOOLEAN UsingGroupAddress; + BOOLEAN ReceivedAPacket; +} TR_BINDING_INFO,*PTR_BINDING_INFO; + +// +// An opaque type that contains a filter database. +// The MAC need not know how it is structured. +// +typedef struct _TR_FILTER { + + // + // Spin lock used to protect the filter from multiple accesses. + // + PNDIS_SPIN_LOCK Lock; + + // + // ORing together of all the FunctionalAddresses. + // + TR_FUNCTIONAL_ADDRESS CombinedFunctionalAddress; + + // + // Current group address in use. + // + TR_FUNCTIONAL_ADDRESS GroupAddress; + + // + // Reference count on group address; + // + UINT GroupReferences; + + // + // Combination of all the filters of all the open bindings. + // + UINT CombinedPacketFilter; + + // + // Pointer to list of current opens. + // + PTR_BINDING_INFO OpenList; + + // + // Address of the adapter associated with this filter. + // + UCHAR AdapterAddress[TR_LENGTH_OF_ADDRESS]; + + // + // Action routines to be invoked on notable changes in the filter. + // + TR_ADDRESS_CHANGE AddressChangeAction; + TR_GROUP_CHANGE GroupChangeAction; + TR_FILTER_CHANGE FilterChangeAction; + TR_DEFERRED_CLOSE CloseAction; + + // + // Bit mask of opens that are available. + // + ULONG FreeBindingMask; + +} TR_FILTER,*PTR_FILTER; + +// +// Only for internal wrapper use. +// +VOID +TrInitializePackage( + VOID + ); + +VOID +TrReferencePackage( + VOID + ); + +VOID +TrDereferencePackage( + VOID + ); + +// +// Exported functions +// +EXPORT +BOOLEAN +TrCreateFilter( + IN TR_ADDRESS_CHANGE AddressChangeAction, + IN TR_GROUP_CHANGE GroupChangeAction, + IN TR_FILTER_CHANGE FilterChangeAction, + IN TR_DEFERRED_CLOSE CloseAction, + IN PUCHAR AdapterAddress, + IN PNDIS_SPIN_LOCK Lock, + OUT PTR_FILTER *Filter + ); + +EXPORT +VOID +TrDeleteFilter( + IN PTR_FILTER Filter + ); + +EXPORT +BOOLEAN +TrNoteFilterOpenAdapter( + IN PTR_FILTER Filter, + IN NDIS_HANDLE MacBindingHandle, + IN NDIS_HANDLE NdisBindingContext, + OUT PNDIS_HANDLE NdisFilterHandle + ); + +EXPORT +NDIS_STATUS +TrDeleteFilterOpenAdapter( + IN PTR_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest + ); + +EXPORT +NDIS_STATUS +TrChangeFunctionalAddress( + IN PTR_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest, + IN CHAR FunctionalAddressArray[TR_LENGTH_OF_FUNCTIONAL], + IN BOOLEAN Set + ); + +EXPORT +NDIS_STATUS +TrChangeGroupAddress( + IN PTR_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest, + IN CHAR GroupAddressArray[TR_LENGTH_OF_FUNCTIONAL], + IN BOOLEAN Set + ); + +EXPORT +BOOLEAN +TrShouldAddressLoopBack( + IN PTR_FILTER Filter, + IN CHAR DestinationAddress[TR_LENGTH_OF_ADDRESS], + IN CHAR SourceAddress[TR_LENGTH_OF_ADDRESS] + ); + +EXPORT +NDIS_STATUS +TrFilterAdjust( + IN PTR_FILTER Filter, + IN NDIS_HANDLE NdisFilterHandle, + IN PNDIS_REQUEST NdisRequest, + IN UINT FilterClasses, + IN BOOLEAN Set + ); + +EXPORT +VOID +TrFilterIndicateReceive( + IN PTR_FILTER Filter, + IN NDIS_HANDLE MacReceiveContext, + IN PVOID HeaderBuffer, + IN UINT HeaderBufferSize, + IN PVOID LookaheadBuffer, + IN UINT LookaheadBufferSize, + IN UINT PacketSize + ); + +EXPORT +VOID +TrFilterDprIndicateReceive( + IN PTR_FILTER Filter, + IN NDIS_HANDLE MacReceiveContext, + IN PVOID HeaderBuffer, + IN UINT HeaderBufferSize, + IN PVOID LookaheadBuffer, + IN UINT LookaheadBufferSize, + IN UINT PacketSize + ); + +EXPORT +VOID +TrFilterIndicateReceiveComplete( + IN PTR_FILTER Filter + ); + +EXPORT +VOID +TrFilterDprIndicateReceiveComplete( + IN PTR_FILTER Filter + ); + + +#endif // _TR_FILTER_DEFS_ diff --git a/private/ntos/ndis/ndis30/wrapper.c b/private/ntos/ndis/ndis30/wrapper.c new file mode 100644 index 000000000..9373647c4 --- /dev/null +++ b/private/ntos/ndis/ndis30/wrapper.c @@ -0,0 +1,17480 @@ +/*++ +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + wrapper.c + +Abstract: + + NDIS wrapper functions + +Author: + + Adam Barr (adamba) 11-Jul-1990 + +Environment: + + Kernel mode, FSD + +Revision History: + + 26-Feb-1991 JohnsonA Added Debugging Code + 10-Jul-1991 JohnsonA Implement revised Ndis Specs + +--*/ + + +#include <precomp.h> +#pragma hdrstop + +#include <stdarg.h> + +// +// The following are counters used for debugging +// + +#if NDISDBG +BOOLEAN NdisChkErrorFlag=TRUE; // parameter checking on +int NdisMsgLevel=TRACE_ALL; // no trace +#endif + +PNDIS_MAC_BLOCK NdisMacList = (PNDIS_MAC_BLOCK)NULL; +NDIS_SPIN_LOCK NdisMacListLock = {0}; + +BOOLEAN NdisInitialInitNeeded = TRUE; +BOOLEAN NdisUpOnlyEventLogged = FALSE; + +// +// Global variables for tracking memory allocated for shared memory +// +ERESOURCE SharedMemoryResource = {0}; + +// +// Global variables for tracking on NT 3.1 protocols that do not +// use any of the filter packages. +// +PNDIS_OPEN_BLOCK GlobalOpenList = NULL; +NDIS_SPIN_LOCK GlobalOpenListLock = {0}; + +// +// Debug variable for filter packages +// +#if DBG +BOOLEAN NdisCheckBadDrivers = FALSE; + +extern NDIS_SPIN_LOCK PacketLogSpinLock; +#endif + +// +// Arcnet specific stuff +// +#define WRAPPER_ARC_BUFFERS 8 +#define WRAPPER_ARC_HEADER_SIZE 4 + +// +// Define constants used internally to identify regular opens from +// query global statistics ones. +// + +#define NDIS_OPEN_INTERNAL 1 +#define NDIS_OPEN_QUERY_STATISTICS 2 + +// +// This is the structure pointed to by the FsContext of an +// open used for query statistics. +// +// NOTE: THIS STRUCTURE MUST, MUST, MUST ALIGN WITH THE +// NDIS_M_USER_OPEN_CONTEXT STRUCTURE!!! +// + +typedef struct _NDIS_USER_OPEN_CONTEXT { + PDEVICE_OBJECT DeviceObject; + PNDIS_ADAPTER_BLOCK AdapterBlock; + ULONG OidCount; + PNDIS_OID OidArray; +} NDIS_USER_OPEN_CONTEXT, *PNDIS_USER_OPEN_CONTEXT; + +// +// An active query single statistic request. +// + +typedef struct _NDIS_QUERY_GLOBAL_REQUEST { + PIRP Irp; + NDIS_REQUEST Request; +} NDIS_QUERY_GLOBAL_REQUEST, *PNDIS_QUERY_GLOBAL_REQUEST; + + +// +// An active query all statistics request. +// + +typedef struct _NDIS_QUERY_ALL_REQUEST { + PIRP Irp; + NDIS_REQUEST Request; + NDIS_STATUS NdisStatus; + KEVENT Event; +} NDIS_QUERY_ALL_REQUEST, *PNDIS_QUERY_ALL_REQUEST; + + +// +// An temporary request used during an open. +// + +typedef struct _NDIS_QUERY_OPEN_REQUEST { + PIRP Irp; + NDIS_REQUEST Request; + NDIS_STATUS NdisStatus; + KEVENT Event; +} NDIS_QUERY_OPEN_REQUEST, *PNDIS_QUERY_OPEN_REQUEST; + + +// +// Used to queue configuration parameters +// + +typedef struct _NDIS_CONFIGURATION_PARAMETER_QUEUE { + struct _NDIS_CONFIGURATION_PARAMETER_QUEUE* Next; + NDIS_CONFIGURATION_PARAMETER Parameter; +} NDIS_CONFIGURATION_PARAMETER_QUEUE, *PNDIS_CONFIGURATION_PARAMETER_QUEUE; + +// +// Configuration Handle +// + +typedef struct _NDIS_CONFIGURATION_HANDLE { + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable; + PNDIS_CONFIGURATION_PARAMETER_QUEUE ParameterList; +} NDIS_CONFIGURATION_HANDLE, *PNDIS_CONFIGURATION_HANDLE; + +// +// This is used during addadapter/miniportinitialize so that when the +// driver calls any NdisImmediatexxx routines we can access its driverobj. +// +typedef struct _NDIS_WRAPPER_CONFIGURATION_HANDLE +{ + RTL_QUERY_REGISTRY_TABLE ParametersQueryTable[4]; + PDRIVER_OBJECT DriverObject; +} + NDIS_WRAPPER_CONFIGURATION_HANDLE, + *PNDIS_WRAPPER_CONFIGURATION_HANDLE; + +// +// Describes an open NDIS file +// + +typedef struct _NDIS_FILE_DESCRIPTOR { + PVOID Data; + NDIS_SPIN_LOCK Lock; + BOOLEAN Mapped; +} NDIS_FILE_DESCRIPTOR, *PNDIS_FILE_DESCRIPTOR; + +// +// IRP handlers established on behalf of NDIS devices by +// the wrapper. +// + +NTSTATUS +NdisCreateIrpHandler( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ); + +NTSTATUS +NdisDeviceControlIrpHandler( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ); + +NTSTATUS +NdisCloseIrpHandler( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ); + +NTSTATUS +NdisSuccessIrpHandler( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ); + + +NTSTATUS +NdisQueryOidList( + PNDIS_USER_OPEN_CONTEXT OpenContext, + PIRP Irp + ); + +NTSTATUS +NdisMQueryOidList( + PNDIS_M_USER_OPEN_CONTEXT OpenContext, + PIRP Irp + ); + +VOID +NdisLastCountRemovedFunction( + IN struct _KDPC *Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2 + ); + + +BOOLEAN +NdisQueueOpenOnProtocol( + IN PNDIS_OPEN_BLOCK OpenP, + IN PNDIS_PROTOCOL_BLOCK ProtP + ); + +NDIS_STATUS +MiniportAdjustMaximumLookahead( + IN PNDIS_MINIPORT_BLOCK Miniport + ); + +BOOLEAN +NdisMKillOpen( + PNDIS_OPEN_BLOCK OldOpenP + ); + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ); + +NDIS_STATUS +NdisMacReceiveHandler( + IN NDIS_HANDLE NdisBindingContext, + IN NDIS_HANDLE MacReceiveContext, + IN PVOID HeaderBuffer, + IN UINT HeaderBufferSize, + IN PVOID LookaheadBuffer, + IN UINT LookaheadBufferSize, + IN UINT PacketSize + ); + +VOID +NdisMacReceiveCompleteHandler( + IN NDIS_HANDLE NdisBindingContext + ); + +PNDIS_OPEN_BLOCK +GetOpenBlockFromProtocolBindingContext( + IN NDIS_HANDLE ProtocolBindingContext + ); + +NTSTATUS +NdisShutdown( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ); + +VOID +NdisUnload( + IN PDRIVER_OBJECT DriverObject + ); + +BOOLEAN +NdisIsr( + IN PKINTERRUPT Interrupt, + IN PVOID Context + ); + +VOID +NdisDpc( + IN PVOID SystemSpecific1, + IN PVOID InterruptContext, + IN PVOID SystemSpecific2, + IN PVOID SystemSpecific3 + ); + +VOID +NdisOpenConfiguration( + OUT PNDIS_STATUS Status, + OUT PNDIS_HANDLE ConfigurationHandle, + IN NDIS_HANDLE WrapperConfigurationContext + ); + +NTSTATUS +WrapperSaveParameters( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ); + +VOID +NdisReadNetworkAddress( + OUT PNDIS_STATUS Status, + OUT PVOID * NetworkAddress, + OUT PUINT NetworkAddressLength, + IN NDIS_HANDLE ConfigurationHandle + ); + +VOID +NdisReadEisaSlotInformation( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE WrapperConfigurationContext, + OUT PUINT SlotNumber, + OUT PNDIS_EISA_FUNCTION_INFORMATION EisaData + ); + +VOID +NdisReadEisaSlotInformationEx( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE WrapperConfigurationContext, + OUT PUINT SlotNumber, + OUT PNDIS_EISA_FUNCTION_INFORMATION *EisaData, + OUT PUINT NumberOfFunctions + ); + +VOID +NdisReadMcaPosInformation( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE WrapperConfigurationContext, + OUT PUINT ChannelNumber, + OUT PNDIS_MCA_POS_DATA McaData + ); + +NDIS_STATUS +NdisCallDriverAddAdapter( + IN PNDIS_MAC_BLOCK NewMacP + ); + +NDIS_STATUS +NdisMWanSend( + IN NDIS_HANDLE NdisBindingHandle, + IN NDIS_HANDLE NdisLinkHandle, + IN PVOID Packet + ); + + +CCHAR NdisMacAdapterDpcTargetProcessor = -1; + +// +// Routines for dealing with making the MAC specific routines pagable +// + +NDIS_SPIN_LOCK NdisMacReferenceLock = {0}; +KEVENT NdisMacPagedInEvent = {0}; +ULONG NdisMacReferenceCount = 0; +PVOID NdisMacImageHandle = {0}; + +VOID +NdisMacInitializePackage(VOID) +{ + // + // Allocate the spin lock + // + NdisAllocateSpinLock(&NdisMacReferenceLock); + + // + // Initialize the "in page" event. + // + KeInitializeEvent( + &NdisMacPagedInEvent, + NotificationEvent, + FALSE + ); +} + +VOID +NdisMacReferencePackage(VOID) +{ + + // + // Grab the spin lock + // + ACQUIRE_SPIN_LOCK(&NdisMacReferenceLock); + + // + // Increment the reference count + // + NdisMacReferenceCount++; + + if (NdisMacReferenceCount == 1) { + + // + // We are the first reference. Page everything in. + // + + // + // Clear the event + // + KeResetEvent( + &NdisMacPagedInEvent + ); + + // + // Set the spin lock free + // + RELEASE_SPIN_LOCK(&NdisMacReferenceLock); + + // + // Page in all the functions + // + NdisMacImageHandle = MmLockPagableCodeSection(NdisIsr); + + // + // Signal to everyone to go + // + KeSetEvent( + &NdisMacPagedInEvent, + 0L, + FALSE + ); + + } else { + + // + // Set the spin lock free + // + RELEASE_SPIN_LOCK(&NdisMacReferenceLock); + + // + // Wait for everything to be paged in + // + KeWaitForSingleObject( + &NdisMacPagedInEvent, + Executive, + KernelMode, + TRUE, + NULL + ); + + } + +} + +VOID +NdisMacDereferencePackage(VOID) +{ + + // + // Get the spin lock + // + ACQUIRE_SPIN_LOCK(&NdisMacReferenceLock); + + NdisMacReferenceCount--; + + if (NdisMacReferenceCount == 0) { + + // + // Let next one in + // + RELEASE_SPIN_LOCK(&NdisMacReferenceLock); + + // + // Page out all the functions + // + MmUnlockPagableImageSection(NdisMacImageHandle); + + } else { + + // + // Let next one in + // + RELEASE_SPIN_LOCK(&NdisMacReferenceLock); + + } + +} + + + +// +// Routines for dealing with making the initialization routines pagable +// + +NDIS_SPIN_LOCK NdisInitReferenceLock = {0}; +KEVENT NdisInitPagedInEvent = {0}; +ULONG NdisInitReferenceCount = 0; +PVOID NdisInitImageHandle = {0}; + +VOID +NdisInitInitializePackage(VOID) +{ + // + // Allocate the spin lock + // + NdisAllocateSpinLock(&NdisInitReferenceLock); + + // + // Initialize the "in page" event. + // + KeInitializeEvent( + &NdisInitPagedInEvent, + NotificationEvent, + FALSE + ); +} + +VOID +NdisInitReferencePackage(VOID) +{ + + // + // Grab the spin lock + // + ACQUIRE_SPIN_LOCK(&NdisInitReferenceLock); + + // + // Increment the reference count + // + NdisInitReferenceCount++; + + if (NdisInitReferenceCount == 1) { + + // + // We are the first reference. Page everything in. + // + + // + // Clear the event + // + KeResetEvent( + &NdisInitPagedInEvent + ); + + // + // Set the spin lock free + // + RELEASE_SPIN_LOCK(&NdisInitReferenceLock); + + // + // Page in all the functions + // + NdisInitImageHandle = MmLockPagableCodeSection(NdisReadConfiguration); + + // + // Signal to everyone to go + // + KeSetEvent( + &NdisInitPagedInEvent, + 0L, + FALSE + ); + + } else { + + // + // Set the spin lock free + // + RELEASE_SPIN_LOCK(&NdisInitReferenceLock); + + // + // Wait for everything to be paged in + // + KeWaitForSingleObject( + &NdisInitPagedInEvent, + Executive, + KernelMode, + TRUE, + NULL + ); + + } + +} + +VOID +NdisInitDereferencePackage(VOID) +{ + + // + // Get the spin lock + // + ACQUIRE_SPIN_LOCK(&NdisInitReferenceLock); + + NdisInitReferenceCount--; + + if (NdisInitReferenceCount == 0) { + + // + // Let next one in + // + RELEASE_SPIN_LOCK(&NdisInitReferenceLock); + + // + // Page out all the functions + // + MmUnlockPagableImageSection(NdisInitImageHandle); + + } else { + + // + // Let next one in + // + RELEASE_SPIN_LOCK(&NdisInitReferenceLock); + + } +} + + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGENDSI, NdisPciAssignResources) +#pragma alloc_text(PAGENDSI, NdisReadMcaPosInformation) +#pragma alloc_text(PAGENDSI, NdisReadEisaSlotInformationEx) +#pragma alloc_text(PAGENDSI, NdisReadEisaSlotInformation) +#pragma alloc_text(PAGENDSI, NdisCallDriverAddAdapter) +#pragma alloc_text(PAGENDSW, NdisDereferenceMac) +#pragma alloc_text(PAGENDSW, NdisDereferenceAdapter) +#pragma alloc_text(PAGENDSW, NdisKillAdapter) +#pragma alloc_text(PAGENDSW, NdisDeQueueAdapterOnMac) +#pragma alloc_text(PAGENDSW, NdisQueueAdapterOnMac) +#pragma alloc_text(PAGENDSW, NdisKillOpen) +#pragma alloc_text(PAGENDSW, NdisKillOpenAndNotifyProtocol) +#pragma alloc_text(PAGENDSW, NdisCloseIrpHandler) +#pragma alloc_text(PAGENDSW, NdisCompleteQueryStatistics) +#pragma alloc_text(PAGENDSW, NdisQueryOidList) +#pragma alloc_text(PAGENDSW, NdisFinishOpen) +#pragma alloc_text(PAGENDSW, NdisCompleteCloseAdapter) +#pragma alloc_text(PAGENDSW, NdisCompleteOpenAdapter) +#pragma alloc_text(PAGENDSI, NdisRegisterAdapterShutdownHandler) +#pragma alloc_text(PAGENDSI, NdisRegisterAdapter) +#pragma alloc_text(PAGENDSI, NdisInitializeWrapper) +#pragma alloc_text(PAGENDSW, NdisMacReceiveCompleteHandler) +#pragma alloc_text(PAGENDSW, NdisMacReceiveHandler) +#pragma alloc_text(PAGENDSW, GetOpenBlockFromProtocolBindingContext) +#pragma alloc_text(PAGENDSI, NdisAllocateDmaChannel) +#pragma alloc_text(PAGENDSW, NdisShutdown) +#pragma alloc_text(PAGENDSW, NdisUnload) +#pragma alloc_text(PAGENDSI, NdisInitializeInterrupt) +#pragma alloc_text(PAGENDSW, NdisDpc) +#pragma alloc_text(PAGENDSW, NdisIsr) +#pragma alloc_text(PAGENDSI, NdisMapIoSpace) +#pragma alloc_text(PAGENDSI, NdisReadNetworkAddress) +#pragma alloc_text(PAGENDSI, NdisCloseConfiguration) +#pragma alloc_text(PAGENDSI, NdisReadConfiguration) +#pragma alloc_text(PAGENDSI, WrapperSaveParameters) +#pragma alloc_text(PAGENDSI, NdisOpenConfiguration) +#pragma alloc_text(PAGENDSI, NdisOverrideBusNumber) +#pragma alloc_text(INIT, DriverEntry) + +#endif + + +// +// This constant is used for places where NdisAllocateMemory +// needs to be called and the HighestAcceptableAddress does +// not matter. +// + +static const NDIS_PHYSICAL_ADDRESS HighestAcceptableMax = + NDIS_PHYSICAL_ADDRESS_CONST(-1,-1); + +#if defined(_ALPHA_) + +typedef struct _NDIS_LOOKAHEAD_ELEMENT { + + ULONG Length; + struct _NDIS_LOOKAHEAD_ELEMENT *Next; + +} NDIS_LOOKAHEAD_ELEMENT, *PNDIS_LOOKAHEAD_ELEMENT; + +NDIS_SPIN_LOCK NdisLookaheadBufferLock = {0}; +ULONG NdisLookaheadBufferLength = 0; +PNDIS_LOOKAHEAD_ELEMENT NdisLookaheadBufferList = NULL; + +#endif + + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) + +/*++ + +Routine Description: + + Temporary entry point needed to initialize the NDIS wrapper driver. + +Arguments: + + DriverObject - Pointer to the driver object created by the system. + +Return Value: + + STATUS_SUCCESS + +--*/ + +{ + UNREFERENCED_PARAMETER(RegistryPath); + + return STATUS_SUCCESS; + +} // DriverEntry + + +NDIS_STATUS +NdisInitialInit( + IN PDRIVER_OBJECT Driver OPTIONAL + ) +/*++ + +Routine Description: + + This routine is used for all one time initialization of NDIS variables. + It seems that DriverEntry is *not* called for ndis.sys due to its type. + +Arguments: + + Driver - Optional pointer to an NT driver object. Used to log an error, + if necessary. + +Return Value: + + NTSTATUS - Status of initialization. Currently, this routine can only + fail if built for UP and loaded on MP. + +--*/ + +{ + Driver; + + if (NdisInitialInitNeeded) { + +#if defined(UP_DRIVER) + // + // If built for UP, ensure that this is a UP system. + // + + if (*KeNumberProcessors != 1) { + + if (ARGUMENT_PRESENT(Driver) && !NdisUpOnlyEventLogged) { + + // + // Log an error + // + + PIO_ERROR_LOG_PACKET errorLogEntry; + + errorLogEntry = IoAllocateErrorLogEntry( Driver, sizeof(IO_ERROR_LOG_PACKET) ); + + if (errorLogEntry != NULL) { + + errorLogEntry->ErrorCode = EVENT_UP_DRIVER_ON_MP; + errorLogEntry->MajorFunctionCode = 0; + errorLogEntry->RetryCount = 0; + errorLogEntry->UniqueErrorValue = 0; + errorLogEntry->FinalStatus = 0; + errorLogEntry->SequenceNumber = 0; + errorLogEntry->IoControlCode = 0; + errorLogEntry->NumberOfStrings = 0; + + IoWriteErrorLogEntry(errorLogEntry); + + NdisUpOnlyEventLogged = TRUE; + } + + } + + return NDIS_STATUS_BAD_VERSION; //!!! better status? + } + +#endif // defined(UP_DRIVER) + + NdisInitialInitNeeded = FALSE; + NdisAllocateSpinLock(&NdisMacListLock); + + ArcInitializePackage(); + EthInitializePackage(); + FddiInitializePackage(); + TrInitializePackage(); + MiniportInitializePackage(); + NdisInitInitializePackage(); + NdisMacInitializePackage(); + +#if defined(_ALPHA_) + NdisAllocateSpinLock(&NdisLookaheadBufferLock); +#endif + + ExInitializeResource(&SharedMemoryResource); + + NdisAllocateSpinLock(&GlobalOpenListLock); + +#if DBG + NdisAllocateSpinLock(&PacketLogSpinLock); +#endif + } + + return NDIS_STATUS_SUCCESS; +} + + +// +// Configuration Requests +// + +VOID +NdisOpenConfiguration( + OUT PNDIS_STATUS Status, + OUT PNDIS_HANDLE ConfigurationHandle, + IN NDIS_HANDLE WrapperConfigurationContext + ) +/*++ + +Routine Description: + + This routine is used to open the parameter subkey of the + adapter registry tree. + +Arguments: + + Status - Returns the status of the request. + + ConfigurationHandle - Returns a handle which is used in calls to + NdisReadConfiguration and NdisCloseConfiguration. + + WrapperConfigurationContext - a handle pointing to an RTL_QUERY_REGISTRY_TABLE + that is set up for this driver's parameters. + +Return Value: + + None. + +--*/ + +{ + // + // Handle to be returned + // + PNDIS_CONFIGURATION_HANDLE HandleToReturn; + + + // + // Allocate the configuration handle + // + + *Status = NdisAllocateMemory( + (PVOID*) &HandleToReturn, + sizeof(NDIS_CONFIGURATION_HANDLE), + 0, + HighestAcceptableMax); + + if (*Status != NDIS_STATUS_SUCCESS) { + return; + } + + HandleToReturn->KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + HandleToReturn->ParameterList = NULL; + *ConfigurationHandle = (NDIS_HANDLE) HandleToReturn; + + return; +} + + +NTSTATUS +WrapperSaveParameters( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ) + +/*++ + +Routine Description: + + This routine is a callback routine for RtlQueryRegistryValues + It is called with the value for a specified parameter. It allocates + memory to hold the data and copies it over. + +Arguments: + + ValueName - The name of the value (ignored). + + ValueType - The type of the value. + + ValueData - The null-terminated data for the value. + + ValueLength - The length of ValueData. + + Context - Points to the head of the parameter chain. + + EntryContext - A pointer to + +Return Value: + + STATUS_SUCCESS + +--*/ + +{ + NDIS_STATUS Status; + + // + // Obtain the actual configuration handle structure + // + + PNDIS_CONFIGURATION_HANDLE NdisConfigHandle = + (PNDIS_CONFIGURATION_HANDLE)Context; + + // + // Where the user wants a pointer returned to the data. + // + + PNDIS_CONFIGURATION_PARAMETER *ParameterValue = + (PNDIS_CONFIGURATION_PARAMETER *)EntryContext; + + // + // Use this to link parameters allocated to this open + // + + PNDIS_CONFIGURATION_PARAMETER_QUEUE ParameterNode; + + + + // + // Allocate our parameter node + // + + Status = NdisAllocateMemory( + (PVOID*)&ParameterNode, + sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE), + 0, + HighestAcceptableMax); + + if (Status != NDIS_STATUS_SUCCESS) { + return (NTSTATUS)Status; + } + + + *ParameterValue = &ParameterNode->Parameter; + + // + // Map registry datatypes to ndis data types + // + + if (ValueType == REG_DWORD) { + + // + // The registry says that the data is in a dword boundary. + // + + (*ParameterValue)->ParameterType = NdisParameterInteger; + (*ParameterValue)->ParameterData.IntegerData = + *((PULONG) ValueData); + + } else if ((ValueType == REG_SZ) || (ValueType == REG_MULTI_SZ)) { + + (*ParameterValue)->ParameterType = + (ValueType == REG_SZ) ? NdisParameterString : NdisParameterMultiString; + + (*ParameterValue)->ParameterData.StringData.Buffer = + ExAllocatePoolWithTag(NonPagedPool, ValueLength, ' DN'); + + if (((*ParameterValue)->ParameterData.StringData.Buffer) == NULL) { + NdisFreeMemory (ParameterNode, sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE), 0); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlCopyMemory ((*ParameterValue)->ParameterData.StringData.Buffer, + ValueData, ValueLength); + (*ParameterValue)->ParameterData.StringData.Length = (USHORT)ValueLength; + (*ParameterValue)->ParameterData.StringData.MaximumLength = (USHORT)ValueLength; + + // + // Special fix; if a string ends in a NULL and that is included + // in the length, remove it. + // + + if (ValueType == REG_SZ) { + if ((((PUCHAR)ValueData)[ValueLength-1] == 0) && + (((PUCHAR)ValueData)[ValueLength-2] == 0)) { + (*ParameterValue)->ParameterData.StringData.Length -= 2; + } + } + + } else { + + NdisFreeMemory( + ParameterNode, + sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE), + 0 + ); + + return STATUS_OBJECT_NAME_NOT_FOUND; + + } + + + // + // Queue this parameter node + // + + ParameterNode->Next = NdisConfigHandle->ParameterList; + NdisConfigHandle->ParameterList = ParameterNode; + + return STATUS_SUCCESS; + +} + + +VOID +NdisReadConfiguration( + OUT PNDIS_STATUS Status, + OUT PNDIS_CONFIGURATION_PARAMETER *ParameterValue, + IN NDIS_HANDLE ConfigurationHandle, + IN PNDIS_STRING Keyword, + IN NDIS_PARAMETER_TYPE ParameterType + ) +/*++ + +Routine Description: + + This routine is used to read the parameter for a configuration + keyword from the configuration database. + +Arguments: + + Status - Returns the status of the request. + + ParameterValue - Returns the value for this keyword. + + ConfigurationHandle - Handle returned by NdisOpenConfiguration. Points + to the parameter subkey. + + Keyword - The keyword to search for. + + ParameterType - Ignored on NT, specifies the type of the value. + +Return Value: + + None. + +--*/ +{ + + // + // Status of our requests + // + NTSTATUS RegistryStatus; + + // + // There are some built-in parameters which can always be + // read, even if not present in the registry. This is the + // number of them. + // + +#define BUILT_IN_COUNT 2 + + // + // The names of the built-in parameters. + // + + static NDIS_STRING BuiltInStrings[BUILT_IN_COUNT] = + { NDIS_STRING_CONST ("Environment"), + NDIS_STRING_CONST ("ProcessorType") }; + + // + // The values to return for the built-in parameters. + // + + static NDIS_CONFIGURATION_PARAMETER BuiltInParameters[BUILT_IN_COUNT] = + { { NdisParameterInteger, NdisEnvironmentWindowsNt }, + { NdisParameterInteger, +#if defined(_M_IX86) + NdisProcessorX86 +#elif defined(_M_MRX000) + NdisProcessorMips +#elif defined(_ALPHA_) + NdisProcessorAlpha +#else + NdisProcessorPpc +#endif + } }; + + + // + // Holds a null-terminated version of the keyword. + // + PWSTR KeywordBuffer; + + // + // index variable + // + UINT i; + + // + // Obtain the actual configuration handle structure + // + PNDIS_CONFIGURATION_HANDLE NdisConfigHandle = + (PNDIS_CONFIGURATION_HANDLE) ConfigurationHandle; + + + + // + // First check if this is one of the built-in parameters. + // + + for (i = 0; i < BUILT_IN_COUNT; i++) { + if (RtlEqualUnicodeString(Keyword, &BuiltInStrings[i], TRUE)) { + *Status = NDIS_STATUS_SUCCESS; + *ParameterValue = &BuiltInParameters[i]; + return; + } + } + + + // + // Allocate room for a null-terminated version of the keyword + // + + KeywordBuffer = (PWSTR)ExAllocatePoolWithTag( + NonPagedPool, + Keyword->Length + sizeof(WCHAR), + ' DN'); + if (KeywordBuffer == NULL) { + *Status = NDIS_STATUS_RESOURCES; + return; + } + RtlCopyMemory (KeywordBuffer, Keyword->Buffer, Keyword->Length); + *(PWCHAR)(((PUCHAR)KeywordBuffer)+Keyword->Length) = (WCHAR)L'\0'; + + + // + // Finish initializing the table for this query. + // + + NdisConfigHandle->KeyQueryTable[1].Name = KeywordBuffer; + NdisConfigHandle->KeyQueryTable[1].EntryContext = ParameterValue; + + // + // Get the value from the registry; this chains it on to the + // parameter list at NdisConfigHandle. + // + + RegistryStatus = RtlQueryRegistryValues( + RTL_REGISTRY_SERVICES, + NdisConfigHandle->KeyQueryTable[3].Name, + NdisConfigHandle->KeyQueryTable, + NdisConfigHandle, // context + NULL); + + + ExFreePool (KeywordBuffer); // no longer needed + + if (!NT_SUCCESS(RegistryStatus)) { + *Status = NDIS_STATUS_FAILURE; + return; + } + + *Status = NDIS_STATUS_SUCCESS; + return; + +} + + +VOID +NdisWriteConfiguration( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE ConfigurationHandle, + IN PNDIS_STRING Keyword, + PNDIS_CONFIGURATION_PARAMETER ParameterValue + ) +/*++ + +Routine Description: + + This routine is used to write a parameter to the configuration database. + +Arguments: + + Status - Returns the status of the request. + + ConfigurationHandle - Handle passed to the driver's AddAdapter routine. + + Keyword - The keyword to set. + + ParameterValue - Specifies the new value for this keyword. + +Return Value: + + None. + +--*/ +{ + + // + // Status of our requests + // + NTSTATUS RegistryStatus; + + // + // The ConfigurationHandle is really a pointer to a registry query table. + // + PNDIS_CONFIGURATION_HANDLE NdisConfigHandle = + (PNDIS_CONFIGURATION_HANDLE) ConfigurationHandle; + + // + // The name of the Parameters key. + // + PWSTR Parameters = L"\\Parameters"; + ULONG ParametersLength = (wcslen(Parameters) + 1) * sizeof(WCHAR); + + ULONG DriverLength = wcslen(NdisConfigHandle->KeyQueryTable[3].Name) * sizeof(WCHAR); + + // + // Holds a null-terminated version of the name of the Parameters key. + // + PWSTR KeyNameBuffer; + + // + // Holds a null-terminated version of the keyword. + // + PWSTR KeywordBuffer; + + // + // Variables describing the parameter value. + // + PVOID ValueData; + ULONG ValueLength; + ULONG ValueType; + + // + // Get the value data. + // + if ( ParameterValue->ParameterType == NdisParameterInteger ) { + ValueData = &ParameterValue->ParameterData.IntegerData; + ValueLength = sizeof(ParameterValue->ParameterData.IntegerData); + ValueType = REG_DWORD; + } else if ( (ParameterValue->ParameterType == NdisParameterString) || + (ParameterValue->ParameterType == NdisParameterMultiString) ) { + ValueData = ParameterValue->ParameterData.StringData.Buffer; + ValueLength = ParameterValue->ParameterData.StringData.Length; + ValueType = ParameterValue->ParameterType == NdisParameterString ? + REG_SZ : REG_MULTI_SZ; + } else { + *Status = NDIS_STATUS_NOT_SUPPORTED; + return; + } + + // + // Allocate room for the Parameters key name (e.g., L"Elnk3\Parameters"). + // + + KeyNameBuffer = (PWSTR)ExAllocatePoolWithTag( + NonPagedPool, + DriverLength + ParametersLength, + ' DN'); + if (KeyNameBuffer == NULL) { + *Status = NDIS_STATUS_RESOURCES; + return; + } + + RtlCopyMemory (KeyNameBuffer, NdisConfigHandle->KeyQueryTable[3].Name, DriverLength); + RtlCopyMemory ((PCHAR)KeyNameBuffer + DriverLength, Parameters, ParametersLength); + + // + // Allocate room for a null-terminated version of the keyword + // + + KeywordBuffer = (PWSTR)ExAllocatePoolWithTag( + NonPagedPool, + Keyword->Length + sizeof(WCHAR), + ' DN'); + if (KeywordBuffer == NULL) { + ExFreePool (KeyNameBuffer); + *Status = NDIS_STATUS_RESOURCES; + return; + } + + RtlCopyMemory (KeywordBuffer, Keyword->Buffer, Keyword->Length); + *(PWCHAR)((PUCHAR)KeywordBuffer+Keyword->Length) = (WCHAR)L'\0'; + + // + // Write the value to the registry. + // + + RegistryStatus = RtlWriteRegistryValue( + RTL_REGISTRY_SERVICES, + KeyNameBuffer, + KeywordBuffer, + ValueType, + ValueData, + ValueLength + ); + + ExFreePool (KeywordBuffer); // no longer needed + ExFreePool (KeyNameBuffer); + + if (!NT_SUCCESS(RegistryStatus)) { + *Status = NDIS_STATUS_FAILURE; + return; + } + + *Status = NDIS_STATUS_SUCCESS; + return; + +} + + + +VOID +NdisCloseConfiguration( + IN NDIS_HANDLE ConfigurationHandle + ) +/*++ + +Routine Description: + + This routine is used to close a configuration database opened by + NdisOpenConfiguration. + +Arguments: + + ConfigurationHandle - Handle returned by NdisOpenConfiguration. + +Return Value: + + None. + +--*/ +{ + // + // Obtain the actual configuration handle structure + // + PNDIS_CONFIGURATION_HANDLE NdisConfigHandle = + (PNDIS_CONFIGURATION_HANDLE) ConfigurationHandle; + + // + // Pointer to a parameter node + // + PNDIS_CONFIGURATION_PARAMETER_QUEUE ParameterNode; + + // + // deallocate the parameter nodes + // + + ParameterNode = NdisConfigHandle->ParameterList; + + while (ParameterNode != NULL) { + + NdisConfigHandle->ParameterList = ParameterNode->Next; + + if ((ParameterNode->Parameter.ParameterType == NdisParameterString) || + (ParameterNode->Parameter.ParameterType == NdisParameterMultiString)) { + ExFreePool (ParameterNode->Parameter.ParameterData.StringData.Buffer); + } + + NdisFreeMemory( + ParameterNode, + sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE), + 0 + ); + + ParameterNode = NdisConfigHandle->ParameterList; + } + + NdisFreeMemory( + ConfigurationHandle, + sizeof(NDIS_CONFIGURATION_HANDLE), + 0); +} + + + +VOID +NdisReadNetworkAddress( + OUT PNDIS_STATUS Status, + OUT PVOID * NetworkAddress, + OUT PUINT NetworkAddressLength, + IN NDIS_HANDLE ConfigurationHandle + ) + +/*++ + +Routine Description: + + This routine is used to read the "NetworkAddress" parameter + from the configuration database. It reads the value as a + string separated by hyphens, then converts it to a binary + array and stores the result. + +Arguments: + + Status - Returns the status of the request. + + NetworkAddress - Returns a pointer to the address. + + NetworkAddressLength - Returns the length of the address. + + ConfigurationHandle - Handle returned by NdisOpenConfiguration. Points + to the parameter subkey. + +Return Value: + + None. + +--*/ + +{ + // + // Convert the handle to its real value + // + + PNDIS_CONFIGURATION_HANDLE NdisConfigHandle = + (PNDIS_CONFIGURATION_HANDLE) ConfigurationHandle; + + // + // Variables used in reading the data from the registry + // + + NTSTATUS NtStatus; + PWSTR NetworkAddressString = L"NetworkAddress"; + PNDIS_CONFIGURATION_PARAMETER ParameterValue; + + // + // Variables used in converting the address + // + + UCHAR ConvertArray[3]; + PWSTR CurrentReadLoc; + PWSTR AddressEnd; + PUCHAR CurrentWriteLoc; + UINT TotalBytesRead; + ULONG TempUlong; + ULONG AddressLength; + + + // + // Finish initializing the table for this query. + // + + NdisConfigHandle->KeyQueryTable[1].Name = NetworkAddressString; + NdisConfigHandle->KeyQueryTable[1].EntryContext = &ParameterValue; + + // + // Get the value from the registry; this chains it on to the + // parameter list at NdisConfigHandle. + // + + NtStatus = RtlQueryRegistryValues( + RTL_REGISTRY_SERVICES, + NdisConfigHandle->KeyQueryTable[3].Name, + NdisConfigHandle->KeyQueryTable, + NdisConfigHandle, // context + NULL); + + if (NtStatus != NDIS_STATUS_SUCCESS) { + *Status = NDIS_STATUS_FAILURE; + return; + } + + if (ParameterValue->ParameterType != NdisParameterString) { + *Status = NDIS_STATUS_FAILURE; + return; + } + + + // + // Now convert the address to binary (we do this + // in-place, since this allows us to use the memory + // already allocated which is automatically freed + // by NdisCloseConfiguration). + // + + ConvertArray[2] = '\0'; + CurrentReadLoc = (PWSTR)ParameterValue->ParameterData.StringData.Buffer; + CurrentWriteLoc = (PUCHAR)CurrentReadLoc; + TotalBytesRead = ParameterValue->ParameterData.StringData.Length; + AddressEnd = CurrentReadLoc + (TotalBytesRead / sizeof(WCHAR)); + AddressLength = 0; + + while ((CurrentReadLoc+2) <= AddressEnd) { + + // + // Copy the current two-character value into ConvertArray + // + + ConvertArray[0] = (UCHAR)(*(CurrentReadLoc++)); + ConvertArray[1] = (UCHAR)(*(CurrentReadLoc++)); + + // + // Convert it to a Ulong and update + // + + NtStatus = RtlCharToInteger ( + ConvertArray, + 16, + &TempUlong); + + if (!NT_SUCCESS(NtStatus)) { + *Status = NDIS_STATUS_FAILURE; + return; + } + + *(CurrentWriteLoc++) = (UCHAR)TempUlong; + ++AddressLength; + + // + // If the next character is a hyphen, skip it. + // + + if (CurrentReadLoc < AddressEnd) { + if (*CurrentReadLoc == (WCHAR)L'-') { + ++CurrentReadLoc; + } + } + } + + + *Status = STATUS_SUCCESS; + *NetworkAddress = ParameterValue->ParameterData.StringData.Buffer; + *NetworkAddressLength = AddressLength; + +} + + +VOID +NdisReadBindingInformation( + OUT PNDIS_STATUS Status, + OUT PNDIS_STRING * Binding, + IN NDIS_HANDLE ConfigurationHandle + ) + +/*++ + +Routine Description: + + This routine is used to read the binding information for + this adapter from the configuration database. The value + returned is a pointer to a string containing the bind + that matches the export for the current AddAdapter call. + + This function is meant for NDIS drivers that are layered + on top of other NDIS drivers. Binding would be passed to + NdisOpenAdapter as the AdapterName. + +Arguments: + + Status - Returns the status of the request. + + Binding - Returns the binding data. + + ConfigurationHandle - Handle returned by NdisOpenConfiguration. Points + to the parameter subkey. + +Return Value: + + None. + +--*/ + +{ + + // + // Convert the handle to its real value + // + + PNDIS_CONFIGURATION_HANDLE NdisConfigHandle = + (PNDIS_CONFIGURATION_HANDLE) ConfigurationHandle; + + // + // Use this to link parameters allocated to this open + // + + PNDIS_CONFIGURATION_PARAMETER_QUEUE ParameterNode; + + + // + // For layered drivers, this points to the binding. For + // non-layered drivers, it is NULL. This is set up before + // the call to AddAdapter. + // + + if (NdisConfigHandle->KeyQueryTable[3].EntryContext == NULL) { + *Status = NDIS_STATUS_FAILURE; + return; + } + + + // + // Allocate our parameter node + // + + *Status = NdisAllocateMemory( + (PVOID*)&ParameterNode, + sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE), + 0, + HighestAcceptableMax); + + if (*Status != NDIS_STATUS_SUCCESS) { + return; + } + + + // + // We set this to Integer because if we set it to String + // then CloseConfiguration would try to free the string, + // which we don't want. + // + + ParameterNode->Parameter.ParameterType = NdisParameterInteger; + + RtlInitUnicodeString( + &ParameterNode->Parameter.ParameterData.StringData, + NdisConfigHandle->KeyQueryTable[3].EntryContext); + + // + // Queue this parameter node + // + + ParameterNode->Next = NdisConfigHandle->ParameterList; + NdisConfigHandle->ParameterList = ParameterNode; + + *Binding = &ParameterNode->Parameter.ParameterData.StringData; + *Status = NDIS_STATUS_SUCCESS; + +} + +// +// Packet and Buffer requests +// + + +VOID +NdisAllocatePacketPool( + OUT PNDIS_STATUS Status, + OUT PNDIS_HANDLE PoolHandle, + IN UINT NumberOfDescriptors, + IN UINT ProtocolReservedLength + ) + +/*++ + +Routine Description: + + Initializes a packet pool. All packets are the same + size for a given pool (as determined by ProtocolReservedLength), + so a simple linked list of free packets is set up initially. + +Arguments: + + Status - Returns the final status (always NDIS_STATUS_SUCCESS). + PoolHandle - Returns a pointer to the pool. + NumberOfDescriptors - Number of packet descriptors needed. + ProtocolReservedLength - How long the ProtocolReserved field + should be for packets in this pool. + +Return Value: + + None. + +--*/ + +{ + PNDIS_PACKET_POOL TmpPool; + PUCHAR FreeEntry; + UINT PacketLength; + UINT i; + + // + // Set up the size of packets in this pool (rounded + // up to sizeof(ULONG) for alignment). + // + + IF_TRACE(TRACE_IMPT) NdisPrint1("==>NdisAllocatePacketPool\n"); + + PacketLength = sizeof(NDIS_PACKET) - 1 + ProtocolReservedLength; + PacketLength = ((PacketLength+(sizeof(ULONG)-1)) / sizeof(ULONG)) + * sizeof(ULONG); + + // + // Allocate space needed + // + TmpPool = (PNDIS_PACKET_POOL) ExAllocatePoolWithTag( + NonPagedPool, + sizeof(NDIS_PACKET_POOL) + + PacketLength * NumberOfDescriptors - + 1, + 'ppDN' + ); + + if (TmpPool == NULL) { + *Status = NDIS_STATUS_RESOURCES; + return; + } + + TmpPool->PacketLength = PacketLength; + + // + // First entry in free list is at beginning of pool space. + // + + TmpPool->FreeList = (PNDIS_PACKET)TmpPool->Buffer; + FreeEntry = TmpPool->Buffer; + + for (i = 1; i < NumberOfDescriptors; i++) { + + // + // Each entry is linked to the "packet" PacketLength bytes + // ahead of it, using the Private.Head field. + // + + ((PNDIS_PACKET)FreeEntry)->Private.Head = + (PNDIS_BUFFER)(FreeEntry + PacketLength); + FreeEntry += PacketLength; + } + + // + // Final free list entry. + // + + ((PNDIS_PACKET)FreeEntry)->Private.Head = (PNDIS_BUFFER)NULL; + + + NdisAllocateSpinLock(&TmpPool->SpinLock); + + *Status = NDIS_STATUS_SUCCESS; + *PoolHandle = (NDIS_HANDLE)TmpPool; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisAllocatePacketPool\n"); +} + + + +VOID +NdisAllocateBufferPool( + OUT PNDIS_STATUS Status, + OUT PNDIS_HANDLE PoolHandle, + IN UINT NumberOfDescriptors + ) +/*++ + +Routine Description: + + Initializes a block of storage so that buffer descriptors can be + allocated. + +Arguments: + + Status - status of the request. + PoolHandle - handle that is used to specify the pool + NumberOfDescriptors - Number of buffer descriptors in the pool. + +Return Value: + + None. + +--*/ +{ + + // + // A nop for NT + // + UNREFERENCED_PARAMETER(NumberOfDescriptors); + *PoolHandle = NULL; + *Status = NDIS_STATUS_SUCCESS; + +} + +VOID +NdisFreeBufferPool( + IN NDIS_HANDLE PoolHandle + ) +/*++ + +Routine Description: + + Terminates usage of a buffer descriptor pool. + +Arguments: + + PoolHandle - handle that is used to specify the pool + +Return Value: + + None. + +--*/ +{ + UNREFERENCED_PARAMETER(PoolHandle); +} + +VOID +NdisAllocateBuffer( + OUT PNDIS_STATUS Status, + OUT PNDIS_BUFFER * Buffer, + IN NDIS_HANDLE PoolHandle, + IN PVOID VirtualAddress, + IN UINT Length + ) +/*++ + +Routine Description: + + Creates a buffer descriptor to describe a segment of virtual memory + allocated via NdisAllocateMemory (which always allocates nonpaged). + +Arguments: + + Status - Status of the request. + Buffer - Pointer to the allocated buffer descriptor. + PoolHandle - Handle that is used to specify the pool. + VirtualAddress - The virtual address of the buffer. + Length - The Length of the buffer. + +Return Value: + + None. + +--*/ +{ + + UNREFERENCED_PARAMETER(PoolHandle); + + if ((*Buffer = IoAllocateMdl( + VirtualAddress, + Length, + FALSE, + FALSE, + NULL + )) == NULL) { + + *Status = NDIS_STATUS_FAILURE; + + } else { + + MmBuildMdlForNonPagedPool(*Buffer); + (*Buffer)->Next = NULL; + *Status = NDIS_STATUS_SUCCESS; + + } + +} + + +VOID +NdisCopyBuffer( + OUT PNDIS_STATUS Status, + OUT PNDIS_BUFFER * Buffer, + IN NDIS_HANDLE PoolHandle, + IN PVOID MemoryDescriptor, + IN UINT Offset, + IN UINT Length + ) +/*++ + +Routine Description: + + Used to create a buffer descriptor given a memory descriptor. + +Arguments: + + Status - Status of the request. + Buffer - Pointer to the allocated buffer descriptor. + PoolHandle - Handle that is used to specify the pool. + MemoryDescriptor - Pointer to the descriptor of the source memory. + Offset - The Offset in the sources memory from which the copy is to + begin + Length - Number of Bytes to copy. + +Return Value: + + None. + +--*/ +{ + + PNDIS_BUFFER SourceDescriptor = (PNDIS_BUFFER)MemoryDescriptor; + PVOID BaseVa = (((PUCHAR)MmGetMdlVirtualAddress(SourceDescriptor)) + Offset); + + UNREFERENCED_PARAMETER(PoolHandle); + + if ((*Buffer = IoAllocateMdl( + BaseVa, + Length, + FALSE, + FALSE, + NULL + )) == NULL ) { + + *Status = NDIS_STATUS_FAILURE; + + } else { + + IoBuildPartialMdl( + SourceDescriptor, + *Buffer, + BaseVa, + Length); + + (*Buffer)->Next = NULL; + *Status = NDIS_STATUS_SUCCESS; + + } + +} + + +VOID +NdisAllocatePacket( + OUT PNDIS_STATUS Status, + OUT PNDIS_PACKET * Packet, + IN NDIS_HANDLE PoolHandle + ) + +/*++ + +Routine Description: + + Allocates a packet out of a packet pool. + +Arguments: + + Status - Returns the final status. + Packet - Return a pointer to the packet. + PoolHandle - The packet pool to allocate from. + +Return Value: + + None. + +--*/ + +{ + PNDIS_PACKET_POOL TmpPool = (PNDIS_PACKET_POOL)PoolHandle; + + ACQUIRE_SPIN_LOCK(&TmpPool->SpinLock); + + + // + // See if any packets are on pool free list. + // + + IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisAllocatePacket\n"); + + IF_ERROR_CHK { + if (DbgIsNull(PoolHandle)) { + NdisPrint1("AllocatePacket: NULL Pool address\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(PoolHandle)) { + NdisPrint1("AllocatePacket: Pool not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + if (TmpPool->FreeList == (PNDIS_PACKET)NULL) { + + // + // No, cannot satisfy request. + // + + RELEASE_SPIN_LOCK(&TmpPool->SpinLock); + *Status = NDIS_STATUS_RESOURCES; + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisAllocatePacket\n"); + return; + } + + // + // Yes, take free packet off head of list and return it. + // + + *Packet = TmpPool->FreeList; + TmpPool->FreeList = (PNDIS_PACKET)(*Packet)->Private.Head; + RELEASE_SPIN_LOCK(&TmpPool->SpinLock); + + + // + // Clear packet elements. + // + + RtlZeroMemory((PVOID)*Packet, TmpPool->PacketLength); + (*Packet)->Private.Head = (PNDIS_BUFFER)NULL; // don't need to set Tail + (*Packet)->Private.Pool = (PNDIS_PACKET_POOL)PoolHandle; + (*Packet)->Private.Count = 0; + (*Packet)->Private.PhysicalCount = 0; + (*Packet)->Private.TotalLength = 0; + (*Packet)->Private.ValidCounts = TRUE; + + *Status = NDIS_STATUS_SUCCESS; + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisAllocatePacket\n"); +} + + +VOID +NdisUnchainBufferAtFront( + IN OUT PNDIS_PACKET Packet, + OUT PNDIS_BUFFER * Buffer + ) + +/*++ + +Routine Description: + + Takes a buffer off the front of a packet. + +Arguments: + + Packet - The packet to be modified. + Buffer - Returns the packet on the front, or NULL. + +Return Value: + + None. + +--*/ + +{ + *Buffer = Packet->Private.Head; + + // + // If packet is not empty, remove head buffer. + // + + IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisUnchainBufferAtFront\n"); + + IF_ERROR_CHK { + if (DbgIsNull(Packet)) { + NdisPrint1("UnchainBufferAtFront: Null Packet Pointer\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(Packet)) { + NdisPrint1("UnchainBufferAtFront: Packet not in NonPaged Memory\n"); + DbgBreakPoint(); + } + if (!DbgIsPacket(Packet)) { + NdisPrint1("UnchainBufferAtFront: Illegal Packet Size\n"); + DbgBreakPoint(); + } + } + + if (*Buffer != (PNDIS_BUFFER)NULL) { + Packet->Private.Head = (*Buffer)->Next; // may be NULL + (*Buffer)->Next = (PNDIS_BUFFER)NULL; + Packet->Private.ValidCounts = FALSE; + } + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisUnchainBufferAtFront\n"); +} + +VOID +NdisUnchainBufferAtBack( + IN OUT PNDIS_PACKET Packet, + OUT PNDIS_BUFFER * Buffer + ) + +/*++ + +Routine Description: + + Takes a buffer off the end of a packet. + +Arguments: + + Packet - The packet to be modified. + Buffer - Returns the packet on the end, or NULL. + +Return Value: + + None. + +--*/ + +{ + PNDIS_BUFFER TmpBufP = Packet->Private.Head; + PNDIS_BUFFER Result; + + IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisUnchainBufferAtBack\n"); + IF_ERROR_CHK { + if (DbgIsNull(Packet)) { + NdisPrint1("UnchainBufferAtBack: Null Packet Pointer\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(Packet)) { + NdisPrint1("UnchainBufferAtBack: Packet not in NonPaged Memory\n"); + DbgBreakPoint(); + } + if (!DbgIsPacket(Packet)) { + NdisPrint1("UnchainBufferAtBack: Illegal Packet Size\n"); + DbgBreakPoint(); + } + } + if (TmpBufP != (PNDIS_BUFFER)NULL) { + + // + // The packet is not empty, return the tail buffer. + // + + Result = Packet->Private.Tail; + if (TmpBufP == Result) { + + // + // There was only one buffer on the queue. + // + + Packet->Private.Head = (PNDIS_BUFFER)NULL; + } else { + + // + // Determine the new tail buffer. + // + + while (TmpBufP->Next != Result) { + TmpBufP = TmpBufP->Next; + } + Packet->Private.Tail = TmpBufP; + TmpBufP->Next = NULL; + } + + Result->Next = (PNDIS_BUFFER)NULL; + Packet->Private.ValidCounts = FALSE; + } else { + + // + // Packet is empty. + // + + Result = (PNDIS_BUFFER)NULL; + } + + *Buffer = Result; + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisUnchainBufferAtBack\n"); +} + + + +VOID +NdisCopyFromPacketToPacket( + IN PNDIS_PACKET Destination, + IN UINT DestinationOffset, + IN UINT BytesToCopy, + IN PNDIS_PACKET Source, + IN UINT SourceOffset, + OUT PUINT BytesCopied + ) + +/*++ + +Routine Description: + + Copy from an ndis packet to an ndis packet. + +Arguments: + + Destination - The packet should be copied in to. + + DestinationOffset - The offset from the beginning of the packet + into which the data should start being placed. + + BytesToCopy - The number of bytes to copy from the source packet. + + Source - The ndis packet from which to copy data. + + SourceOffset - The offset from the start of the packet from which + to start copying data. + + BytesCopied - The number of bytes actually copied from the source + packet. This can be less than BytesToCopy if the source or destination + packet is too short. + +Return Value: + + None + +--*/ + +{ + + // + // Holds the count of the number of ndis buffers comprising the + // destination packet. + // + UINT DestinationBufferCount; + + // + // Holds the count of the number of ndis buffers comprising the + // source packet. + // + UINT SourceBufferCount; + + // + // Points to the buffer into which we are putting data. + // + PNDIS_BUFFER DestinationCurrentBuffer; + + // + // Points to the buffer from which we are extracting data. + // + PNDIS_BUFFER SourceCurrentBuffer; + + // + // Holds the virtual address of the current destination buffer. + // + PVOID DestinationVirtualAddress; + + // + // Holds the virtual address of the current source buffer. + // + PVOID SourceVirtualAddress; + + // + // Holds the length of the current destination buffer. + // + UINT DestinationCurrentLength; + + // + // Holds the length of the current source buffer. + // + UINT SourceCurrentLength; + + // + // Keep a local variable of BytesCopied so we aren't referencing + // through a pointer. + // + UINT LocalBytesCopied = 0; + + // + // Take care of boundary condition of zero length copy. + // + + *BytesCopied = 0; + if (!BytesToCopy) return; + + // + // Get the first buffer of the destination. + // + + NdisQueryPacket( + Destination, + NULL, + &DestinationBufferCount, + &DestinationCurrentBuffer, + NULL + ); + + // + // Could have a null packet. + // + + if (!DestinationBufferCount) return; + + NdisQueryBuffer( + DestinationCurrentBuffer, + &DestinationVirtualAddress, + &DestinationCurrentLength + ); + + // + // Get the first buffer of the source. + // + + NdisQueryPacket( + Source, + NULL, + &SourceBufferCount, + &SourceCurrentBuffer, + NULL + ); + + // + // Could have a null packet. + // + + if (!SourceBufferCount) return; + + NdisQueryBuffer( + SourceCurrentBuffer, + &SourceVirtualAddress, + &SourceCurrentLength + ); + + while (LocalBytesCopied < BytesToCopy) { + + // + // Check to see whether we've exhausted the current destination + // buffer. If so, move onto the next one. + // + + if (!DestinationCurrentLength) { + + NdisGetNextBuffer( + DestinationCurrentBuffer, + &DestinationCurrentBuffer + ); + + if (!DestinationCurrentBuffer) { + + // + // We've reached the end of the packet. We return + // with what we've done so far. (Which must be shorter + // than requested.) + // + + break; + + } + + NdisQueryBuffer( + DestinationCurrentBuffer, + &DestinationVirtualAddress, + &DestinationCurrentLength + ); + continue; + + } + + + // + // Check to see whether we've exhausted the current source + // buffer. If so, move onto the next one. + // + + if (!SourceCurrentLength) { + + NdisGetNextBuffer( + SourceCurrentBuffer, + &SourceCurrentBuffer + ); + + if (!SourceCurrentBuffer) { + + // + // We've reached the end of the packet. We return + // with what we've done so far. (Which must be shorter + // than requested.) + // + + break; + + } + + NdisQueryBuffer( + SourceCurrentBuffer, + &SourceVirtualAddress, + &SourceCurrentLength + ); + continue; + + } + + // + // Try to get us up to the point to start the copy. + // + + if (DestinationOffset) { + + if (DestinationOffset > DestinationCurrentLength) { + + // + // What we want isn't in this buffer. + // + + DestinationOffset -= DestinationCurrentLength; + DestinationCurrentLength = 0; + continue; + + } else { + + DestinationVirtualAddress = (PCHAR)DestinationVirtualAddress + + DestinationOffset; + DestinationCurrentLength -= DestinationOffset; + DestinationOffset = 0; + + } + + } + + // + // Try to get us up to the point to start the copy. + // + + if (SourceOffset) { + + if (SourceOffset > SourceCurrentLength) { + + // + // What we want isn't in this buffer. + // + + SourceOffset -= SourceCurrentLength; + SourceCurrentLength = 0; + continue; + + } else { + + SourceVirtualAddress = (PCHAR)SourceVirtualAddress + + SourceOffset; + SourceCurrentLength -= SourceOffset; + SourceOffset = 0; + + } + + } + + // + // Copy the data. + // + + { + + // + // Holds the amount of data to move. + // + UINT AmountToMove; + + // + // Holds the amount desired remaining. + // + UINT Remaining = BytesToCopy - LocalBytesCopied; + + AmountToMove = + ((SourceCurrentLength <= DestinationCurrentLength)? + (SourceCurrentLength):(DestinationCurrentLength)); + + AmountToMove = ((Remaining < AmountToMove)? + (Remaining):(AmountToMove)); + + RtlCopyMemory( + DestinationVirtualAddress, + SourceVirtualAddress, + AmountToMove + ); + + DestinationVirtualAddress = + (PCHAR)DestinationVirtualAddress + AmountToMove; + SourceVirtualAddress = + (PCHAR)SourceVirtualAddress + AmountToMove; + + LocalBytesCopied += AmountToMove; + SourceCurrentLength -= AmountToMove; + DestinationCurrentLength -= AmountToMove; + + } + + } + + *BytesCopied = LocalBytesCopied; + +} + +// +// Operating System Requests +// +// + + +VOID +NdisMapIoSpace( + OUT PNDIS_STATUS Status, + OUT PVOID * VirtualAddress, + IN NDIS_HANDLE NdisAdapterHandle, + IN NDIS_PHYSICAL_ADDRESS PhysicalAddress, + IN UINT Length + ) +/*++ + +Routine Description: + + Map virtual memory address space onto a physical address. + +Arguments: + + Status - resulting status + VirtualAddress - resulting address in virtual space. + NdisAdapterHandle - value returned by NdisRegisterAdapter. + PhysicalAddress - Physical address. + Length - Size of requested memory mapping + +Return Value: + + none. + +--*/ +{ + ULONG addressSpace = 0; + ULONG NumberOfElements; + PHYSICAL_ADDRESS PhysicalTemp; + PCM_RESOURCE_LIST Resources; + BOOLEAN Conflict; + NTSTATUS NtStatus; + PNDIS_ADAPTER_BLOCK AdptrP = (PNDIS_ADAPTER_BLOCK)(NdisAdapterHandle); + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(NdisAdapterHandle); + + // + // First check if any bus access is allowed + // + + if ((((AdptrP->DeviceObject != NULL) ? + AdptrP->BusType : + Miniport->BusType) == (NDIS_INTERFACE_TYPE)-1) || + (((AdptrP->DeviceObject != NULL) ? + AdptrP->BusNumber : + Miniport->BusNumber) == (ULONG)-1)) { + + *Status = NDIS_STATUS_FAILURE; + return; + + } + + // + // First check for resource conflict by expanding current resource list, + // adding in the mapped space, and then re-submitting the resource list. + // + + if (((AdptrP->DeviceObject != NULL) ? + AdptrP->Resources : + Miniport->Resources) != NULL) { + + NumberOfElements = ((AdptrP->DeviceObject != NULL) ? + AdptrP->Resources->List[0].PartialResourceList.Count + 1: + Miniport->Resources->List[0].PartialResourceList.Count + 1); + + } else { + + NumberOfElements = 1; + } + + // + // First check for resource conflict by expanding current resource list, + // adding in the mapped space, and then re-submitting the resource list. + // + + Resources = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag( + NonPagedPool, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + NumberOfElements, + 'lrDN' + ); + + if (Resources == NULL) { + + *Status = NDIS_STATUS_RESOURCES; + return; + + } + + if (((AdptrP->DeviceObject != NULL) ? + AdptrP->Resources : + Miniport->Resources) != NULL) { + + RtlCopyMemory (Resources, + ((AdptrP->DeviceObject != NULL) ? + AdptrP->Resources: + Miniport->Resources), + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + (NumberOfElements-1) + ); + } else { + + // + // Setup initial resource info -- NOTE: This is definitely a mini-port + // + ASSERT(AdptrP->DeviceObject == NULL); + Resources->Count = 1; + Resources->List[0].InterfaceType = Miniport->AdapterType; + Resources->List[0].BusNumber = Miniport->BusNumber; + Resources->List[0].PartialResourceList.Version = 0; + Resources->List[0].PartialResourceList.Revision = 0; + Resources->List[0].PartialResourceList.Count = 0; + + } + + // + // Setup memory + // + + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type = + CmResourceTypeMemory; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition = + CmResourceShareDeviceExclusive; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags = + CM_RESOURCE_MEMORY_READ_WRITE; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Memory.Start = + PhysicalAddress; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Memory.Length = + Length; + Resources->List[0].PartialResourceList.Count++; + + + // + // Make the call + // + + NtStatus = IoReportResourceUsage( + NULL, + ((AdptrP->DeviceObject != NULL) ? + AdptrP->MacHandle->NdisMacInfo->NdisWrapperDriver : + Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver), + NULL, + 0, + ((AdptrP->DeviceObject != NULL) ? + AdptrP->DeviceObject: + Miniport->DeviceObject), + Resources, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + Resources->List[0].PartialResourceList.Count, + TRUE, + &Conflict + ); + + // + // Check for conflict. + // + + if (((AdptrP->DeviceObject != NULL) ? + AdptrP->Resources : + Miniport->Resources) != NULL) { + ExFreePool(((AdptrP->DeviceObject != NULL) ? + AdptrP->Resources: + Miniport->Resources)); + } + + if (AdptrP->DeviceObject != NULL) { + AdptrP->Resources = Resources; + } else { + Miniport->Resources = Resources; + } + + if (Conflict || (NtStatus != STATUS_SUCCESS)) { + + + if (Conflict) { + + + // + // Log an error + // + + PIO_ERROR_LOG_PACKET errorLogEntry; + volatile ULONG i; + ULONG StringSize; + PUCHAR Place; + PWCH baseFileName; + WCHAR Character; + ULONG Value; + + baseFileName = ((AdptrP->DeviceObject != NULL) ? + AdptrP->AdapterName.Buffer : + Miniport->MiniportName.Buffer); + + // + // Parse out the path name, leaving only the device name. + // + + for ( i = 0; + i < ((AdptrP->DeviceObject != NULL) ? + AdptrP->AdapterName.Length : + Miniport->MiniportName.Length) / sizeof(WCHAR); + i++ ) { + + // + // If s points to a directory separator, set baseFileName to + // the character after the separator. + // + + if ( ((AdptrP->DeviceObject != NULL) ? + AdptrP->AdapterName.Buffer[i] : + Miniport->MiniportName.Buffer[i]) == OBJ_NAME_PATH_SEPARATOR ) { + baseFileName = ((AdptrP->DeviceObject != NULL) ? + &(AdptrP->AdapterName.Buffer[++i]): + &(Miniport->MiniportName.Buffer[++i])); + } + + } + + StringSize = ((AdptrP->DeviceObject != NULL) ? + AdptrP->AdapterName.MaximumLength : + Miniport->MiniportName.MaximumLength) - + (((ULONG)baseFileName) - + ((AdptrP->DeviceObject != NULL) ? + ((ULONG)AdptrP->AdapterName.Buffer) : + ((ULONG)Miniport->MiniportName.Buffer))); + + errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( + ((AdptrP->DeviceObject != NULL) ? + AdptrP->DeviceObject: + Miniport->DeviceObject), + (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) + + StringSize + + 34) // wstrlen("FFFFFFFFFFFFFFFF") * sizeof(WHCAR) + sizeof(UNICODE_NULL) + ); + + if (errorLogEntry != NULL) { + + errorLogEntry->ErrorCode = EVENT_NDIS_MEMORY_CONFLICT; + + // + // store the time + // + + errorLogEntry->MajorFunctionCode = 0; + errorLogEntry->RetryCount = 0; + errorLogEntry->UniqueErrorValue = 0; + errorLogEntry->FinalStatus = 0; + errorLogEntry->SequenceNumber = 0; + errorLogEntry->IoControlCode = 0; + + // + // Set string information + // + + if (StringSize != 0) { + + errorLogEntry->NumberOfStrings = 1; + errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET); + + RtlCopyMemory ( + ((PUCHAR)errorLogEntry) + + sizeof(IO_ERROR_LOG_PACKET), + (PVOID)baseFileName, + StringSize + ); + + Place = ((PUCHAR)errorLogEntry) + + sizeof(IO_ERROR_LOG_PACKET) + + StringSize; + + } else { + + Place = ((PUCHAR)errorLogEntry) + + sizeof(IO_ERROR_LOG_PACKET); + + errorLogEntry->NumberOfStrings = 0; + + } + + errorLogEntry->NumberOfStrings++; + + // + // Put in memory address + // + + for (StringSize = 0; StringSize < 2; StringSize++) { + + if (StringSize == 0) { + + // + // Do high part + // + + Value = NdisGetPhysicalAddressHigh(PhysicalAddress); + + } else { + + // + // Do Low part + // + + Value = NdisGetPhysicalAddressLow(PhysicalAddress); + + } + + // + // Convert value + // + + for (i = 1; i <= (sizeof(ULONG) * 2); i++) { + + switch ((Value >> (((sizeof(ULONG) * 2) - i) * 4)) & 0x0F) { + + case 0: + Character = L'0'; + break; + case 1: + Character = L'1'; + break; + case 2: + Character = L'2'; + break; + case 3: + Character = L'3'; + break; + case 4: + Character = L'4'; + break; + case 5: + Character = L'5'; + break; + case 6: + Character = L'6'; + break; + case 7: + Character = L'7'; + break; + case 8: + Character = L'8'; + break; + case 9: + Character = L'9'; + break; + case 10: + Character = L'A'; + break; + case 11: + Character = L'B'; + break; + case 12: + Character = L'C'; + break; + case 13: + Character = L'D'; + break; + case 14: + Character = L'E'; + break; + case 15: + Character = L'F'; + break; + } + + memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR)); + + Place += sizeof(WCHAR); + + } + + } + + Character = UNICODE_NULL; + + memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR)); + + // + // write it out + // + + IoWriteErrorLogEntry(errorLogEntry); + + } + + *Status = NDIS_STATUS_RESOURCE_CONFLICT; + return; + + } + + *Status = NDIS_STATUS_FAILURE; + return; + + } + + + if ( !HalTranslateBusAddress( + ((AdptrP->DeviceObject != NULL) ? + AdptrP->BusType: + Miniport->BusType), + ((AdptrP->DeviceObject != NULL) ? + AdptrP->BusNumber : + Miniport->BusNumber), + PhysicalAddress, + &addressSpace, + &PhysicalTemp + ) ) { + + // + // It would be nice to return a better status here, but we only get + // TRUE/FALSE back from HalTranslateBusAddress. + // + + *Status = NDIS_STATUS_FAILURE; + return; + } + + if (addressSpace == 0) { + + // + // memory space + // + + *VirtualAddress = MmMapIoSpace(PhysicalTemp, (Length), FALSE); + + } else { + + // + // I/O space + // + + *VirtualAddress = (PVOID)(PhysicalTemp.LowPart); + + } + + if (*VirtualAddress == NULL) { + *Status = NDIS_STATUS_RESOURCES; + } else { + *Status = NDIS_STATUS_SUCCESS; + } +} + +NDIS_STATUS +NdisAllocateMemory( + OUT PVOID *VirtualAddress, + IN UINT Length, + IN UINT MemoryFlags, + IN NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress + ) +/*++ + +Routine Description: + + Allocate memory for use by a protocol or a MAC driver + +Arguments: + + VirtualAddress - Returns a pointer to the allocated memory. + Length - Size of requested allocation in bytes. + MaximumPhysicalAddress - Highest addressable address of the allocated + memory.. 0 means highest system memory possible. + MemoryFlags - Bit mask that allows the caller to specify attributes + of the allocated memory. 0 means standard memory. + + other options: + + NDIS_MEMORY_CONTIGUOUS + NDIS_MEMORY_NONCACHED + +Return Value: + + NDIS_STATUS_SUCCESS if successful. + NDIS_STATUS_FAILURE if not successful. *VirtualAddress will be NULL. + + +--*/ +{ + // + // Depending on the value of MemoryFlags, we allocate three different + // types of memory. + // + + if (MemoryFlags == 0) { + + *VirtualAddress = ExAllocatePoolWithTag(NonPagedPool, Length, 'maDN'); + + } else if (MemoryFlags & NDIS_MEMORY_NONCACHED) { + + *VirtualAddress = MmAllocateNonCachedMemory(Length); + + } else if (MemoryFlags & NDIS_MEMORY_CONTIGUOUS) { + + *VirtualAddress = MmAllocateContiguousMemory(Length, HighestAcceptableAddress); + + } + + if (*VirtualAddress == NULL) { + + return NDIS_STATUS_FAILURE; + + } + + return NDIS_STATUS_SUCCESS; + +} + + +VOID +NdisFreeMemory( + IN PVOID VirtualAddress, + IN UINT Length, + IN UINT MemoryFlags + ) +/*++ + +Routine Description: + + Releases memory allocated using NdisAllocateMemory. + +Arguments: + + VirtualAddress - Pointer to the memory to be freed. + Length - Size of allocation in bytes. + MemoryFlags - Bit mask that allows the caller to specify attributes + of the allocated memory. 0 means standard memory. + + other options: + + NDIS_MEMORY_CONTIGUOUS + NDIS_MEMORY_NONCACHED + +Return Value: + + None. + +--*/ +{ + // + // Depending on the value of MemoryFlags, we allocate three free 3 + // types of memory. + // + + if (MemoryFlags == 0) { + + ExFreePool(VirtualAddress); + + } else if (MemoryFlags & NDIS_MEMORY_NONCACHED) { + + MmFreeNonCachedMemory(VirtualAddress, Length); + + } else if (MemoryFlags & NDIS_MEMORY_CONTIGUOUS) { + + MmFreeContiguousMemory(VirtualAddress); + + } + +} + +VOID +NdisInitializeTimer( + IN OUT PNDIS_TIMER NdisTimer, + IN PNDIS_TIMER_FUNCTION TimerFunction, + IN PVOID FunctionContext + ) +/*++ + +Routine Description: + + Sets up an NdisTimer object, initializing the DPC in the timer to + the function and context. + +Arguments: + + NdisTimer - the timer object. + TimerFunction - Routine to start. + FunctionContext - Context of TimerFunction. + +Return Value: + + None. + +--*/ +{ + + KeInitializeTimer(&(NdisTimer)->Timer); + + // + // Initialize our dpc. If Dpc was previously initialized, this will + // reinitialize it. + // + + KeInitializeDpc( + &NdisTimer->Dpc, + (PKDEFERRED_ROUTINE) TimerFunction, + FunctionContext + ); + + KeSetImportanceDpc( + &NdisTimer->Dpc, + LowImportance + ); +} + + +VOID +NdisSetTimer( + IN PNDIS_TIMER NdisTimer, + IN UINT MillisecondsToDelay + ) +/*++ + +Routine Description: + + Sets up TimerFunction to fire after MillisecondsToDelay. + +Arguments: + + NdisTimer - the timer object. + MillisecondsToDelay - Amount of time before TimerFunction is started. + +Return Value: + + None. + +--*/ +{ + LARGE_INTEGER FireUpTime; + + FireUpTime.QuadPart = Int32x32To64((LONG)MillisecondsToDelay, -10000); + + // + // Set the timer + // + KeSetTimer( + &NdisTimer->Timer, + FireUpTime, + &NdisTimer->Dpc + ); +} + + +BOOLEAN +NdisIsr( + IN PKINTERRUPT Interrupt, + IN PVOID Context + ) +/*++ + +Routine Description: + + Handles ALL Mac interrupts, calling the appropriate Mac ISR and DPC + depending on the context. + +Arguments: + + Interrupt - Interrupt object for the Mac. + + Context - Really a pointer to the interrupt. + +Return Value: + + None. + +--*/ +{ + // + // Get adapter from context. + // + + PNDIS_INTERRUPT NdisInterrupt = (PNDIS_INTERRUPT)(Context); + + BOOLEAN (*InterruptIsr)(PVOID) = (BOOLEAN (*) (PVOID))(NdisInterrupt->MacIsr); + + UNREFERENCED_PARAMETER(Interrupt); + + // + // Call MacIsr + // + + if((*InterruptIsr)(NdisInterrupt->InterruptContext) != FALSE){ + + // + // Queue MacDpc if needed + // + + Increment((PLONG)&NdisInterrupt->DpcCount,&NdisInterrupt->DpcCountLock); + + if (!(KeInsertQueueDpc(&(NdisInterrupt->InterruptDpc),NULL,NULL))) { + + // + // If the DPC was already queued, then we have an extra + // reference (we do it this way to ensure that the reference + // is added *before* the DPC is queued). + // + + Decrement((PLONG)&NdisInterrupt->DpcCount,&NdisInterrupt->DpcCountLock); + + if (NdisInterrupt->Removing && (NdisInterrupt->DpcCount==0)) { + + // + // We need to queue a DPC to set the event because we + // can't do it from the ISR. We know that the interrupt + // DPC won't fire because the refcount is 0, so we reuse it. + // + + KeInitializeDpc( + &NdisInterrupt->InterruptDpc, + NdisLastCountRemovedFunction, + (PVOID)(&NdisInterrupt->DpcsCompletedEvent) + ); + + // + // When NdisLastCountRemovedFunction runs it will set + // the event. + // + + KeInsertQueueDpc (&(NdisInterrupt->InterruptDpc), NULL, NULL); + + } + } + + return TRUE; + + } + + return FALSE; + +} + +VOID +NdisLastCountRemovedFunction( + IN struct _KDPC *Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2 + ) + +/*++ + +Routine Description: + + Queued from NdisIsr if the refcount is zero and we need to + set the event, since we can't do that from an ISR. + +Arguments: + + Dpc - Will be NdisInterrupt->InterruptDpc. + + DeferredContext - Points to the event to set. + +Return Value: + + None. + +--*/ +{ + UNREFERENCED_PARAMETER (Dpc); + UNREFERENCED_PARAMETER (SystemArgument1); + UNREFERENCED_PARAMETER (SystemArgument2); + + KeSetEvent( + (PKEVENT)DeferredContext, + 0L, + FALSE + ); +} + + +VOID +NdisDpc( + IN PVOID SystemSpecific1, + IN PVOID InterruptContext, + IN PVOID SystemSpecific2, + IN PVOID SystemSpecific3 + ) +/*++ + +Routine Description: + + Handles ALL Mac interrupt DPCs, calling the appropriate Mac DPC + depending on the context. + +Arguments: + + Interrupt - Interrupt object for the Mac. + + Context - Really a pointer to the Interrupt. + +Return Value: + + None. + +--*/ +{ + // + // Get adapter from context. + // + + PNDIS_INTERRUPT NdisInterrupt = (PNDIS_INTERRUPT)(InterruptContext); + + VOID (*MacDpc)(PVOID) = (VOID (*) (PVOID))(NdisInterrupt->MacDpc); + + // + // Call MacDpc + // + + (*((PNDIS_DEFERRED_PROCESSING)MacDpc))(SystemSpecific1, + NdisInterrupt->InterruptContext, + SystemSpecific2, + SystemSpecific3 + ); + + Decrement((PLONG)&NdisInterrupt->DpcCount,&NdisInterrupt->DpcCountLock); + + if (NdisInterrupt->Removing && (NdisInterrupt->DpcCount==0)) { + + KeSetEvent( + &NdisInterrupt->DpcsCompletedEvent, + 0L, + FALSE + ); + } + + +} + + +VOID +NdisInitializeInterrupt( + OUT PNDIS_STATUS Status, + IN OUT PNDIS_INTERRUPT NdisInterrupt, + IN NDIS_HANDLE NdisAdapterHandle, + IN PNDIS_INTERRUPT_SERVICE InterruptServiceRoutine, + IN PVOID InterruptContext, + IN PNDIS_DEFERRED_PROCESSING DeferredProcessingRoutine, + IN UINT InterruptVector, + IN UINT InterruptLevel, + IN BOOLEAN SharedInterrupt, + IN NDIS_INTERRUPT_MODE InterruptMode + ) + +/*++ + +Routine Description: + + Initializes the interrupt and sets up the Dpc. + +Arguments: + + Status - Status of this request. + InterruptDpc - The Dpc object corresponding to DeferredProcessingRoutine. + Interrupt - Points to driver allocated memory that the wrapper fills in + with information about the interrupt handler. + InterruptServiceRoutine - The ISR that is called for this interrupt. + InterruptContext - Value passed to the ISR. + DeferredProcessingRoutine - The DPC queued by the ISR. + InterruptVector - Interrupt number used by the ISR. + InterruptMode - Type of interrupt the adapter generates. + +Return Value: + + None. + +--*/ +{ + NTSTATUS NtStatus; + PNDIS_ADAPTER_BLOCK AdptrP = (PNDIS_ADAPTER_BLOCK)(NdisAdapterHandle); + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(NdisAdapterHandle); + ULONG Vector; + ULONG NumberOfElements; + KIRQL Irql; + KAFFINITY InterruptAffinity; + PCM_RESOURCE_LIST Resources; + BOOLEAN Conflict; + BOOLEAN IsAMiniport; + PNDIS_MINIPORT_INTERRUPT MiniportInterrupt = (PNDIS_MINIPORT_INTERRUPT)(NdisInterrupt); + + IsAMiniport = (AdptrP->DeviceObject == NULL); + + // + // First check if any bus access is allowed + // + + if (((IsAMiniport ? + Miniport->BusType: + AdptrP->BusType) == (NDIS_INTERFACE_TYPE)-1) || + ((IsAMiniport ? + Miniport->BusNumber: + AdptrP->BusNumber) == (ULONG)-1)) { + + *Status = NDIS_STATUS_FAILURE; + return; + + } + + *Status = NDIS_STATUS_SUCCESS; + + // + // First check for resource conflict by expanding current resource list, + // adding in the interrupt, and then re-submitting the resource list. + // + + if ((IsAMiniport ? + Miniport->Resources: + AdptrP->Resources) != NULL) { + + NumberOfElements = (IsAMiniport ? + Miniport->Resources->List[0].PartialResourceList.Count + 1 : + AdptrP->Resources->List[0].PartialResourceList.Count + 1); + + } else { + + NumberOfElements = 1; + } + + Resources = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag( + NonPagedPool, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + NumberOfElements, + 'lrDN' + ); + + if (Resources == NULL) { + + *Status = NDIS_STATUS_RESOURCES; + return; + + } + + if ((IsAMiniport ? + Miniport->Resources : + AdptrP->Resources) != NULL) { + + RtlCopyMemory (Resources, + (IsAMiniport ? + Miniport->Resources : + AdptrP->Resources), + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + (NumberOfElements - 1) + ); + + } else { + + // + // Setup initial resource info + // + ASSERT(IsAMiniport); + Resources->Count = 1; + Resources->List[0].InterfaceType = Miniport->AdapterType; + Resources->List[0].BusNumber = Miniport->BusNumber; + Resources->List[0].PartialResourceList.Version = 0; + Resources->List[0].PartialResourceList.Revision = 0; + Resources->List[0].PartialResourceList.Count = 0; + + } + + // + // Setup interrupt + // + + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type = + CmResourceTypeInterrupt; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition = + SharedInterrupt ? CmResourceShareShared : CmResourceShareDeviceExclusive; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags = + (InterruptMode == NdisInterruptLatched) ? + CM_RESOURCE_INTERRUPT_LATCHED : + CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Interrupt.Level = + InterruptLevel; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Interrupt.Vector = + InterruptVector; + Resources->List[0].PartialResourceList.Count++; + + // + // Make the call + // + + NtStatus = IoReportResourceUsage( + NULL, + (IsAMiniport ? + Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver : + AdptrP->MacHandle->NdisMacInfo->NdisWrapperDriver), + NULL, + 0, + (IsAMiniport ? + Miniport->DeviceObject : + AdptrP->DeviceObject), + Resources, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + Resources->List[0].PartialResourceList.Count, + TRUE, + &Conflict + ); + + // + // Check for conflict. + // + + if ((IsAMiniport ? + Miniport->Resources: + AdptrP->Resources) != NULL) { + ExFreePool((IsAMiniport ? + Miniport->Resources: + AdptrP->Resources)); + } + + if (IsAMiniport) { + + Miniport->Resources = Resources; + + } else { + + AdptrP->Resources = Resources; + + + } + if (Conflict || (NtStatus != STATUS_SUCCESS)) { + + if (Conflict) { + + // + // Log an error + // + + PIO_ERROR_LOG_PACKET errorLogEntry; + ULONG i; + ULONG StringSize; + PUCHAR Place; + PWCH baseFileName; + WCHAR Character; + ULONG Value; + + baseFileName = ((AdptrP->DeviceObject != NULL) ? + AdptrP->AdapterName.Buffer : + Miniport->MiniportName.Buffer); + + // + // Parse out the path name, leaving only the device name. + // + + for ( i = 0; + i < ((AdptrP->DeviceObject != NULL) ? + AdptrP->AdapterName.Length : + Miniport->MiniportName.Length) / sizeof(WCHAR); + i++ ) { + + // + // If s points to a directory separator, set baseFileName to + // the character after the separator. + // + + if ( ((AdptrP->DeviceObject != NULL) ? + AdptrP->AdapterName.Buffer[i] : + Miniport->MiniportName.Buffer[i]) == OBJ_NAME_PATH_SEPARATOR ) { + baseFileName = ((AdptrP->DeviceObject != NULL) ? + &(AdptrP->AdapterName.Buffer[++i]): + &(Miniport->MiniportName.Buffer[++i])); + } + + } + + StringSize = ((AdptrP->DeviceObject != NULL) ? + AdptrP->AdapterName.MaximumLength : + Miniport->MiniportName.MaximumLength) - + (((ULONG)baseFileName) - + ((AdptrP->DeviceObject != NULL) ? + ((ULONG)AdptrP->AdapterName.Buffer) : + ((ULONG)Miniport->MiniportName.Buffer))); + + errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( + (IsAMiniport ? + Miniport->DeviceObject : + AdptrP->DeviceObject), + (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) + + StringSize + + 6) // wstrlen("99") * sizeof(WHCAR) + sizeof(UNICODE_NULL) + ); + + if (errorLogEntry != NULL) { + + errorLogEntry->ErrorCode = EVENT_NDIS_INTERRUPT_CONFLICT; + + // + // store the time + // + + errorLogEntry->MajorFunctionCode = 0; + errorLogEntry->RetryCount = 0; + errorLogEntry->UniqueErrorValue = 0; + errorLogEntry->FinalStatus = 0; + errorLogEntry->SequenceNumber = 0; + errorLogEntry->IoControlCode = 0; + + // + // Set string information + // + + if (StringSize != 0) { + + errorLogEntry->NumberOfStrings = 1; + errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET); + + RtlCopyMemory ( + ((PUCHAR)errorLogEntry) + + sizeof(IO_ERROR_LOG_PACKET), + (PVOID)baseFileName, + StringSize + ); + + Place = ((PUCHAR)errorLogEntry) + + sizeof(IO_ERROR_LOG_PACKET) + + StringSize; + + } else { + + Place = ((PUCHAR)errorLogEntry) + + sizeof(IO_ERROR_LOG_PACKET); + + errorLogEntry->NumberOfStrings = 0; + + } + + errorLogEntry->NumberOfStrings++; + + // + // Put in interrupt level + // + + Value = InterruptLevel; + + // + // Convert value + // + // I couldn't think of a better way to do this (with some + // loop). If you find one, plz put it in. + // + + if (Value > 9) { + + switch (Value / 10) { + + case 0: + Character = L'0'; + break; + case 1: + Character = L'1'; + break; + case 2: + Character = L'2'; + break; + case 3: + Character = L'3'; + break; + case 4: + Character = L'4'; + break; + case 5: + Character = L'5'; + break; + case 6: + Character = L'6'; + break; + case 7: + Character = L'7'; + break; + case 8: + Character = L'8'; + break; + case 9: + Character = L'9'; + break; + } + + memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR)); + + Place += sizeof(WCHAR); + + Value -= 10; + + } + + switch (Value) { + + case 0: + Character = L'0'; + break; + case 1: + Character = L'1'; + break; + case 2: + Character = L'2'; + break; + case 3: + Character = L'3'; + break; + case 4: + Character = L'4'; + break; + case 5: + Character = L'5'; + break; + case 6: + Character = L'6'; + break; + case 7: + Character = L'7'; + break; + case 8: + Character = L'8'; + break; + case 9: + Character = L'9'; + break; + } + + memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR)); + + Place += sizeof(WCHAR); + + Character = UNICODE_NULL; + + memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR)); + + // + // write it out + // + + IoWriteErrorLogEntry(errorLogEntry); + } + + *Status = NDIS_STATUS_RESOURCE_CONFLICT; + return; + + } + + *Status = NDIS_STATUS_FAILURE; + return; + + } + + // + // We must do this stuff first because if we connect the + // interrupt first then an interrupt could occur before + // the MacISR is recorded in the Ndis interrupt structure. + // + + if (IsAMiniport) { + + KeInitializeSpinLock(&(MiniportInterrupt->DpcCountLock)); + Miniport->Interrupt = MiniportInterrupt; + MiniportInterrupt->DpcCount = 0; + MiniportInterrupt->MiniportIdField = NULL; + MiniportInterrupt->Miniport = Miniport; + MiniportInterrupt->MiniportIsr = Miniport->DriverHandle->MiniportCharacteristics.ISRHandler; + MiniportInterrupt->MiniportDpc = Miniport->DriverHandle->MiniportCharacteristics.HandleInterruptHandler; + MiniportInterrupt->SharedInterrupt = SharedInterrupt; + MiniportInterrupt->IsrRequested = (BOOLEAN)DeferredProcessingRoutine; + CHECK_FOR_NORMAL_INTERRUPTS(Miniport); + + } else { + + NdisInterrupt->MacIsr = InterruptServiceRoutine; + NdisInterrupt->MacDpc = DeferredProcessingRoutine; + NdisInterrupt->InterruptContext = InterruptContext; + KeInitializeSpinLock(&(NdisInterrupt->DpcCountLock)); + NdisInterrupt->DpcCount = 0; + NdisInterrupt->Removing = FALSE; + + } + + // + // This is used to tell when all Dpcs are completed after the + // interrupt has been removed. + // + + KeInitializeEvent( + (IsAMiniport ? + &MiniportInterrupt->DpcsCompletedEvent : + &NdisInterrupt->DpcsCompletedEvent), + NotificationEvent, + FALSE + ); + + // + // Initialize our dpc. + // + + if (NdisMacAdapterDpcTargetProcessor < 0) { + NdisMacAdapterDpcTargetProcessor = (**(PCCHAR *)&KeNumberProcessors) - 1; + } + + if (IsAMiniport) { + + KeInitializeDpc( + &MiniportInterrupt->InterruptDpc, + (PKDEFERRED_ROUTINE) NdisMDpc, + MiniportInterrupt + ); + + KeSetImportanceDpc( + &MiniportInterrupt->InterruptDpc, + LowImportance + ); + + KeSetTargetProcessorDpc ( + &MiniportInterrupt->InterruptDpc, + NdisMacAdapterDpcTargetProcessor + ); + } else { + + KeInitializeDpc( + &NdisInterrupt->InterruptDpc, + (PKDEFERRED_ROUTINE) NdisDpc, + NdisInterrupt + ); + + KeSetImportanceDpc( + &NdisInterrupt->InterruptDpc, + LowImportance + ); + + KeSetTargetProcessorDpc ( + &NdisInterrupt->InterruptDpc, + NdisMacAdapterDpcTargetProcessor + ); + } + + NdisMacAdapterDpcTargetProcessor -= 1; + + // + // Get the system interrupt vector and IRQL. + // + + Vector = HalGetInterruptVector( + (IsAMiniport ? + Miniport->BusType : + AdptrP->BusType), // InterfaceType + (IsAMiniport ? + Miniport->BusNumber : + AdptrP->BusNumber), // BusNumber + (ULONG)InterruptLevel, // BusInterruptLevel + (ULONG)InterruptVector, // BusInterruptVector + &Irql, // Irql + &InterruptAffinity + ); + + if (IsAMiniport) { + + NtStatus = IoConnectInterrupt( + &MiniportInterrupt->InterruptObject, + (PKSERVICE_ROUTINE)NdisMIsr, + MiniportInterrupt, + NULL, + Vector, + Irql, + Irql, + (KINTERRUPT_MODE)InterruptMode, + SharedInterrupt, + InterruptAffinity, + FALSE + ); + + } else { + + NtStatus = IoConnectInterrupt( + &NdisInterrupt->InterruptObject, + (PKSERVICE_ROUTINE)NdisIsr, + NdisInterrupt, + NULL, + Vector, + Irql, + Irql, + (KINTERRUPT_MODE)InterruptMode, + SharedInterrupt, + InterruptAffinity, + FALSE + ); + } + + + if (!NT_SUCCESS(NtStatus)) { + + *Status = NDIS_STATUS_FAILURE; + return; + + } + +} + +VOID +NdisRemoveInterrupt( + IN PNDIS_INTERRUPT Interrupt + ) +/*++ + +Routine Description: + + Removes the interrupt, will not return until all interrupts and + interrupt dpcs are completed. + +Arguments: + + Interrupt - Points to driver allocated memory that the wrapper filled + with information about the interrupt handler. + +Return Value: + + None. + +--*/ +{ + PNDIS_MINIPORT_INTERRUPT MiniportInterrupt = (PNDIS_MINIPORT_INTERRUPT)Interrupt; + + if (MiniportInterrupt->MiniportIdField == NULL) { + + MiniportInterrupt->Miniport->BeingRemoved = TRUE; + + } else { + + Interrupt->Removing = TRUE; + + } + + // + // Now we disconnect the interrupt. NOTE: they are aligned in both structures + // + + IoDisconnectInterrupt( + Interrupt->InterruptObject + ); + + // + // Right now we know that any Dpcs that may fire are counted. + // We don't have to guard this with a spin lock because the + // Dpc will set the event if if completes first, or we may + // wait for a little while for it to complete. + // + + if (Interrupt->DpcCount > 0) { + + // + // Now we wait for all dpcs to complete. + // + + KeWaitForSingleObject( + &Interrupt->DpcsCompletedEvent, + Executive, + KernelMode, + TRUE, + (PTIME)NULL + ); + + KeResetEvent( + &Interrupt->DpcsCompletedEvent + ); + + + } + +} + + + +VOID +NdisUnload( + IN PDRIVER_OBJECT DriverObject + ) +/*++ + +Routine Description: + + This routine is called when a driver is supposed to unload. Ndis + converts this into a set of calls to MacRemoveAdapter() for each + adapter that the Mac has open. When the last adapter deregisters + itself it will call MacUnload(). + +Arguments: + + DriverObject - the driver object for the mac that is to unload. + +Return Value: + + None. + +--*/ +{ + PNDIS_MAC_BLOCK MacP; + PNDIS_ADAPTER_BLOCK Adapter, NextAdapter; + + ACQUIRE_SPIN_LOCK(&NdisMacListLock); + + // + // Search for the MacP + // + + MacP = NdisMacList; + + while (MacP != (PNDIS_MAC_BLOCK)NULL) { + + if (MacP->NdisMacInfo->NdisWrapperDriver == DriverObject) { + + break; + + } + + MacP = MacP->NextMac; + + } + + RELEASE_SPIN_LOCK(&NdisMacListLock); + + if (MacP == (PNDIS_MAC_BLOCK)NULL) { + + // + // It is already gone. Just return. + // + + return; + + } + + MacP->Unloading = TRUE; + + + // + // Now call MACRemoveAdapter() for each Adapter. + // + + Adapter = MacP->AdapterQueue; + + while (Adapter != (PNDIS_ADAPTER_BLOCK)NULL) { + + NextAdapter = Adapter->NextAdapter; // since queue may change + + (MacP->MacCharacteristics.RemoveAdapterHandler)( + Adapter->MacAdapterContext + ); + + // + // If a shutdown handler was registered then deregister it. + // + NdisDeregisterAdapterShutdownHandler(Adapter); + + Adapter = NextAdapter; + + } + + + // + // Wait for all adapters to be gonzo. + // + + KeWaitForSingleObject( + &MacP->AdaptersRemovedEvent, + Executive, + KernelMode, + TRUE, + (PTIME)NULL + ); + + KeResetEvent( + &MacP->AdaptersRemovedEvent + ); + + + // + // Now call the MACUnload routine + // + + (MacP->MacCharacteristics.UnloadMacHandler)(MacP->MacMacContext); + + + // + // Now remove the last reference (this will remove it from the list) + // + ASSERT(MacP->Ref.ReferenceCount == 1); + + NdisDereferenceMac(MacP); +} + + +NTSTATUS +NdisShutdown( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) + +/*++ + +Routine Description: + + The "shutdown handler" for the SHUTDOWN Irp. Will call the Ndis + shutdown routine, if one is registered. + +Arguments: + + DeviceObject - The adapter's device object. + Irp - The IRP. + +Return Value: + + Always STATUS_SUCCESS. + +--*/ + +{ + PNDIS_WRAPPER_CONTEXT WrapperContext = (PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension; + PNDIS_ADAPTER_BLOCK Miniport = (PNDIS_ADAPTER_BLOCK)(WrapperContext + 1); + + IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisShutdown\n"); + + IF_ERROR_CHK { + if (DbgIsNull(Irp)) { + NdisPrint1(": Null Irp\n"); + DbgBreakPoint(); + } + + if (!DbgIsNonPaged(Irp)) { + NdisPrint1(": Irp not in NonPaged Memory\n"); + DbgBreakPoint(); + } + + } + + if (WrapperContext->ShutdownHandler != NULL) { + + // + // Call the shutdown routine + // + + WrapperContext->ShutdownHandler(WrapperContext->ShutdownContext); + } + + Irp->IoStatus.Status = STATUS_SUCCESS; + + IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); + + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisShutdown\n"); + + return STATUS_SUCCESS; +} + +VOID +NdisAllocateSharedMemory( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG Length, + IN BOOLEAN Cached, + OUT PVOID *VirtualAddress, + OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress + ) + +/*++ + +Routine Description: + + Allocates memory to be shared between the driver and the adapter. + +Arguments: + + NdisAdapterHandle - handle returned by NdisRegisterAdapter. + Length - Length of the memory to allocate. + Cached - TRUE if memory is to be cached. + VirtualAddress - Returns the virtual address of the memory, + or NULL if the memory cannot be allocated. + PhysicalAddress - Returns the physical address of the memory. + +Return Value: + + None. + +--*/ + +{ + + ULONG Alignment; + PNDIS_ADAPTER_BLOCK AdaptP = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle; + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle; + PADAPTER_OBJECT SystemAdapterObject; + PNDIS_WRAPPER_CONTEXT WrapperContext; + PULONG Page; + ULONG Type; + + // + // Get interesting information from the adapter/miniport. + // + + if ( AdaptP->DeviceObject != NULL ) { + SystemAdapterObject = AdaptP->SystemAdapterObject; + WrapperContext = AdaptP->WrapperContext; + } else { + SystemAdapterObject = Miniport->SystemAdapterObject; + WrapperContext = Miniport->WrapperContext; + } + + // + // Non-busmasters shouldn't call this routine. + // + + if (SystemAdapterObject == NULL) { + *VirtualAddress = NULL; + KdPrint(("NDIS: You are not a busmaster\n")); + return; + } + + // + // Compute allocation size by aligning to the proper boundary. + // + + ASSERT(Length != 0); + + Alignment = HalGetDmaAlignmentRequirement(); + if (sizeof(ULONG) > Alignment) { + Alignment = sizeof(ULONG); + } + + Length = (Length + Alignment - 1) & ~(Alignment - 1); + + // + // Check to determine is there is enough room left in the current page + // to satisfy the allocation. + // + + Type = Cached ? 1 : 0; + ExAcquireResourceExclusive(&SharedMemoryResource, TRUE); + if (WrapperContext->SharedMemoryLeft[Type] < Length) { + if ((Length + sizeof(ULONG)) >= PAGE_SIZE) { + + // + // The allocation is greater than a page. + // + + *VirtualAddress = HalAllocateCommonBuffer( + SystemAdapterObject, + Length, + PhysicalAddress, + Cached); + + ExReleaseResource(&SharedMemoryResource); + return; + } + + // + // Allocate a new page for shared alocation. + // + + WrapperContext->SharedMemoryPage[Type] = + HalAllocateCommonBuffer( + SystemAdapterObject, + PAGE_SIZE, + &WrapperContext->SharedMemoryAddress[Type], + Cached); + + if (WrapperContext->SharedMemoryPage[Type] == NULL) { + WrapperContext->SharedMemoryLeft[Type] = 0; + *VirtualAddress = NULL; + ExReleaseResource(&SharedMemoryResource); + return; + } + + // + // Initialize the reference count in the last ULONG of the page. + // + + Page = (PULONG)WrapperContext->SharedMemoryPage[Type]; + Page[(PAGE_SIZE / sizeof(ULONG)) - 1] = 0; + WrapperContext->SharedMemoryLeft[Type] = PAGE_SIZE - sizeof(ULONG); + } + + // + // Increment the reference count, set the address of the allocation, + // compute the physical address, and reduce the space remaining. + // + + Page = (PULONG)WrapperContext->SharedMemoryPage[Type]; + Page[(PAGE_SIZE / sizeof(ULONG)) - 1] += 1; + *VirtualAddress = (PVOID)((PUCHAR)Page + + (PAGE_SIZE - sizeof(ULONG) - WrapperContext->SharedMemoryLeft[Type])); + +#if !defined(BUILD_FOR_3_1) + PhysicalAddress->QuadPart = WrapperContext->SharedMemoryAddress[Type].QuadPart + + ((ULONG)*VirtualAddress & (PAGE_SIZE - 1)); +#else + *PhysicalAddress = RtlLargeIntegerAdd( + WrapperContext->SharedMemoryAddress[Type], + RtlConvertUlongToLargeInteger((ULONG)*VirtualAddress & (PAGE_SIZE - 1)) + ); +#endif + + WrapperContext->SharedMemoryLeft[Type] -= Length; + ExReleaseResource(&SharedMemoryResource); + return; +} + + +#undef NdisUpdateSharedMemory + +VOID +NdisUpdateSharedMemory( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG Length, + IN PVOID VirtualAddress, + IN NDIS_PHYSICAL_ADDRESS PhysicalAddress + ) + +/*++ + +Routine Description: + + Ensures that the data to be read from a shared memory region is + fully up-to-date. + +Arguments: + + NdisAdapterHandle - handle returned by NdisRegisterAdapter. + Length - The length of the shared memory. + VirtualAddress - Virtual address returned by NdisAllocateSharedMemory. + PhysicalAddress - The physical address returned by NdisAllocateSharedMemory. + +Return Value: + + None. + +--*/ + +{ + + // + // There is no underlying HAL routine for this anymore, + // it is not needed. This is macro'd to nothing in the + // header file now. This is there for backward compatibility + + NdisAdapterHandle; Length; VirtualAddress; PhysicalAddress; + +} + + +VOID +NdisFreeSharedMemory( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG Length, + IN BOOLEAN Cached, + IN PVOID VirtualAddress, + IN NDIS_PHYSICAL_ADDRESS PhysicalAddress + ) + +/*++ + +Routine Description: + + Allocates memory to be shared between the driver and the adapter. + +Arguments: + + NdisAdapterHandle - handle returned by NdisRegisterAdapter. + Length - Length of the memory to allocate. + Cached - TRUE if memory was allocated cached. + VirtualAddress - Virtual address returned by NdisAllocateSharedMemory. + PhysicalAddress - The physical address returned by NdisAllocateSharedMemory. + +Return Value: + + None. + +--*/ + +{ + + ULONG Alignment; + PNDIS_ADAPTER_BLOCK AdaptP = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle; + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle; + PADAPTER_OBJECT SystemAdapterObject; + PNDIS_WRAPPER_CONTEXT WrapperContext; + PULONG Page; + ULONG Type; + + // + // Get interesting information from the adapter/miniport. + // + + if ( AdaptP->DeviceObject != NULL ) { + SystemAdapterObject = AdaptP->SystemAdapterObject; + WrapperContext = AdaptP->WrapperContext; + } else { + SystemAdapterObject = Miniport->SystemAdapterObject; + WrapperContext = Miniport->WrapperContext; + } + + // + // Non-busmasters shouldn't call this routine. + // + + ASSERT(SystemAdapterObject != NULL); + + // + // Compute allocation size by aligning to the proper boundary. + // + + ASSERT(Length != 0); + + Alignment = HalGetDmaAlignmentRequirement(); + if (sizeof(ULONG) > Alignment) { + Alignment = sizeof(ULONG); + } + + Length = (Length + Alignment - 1) & ~(Alignment - 1); + + // + // Free the specified memory. + // + + ExAcquireResourceExclusive(&SharedMemoryResource, TRUE); + if ((Length + sizeof(ULONG)) >= PAGE_SIZE) { + + // + // The allocation is greater than a page free the page directly. + // + + HalFreeCommonBuffer( + SystemAdapterObject, + Length, + PhysicalAddress, + VirtualAddress, + Cached); + + } else { + + // + // Decrement the reference count and if the result is zero, then free + // the page. + // + + Page = (PULONG)((ULONG)VirtualAddress & ~(PAGE_SIZE - 1)); + Page[(PAGE_SIZE / sizeof(ULONG)) - 1] -= 1; + if (Page[(PAGE_SIZE / sizeof(ULONG)) - 1] == 0) { + + // + // Compute the physical address of the page and free it. + // + + PhysicalAddress.LowPart &= ~(PAGE_SIZE - 1); + HalFreeCommonBuffer( + SystemAdapterObject, + PAGE_SIZE, + PhysicalAddress, + Page, + Cached); + + Type = Cached ? 1 : 0; + if ((PVOID)Page == WrapperContext->SharedMemoryPage[Type]) { + WrapperContext->SharedMemoryLeft[Type] = 0; + WrapperContext->SharedMemoryPage[Type] = NULL; + } + } + } + + ExReleaseResource(&SharedMemoryResource); + return; +} + + +IO_ALLOCATION_ACTION +NdisDmaExecutionRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID MapRegisterBase, + IN PVOID Context + ) + +/*++ + +Routine Description: + + This routine is an execution routine for AllocateAdapterChannel, + if is called when an adapter channel allocated by NdisAllocate + DmaChannel is available. + +Arguments: + + DeviceObject - The device object of the adapter. + + Irp - ??. + + MapRegisterBase - The address of the first translation table + assigned to us. + + Context - A pointer to the NDIS_DMA_BLOCK in question. + +Return Value: + + None. + +--*/ +{ + PNDIS_DMA_BLOCK DmaBlock = (PNDIS_DMA_BLOCK)Context; + + UNREFERENCED_PARAMETER (Irp); + UNREFERENCED_PARAMETER (DeviceObject); + + + // + // Save the map register base. + // + + DmaBlock->MapRegisterBase = MapRegisterBase; + + // + // This will free the thread that is waiting for this callback. + // + + KeSetEvent( + &DmaBlock->AllocationEvent, + 0L, + FALSE + ); + + return KeepObject; +} + + + +VOID +NdisAllocateDmaChannel( + OUT PNDIS_STATUS Status, + OUT PNDIS_HANDLE NdisDmaHandle, + IN NDIS_HANDLE NdisAdapterHandle, + IN PNDIS_DMA_DESCRIPTION DmaDescription, + IN ULONG MaximumLength + ) + +/*++ + +Routine Description: + + Sets up a DMA channel for future DMA operations. + +Arguments: + + Status - Returns the status of the request. + + NdisDmaHandle - Returns a handle used to specify this channel to + future operations. + + NdisAdapterHandle - handle returned by NdisRegisterAdapter. + + DmaDescription - Details of the DMA channel. + + MaximumLength - The maximum length DMA transfer that will be done + using this channel. + +Return Value: + + None. + +--*/ +{ + // + // For registering this set of resources + // + PCM_RESOURCE_LIST Resources; + BOOLEAN Conflict; + + // + // Needed to call HalGetAdapter. + // + DEVICE_DESCRIPTION DeviceDescription; + + // + // Returned by HalGetAdapter. + // + PADAPTER_OBJECT AdapterObject; + + // + // Map registers needed per channel. + // + ULONG MapRegistersNeeded; + + // + // Map registers allowed per channel. + // + ULONG MapRegistersAllowed; + + // + // Saves the structure we allocate for this channel. + // + PNDIS_DMA_BLOCK DmaBlock; + + // + // Convert the handle to our internal structure. + PNDIS_ADAPTER_BLOCK AdapterBlock = + (PNDIS_ADAPTER_BLOCK) NdisAdapterHandle; + + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) NdisAdapterHandle; + BOOLEAN IsAMiniport; + + // + // Save our IRQL when we raise it to call IoAllocateAdapterChannel. + // + KIRQL OldIrql; + ULONG NumberOfElements; + + NTSTATUS NtStatus; + + LARGE_INTEGER TimeoutValue; + + IsAMiniport = (AdapterBlock->DeviceObject == NULL); + + // + // First check if any bus access is allowed + // + + if (((IsAMiniport ? + Miniport->BusType : + AdapterBlock->BusType) == (NDIS_INTERFACE_TYPE)-1) || + ((IsAMiniport ? + Miniport->BusNumber : + AdapterBlock->BusNumber) == (ULONG)-1)) { + + *Status = NDIS_STATUS_FAILURE; + return; + } + + // + // First check for resource conflict by expanding current resource list, + // adding in the mapped space, and then re-submitting the resource list. + // + + if ((IsAMiniport ? Miniport->Resources : AdapterBlock->Resources) != NULL) { + + NumberOfElements = + (IsAMiniport ? + Miniport->Resources->List[0].PartialResourceList.Count : + AdapterBlock->Resources->List[0].PartialResourceList.Count) + 1; + + } else { + + NumberOfElements = 1; + } + + // + // First check for resource conflict by expanding current resource list, + // adding in the mapped space, and then re-submitting the resource list. + // + + Resources = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag( + NonPagedPool, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + NumberOfElements, + 'lrDN' + ); + + if (Resources == NULL) { + + *Status = NDIS_STATUS_RESOURCES; + return; + + } + + if ((IsAMiniport ? Miniport->Resources : AdapterBlock->Resources) != NULL) { + + RtlCopyMemory (Resources, + (IsAMiniport ? Miniport->Resources : AdapterBlock->Resources), + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + (NumberOfElements - 1) + ); + } else { + + // + // Setup initial resource info + // + ASSERT(IsAMiniport); + Resources->Count = 1; + Resources->List[0].InterfaceType = Miniport->AdapterType; + Resources->List[0].BusNumber = Miniport->BusNumber; + Resources->List[0].PartialResourceList.Version = 0; + Resources->List[0].PartialResourceList.Revision = 0; + Resources->List[0].PartialResourceList.Count = 0; + + } + + // + // Setup DMA Channel + // + + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type = + CmResourceTypeDma; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition = + CmResourceShareDeviceExclusive; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags = + 0; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Dma.Channel = + (IsAMiniport ? Miniport->ChannelNumber : + (DmaDescription->DmaChannelSpecified ? + DmaDescription->DmaChannel : AdapterBlock->ChannelNumber)); + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Dma.Port = + DmaDescription->DmaPort; + Resources->List[0].PartialResourceList.Count++; + + + // + // Make the call + // + + *Status = IoReportResourceUsage( + NULL, + (IsAMiniport ? + Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver : + AdapterBlock->MacHandle->NdisMacInfo->NdisWrapperDriver), + NULL, + 0, + (IsAMiniport ? Miniport->DeviceObject : AdapterBlock->DeviceObject), + Resources, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + Resources->List[0].PartialResourceList.Count, + TRUE, + &Conflict + ); + + if ((IsAMiniport ? Miniport->Resources : AdapterBlock->Resources) != NULL) { + + ExFreePool((IsAMiniport ? Miniport->Resources : AdapterBlock->Resources)); + + } + + if (IsAMiniport) { + + Miniport->Resources = Resources; + + } else { + + AdapterBlock->Resources = Resources; + + } + + // + // Check for conflict. + // + + if (Conflict || (*Status != STATUS_SUCCESS)) { + + + if (Conflict) { + + + // + // Log an error + // + + PIO_ERROR_LOG_PACKET errorLogEntry; + ULONG i; + ULONG StringSize; + PUCHAR Place; + PWCH baseFileName; + WCHAR Character; + ULONG Value; + + baseFileName = (IsAMiniport ? + Miniport->MiniportName.Buffer : + AdapterBlock->AdapterName.Buffer); + + // + // Parse out the path name, leaving only the device name. + // + + for ( i = 0; + i < (IsAMiniport ? Miniport->MiniportName.Length : + AdapterBlock->AdapterName.Length) + / sizeof(WCHAR); + i++ ) { + + // + // If s points to a directory separator, set baseFileName to + // the character after the separator. + // + + if ((IsAMiniport ? + Miniport->MiniportName.Buffer[i] : + AdapterBlock->AdapterName.Buffer[i]) == OBJ_NAME_PATH_SEPARATOR ) { + + baseFileName = (IsAMiniport ? + &(Miniport->MiniportName.Buffer[++i]) : + &(AdapterBlock->AdapterName.Buffer[++i])); + + } + + } + + StringSize = (IsAMiniport ? + Miniport->MiniportName.MaximumLength : + AdapterBlock->AdapterName.MaximumLength) - + (((ULONG)baseFileName) - + (IsAMiniport ? + ((ULONG)Miniport->MiniportName.Buffer) : + ((ULONG)AdapterBlock->AdapterName.Buffer))); + + errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( + (IsAMiniport ? + Miniport->DeviceObject : + AdapterBlock->DeviceObject), + (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) + + StringSize + + 6) // wstrlen("99") * sizeof(WHCAR) + sizeof(UNICODE_NULL) + ); + + if (errorLogEntry != NULL) { + + errorLogEntry->ErrorCode = EVENT_NDIS_DMA_CONFLICT; + + // + // store the time + // + + errorLogEntry->MajorFunctionCode = 0; + errorLogEntry->RetryCount = 0; + errorLogEntry->UniqueErrorValue = 0; + errorLogEntry->FinalStatus = 0; + errorLogEntry->SequenceNumber = 0; + errorLogEntry->IoControlCode = 0; + + // + // Set string information + // + + if (StringSize != 0) { + + errorLogEntry->NumberOfStrings = 1; + errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET); + + RtlCopyMemory ( + ((PUCHAR)errorLogEntry) + + sizeof(IO_ERROR_LOG_PACKET), + (PVOID)baseFileName, + StringSize + ); + + Place = ((PUCHAR)errorLogEntry) + + sizeof(IO_ERROR_LOG_PACKET) + + StringSize; + + } else { + + Place = ((PUCHAR)errorLogEntry) + + sizeof(IO_ERROR_LOG_PACKET); + + errorLogEntry->NumberOfStrings = 0; + + } + + errorLogEntry->NumberOfStrings++; + + // + // Put in dma channel + // + + Value = (IsAMiniport ? Miniport->ChannelNumber : + AdapterBlock->ChannelNumber); + + // + // Convert value + // + // I couldn't think of a better way to do this (with some + // loop). If you find one, plz put it in. + // + + if (Value > 9) { + + switch (Value / 10) { + + case 0: + Character = L'0'; + break; + case 1: + Character = L'1'; + break; + case 2: + Character = L'2'; + break; + case 3: + Character = L'3'; + break; + case 4: + Character = L'4'; + break; + case 5: + Character = L'5'; + break; + case 6: + Character = L'6'; + break; + case 7: + Character = L'7'; + break; + case 8: + Character = L'8'; + break; + case 9: + Character = L'9'; + break; + } + + memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR)); + + Place += sizeof(WCHAR); + + Value -= 10; + + } + + switch (Value) { + + case 0: + Character = L'0'; + break; + case 1: + Character = L'1'; + break; + case 2: + Character = L'2'; + break; + case 3: + Character = L'3'; + break; + case 4: + Character = L'4'; + break; + case 5: + Character = L'5'; + break; + case 6: + Character = L'6'; + break; + case 7: + Character = L'7'; + break; + case 8: + Character = L'8'; + break; + case 9: + Character = L'9'; + break; + } + + memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR)); + + Place += sizeof(WCHAR); + + Character = UNICODE_NULL; + + memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR)); + + // + // write it out + // + + IoWriteErrorLogEntry(errorLogEntry); + + } + + *Status = NDIS_STATUS_RESOURCE_CONFLICT; + return; + + } + + *Status = NDIS_STATUS_FAILURE; + return; + + } + + // + // Set up the device description; zero it out in case its + // size changes. + // + + RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION)); + + DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION; + DeviceDescription.Master = (IsAMiniport ? Miniport->Master : FALSE); + DeviceDescription.ScatterGather = (IsAMiniport ? Miniport->Master : FALSE); + DeviceDescription.DemandMode = DmaDescription->DemandMode; + DeviceDescription.AutoInitialize = DmaDescription->AutoInitialize; + DeviceDescription.Dma32BitAddresses = (IsAMiniport ? Miniport->Dma32BitAddresses : FALSE); + DeviceDescription.BusNumber = (IsAMiniport ? Miniport->BusNumber : AdapterBlock->BusNumber); + DeviceDescription.DmaChannel = (IsAMiniport ? Miniport->ChannelNumber : + (DmaDescription->DmaChannelSpecified ? + DmaDescription->DmaChannel : AdapterBlock->ChannelNumber)); + DeviceDescription.InterfaceType = (IsAMiniport ? Miniport->BusType : AdapterBlock->BusType); + DeviceDescription.DmaWidth = DmaDescription->DmaWidth; + DeviceDescription.DmaSpeed = DmaDescription->DmaSpeed; + DeviceDescription.MaximumLength = MaximumLength; + DeviceDescription.DmaPort = DmaDescription->DmaPort; + + + MapRegistersNeeded = ((MaximumLength - 2) / PAGE_SIZE) + 2; + + // + // Get the adapter object. + // + + AdapterObject = HalGetAdapter (&DeviceDescription, &MapRegistersAllowed); + + if ((AdapterObject == NULL) || (MapRegistersAllowed < MapRegistersNeeded)) { + + *Status = NDIS_STATUS_RESOURCES; + return; + } + + + // + // Allocate storage for our DMA block. + // + + DmaBlock = (PNDIS_DMA_BLOCK)ExAllocatePoolWithTag (NonPagedPool, sizeof(NDIS_DMA_BLOCK), 'bdDN'); + + if (DmaBlock == (PNDIS_DMA_BLOCK)NULL) { + *Status = NDIS_STATUS_RESOURCES; + return; + } + + + // + // Use this event to tell us when NdisAllocationExecutionRoutine + // has been called. + // + + KeInitializeEvent( + &DmaBlock->AllocationEvent, + NotificationEvent, + FALSE + ); + + // + // We save this to call IoFreeAdapterChannel later. + // + + DmaBlock->SystemAdapterObject = AdapterObject; + + + // + // Now allocate the adapter channel. + // + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NtStatus = IoAllocateAdapterChannel( + AdapterObject, + (IsAMiniport ? Miniport->DeviceObject : AdapterBlock->DeviceObject), + MapRegistersNeeded, + NdisDmaExecutionRoutine, + (PVOID)DmaBlock + ); + + KeLowerIrql(OldIrql); + + if (!NT_SUCCESS(NtStatus)) { + NdisPrint2("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus); + ExFreePool (DmaBlock); + *Status = NDIS_STATUS_RESOURCES; + return; + } + + TimeoutValue.QuadPart = Int32x32To64(2 * 1000, -10000); + + // + // NdisDmaExecutionRoutine will set this event + // when it has been called. + // + + NtStatus = KeWaitForSingleObject( + &DmaBlock->AllocationEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + NdisPrint2("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus); + ExFreePool (DmaBlock); + *Status = NDIS_STATUS_RESOURCES; + return; + + } + + KeResetEvent( + &DmaBlock->AllocationEvent + ); + + + // + // We now have the DMA channel allocated, we are done. + // + + DmaBlock->InProgress = FALSE; + + *NdisDmaHandle = (NDIS_HANDLE)DmaBlock; + *Status = NDIS_STATUS_SUCCESS; + +} + + +VOID +NdisFreeDmaChannel( + IN PNDIS_HANDLE NdisDmaHandle + ) + +/*++ + +Routine Description: + + Frees a DMA channel allocated with NdisAllocateDmaChannel. + +Arguments: + + NdisDmaHandle - Handle returned by NdisAllocateDmaChannel, indicating the + DMA channel that is to be freed. + +Return Value: + + None. + +--*/ +{ + + KIRQL OldIrql; + PNDIS_DMA_BLOCK DmaBlock = (PNDIS_DMA_BLOCK)NdisDmaHandle; + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + IoFreeAdapterChannel (DmaBlock->SystemAdapterObject); + KeLowerIrql(OldIrql); + + ExFreePool (DmaBlock); + +} + + +VOID +NdisSetupDmaTransfer( + OUT PNDIS_STATUS Status, + IN PNDIS_HANDLE NdisDmaHandle, + IN PNDIS_BUFFER Buffer, + IN ULONG Offset, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ) + +/*++ + +Routine Description: + + Sets up the host DMA controller for a DMA transfer. The + DMA controller is set up to transfer the specified MDL. + Since we register all DMA channels as non-scatter/gather, + IoMapTransfer will ensure that the entire MDL is + in a single logical piece for transfer. + +Arguments: + + Status - Returns the status of the request. + + NdisDmaHandle - Handle returned by NdisAllocateDmaChannel. + + Buffer - An NDIS_BUFFER which describes the host memory involved in the + transfer. + + Offset - An offset within buffer where the transfer should + start. + + Length - The length of the transfer. VirtualAddress plus Length must not + extend beyond the end of the buffer. + + WriteToDevice - TRUE for a download operation (host to adapter); FALSE + for an upload operation (adapter to host). + +Return Value: + + None. + +--*/ +{ + + PNDIS_DMA_BLOCK DmaBlock = (PNDIS_DMA_BLOCK)NdisDmaHandle; + PHYSICAL_ADDRESS LogicalAddress; + ULONG LengthMapped; + + + // + // Make sure another request is not in progress. + // + + if (DmaBlock->InProgress) { + *Status = NDIS_STATUS_RESOURCES; + return; + } + + DmaBlock->InProgress = TRUE; + + // + // Use IoMapTransfer to set up the transfer. + // + + LengthMapped = Length; + + LogicalAddress = IoMapTransfer( + DmaBlock->SystemAdapterObject, + (PMDL)Buffer, + DmaBlock->MapRegisterBase, + (PUCHAR)(MmGetMdlVirtualAddress(Buffer)) + Offset, + &LengthMapped, + WriteToDevice + ); + + if (LengthMapped != Length) { + + // + // Somehow the request could not be mapped competely, + // this should not happen for a non-scatter/gather adapter. + // + + (VOID)IoFlushAdapterBuffers( + DmaBlock->SystemAdapterObject, + (PMDL)Buffer, + DmaBlock->MapRegisterBase, + (PUCHAR)(MmGetMdlVirtualAddress(Buffer)) + Offset, + LengthMapped, + WriteToDevice + ); + + DmaBlock->InProgress = FALSE; + *Status = NDIS_STATUS_RESOURCES; + return; + + } + + *Status = NDIS_STATUS_SUCCESS; + +} + + +VOID +NdisCompleteDmaTransfer( + OUT PNDIS_STATUS Status, + IN PNDIS_HANDLE NdisDmaHandle, + IN PNDIS_BUFFER Buffer, + IN ULONG Offset, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ) + +/*++ + +Routine Description: + + Completes a previously started DMA transfer. + +Arguments: + + Status - Returns the status of the transfer. + + NdisDmaHandle - Handle returned by NdisAllocateDmaChannel. + + Buffer - An NDIS_BUFFER which was passed to NdisSetupDmaTransfer. + + Offset - the offset passed to NdisSetupDmaTransfer. + + Length - The length passed to NdisSetupDmaTransfer. + + WriteToDevice - TRUE for a download operation (host to adapter); FALSE + for an upload operation (adapter to host). + + +Return Value: + + None. + +--*/ + +{ + + PNDIS_DMA_BLOCK DmaBlock = (PNDIS_DMA_BLOCK)NdisDmaHandle; + BOOLEAN Successful; + + Successful = IoFlushAdapterBuffers( + DmaBlock->SystemAdapterObject, + (PMDL)Buffer, + DmaBlock->MapRegisterBase, + (PUCHAR)(MmGetMdlVirtualAddress(Buffer)) + Offset, + Length, + WriteToDevice); + + *Status = (Successful ? NDIS_STATUS_SUCCESS : NDIS_STATUS_RESOURCES); + DmaBlock->InProgress = FALSE; + +} + +// +// Requests used by protocol modules +// +// + +VOID +NdisRegisterProtocol( + OUT PNDIS_STATUS Status, + OUT PNDIS_HANDLE NdisProtocolHandle, + IN PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics, + IN UINT CharacteristicsLength + ) + +/*++ + +Routine Description: + + Register an NDIS protocol. + +Arguments: + + Status - Returns the final status. + NdisProtocolHandle - Returns a handle referring to this protocol. + ProtocolCharacteritics - The NDIS_PROTOCOL_CHARACTERISTICS table. + CharacteristicsLength - The length of ProtocolCharacteristics. + +Return Value: + + None. + +--*/ + +{ + PNDIS_PROTOCOL_BLOCK NewProtP; + UINT MemNeeded; + + // + // Do any initial initialization that may be necessary. Note: this + // routine will notice if this is the second or later call to it. + // + *Status = NdisInitialInit( NULL ); + if (!NT_SUCCESS(*Status)) { + return; + } + + // + // Check that this is an NDIS 3.1 protocol. + // + + IF_TRACE(TRACE_IMPT) NdisPrint1("==>NdisRegisterProtocol\n"); + IF_ERROR_CHK { + if (DbgIsNull(ProtocolCharacteristics->OpenAdapterCompleteHandler)) { + NdisPrint1("RegisterProtocol: OpenAdapterCompleteHandler Null\n"); + DbgBreakPoint(); + } + if (DbgIsNull(ProtocolCharacteristics->CloseAdapterCompleteHandler)) { + NdisPrint1("RegisterProtocol: CloseAdapterCompleteHandler Null\n"); + DbgBreakPoint(); + } + if (DbgIsNull(ProtocolCharacteristics->SendCompleteHandler)) { + NdisPrint1("RegisterProtocol: SendCompleteHandler Null\n"); + DbgBreakPoint(); + } + if (DbgIsNull(ProtocolCharacteristics->TransferDataCompleteHandler)) { + NdisPrint1("RegisterProtocol: TransferDataCompleteHandler Null\n"); + DbgBreakPoint(); + } + if (DbgIsNull(ProtocolCharacteristics->ResetCompleteHandler)) { + NdisPrint1("RegisterProtocol: ResetCompleteHandler Null\n"); + DbgBreakPoint(); + } + if (DbgIsNull(ProtocolCharacteristics->RequestCompleteHandler)) { + NdisPrint1("RegisterProtocol: RequestCompleteHandler Null\n"); + DbgBreakPoint(); + } + if (DbgIsNull(ProtocolCharacteristics->ReceiveHandler)) { + NdisPrint1("RegisterProtocol: ReceiveHandler Null\n"); + DbgBreakPoint(); + } + if (DbgIsNull(ProtocolCharacteristics->ReceiveCompleteHandler)) { + NdisPrint1("RegisterProtocol: ReceiveCompleteHandler Null\n"); + DbgBreakPoint(); + } + if (DbgIsNull(ProtocolCharacteristics->StatusHandler)) { + NdisPrint1("RegisterProtocol: StatusHandler Null\n"); + DbgBreakPoint(); + } + if (DbgIsNull(ProtocolCharacteristics->StatusCompleteHandler)) { + NdisPrint1("RegisterProtocol: StatusCompleteHandler Null\n"); + DbgBreakPoint(); + } + } + + + if (ProtocolCharacteristics->MajorNdisVersion != 3 || + ProtocolCharacteristics->MinorNdisVersion != 0) { + *Status = NDIS_STATUS_BAD_VERSION; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterProtocol\n"); + return; + } + + + // + // Check that CharacteristicsLength is enough. + // + + if (CharacteristicsLength < sizeof(NDIS_PROTOCOL_CHARACTERISTICS)) { + *Status = NDIS_STATUS_BAD_CHARACTERISTICS; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterProtocol\n"); + return; + } + + + // + // Allocate memory for the NDIS protocol block. + // + + MemNeeded = sizeof(NDIS_PROTOCOL_BLOCK); + NewProtP = (PNDIS_PROTOCOL_BLOCK)ExAllocatePoolWithTag(NonPagedPool, MemNeeded, 'bpDN'); + if (NewProtP == (PNDIS_PROTOCOL_BLOCK)NULL) { + *Status = NDIS_STATUS_RESOURCES; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterProtocol\n"); + return; + } + RtlZeroMemory(NewProtP, sizeof(NDIS_PROTOCOL_BLOCK)); + + NewProtP->Length = MemNeeded; + + // + // Copy over the characteristics table. + // + + RtlCopyMemory((PVOID)&NewProtP->ProtocolCharacteristics, + (PVOID)ProtocolCharacteristics, sizeof(NDIS_PROTOCOL_CHARACTERISTICS)); + +#if NDISDBG + IF_TRACE(TRACE_IMPT) NdisPrint2(" Protocol: %s\n",ProtocolCharacteristics->Name); +#endif + + // + // No opens for this protocol yet. + // + + NewProtP->OpenQueue = (PNDIS_OPEN_BLOCK)NULL; + + NdisInitializeRef(&NewProtP->Ref); + *NdisProtocolHandle = (NDIS_HANDLE)NewProtP; + *Status = NDIS_STATUS_SUCCESS; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterProtocol\n"); +} + +VOID +NdisDeregisterProtocol( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE NdisProtocolHandle + ) + +/*++ + +Routine Description: + + Deregisters an NDIS protocol. + +Arguments: + + Status - Returns the final status. + NdisProtocolHandle - The handle returned by NdisRegisterProtocol. + +Return Value: + + None. + +Note: + + This will kill all the opens for this protocol. + +--*/ + +{ + + PNDIS_PROTOCOL_BLOCK OldProtP = (PNDIS_PROTOCOL_BLOCK)NdisProtocolHandle; + + // + // If the protocol is already closing, return. + // + + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisDeregisterProtocol\n"); + NdisPrint2(" Protocol: %wZ\n",&OldProtP->ProtocolCharacteristics.Name); + } + IF_ERROR_CHK { + if (DbgIsNull(NdisProtocolHandle)) { + NdisPrint1("DeregisterProtocol: Null Handle\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(NdisProtocolHandle)) { + NdisPrint1("DeregisterProtocol: Handle not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + if (!NdisCloseRef(&OldProtP->Ref)) { + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeregisterProtocol\n"); + return; + } + + + // + // Kill all the opens for this protocol. + // + + while (OldProtP->OpenQueue != (PNDIS_OPEN_BLOCK)NULL) { + + // + // This removes it from the protocol's OpenQueue etc. + // + + NdisKillOpenAndNotifyProtocol(OldProtP->OpenQueue); + } + + NdisDereferenceProtocol(OldProtP); + + *Status = NDIS_STATUS_SUCCESS; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeregisterProtocol\n"); +} + + +NDIS_STATUS +NdisMacReceiveHandler( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_HANDLE MacReceiveContext, + IN PVOID HeaderBuffer, + IN UINT HeaderBufferSize, + IN PVOID LookaheadBuffer, + IN UINT LookaheadBufferSize, + IN UINT PacketSize + ) +{ + PNDIS_OPEN_BLOCK Open; + NDIS_STATUS Status; + KIRQL oldIrql; + + KeRaiseIrql( DISPATCH_LEVEL, &oldIrql ); + + // + // Find protocol binding context and get associated open for it. + // + Open = GetOpenBlockFromProtocolBindingContext(ProtocolBindingContext); + ASSERT(Open != NULL); + + Status = + (Open->PostNt31ReceiveHandler) ( + ProtocolBindingContext, + MacReceiveContext, + HeaderBuffer, + HeaderBufferSize, + LookaheadBuffer, + LookaheadBufferSize, + PacketSize); + + KeLowerIrql( oldIrql ); + return Status; +} + + +VOID +NdisMacReceiveCompleteHandler( + IN NDIS_HANDLE ProtocolBindingContext + ) +{ + PNDIS_OPEN_BLOCK Open; + KIRQL oldIrql; + KeRaiseIrql( DISPATCH_LEVEL, &oldIrql ); + + // + // Find protocol binding context and get associated open for it. + // + Open = GetOpenBlockFromProtocolBindingContext(ProtocolBindingContext); + ASSERT(Open != NULL); + + (Open->PostNt31ReceiveCompleteHandler) ( + ProtocolBindingContext + ); + KeLowerIrql( oldIrql ); + return; +} + +PNDIS_OPEN_BLOCK +GetOpenBlockFromProtocolBindingContext( + IN NDIS_HANDLE ProtocolBindingContext + ) +{ + PNDIS_OPEN_BLOCK TmpOpen; + PNDIS_OPEN_BLOCK PrvOpen = NULL; + + ACQUIRE_SPIN_LOCK(&GlobalOpenListLock); + + TmpOpen = GlobalOpenList; + + while (TmpOpen != NULL) { + + if (TmpOpen->ProtocolBindingContext == ProtocolBindingContext) { + + if (TmpOpen != GlobalOpenList) { + + // + // Put this one at the front of the list + // + + PrvOpen->NextGlobalOpen = TmpOpen->NextGlobalOpen; + TmpOpen->NextGlobalOpen = GlobalOpenList; + GlobalOpenList = TmpOpen; + + + } + + RELEASE_SPIN_LOCK(&GlobalOpenListLock); + + return(TmpOpen); + + } + + PrvOpen = TmpOpen; + TmpOpen = TmpOpen->NextGlobalOpen; + + } + + RELEASE_SPIN_LOCK(&GlobalOpenListLock); + + return((PNDIS_OPEN_BLOCK)NULL); + +} + +VOID +MiniportOpenAdapter( + OUT PNDIS_STATUS Status, + OUT PNDIS_STATUS OpenErrorStatus, + OUT PNDIS_HANDLE NdisBindingHandle, + IN NDIS_HANDLE NdisProtocolHandle, + IN NDIS_HANDLE ProtocolBindingContext, + IN PNDIS_STRING AdapterName, + IN UINT OpenOptions, + IN PSTRING AddressingInformation, + IN PNDIS_MINIPORT_BLOCK Miniport, + IN PNDIS_OPEN_BLOCK NewOpenP, + IN PFILE_OBJECT FileObject, + IN BOOLEAN UsingEncapsulation + ) +/*++ + +Routine Description: + + This routine handles opening a miniport either directly from NdisOpenAdapter() + of from our deferred processing routine if the open had to pend. + + NOTE: Must be called with spin lock held. + NOTE: Must be called with lock acquired flag set. + +Arguments: + +Return Value: + + None. + +--*/ +{ + PNDIS_M_OPEN_BLOCK MiniportOpen; + PNDIS_MAC_BLOCK FakeMac; + BOOLEAN FilterOpen; + PNDIS_PROTOCOL_BLOCK TmpProtP; + + ASSERT( MINIPORT_LOCK_ACQUIRED(Miniport) ); + + if (!NdisReferenceMiniport(Miniport)) { + + // + // The adapter is closing. + // + + ObDereferenceObject((PVOID)FileObject); + ExFreePool((PVOID)NewOpenP); + + *Status = NDIS_STATUS_CLOSING; + + return; + } + + // + // Increment the protocol's reference count. + // + + TmpProtP = (PNDIS_PROTOCOL_BLOCK)NdisProtocolHandle; + + if (!NdisReferenceProtocol(TmpProtP)) { + + // + // The protocol is closing. + // + + NdisDereferenceMiniport(Miniport); + ObDereferenceObject((PVOID)FileObject); + ExFreePool((PVOID)NewOpenP); + *Status = NDIS_STATUS_CLOSING; + return; + } + + + // + // Now allocate a complete set of MAC structures for the protocol + // and set them up to transfer to the Miniport handler routines. + // + + if (Miniport->DriverHandle->FakeMac == NULL) { + + FakeMac = (PNDIS_MAC_BLOCK)ExAllocatePoolWithTag(NonPagedPool, + sizeof(NDIS_MAC_BLOCK), + ' DN' + ); + + if (FakeMac == NULL) { + ObDereferenceObject((PVOID)FileObject); + NdisDereferenceMiniport(Miniport); + NdisDereferenceProtocol(TmpProtP); + ExFreePool((PVOID)NewOpenP); + *Status = NDIS_STATUS_RESOURCES; + return; + } + + RtlZeroMemory(FakeMac, sizeof(NDIS_MAC_BLOCK)); + Miniport->DriverHandle->FakeMac = FakeMac; + FakeMac->MacCharacteristics.OpenAdapterHandler = NULL; + FakeMac->MacCharacteristics.CloseAdapterHandler = NULL; + FakeMac->MacCharacteristics.SendHandler = NdisMSend; + FakeMac->MacCharacteristics.ResetHandler = NdisMReset; + FakeMac->MacCharacteristics.RequestHandler = NdisMRequest; + FakeMac->MacCharacteristics.QueryGlobalStatisticsHandler = NULL; + FakeMac->MacCharacteristics.UnloadMacHandler = NULL; + FakeMac->MacCharacteristics.AddAdapterHandler = NULL; + FakeMac->MacCharacteristics.RemoveAdapterHandler = NULL; + + // + // If transfer data calls don't pend then we'll use the faster + // NdisMTransferDataSync(). + // + + if ( (Miniport->MacOptions & NDIS_MAC_OPTION_TRANSFERS_NOT_PEND) != 0 ) { + FakeMac->MacCharacteristics.TransferDataHandler = NdisMTransferDataSync; + } else { + FakeMac->MacCharacteristics.TransferDataHandler = NdisMTransferData; + } + + // + // Keep the SendHandler the same for WAN miniports + // + + if (Miniport->MediaType == NdisMediumWan) { + + FakeMac->MacCharacteristics.SendHandler = + (PVOID)Miniport->DriverHandle->MiniportCharacteristics.SendHandler; + } + + } else { + + FakeMac = Miniport->DriverHandle->FakeMac; + + } + + // + // Allocate an open within the Miniport context + // + MiniportOpen = (PNDIS_M_OPEN_BLOCK)ExAllocatePoolWithTag(NonPagedPool, + sizeof(NDIS_M_OPEN_BLOCK), + ' DN' + ); + + if (MiniportOpen == (PNDIS_M_OPEN_BLOCK)NULL) { + ObDereferenceObject((PVOID)FileObject); + NdisDereferenceMiniport(Miniport); + NdisDereferenceProtocol(TmpProtP); + ExFreePool((PVOID)NewOpenP); + *Status = NDIS_STATUS_RESOURCES; + return; + } + + NdisZeroMemory(MiniportOpen, sizeof(NDIS_M_OPEN_BLOCK)); + + MiniportOpen->DriverHandle = Miniport->DriverHandle; + MiniportOpen->MiniportHandle = Miniport; + MiniportOpen->ProtocolHandle = TmpProtP; + MiniportOpen->FakeOpen = NewOpenP; + MiniportOpen->ProtocolBindingContext = ProtocolBindingContext; + MiniportOpen->MiniportAdapterContext = Miniport->MiniportAdapterContext; + MiniportOpen->FileObject = FileObject; + MiniportOpen->Closing = FALSE; + MiniportOpen->CloseRequestHandle = 0; + MiniportOpen->CurrentLookahead = Miniport->CurrentLookahead; + + NdisAllocateSpinLock(&(MiniportOpen->SpinLock)); + + MiniportOpen->References = 1; + MiniportOpen->UsingEthEncapsulation = UsingEncapsulation; + MiniportOpen->SendHandler = + Miniport->DriverHandle->MiniportCharacteristics.SendHandler; + MiniportOpen->TransferDataHandler = + Miniport->DriverHandle->MiniportCharacteristics.TransferDataHandler; + MiniportOpen->SendCompleteHandler = + TmpProtP->ProtocolCharacteristics.SendCompleteHandler; + MiniportOpen->TransferDataCompleteHandler = + TmpProtP->ProtocolCharacteristics.TransferDataCompleteHandler; + MiniportOpen->ReceiveHandler = + TmpProtP->ProtocolCharacteristics.ReceiveHandler; + MiniportOpen->ReceiveCompleteHandler = + TmpProtP->ProtocolCharacteristics.ReceiveCompleteHandler; + + // + // Set up the elements of the open structure. + // + + NdisAllocateSpinLock(&NewOpenP->SpinLock); + NewOpenP->Closing = FALSE; + + NewOpenP->AdapterHandle = (NDIS_HANDLE) Miniport; + NewOpenP->ProtocolHandle = TmpProtP; + NewOpenP->ProtocolBindingContext = ProtocolBindingContext; + NewOpenP->MacBindingHandle = (NDIS_HANDLE)MiniportOpen; + + // + // for speed, instead of having to use AdapterHandle->MacHandle + // + NewOpenP->MacHandle = (NDIS_HANDLE)FakeMac; + + // + // for even more speed.... + // + + if (Miniport->MediaType == NdisMediumArcnet878_2) { + + NewOpenP->TransferDataHandler = NdisMArcTransferData; + + } else { + + if ( (Miniport->MacOptions & NDIS_MAC_OPTION_TRANSFERS_NOT_PEND) != 0 ) { + NewOpenP->TransferDataHandler = NdisMTransferDataSync; + } else { + NewOpenP->TransferDataHandler = NdisMTransferData; + } + } + + NewOpenP->SendHandler = NdisMSend; + + // + // For WAN miniports, the send handler is different + // + + if ( Miniport->MediaType == NdisMediumWan ) { + + NewOpenP->SendHandler = (PVOID)NdisMWanSend; + } + + NewOpenP->SendCompleteHandler = TmpProtP->ProtocolCharacteristics.SendCompleteHandler; + NewOpenP->TransferDataCompleteHandler = TmpProtP->ProtocolCharacteristics.TransferDataCompleteHandler; + NewOpenP->ReceiveHandler = TmpProtP->ProtocolCharacteristics.ReceiveHandler; + NewOpenP->ReceiveCompleteHandler = TmpProtP->ProtocolCharacteristics.ReceiveCompleteHandler; + NewOpenP->PostNt31ReceiveHandler = TmpProtP->ProtocolCharacteristics.ReceiveHandler; + NewOpenP->PostNt31ReceiveCompleteHandler = TmpProtP->ProtocolCharacteristics.ReceiveCompleteHandler; + + // + // Save a pointer to the file object in the open... + // + + NewOpenP->FileObject = FileObject; + + // + // ...and a pointer to the open in the file object. + // + + FileObject->FsContext = (PVOID)NewOpenP; + + *NdisBindingHandle = (NDIS_HANDLE)NewOpenP; + + // + // Insert the open into the filter package + // + + switch (Miniport->MediaType) { + + case NdisMediumArcnet878_2: + + if ( !UsingEncapsulation ) { + + FilterOpen = ArcNoteFilterOpenAdapter( + Miniport->ArcDB, + MiniportOpen, + (NDIS_HANDLE)NewOpenP, + &MiniportOpen->FilterHandle + ); + + break; + } + + // + // If we're using ethernet encapsulation then + // we simply fall through to the ethernet stuff. + // + + case NdisMedium802_3: + + FilterOpen = EthNoteFilterOpenAdapter( + Miniport->EthDB, + MiniportOpen, + (NDIS_HANDLE)NewOpenP, + &MiniportOpen->FilterHandle + ); + break; + + case NdisMedium802_5: + + FilterOpen = TrNoteFilterOpenAdapter( + Miniport->TrDB, + MiniportOpen, + (NDIS_HANDLE)NewOpenP, + &MiniportOpen->FilterHandle + ); + break; + + case NdisMediumFddi: + + FilterOpen = FddiNoteFilterOpenAdapter( + Miniport->FddiDB, + MiniportOpen, + (NDIS_HANDLE)NewOpenP, + &MiniportOpen->FilterHandle + ); + break; + + + case NdisMediumWan: + // + // Bogus non-NULL value + // + + FilterOpen = 1; + break; + } + + // + // Check for an open filter failure. + // + + if ( !FilterOpen ) { + + // + // Something went wrong, clean up and exit. + // + + ObDereferenceObject((PVOID)FileObject); + NdisDereferenceMiniport(Miniport); + NdisDereferenceProtocol(TmpProtP); + ExFreePool((PVOID)MiniportOpen); + ExFreePool((PVOID)NewOpenP); + *Status = NDIS_STATUS_OPEN_FAILED; + return; + + } + + NdisQueueOpenOnProtocol(NewOpenP, TmpProtP); + + // + // Everything has been filled in. Synchronize access to the + // adapter block and link the new open adapter in. + // + + MiniportOpen->MiniportNextOpen = Miniport->OpenQueue; + Miniport->OpenQueue = MiniportOpen; + + // + // NOTE: This must be called at DPC_LEVEL, which it is. + // + MiniportAdjustMaximumLookahead(Miniport); + + *Status = NDIS_STATUS_SUCCESS; +} + + +VOID +MiniportFinishPendingOpens( + PNDIS_MINIPORT_BLOCK Miniport + ) +/*++ + +Routine Description: + + Handles any pending NdisOpenAdapter() calls for miniports. + + NOTE: Must be called with spin lock held. + + NOTE: Must be called with lock acquired flag set. + +Arguments: + + Miniport. + +Return Value: + + None. + +--*/ + +{ + PMINIPORT_PENDING_OPEN MiniportPendingOpen; + NDIS_STATUS Status; + NDIS_STATUS OpenErrorStatus; + + while( Miniport->FirstPendingOpen != NULL ) { + + MiniportPendingOpen = Miniport->FirstPendingOpen; + + // + // Do the open again. + // + + MiniportOpenAdapter( + &Status, + &OpenErrorStatus, + MiniportPendingOpen->NdisBindingHandle, + MiniportPendingOpen->NdisProtocolHandle, + MiniportPendingOpen->ProtocolBindingContext, + MiniportPendingOpen->AdapterName, + MiniportPendingOpen->OpenOptions, + MiniportPendingOpen->AddressingInformation, + MiniportPendingOpen->Miniport, + MiniportPendingOpen->NewOpenP, + MiniportPendingOpen->FileObject, + MiniportPendingOpen->UsingEncapsulation + ); + + // + // If the open didn't pend then call the NdisCompleteOpenAdapter(), + // + + if ( Status != NDIS_STATUS_PENDING ) { + + PNDIS_OPEN_BLOCK OpenP = MiniportPendingOpen->NewOpenP; + + (OpenP->ProtocolHandle->ProtocolCharacteristics.OpenAdapterCompleteHandler) ( + OpenP->ProtocolBindingContext, + Status, + OpenErrorStatus + ); + } + + // + // Get the next pending open. + // + + Miniport->FirstPendingOpen = MiniportPendingOpen->NextPendingOpen; + + // + // We're done with this pending open context. + // + + NdisFreeMemory( + MiniportPendingOpen, + sizeof(MINIPORT_PENDING_OPEN), + 0 + ); + + } +} + + + +UCHAR NdisInternalEaName[4] = "NDIS"; +UCHAR NdisInternalEaValue[8] = "INTERNAL"; + +VOID +NdisOpenAdapter( + OUT PNDIS_STATUS Status, + OUT PNDIS_STATUS OpenErrorStatus, + OUT PNDIS_HANDLE NdisBindingHandle, + OUT PUINT SelectedMediumIndex, + IN PNDIS_MEDIUM MediumArray, + IN UINT MediumArraySize, + IN NDIS_HANDLE NdisProtocolHandle, + IN NDIS_HANDLE ProtocolBindingContext, + IN PNDIS_STRING AdapterName, + IN UINT OpenOptions, + IN PSTRING AddressingInformation OPTIONAL + ) + +/*++ + +Routine Description: + + Opens a connection between a protocol and an adapter (MAC). + +Arguments: + + Status - Returns the final status. + NdisBindingHandle - Returns a handle referring to this open. + SelectedMediumIndex - Index in MediumArray of the medium type that + the MAC wishes to be viewed as. + MediumArray - Array of medium types which a protocol supports. + MediumArraySize - Number of elements in MediumArray. + NdisProtocolHandle - The handle returned by NdisRegisterProtocol. + ProtocolBindingContext - A context for indications. + AdapterName - The name of the adapter to open. + OpenOptions - bit mask. + AddressingInformation - Information passed to MacOpenAdapter. + +Return Value: + + None. + +Note: + + This function opens the adapter which will cause an IRP_MJ_CREATE + to be sent to the adapter, which is ignored. However, after that we + can access the file object for the open, and fill it in as + appropriate. The work is done here rather than in the IRP_MJ_CREATE + handler because this avoids having to pass the parameters to + NdisOpenAdapter through to the adapter. + +--*/ + +{ + HANDLE FileHandle; + OBJECT_ATTRIBUTES ObjectAttr; + PFILE_OBJECT FileObject; + PDEVICE_OBJECT DeviceObject; + PNDIS_OPEN_BLOCK NewOpenP; + PNDIS_PROTOCOL_BLOCK TmpProtP; + PNDIS_ADAPTER_BLOCK TmpAdaptP; + NDIS_STATUS OpenStatus; + NTSTATUS NtOpenStatus; + IO_STATUS_BLOCK IoStatus; + PFILE_FULL_EA_INFORMATION OpenEa; + ULONG OpenEaLength; + BOOLEAN UsingEncapsulation; + KIRQL OldIrql; + BOOLEAN LocalLock; + + // + // Allocate memory for the NDIS open block. + // + + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisOpenAdapter\n"); + } + IF_ERROR_CHK { + if (DbgIsNull(NdisProtocolHandle)) { + NdisPrint1("OpenAdapter: Null ProtocolHandle\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(NdisProtocolHandle)) { + NdisPrint1("OpenAdapter: ProtocolHandle not in NonPaged Memory\n"); + DbgBreakPoint(); + } + if (DbgIsNull(ProtocolBindingContext)) { + NdisPrint1("OpenAdapter: Null Context\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(ProtocolBindingContext)) { + NdisPrint1("OpenAdapter: Context not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + NewOpenP = (PNDIS_OPEN_BLOCK) ExAllocatePoolWithTag(NonPagedPool, + sizeof(NDIS_OPEN_BLOCK), + 'boDN' + ); + + if (NewOpenP == (PNDIS_OPEN_BLOCK)NULL) { + + *Status = NDIS_STATUS_RESOURCES; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n"); + + return; + } + + RtlZeroMemory(NewOpenP, sizeof(NDIS_OPEN_BLOCK)); + + OpenEaLength = sizeof(FILE_FULL_EA_INFORMATION) + + sizeof(NdisInternalEaName) + + sizeof(NdisInternalEaValue); + + OpenEa = ExAllocatePoolWithTag (NonPagedPool, OpenEaLength, ' DN'); + + if (OpenEa == NULL) { + ExFreePool (NewOpenP); + *Status = NDIS_STATUS_RESOURCES; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n"); + return; + } + + OpenEa->NextEntryOffset = 0; + OpenEa->Flags = 0; + OpenEa->EaNameLength = sizeof(NdisInternalEaName); + OpenEa->EaValueLength = sizeof(NdisInternalEaValue); + + RtlCopyMemory( + OpenEa->EaName, + NdisInternalEaName, + sizeof(NdisInternalEaName) + ); + + RtlCopyMemory( + &OpenEa->EaName[OpenEa->EaNameLength+1], + NdisInternalEaValue, + sizeof(NdisInternalEaValue) + ); + + + // + // Obtain a handle to the driver's file object. + // + + InitializeObjectAttributes( + &ObjectAttr, + AdapterName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + + NtOpenStatus = ZwCreateFile(&FileHandle, + FILE_READ_DATA | FILE_WRITE_DATA, + &ObjectAttr, + &IoStatus, + (PLARGE_INTEGER) NULL, // allocation size + 0L, // file attributes + FILE_SHARE_READ | FILE_SHARE_WRITE, // share access + FILE_OPEN, // create disposition + 0, // create options + OpenEa, + OpenEaLength); + + + ExFreePool(OpenEa); + + if (NtOpenStatus != STATUS_SUCCESS) { + ExFreePool((PVOID)NewOpenP); + *Status = NDIS_STATUS_ADAPTER_NOT_FOUND; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n"); + return; + } + + + // + // Convert the file handle into a pointer to the adapter's + // file object. + // + + ObReferenceObjectByHandle(FileHandle, + 0, + NULL, + KernelMode, + (PVOID *) &FileObject, + NULL + ); + + // + // Close the file handle, now that we have the object reference. + // + + ZwClose(FileHandle); + + // + // From the file object, obtain the device object. + // + + DeviceObject = IoGetRelatedDeviceObject(FileObject); + + + // + // Increment the adapter's reference count. + // + + TmpAdaptP = (PNDIS_ADAPTER_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1); + + // + // Check if this is a Miniport or mac + // + + if (TmpAdaptP->DeviceObject != DeviceObject) { + + // + // It is a Miniport + // + + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)TmpAdaptP; + ULONG i; + + UsingEncapsulation = FALSE; + + // + // Select the medium to use + // + + for (i = 0; i < MediumArraySize; i++){ + + if (MediumArray[i] == Miniport->MediaType) { + + break; + + } + + } + + if (i == MediumArraySize){ + + // + // Check for ethernet encapsulation on Arcnet as + // a possible combination. + // + if (Miniport->MediaType == NdisMediumArcnet878_2) { + + for (i = 0; i < MediumArraySize; i++){ + + if (MediumArray[i] == NdisMedium802_3) { + break; + } + } + + if (i == MediumArraySize) { + + *Status = NDIS_STATUS_UNSUPPORTED_MEDIA; + return; + + } + + // + // encapsulated ethernet, so we add in the wrapper's + // ability to support (emulate) the multicast stuff + // + + Miniport->SupportedPacketFilters |= (NDIS_PACKET_TYPE_MULTICAST | + NDIS_PACKET_TYPE_ALL_MULTICAST); + + UsingEncapsulation = TRUE; + + } else { + + *Status = NDIS_STATUS_UNSUPPORTED_MEDIA; + return; + + } + + } + + *SelectedMediumIndex = i; + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + // + // Lock the miniport. If the lock fails, then + // we must pend this open and try it later. + // + + LOCK_MINIPORT(Miniport, LocalLock); + + if ( LocalLock ) { + + MiniportOpenAdapter( + Status, + OpenErrorStatus, + NdisBindingHandle, + NdisProtocolHandle, + ProtocolBindingContext, + AdapterName, + OpenOptions, + AddressingInformation, + Miniport, + NewOpenP, + FileObject, + UsingEncapsulation + ); + + } else { + + PMINIPORT_PENDING_OPEN MiniportPendingOpen; + + // + // Allocate some space for this pending structure. + // We free in after we call NdisOpenComplete. + // + + *Status = NdisAllocateMemory( + (PVOID *) &MiniportPendingOpen, + sizeof(MINIPORT_PENDING_OPEN), + 0, + HighestAcceptableMax + ); + + if ( *Status == NDIS_STATUS_SUCCESS ) { + + // + // Save off the parameters for this open so we can + // do the actual NdisOpenAdapter() later on. + // + + MiniportPendingOpen->NextPendingOpen = NULL; + MiniportPendingOpen->NdisBindingHandle = NdisBindingHandle; + MiniportPendingOpen->NdisProtocolHandle = NdisProtocolHandle; + MiniportPendingOpen->ProtocolBindingContext = ProtocolBindingContext; + MiniportPendingOpen->AdapterName = AdapterName; + MiniportPendingOpen->OpenOptions = OpenOptions; + MiniportPendingOpen->AddressingInformation = AddressingInformation; + MiniportPendingOpen->Miniport = Miniport; + MiniportPendingOpen->NewOpenP = NewOpenP; + MiniportPendingOpen->FileObject = FileObject; + MiniportPendingOpen->UsingEncapsulation = UsingEncapsulation; + + if ( Miniport->FirstPendingOpen == NULL ) { + + Miniport->FirstPendingOpen = MiniportPendingOpen; + + } else { + + Miniport->LastPendingOpen->NextPendingOpen = MiniportPendingOpen; + } + + Miniport->LastPendingOpen = MiniportPendingOpen; + + // + // Make sure MiniportProcessDeferred() completes the open. + // + + *Status = NDIS_STATUS_PENDING; + + Miniport->ProcessOddDeferredStuff = TRUE; + + } else { + + ObDereferenceObject((PVOID) FileObject); + ExFreePool((PVOID) NewOpenP); + } + } + + // + // Unlock the miniport. + // + + UNLOCK_MINIPORT(Miniport, LocalLock); + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + KeLowerIrql(OldIrql); + + return; + } + + // + // It is a mac + // + + IF_TRACE(TRACE_IMPT) NdisPrint2("openadapter: adaptername=%s\n",TmpAdaptP->AdapterName.Buffer); + if (!NdisReferenceAdapter(TmpAdaptP)) { + + // + // The adapter is closing. + // + + ObDereferenceObject((PVOID)FileObject); + ExFreePool((PVOID)NewOpenP); + *Status = NDIS_STATUS_CLOSING; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n"); + return; + } + + // + // Increment the protocol's reference count. + // + + TmpProtP = (PNDIS_PROTOCOL_BLOCK)NdisProtocolHandle; + if (!NdisReferenceProtocol(TmpProtP)) { + + // + // The protocol is closing. + // + + NdisDereferenceAdapter(TmpAdaptP); + ObDereferenceObject((PVOID)FileObject); + ExFreePool((PVOID)NewOpenP); + *Status = NDIS_STATUS_CLOSING; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n"); + return; + } + + + // + // Set up the elements of the open structure. + // + + NdisAllocateSpinLock(&NewOpenP->SpinLock); + NewOpenP->Closing = FALSE; + + NewOpenP->AdapterHandle = TmpAdaptP; + NewOpenP->ProtocolHandle = TmpProtP; + + // + // for speed, instead of having to use AdapterHandle->MacHandle + // + NewOpenP->MacHandle = TmpAdaptP->MacHandle; + + // + // for even more speed.... + // + + NewOpenP->SendHandler = TmpAdaptP->MacHandle->MacCharacteristics.SendHandler; + NewOpenP->TransferDataHandler = TmpAdaptP->MacHandle->MacCharacteristics.TransferDataHandler; + + NewOpenP->SendCompleteHandler = TmpProtP->ProtocolCharacteristics.SendCompleteHandler; + NewOpenP->TransferDataCompleteHandler = TmpProtP->ProtocolCharacteristics.TransferDataCompleteHandler; + + // + // Now we have to fake some stuff to get all indications to happen + // at DPC_LEVEL. What we do is start the pointer at an NDIS function + // which will guarantee that it occurs. + // + // Then, by extending the OPEN structure and adding the real handlers + // at the end we can use these for drivers compiled with this header. + // + NewOpenP->ProtocolBindingContext = ProtocolBindingContext; + NewOpenP->PostNt31ReceiveHandler = TmpProtP->ProtocolCharacteristics.ReceiveHandler; + NewOpenP->PostNt31ReceiveCompleteHandler = TmpProtP->ProtocolCharacteristics.ReceiveCompleteHandler; + NewOpenP->ReceiveHandler = NdisMacReceiveHandler; + NewOpenP->ReceiveCompleteHandler = NdisMacReceiveCompleteHandler; + + // + // Patch the open into the global list of macs + // + ACQUIRE_SPIN_LOCK(&GlobalOpenListLock); + + NewOpenP->NextGlobalOpen = GlobalOpenList; + GlobalOpenList = NewOpenP; + + RELEASE_SPIN_LOCK(&GlobalOpenListLock); + + + // + // Save a pointer to the file object in the open... + // + + NewOpenP->FileObject = FileObject; + + // + // ...and a pointer to the open in the file object. + // + + FileObject->FsContext = (PVOID)NewOpenP; + + + *NdisBindingHandle = (NDIS_HANDLE)NewOpenP; + + + // + // Call MacOpenAdapter, see what we shall see... + // + + OpenStatus = (TmpAdaptP->MacHandle->MacCharacteristics.OpenAdapterHandler) ( + OpenErrorStatus, + &NewOpenP->MacBindingHandle, + SelectedMediumIndex, + MediumArray, + MediumArraySize, + (NDIS_HANDLE)NewOpenP, + TmpAdaptP->MacAdapterContext, + OpenOptions, + AddressingInformation + ); + + if ((OpenStatus == NDIS_STATUS_SUCCESS) && NdisFinishOpen(NewOpenP)) { + + *Status = NDIS_STATUS_SUCCESS; + + } else if (OpenStatus == NDIS_STATUS_PENDING) { + + *Status = NDIS_STATUS_PENDING; + + } else { + + PNDIS_OPEN_BLOCK TmpOpen; + + // + // Something went wrong, clean up and exit. + // + + ACQUIRE_SPIN_LOCK(&GlobalOpenListLock); + + if (GlobalOpenList == NewOpenP) { + + GlobalOpenList = NewOpenP->NextGlobalOpen; + + } else { + + TmpOpen = GlobalOpenList; + + while (TmpOpen->NextGlobalOpen != NewOpenP) { + + TmpOpen = TmpOpen->NextGlobalOpen; + + } + + TmpOpen->NextGlobalOpen = NewOpenP->NextGlobalOpen; + + } + + RELEASE_SPIN_LOCK(&GlobalOpenListLock); + + ObDereferenceObject((PVOID)FileObject); + NdisDereferenceAdapter(TmpAdaptP); + NdisDereferenceProtocol(TmpProtP); + ExFreePool((PVOID)NewOpenP); + *Status = NDIS_STATUS_OPEN_FAILED; + } + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n"); + return; +} + + +VOID +NdisCloseAdapter( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE NdisBindingHandle + ) + +/*++ + +Routine Description: + + Closes a connection between a protocol and an adapter (MAC). + +Arguments: + + Status - Returns the final status. + NdisBindingHandle - The handle returned by NdisOpenAdapter. + +Return Value: + + None. + +--*/ + +{ + PNDIS_OPEN_BLOCK OpenP = ((PNDIS_OPEN_BLOCK)NdisBindingHandle); + + if (OpenP->AdapterHandle->DeviceObject == NULL) { + + // + // This is a Miniport + // This returns TRUE if it finished synchronously. + // + + if (NdisMKillOpen(OpenP)) { + + *Status = NDIS_STATUS_SUCCESS; + + } else { + + *Status = NDIS_STATUS_PENDING; // will complete later + + } + return; + } + + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisCloseAdapter\n"); + NdisPrint3(" Protocol %wZ is closing Adapter %wZ\n", + &(OpenP->ProtocolHandle)->ProtocolCharacteristics.Name, + &(OpenP->AdapterHandle)->AdapterName); + } + IF_ERROR_CHK { + if (DbgIsNull(NdisBindingHandle)) { + NdisPrint1("OpenAdapter: Null BindingHandle\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(NdisBindingHandle)) { + NdisPrint1("OpenAdapter: BindingHandle not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + // + // This returns TRUE if it finished synchronously. + // + + if (NdisKillOpen(OpenP)) { + + *Status = NDIS_STATUS_SUCCESS; + + } else { + + *Status = NDIS_STATUS_PENDING; // will complete later + + } + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisCloseAdapter\n"); +#undef OpenP +} + + +// +// Requests Used by MAC Drivers +// +// + + + +VOID +NdisInitializeWrapper( + OUT PNDIS_HANDLE NdisWrapperHandle, + IN PVOID SystemSpecific1, + IN PVOID SystemSpecific2, + IN PVOID SystemSpecific3 + ) + +/*++ + +Routine Description: + + Called at the beginning of every MAC's initialization routine. + +Arguments: + + NdisWrapperHandle - A MAC specific handle for the wrapper. + + SystemSpecific1, a pointer to the driver object for the MAC. + SystemSpecific2, a PUNICODE_STRING containing the location of + the registry subtree for this driver. + SystemSpecific3, unused on NT. + +Return Value: + + None. + +--*/ + +{ + NDIS_STATUS Status; + + PNDIS_WRAPPER_HANDLE NdisMacInfo; + + UNREFERENCED_PARAMETER (SystemSpecific3); + + + IF_TRACE(TRACE_IMPT) NdisPrint1("==>NdisInitializeWrapper\n"); + + Status = NdisAllocateMemory( + (PVOID*) (NdisWrapperHandle), + sizeof(NDIS_WRAPPER_HANDLE), + 0, + HighestAcceptableMax + ); + + if ( Status == NDIS_STATUS_SUCCESS ) { + + NdisMacInfo = (PNDIS_WRAPPER_HANDLE) (*NdisWrapperHandle); + NdisMacInfo->NdisWrapperDriver = (PDRIVER_OBJECT) SystemSpecific1; + NdisMacInfo->NdisWrapperConfigurationHandle = (HANDLE) SystemSpecific2; + + } else { + + *NdisWrapperHandle = NULL; + } + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisInitializeWrapper\n"); +} + +VOID +NdisTerminateWrapper( + IN NDIS_HANDLE NdisWrapperHandle, + IN PVOID SystemSpecific + ) + +/*++ + +Routine Description: + + Called at the end of every MAC's termination routine. + +Arguments: + + NdisWrapperHandle - The handle returned from NdisInitializeWrapper. + + SystemSpecific - No defined value. + +Return Value: + + None. + +--*/ + +{ + PNDIS_WRAPPER_HANDLE NdisMacInfo = (PNDIS_WRAPPER_HANDLE)NdisWrapperHandle; + + IF_TRACE(TRACE_IMPT) NdisPrint1("==>NdisTerminateWrapper\n"); + + UNREFERENCED_PARAMETER(SystemSpecific); + + + if (NdisMacInfo != NULL) { + + NdisFreeMemory(NdisMacInfo, sizeof(NDIS_WRAPPER_HANDLE), 0); + + } + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisTerminateWrapper\n"); + + return; +} + +VOID +NdisRegisterMac( + OUT PNDIS_STATUS Status, + OUT PNDIS_HANDLE NdisMacHandle, + IN NDIS_HANDLE NdisWrapperHandle, + IN NDIS_HANDLE MacMacContext, + IN PNDIS_MAC_CHARACTERISTICS MacCharacteristics, + IN UINT CharacteristicsLength + ) + +/*++ + +Routine Description: + + Register an NDIS MAC. + +Arguments: + + Status - Returns the final status. + NdisMacHandle - Returns a handle referring to this MAC. + NdisWrapperHandle - Handle returned by NdisInitializeWrapper. + MacMacContext - Context for calling MACUnloadMac and MACAddAdapter. + MacCharacteritics - The NDIS_MAC_CHARACTERISTICS table. + CharacteristicsLength - The length of MacCharacteristics. + +Return Value: + + None. + +--*/ + +{ + PNDIS_MAC_BLOCK NewMacP; + PNDIS_WRAPPER_HANDLE NdisMacInfo = (PNDIS_WRAPPER_HANDLE)(NdisWrapperHandle); + UINT MemNeeded; + + // + // check that this is an NDIS 3.0 MAC. + // + IF_TRACE(TRACE_IMPT) NdisPrint1("==>NdisRegisterMac\n"); + + // + // Do any initial initialization that may be necessary. Note: this + // routine will notice if this is the second or later call to it. + // + *Status = NdisInitialInit( NdisMacInfo->NdisWrapperDriver ); + if (!NT_SUCCESS(*Status)) { + return; + } + + *NdisMacHandle = (NDIS_HANDLE)NULL; + + if (NdisMacInfo == NULL) { + + *Status = NDIS_STATUS_FAILURE; + + return; + + } + + IF_ERROR_CHK { + if (DbgIsNull(MacCharacteristics->OpenAdapterHandler)) { + NdisPrint1("RegisterMac: Null OpenAdapterHandler \n"); + DbgBreakPoint(); + } + if (DbgIsNull(MacCharacteristics->CloseAdapterHandler)) { + NdisPrint1("RegisterMac: Null CloseAdapterHandler \n"); + DbgBreakPoint(); + } + + if (DbgIsNull(MacCharacteristics->SendHandler)) { + NdisPrint1("RegisterMac: Null SendHandler \n"); + DbgBreakPoint(); + } + if (DbgIsNull(MacCharacteristics->TransferDataHandler)) { + NdisPrint1("RegisterMac: Null TransferDataHandler \n"); + DbgBreakPoint(); + } + + if (DbgIsNull(MacCharacteristics->ResetHandler)) { + NdisPrint1("RegisterMac: Null ResetHandler \n"); + DbgBreakPoint(); + } + + if (DbgIsNull(MacCharacteristics->RequestHandler)) { + NdisPrint1("RegisterMac: Null RequestHandler \n"); + DbgBreakPoint(); + } + if (DbgIsNull(MacCharacteristics->QueryGlobalStatisticsHandler)) { + NdisPrint1("RegisterMac: Null QueryGlobalStatisticsHandler \n"); + DbgBreakPoint(); + } + if (DbgIsNull(MacCharacteristics->UnloadMacHandler)) { + NdisPrint1("RegisterMac: Null UnloadMacHandler \n"); + DbgBreakPoint(); + } + if (DbgIsNull(MacCharacteristics->AddAdapterHandler)) { + NdisPrint1("RegisterMac: Null AddAdapterHandler \n"); + DbgBreakPoint(); + } + if (DbgIsNull(MacCharacteristics->RemoveAdapterHandler)) { + NdisPrint1("RegisterMac: Null RemoveAdapterHandler \n"); + DbgBreakPoint(); + } + } + + if (MacCharacteristics->MajorNdisVersion != 3 || + MacCharacteristics->MinorNdisVersion != 0) { + *Status = NDIS_STATUS_BAD_VERSION; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterMac\n"); + return; + } + + // + // Check that CharacteristicsLength is enough. + // + + if (CharacteristicsLength < sizeof(NDIS_MAC_CHARACTERISTICS)) { + NdisPrint3("char len = %d < %d\n",CharacteristicsLength, + sizeof(NDIS_MAC_CHARACTERISTICS)); + + *Status = NDIS_STATUS_BAD_CHARACTERISTICS; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterMac\n"); + return; + } + + // + // Allocate memory for the NDIS MAC block. + // + MemNeeded = sizeof(NDIS_MAC_BLOCK) + MacCharacteristics->Name.Length; + NewMacP = (PNDIS_MAC_BLOCK)ExAllocatePoolWithTag(NonPagedPool, MemNeeded, 'bmDN'); + if (NewMacP == (PNDIS_MAC_BLOCK)NULL) { + *Status = NDIS_STATUS_RESOURCES; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterMac\n"); + return; + } + RtlZeroMemory(NewMacP, sizeof(NDIS_MAC_BLOCK)); + + NewMacP->Length = MemNeeded; + + // + // Copy over the characteristics table. + // + + RtlCopyMemory((PVOID)&NewMacP->MacCharacteristics, + (PVOID)MacCharacteristics, sizeof(NDIS_MAC_CHARACTERISTICS)); + + // + // Move buffer pointer to correct location (extra space at the end of + // the characteristics table) + // + + (NewMacP->MacCharacteristics).Name.Buffer = + (PWSTR)((PUCHAR)NewMacP + sizeof(NDIS_MAC_BLOCK)); + + + // + // Copy String over. + // + + RtlCopyMemory( + (NewMacP->MacCharacteristics).Name.Buffer, + (MacCharacteristics->Name).Buffer, + (MacCharacteristics->Name).Length + ); + + // + // No adapters yet registered for this MAC. + // + + NewMacP->AdapterQueue = (PNDIS_ADAPTER_BLOCK)NULL; + + NewMacP->MacMacContext = MacMacContext; + + // + // Set up unload handler + // + + NdisMacInfo->NdisWrapperDriver->DriverUnload = NdisUnload; + + // + // Set up shutdown handler + // + NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_SHUTDOWN] = NdisShutdown; + + // + // Set up the handlers for this driver (they all do nothing). + // + + NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CREATE] = NdisCreateIrpHandler; + NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NdisDeviceControlIrpHandler; + NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CLEANUP] = NdisSuccessIrpHandler; + NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CLOSE] = NdisCloseIrpHandler; + + NewMacP->NdisMacInfo = NdisMacInfo; + + // + // Put MAC on global list. + // + + ACQUIRE_SPIN_LOCK(&NdisMacListLock); + + NewMacP->NextMac = NdisMacList; + NdisMacList = NewMacP; + + RELEASE_SPIN_LOCK(&NdisMacListLock); + + // + // Use this event to tell us when all adapters are removed from the mac + // during an unload + // + + KeInitializeEvent( + &NewMacP->AdaptersRemovedEvent, + NotificationEvent, + FALSE + ); + + NewMacP->Unloading = FALSE; + + NdisInitializeRef(&NewMacP->Ref); + + *NdisMacHandle = (NDIS_HANDLE)NewMacP; + + NdisInitReferencePackage(); + + if (NdisMacInfo->NdisWrapperConfigurationHandle) { + + if (NdisCallDriverAddAdapter(NewMacP) == NDIS_STATUS_SUCCESS) { + *Status = NDIS_STATUS_SUCCESS; + } else { + *Status = NDIS_STATUS_FAILURE; + NdisDereferenceMac(NewMacP); + } + } else { + *Status = NDIS_STATUS_FAILURE; + } + + NdisInitDereferencePackage(); + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterMac\n"); +} + + +VOID +NdisDeregisterMac( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE NdisMacHandle + ) + +/*++ + +Routine Description: + + Deregisters an NDIS MAC. + +Arguments: + + Status - Returns the status of the request. + NdisMacHandle - The handle returned by NdisRegisterMac. + +Return Value: + + None. + +--*/ + +{ + + PNDIS_MAC_BLOCK OldMacP = (PNDIS_MAC_BLOCK)NdisMacHandle; + + // + // If the MAC is already closing, return. + // + + *Status = NDIS_STATUS_SUCCESS; + + if (OldMacP == NULL) { + + return; + } + + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisDeregisterMac\n"); + NdisPrint2(" Mac %wZ being deregistered\n",&OldMacP->MacCharacteristics.Name); + } + IF_ERROR_CHK { + if (DbgIsNull(NdisMacHandle)) { + NdisPrint1("DeregisterMac: Null Handle\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(NdisMacHandle)) { + NdisPrint1("DeregisterMac: Handle not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + if (!NdisCloseRef(&OldMacP->Ref)) { + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeregisterMac\n"); + return; + } + + + ASSERT(OldMacP->AdapterQueue == (PNDIS_ADAPTER_BLOCK)NULL); + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeregisterMac\n"); +} + +IO_ALLOCATION_ACTION +NdisAllocationExecutionRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID MapRegisterBase, + IN PVOID Context + ) + +/*++ + +Routine Description: + + This routine is the execution routine for AllocateAdapterChannel, + if is called when the map registers have been assigned. + +Arguments: + + DeviceObject - The device object of the adapter. + + Irp - ??. + + MapRegisterBase - The address of the first translation table + assigned to us. + + Context - A pointer to the Adapter in question. + +Return Value: + + None. + +--*/ +{ + PNDIS_ADAPTER_BLOCK AdaptP = (PNDIS_ADAPTER_BLOCK)Context; + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)Context; + + Irp; DeviceObject; + + // + // Save this translation entry in the correct spot. + // + + if (AdaptP->DeviceObject == NULL) { + + Miniport->MapRegisters[Miniport->CurrentMapRegister].MapRegister = MapRegisterBase; + + } else { + + AdaptP->MapRegisters[AdaptP->CurrentMapRegister].MapRegister = MapRegisterBase; + + } + + // + // This will free the thread that is waiting for this callback. + // + + KeSetEvent( + ((AdaptP->DeviceObject == NULL) ? + &Miniport->AllocationEvent : + &AdaptP->AllocationEvent), + 0L, + FALSE + ); + + return DeallocateObjectKeepRegisters; +} + + + +NDIS_STATUS +NdisRegisterAdapter( + OUT PNDIS_HANDLE NdisAdapterHandle, + IN NDIS_HANDLE NdisMacHandle, + IN NDIS_HANDLE MacAdapterContext, + IN NDIS_HANDLE WrapperConfigurationContext, + IN PNDIS_STRING AdapterName, + IN PVOID AdapterInformation + ) + +/*++ + +Routine Description: + + Register an NDIS adapter. + +Arguments: + + NdisAdapterHandle - Returns a handle referring to this adapter. + NdisMacHandle - A handle for a previously registered MAC. + MacAdapterContext - A context for calls into this MAC. + WrapperConfigurationContext - Context passed to MacAddAdapter. + AdapterName - The name the adapter should be registered under. + AdapterInformation - Contains adapter information. For future + use. NULL for the meantime. Storage for it + must be allocated by the caller. + +Return Value: + + The final status. + +--*/ + +{ + PNDIS_ADAPTER_BLOCK NewAdaptP; + PDEVICE_OBJECT TmpDeviceP; + PNDIS_MAC_BLOCK TmpMacP; + NTSTATUS NtStatus; + NDIS_STRING NdisAdapterName; + PHYSICAL_ADDRESS PortAddress; + PHYSICAL_ADDRESS InitialPortAddress; + ULONG addressSpace; + PNDIS_ADAPTER_INFORMATION AdapterInfo = (PNDIS_ADAPTER_INFORMATION)AdapterInformation; + BOOLEAN Conflict; + PCM_RESOURCE_LIST Resources; + LARGE_INTEGER TimeoutValue; + BOOLEAN AllocateIndividualPorts = TRUE; + ULONG i; + ULONG BusNumber; + NDIS_INTERFACE_TYPE BusType; + NDIS_STATUS Status; + KIRQL OldIrql; + + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisRegisterAdapter\n"); + } + + + IF_ERROR_CHK { + if (DbgIsNull(NdisMacHandle)) { + NdisPrint1("RegisterAdapter: Null Handle\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(NdisMacHandle)) { + NdisPrint1("RegisterAdapter: Handle not in NonPaged Memory\n"); + DbgBreakPoint(); + } + if (DbgIsNull(MacAdapterContext)) { + NdisPrint1("RegisterAdapter: Null Context\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(MacAdapterContext)) { + NdisPrint1("RegisterAdapter: Context not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + // + // Increment the MAC's refernce count. + // + + if (!NdisReferenceMac((PNDIS_MAC_BLOCK)NdisMacHandle)) { + + // + // The MAC is closing. + // + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + return NDIS_STATUS_CLOSING; + } + + // + // Allocate the string structure and space for the string. This + // must be allocated from nonpaged pool, because it is touched by + // NdisWriteErrorLogEntry, which may be called from DPC level. + // + + NdisAdapterName.Buffer = (PWSTR)ExAllocatePoolWithTag( + NonPagedPool, + AdapterName->MaximumLength, + 'naDN' + ); + if (NdisAdapterName.Buffer == NULL) { + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + return NDIS_STATUS_RESOURCES; + } + + NdisAdapterName.MaximumLength = AdapterName->MaximumLength; + NdisAdapterName.Length = AdapterName->Length; + + RtlCopyMemory(NdisAdapterName.Buffer, + AdapterName->Buffer, + AdapterName->MaximumLength + ); + + // + // Create a device object for this adapter. + // + + NtStatus = IoCreateDevice( + ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver, + sizeof(NDIS_ADAPTER_BLOCK) + sizeof(NDIS_WRAPPER_CONTEXT), // device extension size + AdapterName, + FILE_DEVICE_PHYSICAL_NETCARD, + 0, + FALSE, // exclusive flag + &TmpDeviceP + ); + + if (NtStatus != STATUS_SUCCESS) { + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + ExFreePool( NdisAdapterName.Buffer ); + return NDIS_STATUS_DEVICE_FAILED; + } + + + // + // Initialize the NDIS adapter block in the device object extension + // + // *** NDIS_WRAPPER_CONTEXT has a higher alignment requirement than + // NDIS_ADAPTER_BLOCK, so we put it first in the extension. + // + + ASSERT( (sizeof(NDIS_WRAPPER_CONTEXT) & 3) <= (sizeof(NDIS_ADAPTER_BLOCK) & 3) ); + + NewAdaptP = (PNDIS_ADAPTER_BLOCK)((PNDIS_WRAPPER_CONTEXT)TmpDeviceP->DeviceExtension + 1); + RtlZeroMemory(NewAdaptP, sizeof(NDIS_ADAPTER_BLOCK)); + + NewAdaptP->DeviceObject = TmpDeviceP; + NewAdaptP->MacHandle = TmpMacP = (PNDIS_MAC_BLOCK)NdisMacHandle; + NewAdaptP->MacAdapterContext = MacAdapterContext; + NewAdaptP->AdapterName = NdisAdapterName; + // NewAdaptP->OpenQueue = (PNDIS_OPEN_BLOCK)NULL; + + NewAdaptP->WrapperContext = TmpDeviceP->DeviceExtension; + + // + // Get the BusNumber and BusType from the context + // + + if (((PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext)[3].DefaultType == + (NDIS_INTERFACE_TYPE)-1) { + + BusType = (NDIS_INTERFACE_TYPE)-1; + + } else { + + BusType = AdapterInfo->AdapterType; + + } + + BusNumber = ((PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext)[3].DefaultLength; + + // + // Check that if there is no bus number or no bus type that the driver is not + // going to try to acquire any hardware resources + // + + if ((BusType == (NDIS_INTERFACE_TYPE)-1) || (BusNumber == (ULONG)-1)) { + + if ((AdapterInfo != NULL) && + ((AdapterInfo->NumberOfPortDescriptors != 0) || + (AdapterInfo->Master))) { + + // + // Error out + // + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + return NDIS_STATUS_BAD_CHARACTERISTICS; + + } + + } + + // + // Copy over any PCI assigned resources + // + if ((BusType == NdisInterfacePci) && + (BusNumber != -1) && + (AdapterInfo != NULL) && + (TmpMacP->PciAssignedResources != NULL)) { + + // + // Reassign old resources to this device + // + NtStatus = IoReportResourceUsage( + NULL, + ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver, + NULL, + 0, + NewAdaptP->DeviceObject, + TmpMacP->PciAssignedResources, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + TmpMacP->PciAssignedResources->List[0].PartialResourceList.Count, + TRUE, + &Conflict + ); + + // + // Allocate a new buffer + // + Resources = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag( + NonPagedPool, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + (AdapterInfo->NumberOfPortDescriptors + + TmpMacP->PciAssignedResources->List[0].PartialResourceList.Count + + (((AdapterInfo->Master == TRUE) && + (AdapterInfo->AdapterType == NdisInterfaceIsa)) + ?1 + :0)), + 'lrDN' + ); + + if (Resources == NULL) { + + // + // Error out + // + + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + ExFreePool( TmpMacP->PciAssignedResources ); + NdisDereferenceMac(TmpMacP); + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + return NDIS_STATUS_RESOURCES; + + } + + // + // Copy over old resource list + // + NdisMoveMemory(Resources, + TmpMacP->PciAssignedResources, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + TmpMacP->PciAssignedResources->List[0].PartialResourceList.Count + ); + + TmpMacP->PciAssignedResources->Count = 0; + + NtStatus = IoReportResourceUsage( + NULL, + ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver, + TmpMacP->PciAssignedResources, + sizeof(CM_RESOURCE_LIST), + NULL, + NULL, + 0, + TRUE, + &Conflict + ); + + ExFreePool( TmpMacP->PciAssignedResources); + + TmpMacP->PciAssignedResources = NULL; + + } else { + + // + // Allocate a new buffer for non-pci devices + // + Resources = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag( + NonPagedPool, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + (AdapterInfo->NumberOfPortDescriptors + + (((AdapterInfo->Master == TRUE) && + (AdapterInfo->AdapterType == NdisInterfaceIsa)) + ?1 + :0)), + 'lrDN' + ); + + if (Resources == NULL) { + + // + // Error out + // + + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + return NDIS_STATUS_RESOURCES; + + } + + // + // Fix up counts for non-pci devices + // + Resources->List[0].PartialResourceList.Count = 0; + + } + + // + // Setup resources for the ports + // + + if ((BusType != (NDIS_INTERFACE_TYPE)-1) && + (BusNumber != (ULONG)-1)) { + + if (AdapterInfo != NULL) { + + ULONG HighestPort; + ULONG LowestPort; + + Resources->Count = 1; + Resources->List[0].InterfaceType = AdapterInfo->AdapterType; + Resources->List[0].BusNumber = BusNumber; + Resources->List[0].PartialResourceList.Version = 0; + Resources->List[0].PartialResourceList.Revision = 0; + + NewAdaptP->Resources = Resources; + NewAdaptP->BusNumber = BusNumber; + NewAdaptP->BusType = BusType; + NewAdaptP->AdapterType = AdapterInfo->AdapterType; + NewAdaptP->Master = AdapterInfo->Master; + + // + // NewAdaptP->InitialPort and NumberOfPorts refer to the + // union of all port mappings specified; the area must + // cover all possible ports. We scan the list, keeping track + // of the highest and lowest ports used. + // + + if (AdapterInfo->NumberOfPortDescriptors > 0) { + + + // + // Setup port + // + LowestPort = AdapterInfo->PortDescriptors[0].InitialPort; + HighestPort = LowestPort + AdapterInfo->PortDescriptors[0].NumberOfPorts; + + if (AdapterInfo->PortDescriptors[0].PortOffset == NULL) { + + AllocateIndividualPorts = FALSE; + + } + + for (i = 0; i < AdapterInfo->NumberOfPortDescriptors; i++) { + + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].Type = + CmResourceTypePort; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].ShareDisposition = + CmResourceShareDeviceExclusive; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].Flags = + (AdapterInfo->AdapterType == NdisInterfaceInternal)? + CM_RESOURCE_PORT_MEMORY : CM_RESOURCE_PORT_IO; +#if !defined(BUILD_FOR_3_1) + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].u.Port.Start.QuadPart = + (ULONG)AdapterInfo->PortDescriptors[i].InitialPort; +#else + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].u.Port.Start = + RtlConvertUlongToLargeInteger((ULONG)(AdapterInfo->PortDescriptors[i].InitialPort)); +#endif + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].u.Port.Length = + AdapterInfo->PortDescriptors[i].NumberOfPorts; + + if (AdapterInfo->PortDescriptors[i].PortOffset == NULL) { + + AllocateIndividualPorts = FALSE; + + } + + if (AdapterInfo->PortDescriptors[i].InitialPort < LowestPort) { + LowestPort = AdapterInfo->PortDescriptors[i].InitialPort; + } + if ((AdapterInfo->PortDescriptors[i].InitialPort + + AdapterInfo->PortDescriptors[i].NumberOfPorts) > HighestPort) { + HighestPort = AdapterInfo->PortDescriptors[i].InitialPort + + AdapterInfo->PortDescriptors[i].NumberOfPorts; + } + } + + NewAdaptP->InitialPort = LowestPort; + NewAdaptP->NumberOfPorts = HighestPort - LowestPort; + + } else { + + NewAdaptP->NumberOfPorts = 0; + + } + + Resources->List[0].PartialResourceList.Count += AdapterInfo->NumberOfPortDescriptors; + + } else { + + // + // Error out + // + + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + return NDIS_STATUS_FAILURE; + + } + + } + + NewAdaptP->BeingRemoved = FALSE; + + if ((BusType != (NDIS_INTERFACE_TYPE)-1) && + (BusNumber != (ULONG)-1)) { + + // + // Submit Resources + // + + NtStatus = IoReportResourceUsage( + NULL, + ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver, + NULL, + 0, + NewAdaptP->DeviceObject, + Resources, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + Resources->List[0].PartialResourceList.Count, + TRUE, + &Conflict + ); + + // + // Check for conflict. + // + + if (Conflict || (NtStatus != STATUS_SUCCESS)) { + + if (Conflict) { + + // + // Log an error + // + + PIO_ERROR_LOG_PACKET errorLogEntry; + ULONG StringSize; + PWCH baseFileName; + + baseFileName = NewAdaptP->AdapterName.Buffer; + + // + // Parse out the path name, leaving only the device name. + // + + for ( i = 0; i < NewAdaptP->AdapterName.Length / sizeof(WCHAR); i++ ) { + + // + // If s points to a directory separator, set baseFileName to + // the character after the separator. + // + + if ( NewAdaptP->AdapterName.Buffer[i] == OBJ_NAME_PATH_SEPARATOR ) { + baseFileName = &(NewAdaptP->AdapterName.Buffer[++i]); + } + + } + + StringSize = NewAdaptP->AdapterName.MaximumLength - + (((ULONG)baseFileName) - ((ULONG)NewAdaptP->AdapterName.Buffer)) ; + + errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( + TmpDeviceP, + (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) + + StringSize) + ); + + if (errorLogEntry != NULL) { + + errorLogEntry->ErrorCode = EVENT_NDIS_IO_PORT_CONFLICT; + + // + // store the time + // + + errorLogEntry->MajorFunctionCode = 0; + errorLogEntry->RetryCount = 0; + errorLogEntry->UniqueErrorValue = 0; + errorLogEntry->FinalStatus = 0; + errorLogEntry->SequenceNumber = 0; + errorLogEntry->IoControlCode = 0; + + // + // Set string information + // + + if (StringSize != 0) { + + errorLogEntry->NumberOfStrings = 1; + errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET); + + RtlCopyMemory ( + ((PUCHAR)errorLogEntry) + + sizeof(IO_ERROR_LOG_PACKET), + (PVOID)baseFileName, + StringSize + ); + + } else { + + errorLogEntry->NumberOfStrings = 0; + + } + + // + // write it out + // + + IoWriteErrorLogEntry(errorLogEntry); + } + + // + // Free memory + // + + ExFreePool(Resources); + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + + return(NDIS_STATUS_RESOURCE_CONFLICT); + + } + + // + // Free memory + // + + ExFreePool(Resources); + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + + + return(NDIS_STATUS_FAILURE); + } + + // + // If port mapping is needed, we do that. If the result + // is in memory, we have to map it. We map only the + // ports specified in AdapterInformation; the default + // is to map the first 4K. + // + // Note that NumberOfPorts can only be 0 if AdapterInfo + // is provided and explicitly sets it to 0, so in that + // case it is OK to leave the adapter in a state where + // a call to NdisXXXPort will probably crash (because + // PortOffset will be undefined). + // + + if (NewAdaptP->NumberOfPorts > 0) { + + if (AllocateIndividualPorts) { + + // + // We get here if we are supposed to allocate ports on an + // individual bases -- which implies that the driver will + // be using the Raw functions. + // + // Get the system physical address for this card. The card uses + // I/O space, except for "internal" Jazz devices which use + // memory space. + // + + for (i = 0; i < AdapterInfo->NumberOfPortDescriptors; i++) { + + addressSpace = (NewAdaptP->AdapterType == NdisInterfaceInternal) ? 0 : 1; + + InitialPortAddress.LowPart = AdapterInfo->PortDescriptors[i].InitialPort; + InitialPortAddress.HighPart = 0; + + if ( !HalTranslateBusAddress( + NewAdaptP->BusType, // InterfaceType + NewAdaptP->BusNumber, // BusNumber + InitialPortAddress, // Bus Address + &addressSpace, // AddressSpace + &PortAddress // Translated address + ) ) { + + // + // Free memory + // + + ExFreePool(Resources); + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + + + return(NDIS_STATUS_FAILURE); + } + + if (addressSpace == 0) { + + // + // memory space + // + + *(AdapterInfo->PortDescriptors[i].PortOffset) = MmMapIoSpace( + PortAddress, + AdapterInfo->PortDescriptors[i].NumberOfPorts, + FALSE + ); + + if (*(AdapterInfo->PortDescriptors[i].PortOffset) == NULL) { + + ExFreePool(Resources); + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + return NDIS_STATUS_RESOURCES; + + } + + } else { + + // + // I/O space + // + + *(AdapterInfo->PortDescriptors[i].PortOffset) = (PUCHAR)PortAddress.LowPart; + + } + + } + + } else { + + // + // The driver will not use the Raw functions, only the + // old NdisRead and NdisWrite port functions. + // + // Get the system physical address for this card. The card uses + // I/O space, except for "internal" Jazz devices which use + // memory space. + // + + addressSpace = (NewAdaptP->AdapterType == NdisInterfaceInternal) ? 0 : 1; + InitialPortAddress.LowPart = NewAdaptP->InitialPort; + InitialPortAddress.HighPart = 0; + if ( !HalTranslateBusAddress( + NewAdaptP->BusType, // InterfaceType + NewAdaptP->BusNumber, // BusNumber + InitialPortAddress, // Bus Address + &addressSpace, // AddressSpace + &PortAddress // Translated address + ) ) { + + // + // Free memory + // + + ExFreePool(Resources); + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + + + return(NDIS_STATUS_FAILURE); + } + + if (addressSpace == 0) { + + // + // memory space + // + + NewAdaptP->InitialPortMapping = MmMapIoSpace( + PortAddress, + NewAdaptP->NumberOfPorts, + FALSE + ); + + if (NewAdaptP->InitialPortMapping == NULL) { + ExFreePool(Resources); + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + return NDIS_STATUS_RESOURCES; + } + + NewAdaptP->InitialPortMapped = TRUE; + + } else { + + // + // I/O space + // + + NewAdaptP->InitialPortMapping = (PUCHAR)PortAddress.LowPart; + NewAdaptP->InitialPortMapped = FALSE; + + } + + // + // PortOffset holds the mapped address of port 0. + // + + NewAdaptP->PortOffset = NewAdaptP->InitialPortMapping - NewAdaptP->InitialPort; + + } + + } else { + + // + // Technically should not allow this, but do it until + // all drivers register their info correctly. + // + + NewAdaptP->PortOffset = 0; + + } + + } + + // + // If the driver want to be called back now, use + // supplied callback routine. + // + + if ((AdapterInfo != NULL) && (AdapterInfo->ActivateCallback != NULL)) { + + Status = (*(AdapterInfo->ActivateCallback))((NDIS_HANDLE)NewAdaptP, + MacAdapterContext, + AdapterInfo->DmaChannel + ); + + if (Status != NDIS_STATUS_SUCCESS) { + + // + // Exit + // + + ExFreePool(Resources); + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + return Status; + + } + + } + + // + // Set information from AdapterInformation. The call back + // routine can set these values. + // + + NewAdaptP->ChannelNumber = AdapterInfo->DmaChannel; + NewAdaptP->PhysicalMapRegistersNeeded = + AdapterInfo->PhysicalMapRegistersNeeded; + NewAdaptP->MaximumPhysicalMapping = + AdapterInfo->MaximumPhysicalMapping; + + + // + // Check for resource conflic on DmaChannel. + // + + if ((NewAdaptP->Master) && + (BusType != (NDIS_INTERFACE_TYPE)-1) && + (BusNumber != (ULONG)-1)) { + + if (NewAdaptP->AdapterType == NdisInterfaceIsa) { + + // + // Put the DMA channel in the resource list. + // + + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type = + CmResourceTypeDma; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition = + CmResourceShareDeviceExclusive; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags = + 0; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Dma.Channel = + NewAdaptP->ChannelNumber; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Dma.Port = + 0; + Resources->List[0].PartialResourceList.Count++; + + } + + // + // Submit Resources + // + + NtStatus = IoReportResourceUsage( + NULL, + ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver, + NULL, + 0, + NewAdaptP->DeviceObject, + Resources, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + Resources->List[0].PartialResourceList.Count, + TRUE, + &Conflict + ); + + // + // Check for conflict. + // + + if (Conflict || (NtStatus != STATUS_SUCCESS)) { + + if (Conflict) { + + // + // Log an error + // + + PIO_ERROR_LOG_PACKET errorLogEntry; + ULONG StringSize; + PWCH baseFileName; + + baseFileName = NewAdaptP->AdapterName.Buffer; + + // + // Parse out the path name, leaving only the device name. + // + + for ( i = 0; i < NewAdaptP->AdapterName.Length / sizeof(WCHAR); i++ ) { + + // + // If s points to a directory separator, set baseFileName to + // the character after the separator. + // + + if ( NewAdaptP->AdapterName.Buffer[i] == OBJ_NAME_PATH_SEPARATOR ) { + baseFileName = &(NewAdaptP->AdapterName.Buffer[++i]); + } + + } + + StringSize = NewAdaptP->AdapterName.MaximumLength - + (((ULONG)baseFileName) - ((ULONG)NewAdaptP->AdapterName.Buffer)) ; + + errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( + TmpDeviceP, + (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) + + StringSize) + ); + + if (errorLogEntry != NULL) { + + if ((NewAdaptP->Master) && + (NewAdaptP->AdapterType == Isa)){ + + errorLogEntry->ErrorCode = EVENT_NDIS_PORT_OR_DMA_CONFLICT; + + } else { + + errorLogEntry->ErrorCode = EVENT_NDIS_IO_PORT_CONFLICT; + + } + + // + // store the time + // + + errorLogEntry->MajorFunctionCode = 0; + errorLogEntry->RetryCount = 0; + errorLogEntry->UniqueErrorValue = 0; + errorLogEntry->FinalStatus = 0; + errorLogEntry->SequenceNumber = 0; + errorLogEntry->IoControlCode = 0; + + // + // Set string information + // + + if (StringSize != 0) { + + errorLogEntry->NumberOfStrings = 1; + errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET); + + RtlCopyMemory ( + ((PUCHAR)errorLogEntry) + + sizeof(IO_ERROR_LOG_PACKET), + (PVOID)baseFileName, + StringSize + ); + + } else { + + errorLogEntry->NumberOfStrings = 0; + + } + + // + // write it out + // + + IoWriteErrorLogEntry(errorLogEntry); + } + + // + // Free memory + // + + ExFreePool(Resources); + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + + return(NDIS_STATUS_RESOURCE_CONFLICT); + + } + + // + // Free memory + // + + ExFreePool(Resources); + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + + + return(NDIS_STATUS_FAILURE); + } + + } + + // + // If the device is a busmaster, we get an adapter + // object for it. + // If map registers are needed, we loop, allocating an + // adapter channel for each map register needed. + // + + if ((NewAdaptP->Master) && + (BusType != (NDIS_INTERFACE_TYPE)-1) && + (BusNumber != (ULONG)-1)) { + + // + // This is needed by HalGetAdapter. + // + DEVICE_DESCRIPTION DeviceDescription; + + // + // Returned by HalGetAdapter. + // + ULONG MapRegistersAllowed; + + // + // Returned by HalGetAdapter. + // + PADAPTER_OBJECT AdapterObject; + + // + // Map registers needed per channel. + // + ULONG MapRegistersPerChannel; + + NTSTATUS Status; + + // + // Allocate storage for holding the appropriate + // information for each map register. + // + + NewAdaptP->MapRegisters = (PMAP_REGISTER_ENTRY) + ExAllocatePoolWithTag( + NonPagedPool, + sizeof(MAP_REGISTER_ENTRY) * + NewAdaptP->PhysicalMapRegistersNeeded, + 'rmDN'); + + if (NewAdaptP->MapRegisters == (PMAP_REGISTER_ENTRY)NULL) { + + // + // Error out + // + + ExFreePool(Resources); + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + return NDIS_STATUS_RESOURCES; + + } + + // + // Use this event to tell us when NdisAllocationExecutionRoutine + // has been called. + // + + KeInitializeEvent( + &NewAdaptP->AllocationEvent, + NotificationEvent, + FALSE + ); + + + // + // Set up the device description; zero it out in case its + // size changes. + // + + RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION)); + + DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION; + DeviceDescription.Master = TRUE; + DeviceDescription.ScatterGather = TRUE; + + DeviceDescription.BusNumber = NewAdaptP->BusNumber; + DeviceDescription.DmaChannel = NewAdaptP->ChannelNumber; + DeviceDescription.InterfaceType = NewAdaptP->AdapterType; + + if (DeviceDescription.InterfaceType == NdisInterfaceIsa) { + + // + // For ISA devices, the width is based on the DMA channel: + // 0-3 == 8 bits, 5-7 == 16 bits. Timing is compatibility + // mode. + // + + if (NewAdaptP->ChannelNumber > 4) { + DeviceDescription.DmaWidth = Width16Bits; + } else { + DeviceDescription.DmaWidth = Width8Bits; + } + DeviceDescription.DmaSpeed = Compatible; + + } else if ((DeviceDescription.InterfaceType == NdisInterfaceMca) || + (DeviceDescription.InterfaceType == NdisInterfaceEisa) || + (DeviceDescription.InterfaceType == NdisInterfacePci)) + { + DeviceDescription.Dma32BitAddresses = AdapterInfo->Dma32BitAddresses; + DeviceDescription.DmaPort = 0; + + } + + DeviceDescription.MaximumLength = NewAdaptP->MaximumPhysicalMapping; + + + // + // Determine how many map registers we need per channel. + // + + MapRegistersPerChannel = + ((NewAdaptP->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2; + + // + // Get the adapter object. + // + + AdapterObject = HalGetAdapter (&DeviceDescription, &MapRegistersAllowed); + + if (AdapterObject == NULL) { + + ExFreePool(Resources); + ExFreePool(NewAdaptP->MapRegisters); + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + return NDIS_STATUS_RESOURCES; + + } + + ASSERT (MapRegistersAllowed >= MapRegistersPerChannel); + + // + // We save this to call IoFreeMapRegisters later. + // + + NewAdaptP->SystemAdapterObject = AdapterObject; + + + // + // Now loop, allocating an adapter channel each time, then + // freeing everything but the map registers. + // + + for (i=0; i<NewAdaptP->PhysicalMapRegistersNeeded; i++) { + + NewAdaptP->CurrentMapRegister = i; + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + Status = IoAllocateAdapterChannel( + AdapterObject, + NewAdaptP->DeviceObject, + MapRegistersPerChannel, + NdisAllocationExecutionRoutine, + (PVOID)NewAdaptP + ); + + KeLowerIrql(OldIrql); + + if (!NT_SUCCESS(Status)) { + +#if DBG + DbgPrint("NDIS: Failed to load driver because of\n"); + DbgPrint("NDIS: insufficient map registers.\n"); + DbgPrint("NDIS: AllocateAdapterChannel: %lx\n", Status); +#endif + + ExFreePool(Resources); + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + for (; i != 0; i--) { + IoFreeMapRegisters( + NewAdaptP->SystemAdapterObject, + NewAdaptP->MapRegisters[i-1].MapRegister, + MapRegistersPerChannel + ); + } + + KeLowerIrql(OldIrql); + + ExFreePool(NewAdaptP->MapRegisters); + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + return(NDIS_STATUS_RESOURCES); + } + + TimeoutValue.QuadPart = Int32x32To64(2 * 1000, -10000); + + // + // NdisAllocationExecutionRoutine will set this event + // when it has gotten FirstTranslationEntry. + // + + NtStatus = KeWaitForSingleObject( + &NewAdaptP->AllocationEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + NdisPrint2("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus); + ExFreePool(Resources); + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + for (; i != 0; i--) { + IoFreeMapRegisters( + NewAdaptP->SystemAdapterObject, + NewAdaptP->MapRegisters[i-1].MapRegister, + MapRegistersPerChannel + ); + } + + KeLowerIrql(OldIrql); + + ExFreePool(NewAdaptP->MapRegisters); + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + return(NDIS_STATUS_RESOURCES); + + } + + KeResetEvent( + &NewAdaptP->AllocationEvent + ); + + } + + } + + + + NdisInitializeRef(&NewAdaptP->Ref); + + + if (!NdisQueueAdapterOnMac(NewAdaptP, TmpMacP)) { + + // + // The MAC is closing, undo what we have done. + // + + ExFreePool(Resources); + if (NewAdaptP->Master) { + ULONG MapRegistersPerChannel = + ((NewAdaptP->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2; + + for (i=0; i<NewAdaptP->PhysicalMapRegistersNeeded; i++) { + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + IoFreeMapRegisters( + NewAdaptP->SystemAdapterObject, + NewAdaptP->MapRegisters[i].MapRegister, + MapRegistersPerChannel + ); + + KeLowerIrql(OldIrql); + } + + ExFreePool(NewAdaptP->MapRegisters); + } + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + return NDIS_STATUS_CLOSING; + } + + NdisMacReferencePackage(); + + // + // Add an extra reference because the wrapper is using the MAC + // + NdisReferenceAdapter(NewAdaptP); + + *NdisAdapterHandle = (NDIS_HANDLE)NewAdaptP; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + return NDIS_STATUS_SUCCESS; +} + + +NDIS_STATUS +NdisDeregisterAdapter( + IN NDIS_HANDLE NdisAdapterHandle + ) + +/*++ + +Routine Description: + + Deregisters an NDIS adapter. + +Arguments: + + NdisAdapterHandle - The handle returned by NdisRegisterAdapter. + +Return Value: + + NDIS_STATUS_SUCCESS. + +--*/ + +{ + + // + // KillAdapter does all the work. + // + + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisDeregisterAdapter\n"); + NdisPrint2(" Deregistering Adapter %s\n", + ((PNDIS_ADAPTER_BLOCK)NdisAdapterHandle)->AdapterName.Buffer); + } + IF_ERROR_CHK { + if (DbgIsNull(NdisAdapterHandle)) { + NdisPrint1("DeregisterAdapter: Null Handle\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(NdisAdapterHandle)) { + NdisPrint1("DeregisterAdapter: Handle not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + NdisKillAdapter((PNDIS_ADAPTER_BLOCK)NdisAdapterHandle); + + // + // Remove reference from wrapper + // + NdisDereferenceAdapter((PNDIS_ADAPTER_BLOCK)NdisAdapterHandle); + + NdisMacDereferencePackage(); + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeregisterAdapter\n"); + return NDIS_STATUS_SUCCESS; +} + + +VOID +NdisRegisterAdapterShutdownHandler( + IN NDIS_HANDLE NdisAdapterHandle, + IN PVOID ShutdownContext, + IN ADAPTER_SHUTDOWN_HANDLER ShutdownHandler + ) + +/*++ + +Routine Description: + + Deregisters an NDIS adapter. + +Arguments: + + NdisAdapterHandle - The handle returned by NdisRegisterAdapter. + + ShutdownContext - Context to pass the the handler, when called. + + ShutdownHandler - The Handler for the Adapter, to be called on shutdown. + +Return Value: + + NDIS_STATUS_SUCCESS. + +--*/ + +{ + PNDIS_ADAPTER_BLOCK Adapter = (PNDIS_ADAPTER_BLOCK) NdisAdapterHandle; + PNDIS_WRAPPER_CONTEXT WrapperContext = Adapter->WrapperContext; + + if (WrapperContext->ShutdownHandler == NULL) { + + // + // Store information + // + + WrapperContext->ShutdownHandler = ShutdownHandler; + WrapperContext->ShutdownContext = ShutdownContext; + + // + // Register our shutdown handler for either a system shutdown + // notification or a bugcheck. + // + + IoRegisterShutdownNotification(Adapter->DeviceObject); + +#if !defined(BUILD_FOR_3_1) + KeInitializeCallbackRecord(&WrapperContext->BugcheckCallbackRecord); + + KeRegisterBugCheckCallback( + &WrapperContext->BugcheckCallbackRecord, // callback record. + (PVOID) NdisBugcheckHandler, // callback routine. + (PVOID) WrapperContext, // free form buffer. + sizeof(NDIS_WRAPPER_CONTEXT), // buffer size. + "Ndis mac" // component id. + ); +#endif + + } +} + + +VOID +NdisDeregisterAdapterShutdownHandler( + IN NDIS_HANDLE NdisAdapterHandle + ) + +/*++ + +Routine Description: + + Deregisters an NDIS adapter. + +Arguments: + + NdisAdapterHandle - The handle returned by NdisRegisterAdapter. + +Return Value: + + NDIS_STATUS_SUCCESS. + +--*/ + +{ + PNDIS_ADAPTER_BLOCK Adapter = (PNDIS_ADAPTER_BLOCK) NdisAdapterHandle; + PNDIS_WRAPPER_CONTEXT WrapperContext = Adapter->WrapperContext; + + if (WrapperContext->ShutdownHandler != NULL) { + + // + // Clear information + // + + WrapperContext->ShutdownHandler = NULL; + + IoUnregisterShutdownNotification(Adapter->DeviceObject); + +#if !defined(BUILD_FOR_3_1) + KeDeregisterBugCheckCallback(&WrapperContext->BugcheckCallbackRecord); +#endif + + } +} + + +VOID +NdisReleaseAdapterResources( + IN NDIS_HANDLE NdisAdapterHandle + ) + +/*++ + +Routine Description: + + Informs the wrapper that the resources (such as interrupt, + I/O ports, etc.) have been shut down in some way such that + they will not interfere with other devices in the system. + +Arguments: + + NdisAdapterHandle - The handle returned by NdisRegisterAdapter. + +Return Value: + + None. + +--*/ + +{ + PCM_RESOURCE_LIST Resources; + BOOLEAN Conflict; + NTSTATUS NtStatus; + PNDIS_ADAPTER_BLOCK AdptrP = (PNDIS_ADAPTER_BLOCK)(NdisAdapterHandle); + + Resources = AdptrP->Resources; + + // + // Clear count + // + + Resources->List[0].PartialResourceList.Count = 0; + + // + // Make the call + // + + NtStatus = IoReportResourceUsage( + NULL, + AdptrP->MacHandle->NdisMacInfo->NdisWrapperDriver, + NULL, + 0, + AdptrP->DeviceObject, + Resources, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR), + TRUE, + &Conflict + ); + + + return; + +} + + +VOID +NdisWriteErrorLogEntry( + IN NDIS_HANDLE NdisAdapterHandle, + IN NDIS_ERROR_CODE ErrorCode, + IN ULONG NumberOfErrorValues, + ... + ) +/*++ + +Routine Description: + + This function allocates an I/O error log record, fills it in and writes it + to the I/O error log. + + +Arguments: + + NdisAdapterHandle - points to the adapter block. + + ErrorCode - Ndis code mapped to a string. + + NumberOfErrorValues - number of ULONGS to store for the error. + +Return Value: + + None. + + +--*/ +{ + + va_list ArgumentPointer; + + PIO_ERROR_LOG_PACKET errorLogEntry; + PNDIS_ADAPTER_BLOCK AdapterBlock = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle; + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle; + ULONG i; + ULONG StringSize; + PWCH baseFileName; + + if (AdapterBlock == NULL) { + + return; + + } + + if (AdapterBlock->DeviceObject != NULL) { + baseFileName = AdapterBlock->AdapterName.Buffer; + } else { + baseFileName = Miniport->MiniportName.Buffer; + } + + // + // Parse out the path name, leaving only the device name. + // + + for ( i = 0; + i < ((AdapterBlock->DeviceObject != NULL) ? + AdapterBlock->AdapterName.Length : + Miniport->MiniportName.Length) / sizeof(WCHAR); i++ ) { + + // + // If s points to a directory separator, set baseFileName to + // the character after the separator. + // + + if ( ((AdapterBlock->DeviceObject != NULL) ? + AdapterBlock->AdapterName.Buffer[i] : + Miniport->MiniportName.Buffer[i]) == OBJ_NAME_PATH_SEPARATOR ) { + baseFileName = ((AdapterBlock->DeviceObject != NULL) ? + &(AdapterBlock->AdapterName.Buffer[++i]) : + &(Miniport->MiniportName.Buffer[++i])); + } + + } + + StringSize = ((AdapterBlock->DeviceObject != NULL) ? + AdapterBlock->AdapterName.MaximumLength : + Miniport->MiniportName.MaximumLength) - + (((ULONG)baseFileName) - + ((AdapterBlock->DeviceObject != NULL) ? + ((ULONG)AdapterBlock->AdapterName.Buffer) : + ((ULONG)Miniport->MiniportName.Buffer))) ; + + errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( + ((AdapterBlock->DeviceObject != NULL) ? + AdapterBlock->DeviceObject : + Miniport->DeviceObject), + (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) + + NumberOfErrorValues * sizeof(ULONG) + + StringSize) + ); + + if (errorLogEntry != NULL) { + + errorLogEntry->ErrorCode = ErrorCode; + + // + // store the time + // + + errorLogEntry->MajorFunctionCode = 0; + errorLogEntry->RetryCount = 0; + errorLogEntry->UniqueErrorValue = 0; + errorLogEntry->FinalStatus = 0; + errorLogEntry->SequenceNumber = 0; + errorLogEntry->IoControlCode = 0; + + // + // Store Data + // + + errorLogEntry->DumpDataSize = (USHORT)(NumberOfErrorValues * sizeof(ULONG)); + + va_start(ArgumentPointer, NumberOfErrorValues); + + for (i = 0; i < NumberOfErrorValues; i++) { + + errorLogEntry->DumpData[i] = va_arg(ArgumentPointer, ULONG); + + } + + va_end(ArgumentPointer); + + + // + // Set string information + // + + if (StringSize != 0) { + + errorLogEntry->NumberOfStrings = 1; + errorLogEntry->StringOffset = + sizeof(IO_ERROR_LOG_PACKET) + + NumberOfErrorValues * sizeof(ULONG); + + + RtlCopyMemory ( + ((PUCHAR)errorLogEntry) + + (sizeof(IO_ERROR_LOG_PACKET) + + NumberOfErrorValues * sizeof(ULONG)), + (PVOID)baseFileName, + StringSize + ); + + } else { + + errorLogEntry->NumberOfStrings = 0; + + } + + // + // write it out + // + + IoWriteErrorLogEntry(errorLogEntry); + } + +} + + +VOID +NdisCompleteOpenAdapter( + IN NDIS_HANDLE NdisBindingContext, + IN NDIS_STATUS Status, + IN NDIS_STATUS OpenErrorStatus + ) + +{ + PNDIS_OPEN_BLOCK OpenP = (PNDIS_OPEN_BLOCK)NdisBindingContext; + PNDIS_OPEN_BLOCK TmpOpen; + + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisCompleteOpenAdapter\n"); + } + IF_ERROR_CHK { + if (!DbgIsNonPaged(NdisBindingContext)) { + NdisPrint1("NdisCompleteOpenAdapter: Handle not in NonPaged Memory\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(NdisBindingContext)) { + NdisPrint1("NdisCompleteOpenAdapter: Binding Context not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + if (Status == NDIS_STATUS_SUCCESS) { + if (!NdisFinishOpen(OpenP)) { + Status = NDIS_STATUS_CLOSING; + } + } + + (OpenP->ProtocolHandle->ProtocolCharacteristics.OpenAdapterCompleteHandler) ( + OpenP->ProtocolBindingContext, + Status, + OpenErrorStatus + ); + + if (Status != NDIS_STATUS_SUCCESS) { + + // + // Something went wrong, clean up and exit. + // + + ACQUIRE_SPIN_LOCK(&GlobalOpenListLock); + + if (GlobalOpenList == OpenP) { + + GlobalOpenList = OpenP->NextGlobalOpen; + + } else { + + TmpOpen = GlobalOpenList; + + while (TmpOpen->NextGlobalOpen != OpenP) { + + TmpOpen = TmpOpen->NextGlobalOpen; + + } + + TmpOpen->NextGlobalOpen = OpenP->NextGlobalOpen; + + } + + RELEASE_SPIN_LOCK(&GlobalOpenListLock); + + ObDereferenceObject((PVOID)OpenP->FileObject); + NdisDereferenceAdapter(OpenP->AdapterHandle); + NdisDereferenceProtocol(OpenP->ProtocolHandle); + ExFreePool((PVOID)OpenP); + + } + +} + + +VOID +NdisCompleteCloseAdapter( + IN NDIS_HANDLE NdisBindingContext, + IN NDIS_STATUS Status + ) + +{ + PNDIS_OPEN_BLOCK Open = (PNDIS_OPEN_BLOCK) NdisBindingContext; + PNDIS_OPEN_BLOCK TmpOpen; + + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisCompleteCloseAdapter\n"); + } + IF_ERROR_CHK { + if (!DbgIsNonPaged(NdisBindingContext)) { + NdisPrint1("NdisCompleteCloseAdapter: Handle not in NonPaged Memory\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(NdisBindingContext)) { + NdisPrint1("NdisCompleteCloseAdapter: Binding Context not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + + (Open->ProtocolHandle->ProtocolCharacteristics.CloseAdapterCompleteHandler) ( + Open->ProtocolBindingContext, + Status + ); + + NdisDeQueueOpenOnAdapter(Open, Open->AdapterHandle); + NdisDeQueueOpenOnProtocol(Open, Open->ProtocolHandle); + + NdisDereferenceProtocol(Open->ProtocolHandle); + NdisDereferenceAdapter(Open->AdapterHandle); + NdisFreeSpinLock(&Open->SpinLock); + + // + // This sends an IRP_MJ_CLOSE IRP. + // + + ObDereferenceObject((PVOID)(Open->FileObject)); + + // + // Remove from global list + // + ACQUIRE_SPIN_LOCK(&GlobalOpenListLock); + + if (GlobalOpenList == Open) { + + GlobalOpenList = Open->NextGlobalOpen; + + } else { + + TmpOpen = GlobalOpenList; + + while (TmpOpen->NextGlobalOpen != Open) { + + TmpOpen = TmpOpen->NextGlobalOpen; + + } + + TmpOpen->NextGlobalOpen = Open->NextGlobalOpen; + + } + + RELEASE_SPIN_LOCK(&GlobalOpenListLock); + + ExFreePool((PVOID)(NdisBindingContext)); +} + + + + +BOOLEAN +NdisReferenceRef( + IN PREFERENCE RefP + ) + +/*++ + +Routine Description: + + Adds a reference to an object. + +Arguments: + + RefP - A pointer to the REFERENCE portion of the object. + +Return Value: + + TRUE if the reference was added. + FALSE if the object was closing. + +--*/ + +{ + IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisReferenceRef\n"); + + IF_ERROR_CHK { + if (DbgIsNull(RefP)) { + NdisPrint1("NdisReferenceRef: NULL Reference address\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(RefP)) { + NdisPrint1("NdisReferenceRef: Reference not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + ACQUIRE_SPIN_LOCK(&RefP->SpinLock); + + if (RefP->Closing) { + RELEASE_SPIN_LOCK(&RefP->SpinLock); + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisReferenceRef\n"); + return FALSE; + } + + ++(RefP->ReferenceCount); + + RELEASE_SPIN_LOCK(&RefP->SpinLock); + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisReferenceRef\n"); + return TRUE; +} + +BOOLEAN +NdisDereferenceRef( + PREFERENCE RefP + ) + +/*++ + +Routine Description: + + Removes a reference to an object. + +Arguments: + + RefP - A pointer to the REFERENCE portion of the object. + +Return Value: + + TRUE if the reference count is now 0. + FALSE otherwise. + +--*/ + +{ + IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisDereferenceRef\n"); + + IF_ERROR_CHK { + if (DbgIsNull(RefP)) { + NdisPrint1("NdisDereferenceRef: NULL Reference address\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(RefP)) { + NdisPrint1("NdisDereferenceRef: Reference not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + ACQUIRE_SPIN_LOCK(&RefP->SpinLock); + --(RefP->ReferenceCount); + if (RefP->ReferenceCount == 0) { + RELEASE_SPIN_LOCK(&RefP->SpinLock); + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisDereferenceRef\n"); + return TRUE; + } + + RELEASE_SPIN_LOCK(&RefP->SpinLock); + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisDereferenceRef\n"); + return FALSE; +} + + +VOID +NdisInitializeRef( + PREFERENCE RefP + ) + +/*++ + +Routine Description: + + Initialize a reference count structure. + +Arguments: + + RefP - The structure to be initialized. + +Return Value: + + None. + +--*/ + +{ + IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisInitializeRef\n"); + + IF_ERROR_CHK { + if (DbgIsNull(RefP)) { + NdisPrint1("NdisInitializeRef: NULL Reference address\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(RefP)) { + NdisPrint1("NdisInitializeRef: Reference not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + RefP->Closing = FALSE; + RefP->ReferenceCount = 1; + NdisAllocateSpinLock(&RefP->SpinLock); + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisInitializeRef\n"); +} + +BOOLEAN +NdisCloseRef( + PREFERENCE RefP + ) + +/*++ + +Routine Description: + + Closes a reference count structure. + +Arguments: + + RefP - The structure to be closed. + +Return Value: + + FALSE if it was already closing. + TRUE otherwise. + +--*/ + +{ + IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisCloseRef\n"); + + IF_ERROR_CHK { + if (DbgIsNull(RefP)) { + NdisPrint1("NdisCloseRef: NULL Reference address\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(RefP)) { + NdisPrint1("NdisCloseRef: Reference not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + ACQUIRE_SPIN_LOCK(&RefP->SpinLock); + + if (RefP->Closing) { + RELEASE_SPIN_LOCK(&RefP->SpinLock); + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisCloseRef\n"); + return FALSE; + } + + RefP->Closing = TRUE; + + RELEASE_SPIN_LOCK(&RefP->SpinLock); + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisCloseRef\n"); + return TRUE; +} + + + +BOOLEAN +NdisQueueOpenOnProtocol( + IN PNDIS_OPEN_BLOCK OpenP, + IN PNDIS_PROTOCOL_BLOCK ProtP + ) + +/*++ + +Routine Description: + + Attaches an open block to the list of opens for a protocol. + +Arguments: + + OpenP - The open block to be queued. + ProtP - The protocol block to queue it to. + +Return Value: + + TRUE if the operation is successful. + FALSE if the protocol is closing. + +--*/ + +{ + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisQueueOpenOnProtocol\n"); + NdisPrint2(" Protocol: %wZ\n",&ProtP->ProtocolCharacteristics.Name); + } + + IF_ERROR_CHK { + if (DbgIsNull(OpenP)) { + NdisPrint1("NdisQueueOpenOnProtocol: Null Open Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(OpenP)) { + NdisPrint1("NdisQueueOpenOnProtocol: Open Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + + if (DbgIsNull(ProtP)) { + NdisPrint1("NdisQueueOpenOnProtocol: Null Protocol Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(ProtP)) { + NdisPrint1("NdisQueueOpenOnProtocol: Protocol Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + + } + ACQUIRE_SPIN_LOCK(&ProtP->Ref.SpinLock); + + // + // Make sure the protocol is not closing. + // + + if (ProtP->Ref.Closing) { + RELEASE_SPIN_LOCK(&ProtP->Ref.SpinLock); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueOpenOnProtocol\n"); + return FALSE; + } + + + // + // Attach this open at the head of the queue. + // + + OpenP->ProtocolNextOpen = ProtP->OpenQueue; + ProtP->OpenQueue = OpenP; + + + RELEASE_SPIN_LOCK(&ProtP->Ref.SpinLock); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueOpenOnProtocol\n"); + return TRUE; +} + +VOID +NdisDeQueueOpenOnProtocol( + IN PNDIS_OPEN_BLOCK OpenP, + IN PNDIS_PROTOCOL_BLOCK ProtP + ) + +/*++ + +Routine Description: + + Detaches an open block from the list of opens for a protocol. + +Arguments: + + OpenP - The open block to be dequeued. + ProtP - The protocol block to dequeue it from. + +Return Value: + + None. + +--*/ + +{ + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisDeQueueOpenOnProtocol\n"); + NdisPrint2(" Protocol: %wZ\n",&ProtP->ProtocolCharacteristics.Name); + } + + IF_ERROR_CHK { + if (DbgIsNull(OpenP)) { + NdisPrint1("NdisDeQueueOpenOnProtocol: Null Open Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(OpenP)) { + NdisPrint1("NdisDeQueueOpenOnProtocol: Open Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + + if (DbgIsNull(ProtP)) { + NdisPrint1("NdisDeQueueOpenOnProtocol: Null Protocol Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(ProtP)) { + NdisPrint1("NdisDeQueueOpenOnProtocol: Protocol Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + + } + + ACQUIRE_SPIN_LOCK(&ProtP->Ref.SpinLock); + + // + // Find the open on the queue, and remove it. + // + + if (ProtP->OpenQueue == OpenP) { + ProtP->OpenQueue = OpenP->ProtocolNextOpen; + } else { + PNDIS_OPEN_BLOCK PP = ProtP->OpenQueue; + + while (PP->ProtocolNextOpen != OpenP) { + PP = PP->ProtocolNextOpen; + } + + PP->ProtocolNextOpen = PP->ProtocolNextOpen->ProtocolNextOpen; + } + + RELEASE_SPIN_LOCK(&ProtP->Ref.SpinLock); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeQueueOpenOnProtocol\n"); +} + +VOID +NdisDeQueueOpenOnMiniport( + IN PNDIS_M_OPEN_BLOCK OpenP, + IN PNDIS_MINIPORT_BLOCK Miniport + ) + +/*++ + +Routine Description: + + Detaches an open block from the list of opens for a Miniport. + +Arguments: + + OpenP - The open block to be dequeued. + Miniport - The Miniport block to dequeue it from. + +Return Value: + + None. + +--*/ + +{ + ACQUIRE_SPIN_LOCK(&Miniport->Ref.SpinLock); + + OpenP->References--; + + // + // Find the open on the queue, and remove it. + // + + if (Miniport->OpenQueue == OpenP) { + Miniport->OpenQueue = OpenP->MiniportNextOpen; + } else { + PNDIS_M_OPEN_BLOCK PP = Miniport->OpenQueue; + + while (PP->MiniportNextOpen != OpenP) { + PP = PP->MiniportNextOpen; + } + + PP->MiniportNextOpen = PP->MiniportNextOpen->MiniportNextOpen; + } + + RELEASE_SPIN_LOCK(&Miniport->Ref.SpinLock); +} + + + +BOOLEAN +NdisFinishOpen( + IN PNDIS_OPEN_BLOCK OpenP + ) + +/*++ + +Routine Description: + + Performs the final functions of NdisOpenAdapter. Called when + MacOpenAdapter is done. + +Arguments: + + OpenP - The open block to finish up. + +Return Value: + + FALSE if the adapter or the protocol is closing. + TRUE otherwise. + +--*/ + +{ + // + // Add us to the adapter's queue of opens. + // + + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisFinishOpen\n"); + NdisPrint3(" Protocol %wZ is being bound to Adapter %wZ\n", + &(OpenP->ProtocolHandle)->ProtocolCharacteristics.Name, + &OpenP->AdapterHandle->AdapterName); + } + IF_ERROR_CHK { + if (DbgIsNull(OpenP)) { + NdisPrint1("NdisFinishOpen: Null Open Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(OpenP)) { + NdisPrint1("NdisFinishOpen: Open Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + if (!NdisQueueOpenOnAdapter(OpenP, OpenP->AdapterHandle)) { + + // + // The adapter is closing. + // + // Call MacCloseAdapter(), don't worry about it completing. + // + + (OpenP->MacHandle->MacCharacteristics.CloseAdapterHandler) ( + OpenP->MacBindingHandle); + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisFinishOpen\n"); + return FALSE; + } + + + // + // Add us to the protocol's queue of opens. + // + + if (!NdisQueueOpenOnProtocol(OpenP, OpenP->ProtocolHandle)) { + + // + // The protocol is closing. + // + // Call MacCloseAdapter(), don't worry about it completing. + // + + (OpenP->MacHandle->MacCharacteristics.CloseAdapterHandler) ( + OpenP->MacBindingHandle); + + // + // Undo the queueing we just did. + // + + NdisDeQueueOpenOnAdapter(OpenP, OpenP->AdapterHandle); + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisFinishOpen\n"); + return FALSE; + } + + + // + // Both queueings succeeded. + // + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisFinishOpen\n"); + return TRUE; +} + +NTSTATUS +NdisCreateIrpHandler( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) + +/*++ + +Routine Description: + + The handle for IRP_MJ_CREATE IRPs. + +Arguments: + + DeviceObject - The adapter's device object. + Irp - The IRP. + +Return Value: + + STATUS_SUCCESS if it should be. + +--*/ + +{ + + PIO_STACK_LOCATION IrpSp; + PFILE_FULL_EA_INFORMATION IrpEaInfo; + PNDIS_USER_OPEN_CONTEXT OpenContext; + NTSTATUS Status = STATUS_SUCCESS; + PNDIS_ADAPTER_BLOCK AdapterBlock; + BOOLEAN IsAMiniport; + + IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisCreateIrpHandler\n"); + IF_ERROR_CHK { + if (DbgIsNull(Irp)) { + NdisPrint1(": Null Irp\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(Irp)) { + NdisPrint1(": Irp not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + AdapterBlock = (PNDIS_ADAPTER_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1); + IsAMiniport = (AdapterBlock->DeviceObject == NULL); + IrpSp = IoGetCurrentIrpStackLocation (Irp); + IrpEaInfo = (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer; + + if (IrpEaInfo == NULL) { + + // + // This is a user-mode open, do whatever. + // + + OpenContext = (PNDIS_USER_OPEN_CONTEXT) + ExAllocatePoolWithTag(NonPagedPool, sizeof(NDIS_USER_OPEN_CONTEXT), ' DN'); + + if (OpenContext == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + + } else { + + OpenContext->DeviceObject = DeviceObject; + + OpenContext->AdapterBlock = AdapterBlock; + OpenContext->OidCount = 0; + OpenContext->OidArray = NULL; + + IrpSp->FileObject->FsContext = (PVOID)OpenContext; + IrpSp->FileObject->FsContext2 = (PVOID)NDIS_OPEN_QUERY_STATISTICS; + + if (IsAMiniport) { + Status = NdisMQueryOidList((PNDIS_M_USER_OPEN_CONTEXT)OpenContext, Irp); + } else { + Status = NdisQueryOidList(OpenContext, Irp); + } + + if (Status != STATUS_SUCCESS) { + ExFreePool (OpenContext); + } + + } + + } else { + + // + // This is an internal open, verify the EA. + // + + if ((IrpEaInfo->EaNameLength != sizeof(NdisInternalEaName)) || + (RtlCompareMemory(IrpEaInfo->EaName, NdisInternalEaName, sizeof(NdisInternalEaName)) != + sizeof(NdisInternalEaName)) || + (IrpEaInfo->EaValueLength != sizeof(NdisInternalEaValue)) || + (RtlCompareMemory(&IrpEaInfo->EaName[IrpEaInfo->EaNameLength+1], + NdisInternalEaValue, sizeof(NdisInternalEaValue)) != + sizeof(NdisInternalEaValue))) { + + // + // Something is wrong, reject it. + // + + Status = STATUS_UNSUCCESSFUL; + + } else { + + // + // It checks out, just return success and everything + // else is done directly using the device object. + // + + IrpSp->FileObject->FsContext = NULL; + IrpSp->FileObject->FsContext2 = (PVOID)NDIS_OPEN_INTERNAL; + + } + } + + Irp->IoStatus.Status = Status; + + IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); + + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisCreateIrplHandler\n"); + return Status; +} + + + +NTSTATUS +NdisQueryOidList( + PNDIS_USER_OPEN_CONTEXT OpenContext, + PIRP Irp + ) + +/*++ + +Routine Description: + + This routine will take care of querying the complete OID + list for the MAC and filling in OpenContext->OidArray + with the ones that are statistics. It blocks when the + MAC pends and so is synchronous. + +Arguments: + + OpenContext - The open context. + Irp = The IRP that the open was done on (used at completion + to distinguish the request). + +Return Value: + + STATUS_SUCCESS if it should be. + +--*/ + +{ + + NDIS_QUERY_OPEN_REQUEST OpenRequest; + NDIS_STATUS NdisStatus; + PNDIS_OID TmpBuffer; + ULONG TmpBufferLength; + UINT i, j; + + // + // First query the OID list with no buffer, to find out + // how big it should be. + // + + KeInitializeEvent( + &OpenRequest.Event, + NotificationEvent, + FALSE + ); + + OpenRequest.Irp = Irp; + + OpenRequest.Request.RequestType = NdisRequestQueryStatistics; + OpenRequest.Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_SUPPORTED_LIST; + OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBuffer = NULL; + OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBufferLength = 0; + OpenRequest.Request.DATA.QUERY_INFORMATION.BytesWritten = 0; + OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded = 0; + + NdisStatus = + (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler) ( + OpenContext->AdapterBlock->MacAdapterContext, + &OpenRequest.Request); + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + KeWaitForSingleObject( + &OpenRequest.Event, + Executive, + KernelMode, + TRUE, + (PLARGE_INTEGER)NULL + ); + + NdisStatus = OpenRequest.NdisStatus; + + } else if ((NdisStatus != NDIS_STATUS_INVALID_LENGTH) && + (NdisStatus != NDIS_STATUS_BUFFER_TOO_SHORT)) { + + return(NdisStatus); + + } + + // + // Now we know how much is needed, allocate temp storage... + // + + TmpBufferLength = OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded; + TmpBuffer = ExAllocatePoolWithTag(NonPagedPool, TmpBufferLength, ' DN'); + + if (TmpBuffer == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // ...and query the real list. + // + + KeResetEvent( + &OpenRequest.Event + ); + + + OpenRequest.Request.RequestType = NdisRequestQueryStatistics; + OpenRequest.Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_SUPPORTED_LIST; + OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBuffer = TmpBuffer; + OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBufferLength = TmpBufferLength; + OpenRequest.Request.DATA.QUERY_INFORMATION.BytesWritten = 0; + OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded = 0; + + NdisStatus = + (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler) ( + OpenContext->AdapterBlock->MacAdapterContext, + &OpenRequest.Request); + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + KeWaitForSingleObject( + &OpenRequest.Event, + Executive, + KernelMode, + TRUE, + (PLARGE_INTEGER)NULL + ); + + NdisStatus = OpenRequest.NdisStatus; + + } + + ASSERT (NdisStatus == NDIS_STATUS_SUCCESS); + + + // + // Now go through the buffer, counting the statistics OIDs. + // + + for (i=0; i<TmpBufferLength/sizeof(NDIS_OID); i++) { + if ((TmpBuffer[i] & 0x00ff0000) == 0x00020000) { + ++OpenContext->OidCount; + } + } + + // + // Now allocate storage for the real OID array. + // + + OpenContext->OidArray = ExAllocatePoolWithTag (NonPagedPool, OpenContext->OidCount * sizeof(NDIS_OID), ' DN'); + + if (OpenContext->OidArray == NULL) { + ExFreePool (TmpBuffer); + return STATUS_INSUFFICIENT_RESOURCES; + } + + + // + // Now go through the buffer, copying the statistics OIDs. + // + + j = 0; + for (i=0; i<TmpBufferLength/sizeof(NDIS_OID); i++) { + + if ((TmpBuffer[i] & 0x00ff0000) == 0x00020000) { + OpenContext->OidArray[j] = TmpBuffer[i]; + ++j; + } + } + + ASSERT (j == OpenContext->OidCount); + + ExFreePool (TmpBuffer); + return STATUS_SUCCESS; +} + +#define NDIS_STATISTICS_HEADER_SIZE FIELD_OFFSET(NDIS_STATISTICS_VALUE,Data[0]) + + + +NTSTATUS +NdisDeviceControlIrpHandler( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) + +/*++ + +Routine Description: + + The handle for IRP_MJ_DEVICE_CONTROL IRPs. + +Arguments: + + DeviceObject - The adapter's device object. + Irp - The IRP. + +Return Value: + + STATUS_SUCCESS if it should be. + +--*/ + +{ + + PIO_STACK_LOCATION IrpSp; + PNDIS_USER_OPEN_CONTEXT OpenContext; + PNDIS_QUERY_GLOBAL_REQUEST GlobalRequest; + PNDIS_QUERY_ALL_REQUEST AllRequest; + NDIS_STATUS NdisStatus; + UINT CurrentOid; + ULONG BytesWritten, BytesWrittenThisOid; + PUCHAR Buffer; + ULONG BufferLength; + NTSTATUS Status = STATUS_SUCCESS; + PNDIS_MINIPORT_BLOCK Miniport; + BOOLEAN LocalLock; + KIRQL OldIrql; + + IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisDeviceControlIrpHandler\n"); + IF_ERROR_CHK { + if (DbgIsNull(Irp)) { + NdisPrint1(": Null Irp\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(Irp)) { + NdisPrint1(": Irp not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + IoMarkIrpPending (Irp); + Irp->IoStatus.Status = STATUS_PENDING; + Irp->IoStatus.Information = 0; + IrpSp = IoGetCurrentIrpStackLocation (Irp); + + if (IrpSp->FileObject->FsContext2 != (PVOID)NDIS_OPEN_QUERY_STATISTICS) { + return STATUS_UNSUCCESSFUL; + } + + switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) { + + case IOCTL_NDIS_QUERY_GLOBAL_STATS: + + // + // Allocate a request. + // + + OpenContext = IrpSp->FileObject->FsContext; + GlobalRequest = (PNDIS_QUERY_GLOBAL_REQUEST) + ExAllocatePoolWithTag(NonPagedPool, sizeof(NDIS_QUERY_GLOBAL_REQUEST), ' DN'); + + if (GlobalRequest == NULL) { + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + GlobalRequest->Irp = Irp; + + if (OpenContext->AdapterBlock->DeviceObject == NULL) { + + Miniport = (PNDIS_MINIPORT_BLOCK)(OpenContext->AdapterBlock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + ACQUIRE_SPIN_LOCK_DPC(&(Miniport->Lock)); + LOCK_MINIPORT(Miniport, LocalLock); + + } else { + + Miniport = NULL; + + } + + // + // Fill in the NDIS request. + // + + GlobalRequest->Request.RequestType = NdisRequestQueryStatistics; + GlobalRequest->Request.DATA.QUERY_INFORMATION.Oid = + *((PULONG)(Irp->AssociatedIrp.SystemBuffer)); + GlobalRequest->Request.DATA.QUERY_INFORMATION.InformationBuffer = + MmGetSystemAddressForMdl (Irp->MdlAddress); + GlobalRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength = + MmGetMdlByteCount (Irp->MdlAddress); + GlobalRequest->Request.DATA.QUERY_INFORMATION.BytesWritten = 0; + GlobalRequest->Request.DATA.QUERY_INFORMATION.BytesNeeded = 0; + + + if (Miniport != NULL) { + PNDIS_REQUEST_RESERVED Reserved; + + Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(&(GlobalRequest->Request)); + Reserved->Next = NULL; + Miniport->LastPendingRequest = &(GlobalRequest->Request); + + if (Miniport->FirstPendingRequest == NULL) { + + Miniport->FirstPendingRequest = &(GlobalRequest->Request); + + } else { + + PNDIS_RESERVED_FROM_PNDIS_REQUEST(Miniport->LastPendingRequest)->Next = + &(GlobalRequest->Request); + + } + + if (Miniport->MiniportRequest == NULL) { + + Miniport->RunDoRequests = TRUE; + Miniport->ProcessOddDeferredStuff = TRUE; + + + } + + // + // If we were able to grab the local lock then we can do some + // deferred processing now. + // + + if ( LocalLock ) { + if (!Miniport->ProcessingDeferred) { + MiniportProcessDeferred(Miniport); + } + } + + UNLOCK_MINIPORT(Miniport, LocalLock); + RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock)); + KeLowerIrql(OldIrql); + + } else { + + // + // Pass the request to the MAC. + // + + NdisStatus = + (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler) ( + OpenContext->AdapterBlock->MacAdapterContext, + &GlobalRequest->Request); + + // + // NdisCompleteQueryStatistics handles the completion. + // + + if (NdisStatus != NDIS_STATUS_PENDING) { + NdisCompleteQueryStatistics( + (NDIS_HANDLE)OpenContext->AdapterBlock, + &GlobalRequest->Request, + NdisStatus); + } + + } + + Status = STATUS_PENDING; + + break; + + case IOCTL_NDIS_QUERY_ALL_STATS: + + + // + // Allocate a request. + // + + OpenContext = IrpSp->FileObject->FsContext; + AllRequest = (PNDIS_QUERY_ALL_REQUEST) + ExAllocatePoolWithTag(NonPagedPool, sizeof(NDIS_QUERY_ALL_REQUEST), ' DN'); + + if (AllRequest == NULL) { + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + if (OpenContext->AdapterBlock->DeviceObject == NULL) { + + Miniport = (PNDIS_MINIPORT_BLOCK)(OpenContext->AdapterBlock); + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + ACQUIRE_SPIN_LOCK_DPC(&(Miniport->Lock)); + LOCK_MINIPORT(Miniport, LocalLock); + + } else { + + Miniport = NULL; + + } + + AllRequest->Irp = Irp; + + Buffer = (PUCHAR)MmGetSystemAddressForMdl (Irp->MdlAddress); + BufferLength = MmGetMdlByteCount (Irp->MdlAddress); + BytesWritten = 0; + + KeInitializeEvent( + &AllRequest->Event, + NotificationEvent, + FALSE + ); + + NdisStatus = NDIS_STATUS_SUCCESS; + + for (CurrentOid = 0; CurrentOid<OpenContext->OidCount; CurrentOid++) { + + // + // We need room for an NDIS_STATISTICS_VALUE (OID, + // Length, Data). + // + + if (BufferLength < (ULONG)NDIS_STATISTICS_HEADER_SIZE) { + NdisStatus = NDIS_STATUS_INVALID_LENGTH; + break; + } + + AllRequest->Request.RequestType = NdisRequestQueryStatistics; + + AllRequest->Request.DATA.QUERY_INFORMATION.Oid = + OpenContext->OidArray[CurrentOid]; + AllRequest->Request.DATA.QUERY_INFORMATION.InformationBuffer = + Buffer + NDIS_STATISTICS_HEADER_SIZE; + AllRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength = + BufferLength - NDIS_STATISTICS_HEADER_SIZE; + + AllRequest->Request.DATA.QUERY_INFORMATION.BytesWritten = 0; + AllRequest->Request.DATA.QUERY_INFORMATION.BytesNeeded = 0; + + if (Miniport != NULL) { + + PNDIS_REQUEST_RESERVED Reserved; + + Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(&(AllRequest->Request)); + Reserved->Next = NULL; + Miniport->LastPendingRequest = &(AllRequest->Request); + + if (Miniport->FirstPendingRequest == NULL) { + + Miniport->FirstPendingRequest = &(AllRequest->Request); + + } else { + + PNDIS_RESERVED_FROM_PNDIS_REQUEST(Miniport->LastPendingRequest)->Next = + &(AllRequest->Request); + + } + + if (Miniport->MiniportRequest == NULL) { + + Miniport->RunDoRequests = TRUE; + Miniport->ProcessOddDeferredStuff = TRUE; + + } + + // + // If we were able to grab the local lock then we can do some + // deferred processing now. + // + + if ( LocalLock ) { + if (!Miniport->ProcessingDeferred) { + MiniportProcessDeferred(Miniport); + } + } + + NdisStatus = NDIS_STATUS_PENDING; + + } else { + + NdisStatus = + (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler) ( + OpenContext->AdapterBlock->MacAdapterContext, + &AllRequest->Request); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + if (Miniport != NULL) { + UNLOCK_MINIPORT(Miniport, LocalLock); + RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock)); + KeLowerIrql(OldIrql); + } + + // + // The completion routine will set NdisRequestStatus. + // + + KeWaitForSingleObject( + &AllRequest->Event, + Executive, + KernelMode, + TRUE, + (PLARGE_INTEGER)NULL + ); + + NdisStatus = AllRequest->NdisStatus; + + if (Miniport != NULL) { + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + ACQUIRE_SPIN_LOCK_DPC(&(Miniport->Lock)); + LOCK_MINIPORT(Miniport, LocalLock); + } + + } + + if (NdisStatus == NDIS_STATUS_SUCCESS) { + + PNDIS_STATISTICS_VALUE StatisticsValue = + (PNDIS_STATISTICS_VALUE)Buffer; + + // + // Create the equivalent of an NDIS_STATISTICS_VALUE + // element for this OID value (the data itself was + // already written in the right place. + // + + StatisticsValue->Oid = OpenContext->OidArray[CurrentOid]; + StatisticsValue->DataLength = AllRequest->Request.DATA.QUERY_INFORMATION.BytesWritten; + + // + // Advance our pointers. + // + + BytesWrittenThisOid = + AllRequest->Request.DATA.QUERY_INFORMATION.BytesWritten + + NDIS_STATISTICS_HEADER_SIZE; + Buffer += BytesWrittenThisOid; + BufferLength -= BytesWrittenThisOid; + BytesWritten += BytesWrittenThisOid; + + } else { + + break; + + } + + KeResetEvent( + &AllRequest->Event + ); + + } + + if (Miniport != NULL) { + + UNLOCK_MINIPORT(Miniport, LocalLock); + RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock)); + KeLowerIrql(OldIrql); + + } + + if (NdisStatus == NDIS_STATUS_INVALID_LENGTH) { + Status = STATUS_BUFFER_OVERFLOW; + } else if (NdisStatus != NDIS_STATUS_SUCCESS) { + Status = STATUS_UNSUCCESSFUL; + } + + Irp->IoStatus.Information = BytesWritten; + Irp->IoStatus.Status = Status; + + break; + + default: + + Status = STATUS_NOT_IMPLEMENTED; + break; + + } + + if (Status != STATUS_PENDING) { + IrpSp->Control &= ~SL_PENDING_RETURNED; + Irp->IoStatus.Status = Status; + IoCompleteRequest (Irp, IO_NETWORK_INCREMENT); + } + + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisCreateIrplHandler\n"); + return Status; +} + + + +VOID +NdisCompleteQueryStatistics( + IN NDIS_HANDLE NdisAdapterHandle, + IN PNDIS_REQUEST NdisRequest, + IN NDIS_STATUS Status + ) + +/*++ + +Routine Description: + + This routine is called by MACs when they have completed + processing of a MacQueryGlobalStatistics call. + +Arguments: + + NdisAdapterHandle - The NDIS adapter context. + NdisRequest - The request that has been completed. + Status - The status of the request. + +Return Value: + + None. + +--*/ + +{ + + PNDIS_ADAPTER_BLOCK AdapterBlock = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle; + PNDIS_QUERY_GLOBAL_REQUEST GlobalRequest; + PNDIS_QUERY_ALL_REQUEST AllRequest; + PNDIS_QUERY_OPEN_REQUEST OpenRequest; + PIRP Irp; + PIO_STACK_LOCATION IrpSp; + + // + // Rely on the fact that all our request structures start with + // the same fields: Irp followed by the NdisRequest. + // + + GlobalRequest = CONTAINING_RECORD (NdisRequest, NDIS_QUERY_GLOBAL_REQUEST, Request); + Irp = GlobalRequest->Irp; + IrpSp = IoGetCurrentIrpStackLocation (Irp); + + switch (IrpSp->MajorFunction) { + + case IRP_MJ_CREATE: + + // + // This request is one of the ones made during an open, + // while we are trying to determine the OID list. We + // set the event we are waiting for, the open code + // takes care of the rest. + // + + OpenRequest = (PNDIS_QUERY_OPEN_REQUEST)GlobalRequest; + + OpenRequest->NdisStatus = Status; + KeSetEvent( + &OpenRequest->Event, + 0L, + FALSE); + + break; + + case IRP_MJ_DEVICE_CONTROL: + + // + // This is a real user request, process it as such. + // + + switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) { + + case IOCTL_NDIS_QUERY_GLOBAL_STATS: + + // + // A single query, complete the IRP. + // + + Irp->IoStatus.Information = + NdisRequest->DATA.QUERY_INFORMATION.BytesWritten; + + if (Status == NDIS_STATUS_SUCCESS) { + Irp->IoStatus.Status = STATUS_SUCCESS; + } else if (Status == NDIS_STATUS_INVALID_LENGTH) { + Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; + } else { + Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; // what else ? + } + + IoCompleteRequest (Irp, IO_NETWORK_INCREMENT); + + ExFreePool (GlobalRequest); + break; + + case IOCTL_NDIS_QUERY_ALL_STATS: + + // + // An "all" query. + // + + AllRequest = (PNDIS_QUERY_ALL_REQUEST)GlobalRequest; + + AllRequest->NdisStatus = Status; + KeSetEvent( + &AllRequest->Event, + 0L, + FALSE); + + break; + + } + + break; + + } + +} + + + +NTSTATUS +NdisCloseIrpHandler( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) + +/*++ + +Routine Description: + + The handle for IRP_MJ_CLOSE IRPs. + +Arguments: + + DeviceObject - The adapter's device object. + Irp - The IRP. + +Return Value: + + STATUS_SUCCESS if it should be. + +--*/ + +{ + + PIO_STACK_LOCATION IrpSp; + PNDIS_USER_OPEN_CONTEXT OpenContext; + NTSTATUS Status = STATUS_SUCCESS; + + + IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisCloseIrpHandler\n"); + IF_ERROR_CHK { + if (DbgIsNull(Irp)) { + NdisPrint1(": Null Irp\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(Irp)) { + NdisPrint1(": Irp not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + IrpSp = IoGetCurrentIrpStackLocation (Irp); + + if (IrpSp->FileObject->FsContext2 == (PVOID)NDIS_OPEN_INTERNAL) { + + // + // An internal open, nothing needs to be done. + // + + } else { + + // + // Free the query context. + // + + ASSERT (IrpSp->FileObject->FsContext2 == (PVOID)NDIS_OPEN_QUERY_STATISTICS); + + OpenContext = IrpSp->FileObject->FsContext; + ExFreePool (OpenContext->OidArray); + ExFreePool (OpenContext); + + } + + Irp->IoStatus.Status = Status; + + IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); + + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisCloseIrplHandler\n"); + return Status; +} + +NTSTATUS +NdisSuccessIrpHandler( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) + +/*++ + +Routine Description: + + The "success handler" for any IRPs that we can ignore. + +Arguments: + + DeviceObject - The adapter's device object. + Irp - The IRP. + +Return Value: + + Always STATUS_SUCCESS. + +--*/ + +{ + + DeviceObject; // to avoid "unused formal parameter" warning + + IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisSuccessIrplHandler\n"); + IF_ERROR_CHK { + if (DbgIsNull(Irp)) { + NdisPrint1(": Null Irp\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(Irp)) { + NdisPrint1(": Irp not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + Irp->IoStatus.Status = STATUS_SUCCESS; + + IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); + + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisSuccessIrplHandler\n"); + return STATUS_SUCCESS; +} + + +VOID +NdisKillOpenAndNotifyProtocol( + IN PNDIS_OPEN_BLOCK OldOpenP + ) + +/*++ + +Routine Description: + + Closes an open and notifies the protocol; used when the + close is internally generated by the NDIS wrapper (due to + a protocol or adapter deregistering with outstanding opens). + +Arguments: + + OldOpenP - The open to be closed. + +Return Value: + + None. + +--*/ + +{ + // + // Indicate the status to the protocol. + // + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisKillOpenAndNotifyProtocol\n"); + NdisPrint3(" Closing Adapter %wZ and notifying Protocol %wZ\n", + &OldOpenP->AdapterHandle->AdapterName, + &(OldOpenP->ProtocolHandle)->ProtocolCharacteristics.Name); + } + + IF_ERROR_CHK { + if (DbgIsNull(OldOpenP)) { + NdisPrint1("NdisKillOpenAndNotifyProtocol: Null Open Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(OldOpenP)) { + NdisPrint1("NdisKillOpenAndNotifyProtocol: Open Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + (OldOpenP->ProtocolHandle->ProtocolCharacteristics.StatusHandler) ( + OldOpenP->ProtocolBindingContext, + NDIS_STATUS_CLOSING, + NULL, + 0); // need real reason here + + + // + // Now KillOpen will do the real work. + // + + if (OldOpenP->AdapterHandle->DeviceObject == NULL) { + // + // Miniport + // + (void)NdisMKillOpen(OldOpenP); + } else { + // + // Mac + // + (void)NdisKillOpen(OldOpenP); + } + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillOpenAndNotifyProtocol\n"); +} + + +BOOLEAN +NdisKillOpen( + PNDIS_OPEN_BLOCK OldOpenP + ) + +/*++ + +Routine Description: + + Closes an open. Used when NdisCloseAdapter is called, and also + for internally generated closes. + +Arguments: + + OldOpenP - The open to be closed. + +Return Value: + + TRUE if the open finished, FALSE if it pended. + +--*/ + +{ + PNDIS_OPEN_BLOCK TmpOpen; + PFILE_OBJECT FileObject = OldOpenP->FileObject; + + + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisKillOpen\n"); + NdisPrint3(" Closing Adapter %wZ as requested by %wZ\n", + &OldOpenP->AdapterHandle->AdapterName, + &(OldOpenP->ProtocolHandle)->ProtocolCharacteristics.Name); + } + IF_ERROR_CHK { + if (DbgIsNull(OldOpenP)) { + NdisPrint1("NdisKillOpen: Null Open Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(OldOpenP)) { + NdisPrint1("NdisKillOpen: Open Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + ACQUIRE_SPIN_LOCK(&OldOpenP->SpinLock); + + // + // See if this open is already closing. + // + + if (OldOpenP->Closing) { + RELEASE_SPIN_LOCK(&OldOpenP->SpinLock); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillOpen\n"); + return TRUE; + } + + + // + // Indicate to others that this open is closing. + // + + OldOpenP->Closing = TRUE; + RELEASE_SPIN_LOCK(&OldOpenP->SpinLock); + + // + // Inform the MAC. + // + + if ((OldOpenP->MacHandle->MacCharacteristics.CloseAdapterHandler) ( + OldOpenP->MacBindingHandle) == NDIS_STATUS_PENDING) { + + // + // MacCloseAdapter pended, will complete later. + // + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillOpen\n"); + return FALSE; + } + + // + // Remove the reference for this open. + // + ObDereferenceObject((PVOID)FileObject); + + // + // Remove us from the adapter and protocol open queues. + // + + NdisDeQueueOpenOnAdapter(OldOpenP, OldOpenP->AdapterHandle); + NdisDeQueueOpenOnProtocol(OldOpenP, OldOpenP->ProtocolHandle); + + + // + // MacCloseAdapter did not pend; we ignore the return code. + // + + NdisDereferenceProtocol(OldOpenP->ProtocolHandle); + NdisDereferenceAdapter(OldOpenP->AdapterHandle); + + NdisFreeSpinLock(&OldOpenP->SpinLock); + + // + // Remove from global adpater list + // + ACQUIRE_SPIN_LOCK(&GlobalOpenListLock); + + if (GlobalOpenList == OldOpenP) { + + GlobalOpenList = OldOpenP->NextGlobalOpen; + + } else { + + TmpOpen = GlobalOpenList; + + while (TmpOpen->NextGlobalOpen != OldOpenP) { + + TmpOpen = TmpOpen->NextGlobalOpen; + + } + + TmpOpen->NextGlobalOpen = OldOpenP->NextGlobalOpen; + + } + + RELEASE_SPIN_LOCK(&GlobalOpenListLock); + + ExFreePool((PVOID)OldOpenP); + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillOpen\n"); + return TRUE; +} + + +BOOLEAN +NdisQueueAdapterOnMac( + IN PNDIS_ADAPTER_BLOCK AdaptP, + IN PNDIS_MAC_BLOCK MacP + ) + +/*++ + +Routine Description: + + Adds an adapter to a list of adapters for a MAC. + +Arguments: + + AdaptP - The adapter block to queue. + MacP - The MAC block to queue it to. + +Return Value: + + FALSE if the MAC is closing. + TRUE otherwise. + +--*/ + +{ + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisQueueAdapterOnMac\n"); + NdisPrint2(" Adapter %wZ being added to MAC list\n",&AdaptP->MacHandle->MacCharacteristics.Name); + } + + IF_ERROR_CHK { + if (DbgIsNull(AdaptP)) { + NdisPrint1("NdisQueueAdapterOnMac: Null Adapter Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(AdaptP)) { + NdisPrint1("NdisQueueAdapterOnMac: Adapter Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + if (DbgIsNull(MacP)) { + NdisPrint1("NdisQueueAdapterOnMac: Null Mac Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(MacP)) { + NdisPrint1("NdisQueueAdapterOnMac: Mac Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + ACQUIRE_SPIN_LOCK(&MacP->Ref.SpinLock); + + // + // Make sure the MAC is not closing. + // + + if (MacP->Ref.Closing) { + RELEASE_SPIN_LOCK(&MacP->Ref.SpinLock); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueAdapterOnMac\n"); + return FALSE; + } + + + // + // Add this adapter at the head of the queue + // + + AdaptP->NextAdapter = MacP->AdapterQueue; + MacP->AdapterQueue = AdaptP; + + RELEASE_SPIN_LOCK(&MacP->Ref.SpinLock); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueAdapterOnMac\n"); + return TRUE; +} + + +VOID +NdisDeQueueAdapterOnMac( + PNDIS_ADAPTER_BLOCK AdaptP, + PNDIS_MAC_BLOCK MacP + ) + +/*++ + +Routine Description: + + Removes an adapter from a list of adapters for a MAC. + +Arguments: + + AdaptP - The adapter block to dequeue. + MacP - The MAC block to dequeue it from. + +Return Value: + + None. + +--*/ + +{ + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisDeQueueAdapterOnMac\n"); + NdisPrint2(" Adapter %wZ being removed from MAC list\n",&AdaptP->MacHandle->MacCharacteristics.Name); + } + IF_ERROR_CHK { + if (DbgIsNull(AdaptP)) { + NdisPrint1("NdisDeQueueAdapterOnMac: Null Adapter Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(AdaptP)) { + NdisPrint1("NdisDeQueueAdapterOnMac: Adapter Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + if (DbgIsNull(MacP)) { + NdisPrint1("NdisDeQueueAdapterOnMac: Null Mac Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(MacP)) { + NdisPrint1("NdisDeQueueAdapterOnMac: Mac Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + ACQUIRE_SPIN_LOCK(&MacP->Ref.SpinLock); + + // + // Find the MAC on the queue, and remove it. + // + + if (MacP->AdapterQueue == AdaptP) { + MacP->AdapterQueue = AdaptP->NextAdapter; + } else { + PNDIS_ADAPTER_BLOCK MP = MacP->AdapterQueue; + + while (MP->NextAdapter != AdaptP) { + MP = MP->NextAdapter; + } + + MP->NextAdapter = MP->NextAdapter->NextAdapter; + } + + RELEASE_SPIN_LOCK(&MacP->Ref.SpinLock); + + if (MacP->Unloading && (MacP->AdapterQueue == (PNDIS_ADAPTER_BLOCK)NULL)) { + + KeSetEvent( + &MacP->AdaptersRemovedEvent, + 0L, + FALSE + ); + + } + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeQueueAdapterOnMac\n"); +} + + + +VOID +NdisKillAdapter( + PNDIS_ADAPTER_BLOCK OldAdaptP + ) + +/*++ + +Routine Description: + + Removes an adapter. Called by NdisDeregisterAdapter and also + for internally generated deregistrations. + +Arguments: + + OldAdaptP - The adapter to be removed. + +Return Value: + + None. + +--*/ + +{ + // + // If the adapter is already closing, return. + // + + + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisKillAdapter\n"); + NdisPrint2(" Removing Adapter %s\n",OldAdaptP->AdapterName.Buffer); + } + IF_ERROR_CHK { + if (DbgIsNull(OldAdaptP)) { + NdisPrint1("NdisKillAdapter: Null Adapter Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(OldAdaptP)) { + NdisPrint1("NdisKillAdapter: Adapter Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + if (!NdisCloseRef(&OldAdaptP->Ref)) { + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillAdapter\n"); + return; + } + + + // + // Kill all the opens for this adapter. + // + + while (OldAdaptP->OpenQueue != (PNDIS_OPEN_BLOCK)NULL) { + + // + // This removes it from the adapter's OpenQueue etc. + // + + NdisKillOpenAndNotifyProtocol(OldAdaptP->OpenQueue); + } + + + // + // Remove the adapter from the MAC's list. + // + + NdisDeQueueAdapterOnMac(OldAdaptP, OldAdaptP->MacHandle); + + NdisDereferenceAdapter(OldAdaptP); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillAdapter\n"); +} + + + +VOID +NdisDereferenceAdapter( + PNDIS_ADAPTER_BLOCK AdaptP + ) + +/*++ + +Routine Description: + + Dereferences an adapter. If the reference count goes to zero, + it frees resources associated with the adapter. + +Arguments: + + AdaptP - The adapter to be dereferenced. + +Return Value: + + None. + +--*/ + +{ + if (NdisDereferenceRef(&AdaptP->Ref)) { + + // + // Free resource memory + // + + if (AdaptP->Resources != NULL) { + + ExFreePool(AdaptP->Resources); + + } + + ExFreePool(AdaptP->AdapterName.Buffer); + + if (AdaptP->Master) { + UINT i; + ULONG MapRegistersPerChannel = + ((AdaptP->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2; + KIRQL OldIrql; + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + for (i=0; i<AdaptP->PhysicalMapRegistersNeeded; i++) { + IoFreeMapRegisters( + AdaptP->SystemAdapterObject, + AdaptP->MapRegisters[i].MapRegister, + MapRegistersPerChannel); + } + + KeLowerIrql(OldIrql); + } + + if ((AdaptP->NumberOfPorts > 0) && AdaptP->InitialPortMapped) { + MmUnmapIoSpace (AdaptP->InitialPortMapping, AdaptP->NumberOfPorts); + } + + NdisDereferenceMac(AdaptP->MacHandle); + IoDeleteDevice(AdaptP->DeviceObject); + + } +} + + +BOOLEAN +NdisQueueOpenOnAdapter( + IN PNDIS_OPEN_BLOCK OpenP, + IN PNDIS_ADAPTER_BLOCK AdaptP + ) + +/*++ + +Routine Description: + + Adds an open to a list of opens for an adapter. + +Arguments: + + OpenP - The open block to queue. + AdaptP - The adapter block to queue it to. + +Return Value: + + None. + +--*/ + +{ + // attach ourselves to the adapter object linked list of opens + ACQUIRE_SPIN_LOCK(&AdaptP->Ref.SpinLock); + + // + // Make sure the adapter is not closing. + // + + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisQueueAdapterOnAdapter\n"); + NdisPrint2(" Open being added to list for Adapter %s\n",AdaptP->AdapterName.Buffer); + } + IF_ERROR_CHK { + if (DbgIsNull(OpenP)) { + NdisPrint1("NdisQueueOpenOnAdapter: Null Open Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(OpenP)) { + NdisPrint1("NdisQueueOpenOnAdapter: Open Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + if (DbgIsNull(AdaptP)) { + NdisPrint1("NdisQueueOpenOnAdapter: Null Adapter Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(AdaptP)) { + NdisPrint1("NdisQueueOpenOnAdapter: Adapter Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + if (AdaptP->Ref.Closing) { + RELEASE_SPIN_LOCK(&AdaptP->Ref.SpinLock); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueAdapterOnAdapter\n"); + return FALSE; + } + + + // + // Attach this open at the head of the queue. + // + + OpenP->AdapterNextOpen = AdaptP->OpenQueue; + AdaptP->OpenQueue = OpenP; + + + RELEASE_SPIN_LOCK(&AdaptP->Ref.SpinLock); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueAdapterOnAdapter\n"); + return TRUE; +} + +VOID +NdisDeQueueOpenOnAdapter( + PNDIS_OPEN_BLOCK OpenP, + PNDIS_ADAPTER_BLOCK AdaptP + ) + +/*++ + +Routine Description: + + Removes an open from a list of opens for an adapter. + +Arguments: + + OpenP - The open block to dequeue. + AdaptP - The adapter block to dequeue it from. + +Return Value: + + None. + +--*/ + +{ + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisDeQueueAdapterOnAdapter\n"); + NdisPrint2(" Open being removed from list for Adapter %s\n",AdaptP->AdapterName.Buffer); + } + IF_ERROR_CHK { + if (DbgIsNull(OpenP)) { + NdisPrint1("NdisDeQueueOpenOnAdapter: Null Open Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(OpenP)) { + NdisPrint1("NdisDeQueueOpenOnAdapter: Open Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + if (DbgIsNull(AdaptP)) { + NdisPrint1("NdisDeQueueOpenOnAdapter: Null Adapter Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(AdaptP)) { + NdisPrint1("NdisDeQueueOpenOnAdapter: Adapter Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + ACQUIRE_SPIN_LOCK(&AdaptP->Ref.SpinLock); + // + // Find the open on the queue, and remove it. + // + + if (AdaptP->OpenQueue == OpenP) { + AdaptP->OpenQueue = OpenP->AdapterNextOpen; + } else { + PNDIS_OPEN_BLOCK AP = AdaptP->OpenQueue; + + while (AP->AdapterNextOpen != OpenP) { + AP = AP->AdapterNextOpen; + } + + AP->AdapterNextOpen = AP->AdapterNextOpen->AdapterNextOpen; + } + + RELEASE_SPIN_LOCK(&AdaptP->Ref.SpinLock); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeQueueAdapterOnAdapter\n"); +} + + +VOID +NdisDereferenceMac( + PNDIS_MAC_BLOCK MacP + ) +/*++ + +Routine Description: + + Removes a reference from the mac, deleting it if the count goes to 0. + +Arguments: + + MacP - The Mac block to dereference. + +Return Value: + + None. + +--*/ +{ + if (NdisDereferenceRef(&(MacP)->Ref)) { + + // + // Remove it from the global list. + // + + ACQUIRE_SPIN_LOCK(&NdisMacListLock); + + if (NdisMacList == MacP) { + + NdisMacList = MacP->NextMac; + + } else { + + PNDIS_MAC_BLOCK TmpMacP = NdisMacList; + + while(TmpMacP->NextMac != MacP) { + + TmpMacP = TmpMacP->NextMac; + + } + + TmpMacP->NextMac = TmpMacP->NextMac->NextMac; + + } + + RELEASE_SPIN_LOCK(&NdisMacListLock); + + if ( MacP->PciAssignedResources != NULL ) { + ExFreePool( MacP->PciAssignedResources ); + } + + ExFreePool((PVOID)(MacP)); + } + + +} + + + +// +// Stubs to compile with Ndis 3.0 kernel. +// + +NDIS_STATUS +EthAddFilterAddress() { + return(NDIS_STATUS_FAILURE); +} + +NDIS_STATUS +EthDeleteFilterAddress() { + return(NDIS_STATUS_FAILURE); +} + +NDIS_STATUS +NdisInitializePacketPool() { + return(NDIS_STATUS_FAILURE); +} + + + +NTSTATUS +WrapperSaveLinkage( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ) + +/*++ + +Routine Description: + + This routine is a callback routine for RtlQueryRegistryValues + It is called with the values for the "Bind" and "Export" multi-strings + for a given driver. It allocates memory to hold the data and copies + it over. + +Arguments: + + ValueName - The name of the value ("Bind" or "Export" -- ignored). + + ValueType - The type of the value (REG_MULTI_SZ -- ignored). + + ValueData - The null-terminated data for the value. + + ValueLength - The length of ValueData. + + Context - Unused. + + EntryContext - A pointer to the pointer that holds the copied data. + +Return Value: + + STATUS_SUCCESS + +--*/ + +{ + PWSTR * Data = ((PWSTR *)EntryContext); + + UNREFERENCED_PARAMETER(ValueName); + UNREFERENCED_PARAMETER(ValueType); + UNREFERENCED_PARAMETER(Context); + + + *Data = ExAllocatePoolWithTag (NonPagedPool, ValueLength, ' DN'); + + if (*Data == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlCopyMemory (*Data, ValueData, ValueLength); + + return STATUS_SUCCESS; + +} + + +NTSTATUS +WrapperCheckRoute( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ) + +/*++ + +Routine Description: + + This routine is a callback routine for RtlQueryRegistryValues + It is called with the value for the "Route" multi-string. It + counts the number of "'s in the first string and if it is + more than two than it knows that this is a layered driver. + +Arguments: + + ValueName - The name of the value ("Route" -- ignored). + + ValueType - The type of the value (REG_MULTI_SZ -- ignored). + + ValueData - The null-terminated data for the value. + + ValueLength - The length of ValueData. + + Context - Unused. + + EntryContext - A pointer to a BOOLEAN that is set to TRUE + if the driver is layered. + +Return Value: + + STATUS_SUCCESS + +--*/ + +{ + + PWSTR CurRouteLoc = (PWSTR)ValueData; + UINT QuoteCount = 0; + + UNREFERENCED_PARAMETER(ValueName); + UNREFERENCED_PARAMETER(ValueType); + UNREFERENCED_PARAMETER(ValueLength); + UNREFERENCED_PARAMETER(Context); + + while (*CurRouteLoc != 0) { + + if (*CurRouteLoc == (WCHAR)L'"') { + ++QuoteCount; + } + ++CurRouteLoc; + } + + if (QuoteCount > 2) { + *(PBOOLEAN)EntryContext = TRUE; + } + + return STATUS_SUCCESS; + +} + +NDIS_STATUS +NdisCallDriverAddAdapter( + IN PNDIS_MAC_BLOCK NewMacP + ) + +/*++ + +Routine Description: + + Reads the driver registry bindings and calls add adapter for each + one. + +Arguments: + + NewMacP - Pointer to the Mac block allocated for this Mac. + +Return Value: + + None. + +--*/ +{ + // + // Pointer to a Miniport + // + PNDIS_M_DRIVER_BLOCK WDriver = (PNDIS_M_DRIVER_BLOCK)NewMacP; + + // + // Number of adapters added successfully + // + UINT AdaptersAdded = 0; + + // + // Status of calls to MacAddAdapter + // + NDIS_STATUS AddAdapterStatus; + + // + // Status of calls to MiniportInitialize + // + NDIS_STATUS MiniportInitializeStatus; + NDIS_STATUS OpenErrorStatus; + + UINT SelectedMediumIndex; + + NDIS_MEDIUM MediumArray[] = {NdisMedium802_3, + NdisMedium802_5, + NdisMediumFddi, + NdisMediumArcnet878_2, + NdisMediumWan }; + + UINT MediumArraySize = 5; + + // + // Status of registry requests. + // + NTSTATUS RegistryStatus; + NTSTATUS NtStatus; + + // + // subkey containing the card parameters + // + PWSTR Linkage = L"Linkage"; + + // + // subkeys below "Linkage" + // + + PWSTR Bind = L"Bind"; + PWSTR Export = L"Export"; + PWSTR Route = L"Route"; + + // + // These hold the REG_MULTI_SZ read from "Bind" and "Export". + // + + PWSTR BindData; + PWSTR ExportData; + + // + // These hold our place in the REG_MULTI_SZ read for + // "Bind" and "Export". + // + + PWSTR CurBindValue; + PWSTR CurExportValue; + + // + // Will be set to TRUE if the driver is layered (that is, + // it binds to another NDIS driver, not to an adapter). + // + + BOOLEAN LayeredDriver; + + // + // subkey below the driver's service key. + // + + PWSTR Parameters = L"Parameters"; + + // + // The path to our configuration data. + // + PUNICODE_STRING ConfigurationString; + + // + // Holds a null-terminated copy of ConfigurationString + // + PWSTR ConfigurationPath; + + ULONG i; + ULONG BusNumber; + NDIS_INTERFACE_TYPE BusType; + + // + // Holds the key below services where Parameters are stored. + // + PWCH BaseFileName; + + // + // Used to instruct RtlQueryRegistryValues to read the + // Linkage\Bind and Linkage\Export keys + // + RTL_QUERY_REGISTRY_TABLE LinkageQueryTable[5]; + + // + // Used to instruct RtlQueryRegistryValues to read the + // [Driver]\Parameters keys. This is passed as the + // ConfigContext to the MacAddAdapter routine. + // + + NDIS_WRAPPER_CONFIGURATION_HANDLE ConfigurationHandle; + + NDIS_WRAPPER_CONFIGURATION_HANDLE WrapperConfigurationHandle; + + // + // Used for calls to other Ndis routines + // + NDIS_STATUS NdisStatus; + + BOOLEAN IsAMiniport; + +#define BLOCK_LOCK_MINIPORT(_M, _L) \ + { \ + ACQUIRE_SPIN_LOCK(&_M->Lock); \ + LOCK_MINIPORT(_M, _L); \ + while (!_L) { \ + UNLOCK_MINIPORT(_M, _L); \ + RELEASE_SPIN_LOCK(&_M->Lock); \ + ACQUIRE_SPIN_LOCK(&_M->Lock); \ + LOCK_MINIPORT(_M, _L); \ + } \ + RELEASE_SPIN_LOCK(&_M->Lock); \ + } + + IsAMiniport = (WDriver->MiniportIdField == (NDIS_HANDLE)0x01); + + // + // Set up LinkageQueryTable to do the following: + // + + // + // 1) Switch to the Linkage key below this driver's key + // + + LinkageQueryTable[0].QueryRoutine = NULL; + LinkageQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY; + LinkageQueryTable[0].Name = Linkage; + + // + // 2) Call WrapperSaveLinkage for "Bind" (as a single multi-string), + // which will allocate storage and save the data in BindData. + // + + LinkageQueryTable[1].QueryRoutine = WrapperSaveLinkage; + LinkageQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND; + LinkageQueryTable[1].Name = Bind; + LinkageQueryTable[1].EntryContext = (PVOID)&BindData; + LinkageQueryTable[1].DefaultType = REG_NONE; + + // + // 3) Call WrapperSaveLinkage for "Export" (as a single multi-string) + // which will allocate storage and save the data in ExportData. + // + + LinkageQueryTable[2].QueryRoutine = WrapperSaveLinkage; + LinkageQueryTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND; + LinkageQueryTable[2].Name = Export; + LinkageQueryTable[2].EntryContext = (PVOID)&ExportData; + LinkageQueryTable[2].DefaultType = REG_NONE; + + // + // 4) Call WrapperCheckRoute for "Route" (as a single multi-string) + // which will set LayeredDriver to TRUE for a layered driver (this + // is optional, the default is FALSE). + // + + LinkageQueryTable[3].QueryRoutine = WrapperCheckRoute; + LinkageQueryTable[3].Flags = RTL_QUERY_REGISTRY_NOEXPAND; + LinkageQueryTable[3].Name = Route; + LinkageQueryTable[3].EntryContext = (PVOID)&LayeredDriver; + LinkageQueryTable[3].DefaultType = REG_NONE; + + LayeredDriver = FALSE; + + // + // 5) Stop + // + + LinkageQueryTable[4].QueryRoutine = NULL; + LinkageQueryTable[4].Flags = 0; + LinkageQueryTable[4].Name = NULL; + + + // + // Allocate room for a null-terminated version of the config path + // + + if (IsAMiniport) { + + ConfigurationString = (PUNICODE_STRING)(WDriver->NdisDriverInfo->NdisWrapperConfigurationHandle); + + } else { + + ConfigurationString = (PUNICODE_STRING)(NewMacP->NdisMacInfo->NdisWrapperConfigurationHandle); + + } + + ConfigurationPath = (PWSTR)ExAllocatePoolWithTag( + NonPagedPool, + ConfigurationString->Length + sizeof(WCHAR), + ' DN'); + if (ConfigurationPath == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlCopyMemory (ConfigurationPath, ConfigurationString->Buffer, ConfigurationString->Length); + *(PWCHAR)(((PUCHAR)ConfigurationPath)+ConfigurationString->Length) = (WCHAR)L'\0'; + + BindData = NULL; + ExportData = NULL; + + RegistryStatus = RtlQueryRegistryValues( + RTL_REGISTRY_ABSOLUTE, + ConfigurationPath, + LinkageQueryTable, + (PVOID)NULL, // no context needed + NULL); + + if (!NT_SUCCESS(RegistryStatus)) { + + // + // Free memory if needed, exit. + // + + ExFreePool (ConfigurationPath); + + if (BindData != NULL) { + ExFreePool (BindData); + } + if (ExportData != NULL) { + ExFreePool (ExportData); + } + +#if DBG + if (IsAMiniport) { + + DbgPrint("NDIS: Could not read Bind/Export for %Z: %lx\n", + (PUNICODE_STRING)(WDriver->NdisDriverInfo->NdisWrapperConfigurationHandle), + RegistryStatus); + + } else { + + DbgPrint("NDIS: Could not read Bind/Export for %Z: %lx\n", + (PUNICODE_STRING)(NewMacP->NdisMacInfo->NdisWrapperConfigurationHandle), + RegistryStatus); + + } +#endif + return NDIS_STATUS_FAILURE; + + } + + // + // NdisReadConfiguration assumes that ParametersQueryTable[3].Name is + // a key below the services key where the Parameters should be read, + // for layered drivers we store the last piece of Configuration + // Path there, leading to the desired effect. + // + // I.e, ConfigurationPath == "...\Services\Driver". + // + // For a layered driver, ParameterQueryTable[3].Name is "Driver" + // for all calls to AddAdapter, and parameters are read from + // "...\Services\Driver\Parameters" for all calls. + // + // For a non-layered driver, ParametersQueryTable[3].Name might be + // "Driver01" for the first call to AddAdapter, "Driver02" for the + // second, etc., and parameters are read from + // "..\Services\Driver01\Parameters" for the first call to + // AddAdapter, "...\Services\Driver02\Parameters" for the second + // call, etc. + // + + if (LayeredDriver) { + + BaseFileName = ConfigurationPath; + + for ( i = 0; i < ConfigurationString->Length / sizeof(WCHAR); i++ ) { + + // + // If s points to a directory separator, set BaseFileName to + // the character after the separator. + // + + if ( ConfigurationPath[i] == OBJ_NAME_PATH_SEPARATOR ) { + BaseFileName = &(ConfigurationPath[++i]); + } + + } + +#if DBG + DbgPrint ("NDIS: Loading layered driver %ws\n", BaseFileName); +#endif + + } + + + // + // Set up ParametersQueryTable. We set most of it up here, + // then call the MAC's AddAdapter routine with its address + // as a ConfigContext. Inside ReadConfiguration, we get + // the ConfigContext back and can then finish initializing + // the table and use RtlQueryRegistryValues (with a + // callback to WrapperSaveParameter) to read the value + // specified. + // + + + // + // 1) Switch to the Parameters key below the [DriverName] key + // (DriverName is passed as a parameter to RtlQueryRegistryValues). + // + + ConfigurationHandle.ParametersQueryTable[0].QueryRoutine = NULL; + ConfigurationHandle.ParametersQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY; + ConfigurationHandle.ParametersQueryTable[0].Name = Parameters; + + // + // 2) Call WrapperSaveParameter for a parameter, which + // will allocate storage for it. + // + // ParametersQueryTable[1].Name and ParametersQueryTable[1].EntryContext + // are filled in inside ReadConfiguration, in preparation + // for the callback. + // + + ConfigurationHandle.ParametersQueryTable[1].QueryRoutine = WrapperSaveParameters; + ConfigurationHandle.ParametersQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND; + ConfigurationHandle.ParametersQueryTable[1].DefaultType = REG_NONE; + + // + // 3) Stop + // + + ConfigurationHandle.ParametersQueryTable[2].QueryRoutine = NULL; + ConfigurationHandle.ParametersQueryTable[2].Flags = 0; + ConfigurationHandle.ParametersQueryTable[2].Name = NULL; + + // + // NOTE: Some fields in ParametersQueryTable[3] are used to + // store information for later retrieval. + // + + + + // + // OK, Now lock down all the filter packages. If a MAC or + // Miniport driver uses any of these, then the filter package + // will reference itself, to keep the image in memory. + // + ArcReferencePackage(); + EthReferencePackage(); + FddiReferencePackage(); + TrReferencePackage(); + MiniportReferencePackage(); + NdisMacReferencePackage(); + + // + // For each binding, get the handle to the card object. + // Call the driver's addadapter routine. + // + + CurBindValue = BindData; + CurExportValue = ExportData; + + while ((*CurBindValue != 0) && (*CurExportValue != 0)) { + + UNICODE_STRING CurBindString; + UNICODE_STRING CurExportString; + NDIS_CONFIGURATION_HANDLE TmpConfigHandle; + NDIS_STRING BusTypeStr = NDIS_STRING_CONST("BusType"); + NDIS_STRING BusNumberStr = NDIS_STRING_CONST("BusNumber"); + PNDIS_CONFIGURATION_PARAMETER ReturnedValue; + PDEVICE_OBJECT TmpDeviceP; + PNDIS_MINIPORT_BLOCK Miniport; + LARGE_INTEGER TimeoutValue; + + TimeoutValue.QuadPart = Int32x32To64(100 * 1000, -10000); + + // + // Setup the query table to point to the section in + // the registry corresponding to what was specified + // in "Bind". The "Parameters" key below this is where + // config parameters are read from. + // + + RtlInitUnicodeString (&CurBindString, CurBindValue); + + // + // For layered drivers, BaseFileName is already + // initialized. + // + + if (!LayeredDriver) { + + // + // Parse out the path name, leaving only the driver name. + // + + BaseFileName = CurBindString.Buffer; + + for ( i = 0; i < CurBindString.Length / sizeof(WCHAR); i++ ) { + + // + // If s points to a directory separator, set fileBaseName to + // the character after the separator. + // + + if ( CurBindString.Buffer[i] == OBJ_NAME_PATH_SEPARATOR ) { + BaseFileName = &(CurBindString.Buffer[++i]); + } + + } + + // + // Set this to NULL, in case NdisReadBindingInformation + // is called. + // + + ConfigurationHandle.ParametersQueryTable[3].EntryContext = NULL; + + } else { + + // + // This will be returned by NdisReadBindingInformation. + // + + ConfigurationHandle.ParametersQueryTable[3].EntryContext = CurBindValue; + + } + + + // + // Save the driver name here; later we will use this as + // a parameter to RtlQueryRegistryValues. + // + + ConfigurationHandle.ParametersQueryTable[3].Name = BaseFileName; + + // + // Also, save the BusType and BusNumber so that we can pull them + // out in NdisRegisterAdapter(), NdisReadEisaSlotInformation() and + // NdisReadPosInformation(). + // + + TmpConfigHandle.KeyQueryTable = ConfigurationHandle.ParametersQueryTable; + TmpConfigHandle.ParameterList = NULL; + + // + // Read Bus Number + // + + NdisReadConfiguration( + &NdisStatus, + &ReturnedValue, + &TmpConfigHandle, + &BusNumberStr, + NdisParameterInteger + ); + + if (NdisStatus == NDIS_STATUS_SUCCESS) { + + BusNumber = ReturnedValue->ParameterData.IntegerData; + + } else { + + BusNumber = (ULONG)(-1); + } + + // + // Read Bus Type + // + + NdisReadConfiguration( + &NdisStatus, + &ReturnedValue, + &TmpConfigHandle, + &BusTypeStr, + NdisParameterInteger + ); + + if (NdisStatus == NDIS_STATUS_SUCCESS) { + + BusType = (NDIS_INTERFACE_TYPE)(ReturnedValue->ParameterData.IntegerData); + + } else { + + BusType = (NDIS_INTERFACE_TYPE)(-1); + + } + + ConfigurationHandle.ParametersQueryTable[3].DefaultType = (ULONG)(BusType); + ConfigurationHandle.ParametersQueryTable[3].DefaultLength = (ULONG)(BusNumber); + ConfigurationHandle.ParametersQueryTable[3].DefaultData = NULL; + + // + // Call adapter callback. The current value for "Export" + // is what we tell him to name this device. + // + + RtlInitUnicodeString (&CurExportString, CurExportValue); + + if (IsAMiniport) + { + ConfigurationHandle.DriverObject = WDriver->NdisDriverInfo->NdisWrapperDriver; + } + else + { + ConfigurationHandle.DriverObject = NewMacP->NdisMacInfo->NdisWrapperDriver; + } + + if (IsAMiniport) + { + KIRQL OldIrql; + ULONG MaximumLongAddresses; + UCHAR CurrentLongAddress[6]; + ULONG MaximumShortAddresses; + UCHAR CurrentShortAddress[2]; + UINT BytesWritten; + UINT BytesNeeded; + UINT PacketFilter = 0x1; + UCHAR i; + BOOLEAN LocalLock; + PARC_BUFFER_LIST Buffer; + PVOID DataBuffer; + + // + // Initialize device. + // + + if (!NdisReferenceDriver((PNDIS_M_DRIVER_BLOCK)WDriver)) { + + // + // The driver is closing. + // + + goto LoopBottom; + + } + + NtStatus = IoCreateDevice( + WDriver->NdisDriverInfo->NdisWrapperDriver, + sizeof(NDIS_MINIPORT_BLOCK) + sizeof(NDIS_WRAPPER_CONTEXT), // device extension size + &CurExportString, + FILE_DEVICE_PHYSICAL_NETCARD, + 0, + FALSE, // exclusive flag + &TmpDeviceP + ); + + if (NtStatus != STATUS_SUCCESS) { + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + + // + // Initialize the Miniport adapter block in the device object extension + // + // *** NDIS_WRAPPER_CONTEXT has a higher alignment requirement than + // NDIS_MINIPORT_BLOCK, so we put it first in the extension. + // + + Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)TmpDeviceP->DeviceExtension + 1); + + Miniport->WrapperContext = TmpDeviceP->DeviceExtension; + + Miniport->BusType = BusType; + Miniport->BusNumber = BusNumber; + Miniport->DeviceObject = TmpDeviceP; + Miniport->DriverHandle = WDriver; + Miniport->MiniportName.Buffer = (PWSTR)ExAllocatePoolWithTag( + NonPagedPool, + CurExportString.MaximumLength, + 'naDN' + ); + + if (Miniport->MiniportName.Buffer == NULL) { + NdisDereferenceDriver(WDriver); + IoDeleteDevice(TmpDeviceP); + goto LoopBottom; + } + + Miniport->MiniportName.MaximumLength = CurExportString.MaximumLength; + Miniport->MiniportName.Length = CurExportString.Length; + + RtlCopyMemory(Miniport->MiniportName.Buffer, + CurExportString.Buffer, + CurExportString.MaximumLength + ); + + Miniport->OpenQueue = (PNDIS_M_OPEN_BLOCK)NULL; + Miniport->EthDB = NULL; + Miniport->TrDB = NULL; + Miniport->FddiDB = NULL; + Miniport->ArcDB = NULL; + Miniport->BeingRemoved = FALSE; + Miniport->SendResourcesAvailable = 0xffffff; + Miniport->Flags = 0; // a value that cannot be a pointer. + Miniport->InAddDriver = TRUE; + NdisAllocateSpinLock(&Miniport->Lock); + //KeSetSpecialSpinLock(&Miniport->Lock, "miniport lock" ); + + NdisInitializeRef(&Miniport->Ref); + + NdisInitializeTimer( + &Miniport->DpcTimer, + (PVOID) NdisMDpcTimer, + (PVOID) Miniport + ); + + NdisInitializeTimer( + &Miniport->WakeUpDpcTimer, + (PVOID) NdisMWakeUpDpc, + (PVOID) Miniport + ); + + if (!NdisQueueMiniportOnDriver(Miniport, WDriver)) { + + // + // The Driver is closing, undo what we have done. + // + + ExFreePool(Miniport->MiniportName.Buffer); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + + // + // Now we do something really bogus. We create many + // temporary filter databases, just in case any indications + // happen. + // + + if (!EthCreateFilter( + 1, + NdisMChangeEthAddresses, + NdisMChangeClass, + NdisMCloseAction, + CurrentLongAddress, + &Miniport->Lock, + &(Miniport->EthDB) + )) { + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 0 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + if (!TrCreateFilter( + NdisMChangeFunctionalAddress, + NdisMChangeGroupAddress, + NdisMChangeClass, + NdisMCloseAction, + CurrentLongAddress, + &Miniport->Lock, + &(Miniport->TrDB) + )) { + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 0 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + if (!FddiCreateFilter( + 1, + 1, + NdisMChangeFddiAddresses, + NdisMChangeClass, + NdisMCloseAction, + CurrentLongAddress, + CurrentShortAddress, + &Miniport->Lock, + &(Miniport->FddiDB) + )) { + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 0 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + if (!ArcCreateFilter( + Miniport, + NdisMChangeClass, + NdisMCloseAction, + CurrentLongAddress[0], + &Miniport->Lock, + &(Miniport->ArcDB) + )) { + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 0 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + // + // Call adapter callback. The current value for "Export" + // is what we tell him to name this device. + // + + Miniport->InInitialize = TRUE; + Miniport->NormalInterrupts = FALSE; + + MiniportInitializeStatus = + (WDriver->MiniportCharacteristics.InitializeHandler)( + &OpenErrorStatus, + &SelectedMediumIndex, + MediumArray, + MediumArraySize, + (NDIS_HANDLE)(Miniport), + (NDIS_HANDLE)&ConfigurationHandle + ); + + Miniport->InInitialize = FALSE; + CHECK_FOR_NORMAL_INTERRUPTS(Miniport); + + // + // Free the slot information buffer + // + + if (ConfigurationHandle.ParametersQueryTable[3].DefaultData != NULL ) { + + ExFreePool(ConfigurationHandle.ParametersQueryTable[3].DefaultData); + + } + + if (MiniportInitializeStatus == NDIS_STATUS_SUCCESS) { + + ASSERT(SelectedMediumIndex < MediumArraySize); + + Miniport->MediaType = MediumArray[SelectedMediumIndex]; + + KeInitializeEvent( + &Miniport->RequestEvent, + NotificationEvent, + FALSE + ); + + KeResetEvent( + &Miniport->RequestEvent + ); + + // + // Query maximum lookahead + // + Miniport->MiniportRequest = &Miniport->InternalRequest; + Miniport->InternalRequest.RequestType = NdisRequestQueryInformation; + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NdisStatus = + (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) ( + Miniport->MiniportAdapterContext, + OID_GEN_MAXIMUM_LOOKAHEAD, + &MaximumLongAddresses, + sizeof(MaximumLongAddresses), + &BytesWritten, + &BytesNeeded + ); + + KeLowerIrql(OldIrql); + UNLOCK_MINIPORT(Miniport, LocalLock); + + // + // Fire a DPC to do anything + // + if ((NdisStatus == NDIS_STATUS_PENDING) || + (NdisStatus == NDIS_STATUS_SUCCESS)) { + + Miniport->RunDpc = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 1); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + NtStatus = KeWaitForSingleObject( + &Miniport->RequestEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x1 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + KeResetEvent( + &Miniport->RequestEvent + ); + + NdisStatus = Miniport->RequestStatus; + + } + + if (NdisStatus != NDIS_STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x2 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + // + // Now adjust based on media type + // + + switch(Miniport->MediaType) { + + case NdisMedium802_3: + + Miniport->MaximumLookahead = (NDIS_M_MAX_LOOKAHEAD - 14 < MaximumLongAddresses) ? + NDIS_M_MAX_LOOKAHEAD - 14 : + MaximumLongAddresses; + break; + + case NdisMedium802_5: + + Miniport->MaximumLookahead = (NDIS_M_MAX_LOOKAHEAD - 32 < MaximumLongAddresses) ? + NDIS_M_MAX_LOOKAHEAD - 32 : + MaximumLongAddresses; + break; + + case NdisMediumFddi: + Miniport->MaximumLookahead = (NDIS_M_MAX_LOOKAHEAD - 16 < MaximumLongAddresses) ? + NDIS_M_MAX_LOOKAHEAD - 16 : + MaximumLongAddresses; + break; + + case NdisMediumArcnet878_2: + Miniport->MaximumLookahead = (NDIS_M_MAX_LOOKAHEAD - 50 < MaximumLongAddresses) ? + NDIS_M_MAX_LOOKAHEAD - 50 : + MaximumLongAddresses; + break; + + case NdisMediumWan: + Miniport->MaximumLookahead = 1514; + + } + + Miniport->CurrentLookahead = Miniport->MaximumLookahead; + + // + // Query mac options + // + Miniport->MiniportRequest = &Miniport->InternalRequest; + Miniport->InternalRequest.RequestType = NdisRequestQueryInformation; + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NdisStatus = + (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) ( + Miniport->MiniportAdapterContext, + OID_GEN_MAC_OPTIONS, + &MaximumLongAddresses, + sizeof(MaximumLongAddresses), + &BytesWritten, + &BytesNeeded + ); + + KeLowerIrql(OldIrql); + UNLOCK_MINIPORT(Miniport, LocalLock); + + // + // Fire a DPC to do anything + // + if ((NdisStatus == NDIS_STATUS_PENDING) || + (NdisStatus == NDIS_STATUS_SUCCESS)) { + + Miniport->RunDpc = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 1); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + NtStatus = KeWaitForSingleObject( + &Miniport->RequestEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x3 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + KeResetEvent( + &Miniport->RequestEvent + ); + + NdisStatus = Miniport->RequestStatus; + + } + + Miniport->MacOptions = (UINT)MaximumLongAddresses; + + if (NdisStatus != NDIS_STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x4 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + // + // Create filter package + // + switch(Miniport->MediaType) { + + case NdisMedium802_3: + + // + // Query maximum MulticastAddress + // + Miniport->MiniportRequest = &Miniport->InternalRequest; + Miniport->InternalRequest.RequestType = NdisRequestQueryInformation; + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NdisStatus = + (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) ( + Miniport->MiniportAdapterContext, + OID_802_3_MAXIMUM_LIST_SIZE, + &MaximumLongAddresses, + sizeof(MaximumLongAddresses), + &BytesWritten, + &BytesNeeded + ); + + KeLowerIrql(OldIrql); + UNLOCK_MINIPORT(Miniport, LocalLock); + + // + // Fire a DPC to do anything + // + if ((NdisStatus == NDIS_STATUS_PENDING) || + (NdisStatus == NDIS_STATUS_SUCCESS)) { + + Miniport->RunDpc = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 1); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + NtStatus = KeWaitForSingleObject( + &Miniport->RequestEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x5 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + KeResetEvent( + &Miniport->RequestEvent + ); + + NdisStatus = Miniport->RequestStatus; + + } + + if (MaximumLongAddresses > NDIS_M_MAX_MULTI_LIST) { + + MaximumLongAddresses = NDIS_M_MAX_MULTI_LIST; + + } + + Miniport->MaximumLongAddresses = MaximumLongAddresses; + + if (NdisStatus != NDIS_STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x6 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + Miniport->MiniportRequest = &Miniport->InternalRequest; + Miniport->InternalRequest.RequestType = NdisRequestQueryInformation; + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NdisStatus = + (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) ( + Miniport->MiniportAdapterContext, + OID_802_3_CURRENT_ADDRESS, + &(CurrentLongAddress), + sizeof(CurrentLongAddress), + &BytesWritten, + &BytesNeeded + ); + + KeLowerIrql(OldIrql); + UNLOCK_MINIPORT(Miniport, LocalLock); + + // + // Fire a DPC to do anything + // + if ((NdisStatus == NDIS_STATUS_PENDING) || + (NdisStatus == NDIS_STATUS_SUCCESS)) { + + Miniport->RunDpc = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 1); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + NtStatus = KeWaitForSingleObject( + &Miniport->RequestEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x7 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + KeResetEvent( + &Miniport->RequestEvent + ); + + NdisStatus = Miniport->RequestStatus; + + } + + if (NdisStatus != NDIS_STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x8 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + // + // Now undo the bogus filter package. We lock + // the miniport so that no dpcs will get queued. + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + Miniport->InInitialize = TRUE; + Miniport->NormalInterrupts = FALSE; + + EthDeleteFilter(Miniport->EthDB); + Miniport->EthDB = NULL; + TrDeleteFilter(Miniport->TrDB); + Miniport->TrDB = NULL; + FddiDeleteFilter(Miniport->FddiDB); + Miniport->FddiDB = NULL; + ArcDeleteFilter(Miniport->ArcDB); + Miniport->ArcDB = NULL; + + if (!EthCreateFilter( + MaximumLongAddresses, + NdisMChangeEthAddresses, + NdisMChangeClass, + NdisMCloseAction, + CurrentLongAddress, + &Miniport->Lock, + &Miniport->EthDB + )) { + + // + // Halt the miniport driver + // + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 2, + 0xFF00FF00, + 0x9 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + Miniport->InInitialize = FALSE; + CHECK_FOR_NORMAL_INTERRUPTS(Miniport); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + break; + + case NdisMedium802_5: + + Miniport->MiniportRequest = &Miniport->InternalRequest; + Miniport->InternalRequest.RequestType = NdisRequestQueryInformation; + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NdisStatus = + (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) ( + Miniport->MiniportAdapterContext, + OID_802_5_CURRENT_ADDRESS, + &(CurrentLongAddress), + sizeof(CurrentLongAddress), + &BytesWritten, + &BytesNeeded + ); + + KeLowerIrql(OldIrql); + UNLOCK_MINIPORT(Miniport, LocalLock); + + // + // Fire a DPC to do anything + // + if ((NdisStatus == NDIS_STATUS_PENDING) || + (NdisStatus == NDIS_STATUS_SUCCESS)) { + + Miniport->RunDpc = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 1); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + NtStatus = KeWaitForSingleObject( + &Miniport->RequestEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0xA + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + KeResetEvent( + &Miniport->RequestEvent + ); + + NdisStatus = Miniport->RequestStatus; + + } + + if (NdisStatus != NDIS_STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0xB + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + // + // Now undo the bogus filter package. We lock + // the miniport so that no dpcs will get queued. + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + Miniport->InInitialize = TRUE; + Miniport->NormalInterrupts = FALSE; + + EthDeleteFilter(Miniport->EthDB); + Miniport->EthDB = NULL; + TrDeleteFilter(Miniport->TrDB); + Miniport->TrDB = NULL; + FddiDeleteFilter(Miniport->FddiDB); + Miniport->FddiDB = NULL; + ArcDeleteFilter(Miniport->ArcDB); + Miniport->ArcDB = NULL; + + if (!TrCreateFilter( + NdisMChangeFunctionalAddress, + NdisMChangeGroupAddress, + NdisMChangeClass, + NdisMCloseAction, + CurrentLongAddress, + &Miniport->Lock, + &Miniport->TrDB + )) { + + // + // Halt the miniport driver + // + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 2, + 0xFF00FF00, + 0xC + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + Miniport->InInitialize = FALSE; + CHECK_FOR_NORMAL_INTERRUPTS(Miniport); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + break; + + case NdisMediumFddi: + + // + // Query maximum MulticastAddress + // + Miniport->MiniportRequest = &Miniport->InternalRequest; + Miniport->InternalRequest.RequestType = NdisRequestQueryInformation; + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NdisStatus = + (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) ( + Miniport->MiniportAdapterContext, + OID_FDDI_LONG_MAX_LIST_SIZE, + &MaximumLongAddresses, + sizeof(MaximumLongAddresses), + &BytesWritten, + &BytesNeeded + ); + + KeLowerIrql(OldIrql); + UNLOCK_MINIPORT(Miniport, LocalLock); + + // + // Fire a DPC to do anything + // + if ((NdisStatus == NDIS_STATUS_PENDING) || + (NdisStatus == NDIS_STATUS_SUCCESS)) { + + Miniport->RunDpc = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 1); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + NtStatus = KeWaitForSingleObject( + &Miniport->RequestEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0xD + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + KeResetEvent( + &Miniport->RequestEvent + ); + + NdisStatus = Miniport->RequestStatus; + + } + + if (MaximumLongAddresses > NDIS_M_MAX_MULTI_LIST) { + + MaximumLongAddresses = NDIS_M_MAX_MULTI_LIST; + + } + + Miniport->MaximumLongAddresses = MaximumLongAddresses; + + if (NdisStatus != NDIS_STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0xE + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + // + // Query maximum MulticastAddress + // + Miniport->MiniportRequest = &Miniport->InternalRequest; + Miniport->InternalRequest.RequestType = NdisRequestQueryInformation; + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NdisStatus = + (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) ( + Miniport->MiniportAdapterContext, + OID_FDDI_SHORT_MAX_LIST_SIZE, + &MaximumShortAddresses, + sizeof(MaximumShortAddresses), + &BytesWritten, + &BytesNeeded + ); + + KeLowerIrql(OldIrql); + UNLOCK_MINIPORT(Miniport, LocalLock); + + // + // Fire a DPC to do anything + // + if ((NdisStatus == NDIS_STATUS_PENDING) || + (NdisStatus == NDIS_STATUS_SUCCESS)) { + + Miniport->RunDpc = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 1); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + NtStatus = KeWaitForSingleObject( + &Miniport->RequestEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0xF + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + KeResetEvent( + &Miniport->RequestEvent + ); + + NdisStatus = Miniport->RequestStatus; + + } + + if (MaximumShortAddresses > NDIS_M_MAX_MULTI_LIST) { + + MaximumShortAddresses = NDIS_M_MAX_MULTI_LIST; + + } + + Miniport->MaximumShortAddresses = MaximumShortAddresses; + + if (NdisStatus != NDIS_STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x10 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NdisStatus = + (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) ( + Miniport->MiniportAdapterContext, + OID_FDDI_LONG_CURRENT_ADDR, + &(CurrentLongAddress), + sizeof(CurrentLongAddress), + &BytesWritten, + &BytesNeeded + ); + + KeLowerIrql(OldIrql); + UNLOCK_MINIPORT(Miniport, LocalLock); + + // + // Fire a DPC to do anything + // + if ((NdisStatus == NDIS_STATUS_PENDING) || + (NdisStatus == NDIS_STATUS_SUCCESS)) { + + Miniport->RunDpc = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 1); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + NtStatus = KeWaitForSingleObject( + &Miniport->RequestEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x11 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + KeResetEvent( + &Miniport->RequestEvent + ); + + NdisStatus = Miniport->RequestStatus; + + } + + if (NdisStatus != NDIS_STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x12 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + Miniport->MiniportRequest = &Miniport->InternalRequest; + Miniport->InternalRequest.RequestType = NdisRequestQueryInformation; + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NdisStatus = + (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) ( + Miniport->MiniportAdapterContext, + OID_FDDI_SHORT_CURRENT_ADDR, + &(CurrentShortAddress), + sizeof(CurrentShortAddress), + &BytesWritten, + &BytesNeeded + ); + + KeLowerIrql(OldIrql); + UNLOCK_MINIPORT(Miniport, LocalLock); + + // + // Fire a DPC to do anything + // + if ((NdisStatus == NDIS_STATUS_PENDING) || + (NdisStatus == NDIS_STATUS_SUCCESS)) { + + Miniport->RunDpc = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 1); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + NtStatus = KeWaitForSingleObject( + &Miniport->RequestEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x13 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + KeResetEvent( + &Miniport->RequestEvent + ); + + NdisStatus = Miniport->RequestStatus; + + } + + if (NdisStatus != NDIS_STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x14 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + // + // Now undo the bogus filter package. We lock + // the miniport so that no dpcs will get queued. + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + Miniport->InInitialize = TRUE; + Miniport->NormalInterrupts = FALSE; + + EthDeleteFilter(Miniport->EthDB); + Miniport->EthDB = NULL; + TrDeleteFilter(Miniport->TrDB); + Miniport->TrDB = NULL; + FddiDeleteFilter(Miniport->FddiDB); + Miniport->FddiDB = NULL; + ArcDeleteFilter(Miniport->ArcDB); + Miniport->ArcDB = NULL; + + if (!FddiCreateFilter( + MaximumLongAddresses, + MaximumShortAddresses, + NdisMChangeFddiAddresses, + NdisMChangeClass, + NdisMCloseAction, + CurrentLongAddress, + CurrentShortAddress, + &Miniport->Lock, + &Miniport->FddiDB + )) { + + // + // Halt the miniport driver + // + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 2, + 0xFF00FF00, + 0x15 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + Miniport->InInitialize = FALSE; + CHECK_FOR_NORMAL_INTERRUPTS(Miniport); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + break; + + case NdisMediumArcnet878_2: + + // + // In case of an encapsulated ethernet binding, we need + // to return the maximum number of multicast addresses + // possible. + // + + Miniport->MaximumLongAddresses = NDIS_M_MAX_MULTI_LIST; + + // + // Allocate Buffer pools + // + NdisAllocateBufferPool(&NdisStatus, + &Miniport->ArcnetBufferPool, + WRAPPER_ARC_BUFFERS + ); + if (NdisStatus != NDIS_STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 2, + 0xFF00FF00, + 0x16 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + NdisAllocateMemory((PVOID)&Buffer, + sizeof(ARC_BUFFER_LIST) * + WRAPPER_ARC_BUFFERS, + 0, + HighestAcceptableMax + ); + + if (Buffer == NULL) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 2, + 0xFF00FF00, + 0x18 + ); + NdisFreeBufferPool(Miniport->ArcnetBufferPool); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + NdisAllocateMemory((PVOID)&DataBuffer, + WRAPPER_ARC_HEADER_SIZE * + WRAPPER_ARC_BUFFERS, + 0, + HighestAcceptableMax + ); + + + if (DataBuffer == NULL) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 2, + 0xFF00FF00, + 0x19 + ); + NdisFreeMemory(Buffer, + sizeof(ARC_BUFFER_LIST) * + WRAPPER_ARC_BUFFERS, + 0 + ); + NdisFreeBufferPool(Miniport->ArcnetBufferPool); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + for (i = WRAPPER_ARC_BUFFERS; i != 0 ; i--) { + + Buffer->BytesLeft = Buffer->Size = WRAPPER_ARC_HEADER_SIZE; + Buffer->Buffer = DataBuffer; + Buffer->Next = Miniport->ArcnetFreeBufferList; + Miniport->ArcnetFreeBufferList = Buffer; + + Buffer++; + DataBuffer = (PVOID)(((PUCHAR)DataBuffer) + + WRAPPER_ARC_HEADER_SIZE); + + } + + + // + // Get current address + // + + Miniport->MiniportRequest = &Miniport->InternalRequest; + Miniport->InternalRequest.RequestType = NdisRequestQueryInformation; + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NdisStatus = + (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) ( + Miniport->MiniportAdapterContext, + OID_ARCNET_CURRENT_ADDRESS, + &CurrentLongAddress[5], // address = 00-00-00-00-00-XX + 1, + &BytesWritten, + &BytesNeeded + ); + + KeLowerIrql(OldIrql); + UNLOCK_MINIPORT(Miniport, LocalLock); + + // + // Fire a DPC to do anything + // + if ((NdisStatus == NDIS_STATUS_PENDING) || + (NdisStatus == NDIS_STATUS_SUCCESS)) { + + Miniport->RunDpc = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 1); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + NtStatus = KeWaitForSingleObject( + &Miniport->RequestEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x1A + ); + NdisFreeMemory(Buffer, + sizeof(ARC_BUFFER_LIST) * + WRAPPER_ARC_BUFFERS, + 0 + ); + NdisFreeMemory(DataBuffer, + WRAPPER_ARC_HEADER_SIZE * + WRAPPER_ARC_BUFFERS, + 0 + ); + NdisFreeBufferPool(Miniport->ArcnetBufferPool); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + KeResetEvent( + &Miniport->RequestEvent + ); + + NdisStatus = Miniport->RequestStatus; + + } + + if (NdisStatus != NDIS_STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x1B + ); + NdisFreeMemory(Buffer, + sizeof(ARC_BUFFER_LIST) * + WRAPPER_ARC_BUFFERS, + 0 + ); + NdisFreeMemory(DataBuffer, + WRAPPER_ARC_HEADER_SIZE * + WRAPPER_ARC_BUFFERS, + 0 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + Miniport->ArcnetAddress = CurrentLongAddress[5]; + + // + // Now undo the bogus filter package. We lock + // the miniport so that no dpcs will get queued. + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + Miniport->InInitialize = TRUE; + Miniport->NormalInterrupts = FALSE; + + EthDeleteFilter(Miniport->EthDB); + Miniport->EthDB = NULL; + TrDeleteFilter(Miniport->TrDB); + Miniport->TrDB = NULL; + FddiDeleteFilter(Miniport->FddiDB); + Miniport->FddiDB = NULL; + ArcDeleteFilter(Miniport->ArcDB); + Miniport->ArcDB = NULL; + + if (!ArcCreateFilter( + Miniport, + NdisMChangeClass, + NdisMCloseAction, + CurrentLongAddress[5], + &Miniport->Lock, + &(Miniport->ArcDB) + )) { + + // + // Halt the miniport driver + // + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 2, + 0xFF00FF00, + 0x1C + ); + NdisFreeMemory(Buffer, + sizeof(ARC_BUFFER_LIST) * + WRAPPER_ARC_BUFFERS, + 0 + ); + NdisFreeMemory(DataBuffer, + WRAPPER_ARC_HEADER_SIZE * + WRAPPER_ARC_BUFFERS, + 0 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + // Zero all but the last one. + + CurrentLongAddress[0] = 0; + CurrentLongAddress[1] = 0; + CurrentLongAddress[2] = 0; + CurrentLongAddress[3] = 0; + CurrentLongAddress[4] = 0; + + if (!EthCreateFilter( + 32, + NdisMChangeEthAddresses, + NdisMChangeClass, + NdisMCloseAction, + CurrentLongAddress, + &Miniport->Lock, + &Miniport->EthDB + )) { + + // + // Halt the miniport driver + // + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 2, + 0xFF00FF00, + 0x1D + ); + NdisFreeMemory(Buffer, + sizeof(ARC_BUFFER_LIST) * + WRAPPER_ARC_BUFFERS, + 0 + ); + NdisFreeMemory(DataBuffer, + WRAPPER_ARC_HEADER_SIZE * + WRAPPER_ARC_BUFFERS, + 0 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + Miniport->InInitialize = FALSE; + CHECK_FOR_NORMAL_INTERRUPTS(Miniport); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + break; + + case NdisMediumWan: + + Miniport->MiniportRequest = &Miniport->InternalRequest; + Miniport->InternalRequest.RequestType = NdisRequestQueryInformation; + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NdisStatus = + (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) ( + Miniport->MiniportAdapterContext, + OID_WAN_CURRENT_ADDRESS, + &(CurrentLongAddress), + sizeof(CurrentLongAddress), + &BytesWritten, + &BytesNeeded + ); + + KeLowerIrql(OldIrql); + UNLOCK_MINIPORT(Miniport, LocalLock); + + // + // Fire a DPC to do anything + // + if ((NdisStatus == NDIS_STATUS_PENDING) || + (NdisStatus == NDIS_STATUS_SUCCESS)) { + + Miniport->RunDpc = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 1); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + NtStatus = KeWaitForSingleObject( + &Miniport->RequestEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x7 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + KeResetEvent( + &Miniport->RequestEvent + ); + + NdisStatus = Miniport->RequestStatus; + + } + + if (NdisStatus != NDIS_STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x8 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + // + // Now undo the bogus filter package. We lock + // the miniport so that no dpcs will get queued. + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + Miniport->InInitialize = TRUE; + Miniport->NormalInterrupts = FALSE; + + EthDeleteFilter(Miniport->EthDB); + Miniport->EthDB = NULL; + TrDeleteFilter(Miniport->TrDB); + Miniport->TrDB = NULL; + FddiDeleteFilter(Miniport->FddiDB); + Miniport->FddiDB = NULL; + ArcDeleteFilter(Miniport->ArcDB); + Miniport->ArcDB = NULL; + + Miniport->InInitialize = FALSE; + CHECK_FOR_NORMAL_INTERRUPTS(Miniport); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + break; + + } + + // + // Get supported packet filters + // + Miniport->SupportedPacketFilters = 0; + + // + // Set the filter packages bit mask to fake it out. + // + if (Miniport->EthDB) { + Miniport->EthDB->CombinedPacketFilter = 0xFFFFFFFF; + } + if (Miniport->TrDB) { + Miniport->TrDB->CombinedPacketFilter = 0xFFFFFFFF; + } + if (Miniport->FddiDB) { + Miniport->FddiDB->CombinedPacketFilter = 0xFFFFFFFF; + } + + // + // For WAN there is no packet filter + // + + if (Miniport->MediaType==NdisMediumWan) { + goto SkipFilter; + } + + for (i=0; i<31; i++) { + + // + // Set packet filter + // + Miniport->MiniportRequest = &Miniport->InternalRequest; + Miniport->InternalRequest.RequestType = NdisRequestQueryStatistics; + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NdisStatus = + (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler) ( + Miniport->MiniportAdapterContext, + OID_GEN_CURRENT_PACKET_FILTER, + &PacketFilter, + sizeof(PacketFilter), + &BytesWritten, + &BytesNeeded + ); + + KeLowerIrql(OldIrql); + UNLOCK_MINIPORT(Miniport, LocalLock); + + // + // Fire a DPC to do anything + // + if ((NdisStatus == NDIS_STATUS_PENDING) || + (NdisStatus == NDIS_STATUS_SUCCESS)) { + + Miniport->RunDpc = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 1); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + NtStatus = KeWaitForSingleObject( + &Miniport->RequestEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x1E + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + KeResetEvent( + &Miniport->RequestEvent + ); + + NdisStatus = Miniport->RequestStatus; + + } + + + if (NdisStatus == NDIS_STATUS_SUCCESS) { + Miniport->SupportedPacketFilters |= PacketFilter; + } + + PacketFilter = PacketFilter << 1; + + } + + // + // Set packet filter + // + Miniport->MiniportRequest = &Miniport->InternalRequest; + PacketFilter = 0; + + Miniport->InternalRequest.RequestType = NdisRequestQueryStatistics; + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NdisStatus = + (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler) ( + Miniport->MiniportAdapterContext, + OID_GEN_CURRENT_PACKET_FILTER, + &PacketFilter, + sizeof(PacketFilter), + &BytesWritten, + &BytesNeeded + ); + + KeLowerIrql(OldIrql); + UNLOCK_MINIPORT(Miniport, LocalLock); + + // + // Fire a DPC to do anything + // + if ((NdisStatus == NDIS_STATUS_PENDING) || + (NdisStatus == NDIS_STATUS_SUCCESS)) { + + Miniport->RunDpc = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 1); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + KeWaitForSingleObject( + &Miniport->RequestEvent, + Executive, + KernelMode, + TRUE, + (PLARGE_INTEGER)NULL + ); + + KeResetEvent( + &Miniport->RequestEvent + ); + + NdisStatus = Miniport->RequestStatus; + + } + + // + // Set the filter packages bit mask to fake it out. + // + if (Miniport->EthDB) { + Miniport->EthDB->CombinedPacketFilter = 0; + } + if (Miniport->TrDB) { + Miniport->TrDB->CombinedPacketFilter = 0; + } + if (Miniport->FddiDB) { + Miniport->FddiDB->CombinedPacketFilter = 0; + } + +SkipFilter: + + // + // Start wake up timer + // + NdisSetTimer(&(Miniport->WakeUpDpcTimer), 2000); + + // + // Done with adding this MINIPORT!!! + // + Miniport->MiniportRequest = NULL; + Miniport->InAddDriver = FALSE; + + IoRegisterShutdownNotification(Miniport->DeviceObject); + + ++AdaptersAdded; + + } else{ + + // + // Undo all the stuff from this mini-port + // + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + } else { + + // + // NDIS 3.0 MAC + // + AddAdapterStatus = + (NewMacP->MacCharacteristics.AddAdapterHandler)( + NewMacP->MacMacContext, + &ConfigurationHandle, + &CurExportString + ); + + + // + // Free the slot information buffer + // + + if (ConfigurationHandle.ParametersQueryTable[3].DefaultData != NULL ) { + + ExFreePool(ConfigurationHandle.ParametersQueryTable[3].DefaultData); + + } + + if (AddAdapterStatus == NDIS_STATUS_SUCCESS) { + ++AdaptersAdded; + } + + } + +LoopBottom: + + + // + // Now advance the "Bind" and "Export" values. + // + + CurBindValue = (PWCHAR)((PUCHAR)CurBindValue + CurBindString.MaximumLength); + CurExportValue = (PWCHAR)((PUCHAR)CurExportValue + CurExportString.MaximumLength); + + } + + + // + // OK, Now dereference all the filter packages. If a MAC or + // Miniport driver uses any of these, then the filter package + // will reference itself, to keep the image in memory. + // + ArcDereferencePackage(); + EthDereferencePackage(); + FddiDereferencePackage(); + TrDereferencePackage(); + MiniportDereferencePackage(); + NdisMacDereferencePackage(); + + // + // Now close the handles we opened at the beginning. + // + + + ExFreePool (ConfigurationPath); + ExFreePool (BindData); + ExFreePool (ExportData); + + // + // Succeed if any adapters were added. + // + + if (AdaptersAdded > 0) { + return NDIS_STATUS_SUCCESS; + } else { + return NDIS_STATUS_FAILURE; + } + +#undef BLOCK_LOCK_MINIPORT + +} + + +VOID +NdisReadEisaSlotInformation( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE WrapperConfigurationContext, + OUT PUINT SlotNumber, + OUT PNDIS_EISA_FUNCTION_INFORMATION EisaData + ) + +/*++ + +Routine Description: + + This routine reads the EISA data from the slot given. + +Arguments: + + Status - Status of request to be returned to the user. + WrapperConfigurationContext - Context passed to MacAddAdapter. + SlotNumber - the EISA Slot where the card is at. + EisaData - pointer to a buffer where the EISA configuration is to be + returned. + +Return Value: + + None. + +--*/ +{ + PNDIS_EISA_FUNCTION_INFORMATION EisaBlockPointer; + PNDIS_EISA_SLOT_INFORMATION SlotInformation; + NTSTATUS NtStatus; + ULONG BusNumber; + ULONG DataLength; + ULONG SearchSlotNumber; + ULONG FoundSlotNumber; + BOOLEAN Found; + NDIS_INTERFACE_TYPE BusType; + ULONG CompressedId = 0; + PWSTR CompressedIDString = L"EisaCompressedId"; + PWSTR SlotNumberString = L"SlotNumber"; + PWSTR Parameters = L"\\Parameters"; + PNDIS_CONFIGURATION_PARAMETER ParameterValue; + NDIS_CONFIGURATION_HANDLE NdisConfiguration; + ULONG Length; + PWSTR PathName; + + // + // Get the BusNumber and the BusType from the Context here!! + // + + NdisConfiguration.KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + + BusType = (NDIS_INTERFACE_TYPE)(NdisConfiguration.KeyQueryTable[3].DefaultType); + + BusNumber = NdisConfiguration.KeyQueryTable[3].DefaultLength; + + // + // First check if any bus access is allowed + // + + if ((BusType == (NDIS_INTERFACE_TYPE)-1) || + (BusNumber == (ULONG)-1)) { + + *Status = NDIS_STATUS_FAILURE; + return; + + } + + SlotInformation = NdisConfiguration.KeyQueryTable[3].DefaultData; + + *SlotNumber = 0; + + if (BusType != Eisa) { + + *Status = NDIS_STATUS_FAILURE; + return; + + } + + + // + // Find the CompressedId for this board. + // + + NdisConfiguration.KeyQueryTable[1].Name = CompressedIDString; + NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue; + + // + // Get the value from the registry; this chains it on to the + // parameter list at NdisConfiguration. + // + + NtStatus = RtlQueryRegistryValues( + RTL_REGISTRY_SERVICES, + NdisConfiguration.KeyQueryTable[3].Name, + NdisConfiguration.KeyQueryTable, + &NdisConfiguration, // context + NULL); + + if (NtStatus != NDIS_STATUS_SUCCESS) { + CompressedId = 0xffffffff; + } else if (ParameterValue->ParameterType != NdisParameterInteger) { + CompressedId = 0xffffffff; + } else { + CompressedId = ParameterValue->ParameterData.IntegerData; + } + + // + // Was there already a buffer allocated? + // + + if (SlotInformation == NULL) { + + // + // No, allocate a buffer + // + + SlotInformation = (PNDIS_EISA_SLOT_INFORMATION)ExAllocatePoolWithTag( + NonPagedPool, + sizeof(NDIS_EISA_SLOT_INFORMATION) + + sizeof(NDIS_EISA_FUNCTION_INFORMATION), + 'isDN' + ); + + if (SlotInformation == NULL) { + + *Status = NDIS_STATUS_RESOURCES; + return; + + } + + // + // Free any old buffer + // + + if (NdisConfiguration.KeyQueryTable[3].DefaultData != NULL) { + + ExFreePool(NdisConfiguration.KeyQueryTable[3].DefaultData); + + } + + NdisConfiguration.KeyQueryTable[3].DefaultData = SlotInformation; + + } + + // + // Now read the slot number + // + + NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString; + NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue; + + // + // Get the value from the registry; this chains it on to the + // parameter list at NdisConfiguration. + // + + NtStatus = RtlQueryRegistryValues( + RTL_REGISTRY_SERVICES, + NdisConfiguration.KeyQueryTable[3].Name, + NdisConfiguration.KeyQueryTable, + &NdisConfiguration, // context + NULL); + + if ((NtStatus == NDIS_STATUS_SUCCESS) && + (ParameterValue->ParameterType == NdisParameterInteger)) { + + *SlotNumber = ParameterValue->ParameterData.IntegerData; + + } else { + + *Status = NDIS_STATUS_FAILURE; + return; + + } + + DataLength = HalGetBusData( + EisaConfiguration, + BusNumber, + *SlotNumber, + (PVOID)SlotInformation, + sizeof(NDIS_EISA_SLOT_INFORMATION) + + sizeof(NDIS_EISA_FUNCTION_INFORMATION) + ); + + if ((CompressedId != 0xFFFFFFFF) && + ((SlotInformation->CompressedId & 0xFFFFFF) != CompressedId)) { + + // + // The card seems to have been moved on us. Now we search for it. + // + + SearchSlotNumber = 1; + Found = FALSE; + + while (TRUE) { + + // + // Search this slot + // + DataLength = HalGetBusData( + EisaConfiguration, + BusNumber, + SearchSlotNumber, + (PVOID)SlotInformation, + sizeof(NDIS_EISA_SLOT_INFORMATION) + + sizeof(NDIS_EISA_FUNCTION_INFORMATION) + ); + + if ((DataLength == 0) || + (SearchSlotNumber == 0xFF)) { + // + // End of slots. + // + break; + + } + + if ((SlotInformation->CompressedId & 0xFFFFFF) == CompressedId) { + + // + // Found one! + // + + if (Found) { + + // + // Uh-oh, found two of them! Fail + // + *Status = NDIS_STATUS_FAILURE; + return; + + } + + Found = TRUE; + FoundSlotNumber = SearchSlotNumber; + + } + + SearchSlotNumber++; + + } + + if (!Found) { + // + // No card found + // + *Status = NDIS_STATUS_FAILURE; + return; + + } + + // + // Find the SlotNumber parameter in the registry. + // + + *SlotNumber = FoundSlotNumber; + + NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString; + NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue; + + Length = wcslen(NdisConfiguration.KeyQueryTable[3].Name); + + PathName = ExAllocatePoolWithTag(NonPagedPool, + sizeof(L"\\Parameters") + + (Length * sizeof(WCHAR)) + + sizeof(WCHAR), + ' DN' + ); + + if (PathName != NULL) { + + NdisZeroMemory(PathName, sizeof(L"\\Parameters") + + (Length * sizeof(WCHAR)) + + sizeof(WCHAR) + ); + + NdisMoveMemory(PathName, + NdisConfiguration.KeyQueryTable[3].Name, + Length * sizeof(WCHAR) + ); + + NdisMoveMemory(PathName + Length, Parameters, sizeof(L"\\Parameters")); + + // + // Update the value + // + + NtStatus = RtlWriteRegistryValue( + RTL_REGISTRY_SERVICES, + PathName, + SlotNumberString, + REG_DWORD, + &FoundSlotNumber, + sizeof(FoundSlotNumber) + ); + + ExFreePool(PathName); + + } + + // + // Get the new information + // + + DataLength = HalGetBusData( + EisaConfiguration, + BusNumber, + FoundSlotNumber, + (PVOID)SlotInformation, + sizeof(NDIS_EISA_SLOT_INFORMATION) + + sizeof(NDIS_EISA_FUNCTION_INFORMATION) + ); + + } + + EisaBlockPointer = (PNDIS_EISA_FUNCTION_INFORMATION) + ((PUCHAR)SlotInformation + sizeof(CM_EISA_SLOT_INFORMATION)); + + *EisaData = *EisaBlockPointer; + *Status = NDIS_STATUS_SUCCESS; + +} + + +VOID +NdisReadEisaSlotInformationEx( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE WrapperConfigurationContext, + OUT PUINT SlotNumber, + OUT PNDIS_EISA_FUNCTION_INFORMATION *EisaData, + OUT PUINT NumberOfFunctions + ) + +/*++ + +Routine Description: + + This routine reads the EISA data from the slot given. + +Arguments: + + Status - Status of request to be returned to the user. + WrapperConfigurationContext - Context passed to MacAddAdapter. + SlotNumber - the EISA Slot where the card is at. + EisaData - pointer to a buffer where the EISA configuration is to be + returned. + NumberOfFunctions - Returns the number of function structures in the EisaData. + +Return Value: + + None. + +--*/ +{ + PNDIS_EISA_FUNCTION_INFORMATION EisaBlockPointer; + PNDIS_EISA_SLOT_INFORMATION SlotInformation; + NTSTATUS NtStatus; + ULONG BusNumber; + ULONG DataLength; + ULONG SearchSlotNumber; + ULONG FoundSlotNumber; + BOOLEAN Found; + NDIS_INTERFACE_TYPE BusType; + ULONG CompressedId = 0; + PWSTR CompressedIDString = L"EisaCompressedId"; + PWSTR SlotNumberString = L"SlotNumber"; + PWSTR Parameters = L"\\Parameters"; + PNDIS_CONFIGURATION_PARAMETER ParameterValue; + NDIS_CONFIGURATION_HANDLE NdisConfiguration; + ULONG Length; + PWSTR PathName; + + // + // Get the BusNumber and the BusType from the Context here!! + // + + NdisConfiguration.KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + + BusType = (NDIS_INTERFACE_TYPE)(NdisConfiguration.KeyQueryTable[3].DefaultType); + + BusNumber = NdisConfiguration.KeyQueryTable[3].DefaultLength; + + // + // First check if any bus access is allowed + // + + if ((BusType == (NDIS_INTERFACE_TYPE)-1) || + (BusNumber == (ULONG)-1)) { + + *Status = NDIS_STATUS_FAILURE; + return; + + } + + SlotInformation = NdisConfiguration.KeyQueryTable[3].DefaultData; + + *SlotNumber = 0; + *NumberOfFunctions = 2; + + if (BusType != Eisa) { + + *Status = NDIS_STATUS_FAILURE; + return; + + } + + + // + // Find the CompressedId for this board. + // + + NdisConfiguration.KeyQueryTable[1].Name = CompressedIDString; + NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue; + + // + // Get the value from the registry; this chains it on to the + // parameter list at NdisConfiguration. + // + + NtStatus = RtlQueryRegistryValues( + RTL_REGISTRY_SERVICES, + NdisConfiguration.KeyQueryTable[3].Name, + NdisConfiguration.KeyQueryTable, + &NdisConfiguration, // context + NULL); + + if (NtStatus != NDIS_STATUS_SUCCESS) { + CompressedId = 0xffffffff; + } else if (ParameterValue->ParameterType != NdisParameterInteger) { + CompressedId = 0xffffffff; + } else { + CompressedId = ParameterValue->ParameterData.IntegerData; + } + + // + // Was there already a buffer allocated? + // + + if (SlotInformation == NULL) { + + // + // No, allocate a buffer + // + + SlotInformation = (PNDIS_EISA_SLOT_INFORMATION)ExAllocatePoolWithTag( + NonPagedPool, + sizeof(NDIS_EISA_SLOT_INFORMATION) + + (*NumberOfFunctions * + sizeof(NDIS_EISA_FUNCTION_INFORMATION)), + 'isDN' + ); + + if (SlotInformation == NULL) { + + *Status = NDIS_STATUS_RESOURCES; + return; + + } + + // + // Free any old buffer + // + + if (NdisConfiguration.KeyQueryTable[3].DefaultData != NULL) { + + ExFreePool(NdisConfiguration.KeyQueryTable[3].DefaultData); + + } + + NdisConfiguration.KeyQueryTable[3].DefaultData = SlotInformation; + + } + + // + // Now read the slot number + // + + NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString; + NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue; + + // + // Get the value from the registry; this chains it on to the + // parameter list at NdisConfiguration. + // + + NtStatus = RtlQueryRegistryValues( + RTL_REGISTRY_SERVICES, + NdisConfiguration.KeyQueryTable[3].Name, + NdisConfiguration.KeyQueryTable, + &NdisConfiguration, // context + NULL); + + if ((NtStatus == NDIS_STATUS_SUCCESS) && + (ParameterValue->ParameterType == NdisParameterInteger)) { + + *SlotNumber = ParameterValue->ParameterData.IntegerData; + + } else { + + *Status = NDIS_STATUS_FAILURE; + return; + + } + + DataLength = HalGetBusData( + EisaConfiguration, + BusNumber, + *SlotNumber, + (PVOID)SlotInformation, + sizeof(NDIS_EISA_SLOT_INFORMATION) + + (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION)) + ); + + if ((CompressedId != 0xFFFFFFFF) && + ((SlotInformation->CompressedId & 0xFFFFFF) != CompressedId)) { + + // + // The card seems to have been moved on us. Now we search for it. + // + + SearchSlotNumber = 1; + Found = FALSE; + + while (TRUE) { + + // + // Search this slot + // + DataLength = HalGetBusData( + EisaConfiguration, + BusNumber, + SearchSlotNumber, + (PVOID)SlotInformation, + sizeof(NDIS_EISA_SLOT_INFORMATION) + + (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION)) + ); + + if ((DataLength == 0) || + (SearchSlotNumber == 0xFF)) { + // + // End of slots. + // + break; + + } + + if ((SlotInformation->CompressedId & 0xFFFFFF) == CompressedId) { + + // + // Found one! + // + + if (Found) { + + // + // Uh-oh, found two of them! Fail + // + *Status = NDIS_STATUS_FAILURE; + return; + + } + + Found = TRUE; + FoundSlotNumber = SearchSlotNumber; + + } + + SearchSlotNumber++; + + } + + if (!Found) { + // + // No card found + // + *Status = NDIS_STATUS_FAILURE; + return; + + } + + // + // Find the SlotNumber parameter in the registry. + // + + *SlotNumber = FoundSlotNumber; + + NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString; + NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue; + + Length = wcslen(NdisConfiguration.KeyQueryTable[3].Name); + + PathName = ExAllocatePoolWithTag(NonPagedPool, + sizeof(L"\\Parameters") + + (Length * sizeof(WCHAR)) + + sizeof(WCHAR), + ' DN' + ); + + if (PathName != NULL) { + + NdisZeroMemory(PathName, sizeof(L"\\Parameters") + + (Length * sizeof(WCHAR)) + + sizeof(WCHAR) + ); + + NdisMoveMemory(PathName, + NdisConfiguration.KeyQueryTable[3].Name, + Length * sizeof(WCHAR) + ); + + NdisMoveMemory(PathName + Length, Parameters, sizeof(L"\\Parameters")); + + // + // Update the value + // + + NtStatus = RtlWriteRegistryValue( + RTL_REGISTRY_SERVICES, + PathName, + SlotNumberString, + REG_DWORD, + &FoundSlotNumber, + sizeof(FoundSlotNumber) + ); + + ExFreePool(PathName); + + } + + // + // Get the new information + // + + DataLength = HalGetBusData( + EisaConfiguration, + BusNumber, + FoundSlotNumber, + (PVOID)SlotInformation, + sizeof(NDIS_EISA_SLOT_INFORMATION) + + (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION)) + ); + + } + + + // + // Now check for multiple functions in the Eisa data. + // + + while (DataLength == (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION))) { + + *NumberOfFunctions++; + + // + // Now allocate a new buffer + // + + SlotInformation = (PNDIS_EISA_SLOT_INFORMATION)ExAllocatePoolWithTag( + NonPagedPool, + sizeof(NDIS_EISA_SLOT_INFORMATION) + + (*NumberOfFunctions * + sizeof(NDIS_EISA_FUNCTION_INFORMATION)), + 'isDN' + ); + + if (SlotInformation == NULL) { + + *Status = NDIS_STATUS_RESOURCES; + return; + + } + + // + // Free any old buffer + // + + if (NdisConfiguration.KeyQueryTable[3].DefaultData != NULL) { + + ExFreePool(NdisConfiguration.KeyQueryTable[3].DefaultData); + + } + + NdisConfiguration.KeyQueryTable[3].DefaultData = SlotInformation; + + // + // Get new information + // + + DataLength = HalGetBusData( + EisaConfiguration, + BusNumber, + FoundSlotNumber, + (PVOID)SlotInformation, + sizeof(NDIS_EISA_SLOT_INFORMATION) + + (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION)) + ); + + } + + EisaBlockPointer = (PNDIS_EISA_FUNCTION_INFORMATION) + ((PUCHAR)SlotInformation + sizeof(CM_EISA_SLOT_INFORMATION)); + + *EisaData = EisaBlockPointer; + *NumberOfFunctions--; // We overshoot by 1 to verify last one found. + *Status = NDIS_STATUS_SUCCESS; + +} + + +VOID +NdisReadMcaPosInformation( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE WrapperConfigurationContext, + OUT PUINT ChannelNumber, + OUT PNDIS_MCA_POS_DATA McaData + ) + +/*++ + +Routine Description: + + This routine reads the MCA data from the POS corresponding to + the channel specified. + +Arguments: + + WrapperConfigurationContext - Context passed to MacAddAdapter. + ChannelNumber - the MCA channel number. + McaData - pointer to a buffer where the channel information is to be + returned. + +Return Value: + + None. + +--*/ +{ + OBJECT_ATTRIBUTES ObjectAttributes; + OBJECT_ATTRIBUTES BusObjectAttributes; + PWSTR McaPath = L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter"; + PWSTR ConfigData = L"Configuration Data"; + PWSTR PosIdString = L"McaPosId"; + PWSTR SlotNumberString = L"SlotNumber"; + UNICODE_STRING RootName; + UNICODE_STRING BusName; + UNICODE_STRING ConfigDataName; + NTSTATUS NtStatus; + PKEY_BASIC_INFORMATION BasicInformation; + PKEY_VALUE_FULL_INFORMATION ValueInformation; + PUCHAR BufferPointer; + PCM_FULL_RESOURCE_DESCRIPTOR FullResource; + PCM_PARTIAL_RESOURCE_LIST ResourceList; + PNDIS_MCA_POS_DATA McaBlockPointer; + HANDLE McaHandle, BusHandle; + ULONG BytesWritten, BytesNeeded; + ULONG Index; + ULONG i; + ULONG BusNumber; + ULONG MaxSlotNumber; + ULONG SearchSlotNumber; + ULONG FoundSlotNumber; + BOOLEAN Found; + USHORT PosId; + NDIS_INTERFACE_TYPE BusType; + NDIS_CONFIGURATION_HANDLE NdisConfiguration; + PNDIS_CONFIGURATION_PARAMETER ParameterValue; + PWSTR Parameters = L"\\Parameters"; + ULONG Length; + PWSTR PathName; + + *Status = NDIS_STATUS_FAILURE; + + NdisConfiguration.KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + + // + // Get the BusNumber and the BusType from the Context here!! + // + + BusType = (NDIS_INTERFACE_TYPE)(NdisConfiguration.KeyQueryTable[3].DefaultType); + BusNumber = NdisConfiguration.KeyQueryTable[3].DefaultLength; + + // + // First check if any bus access is allowed + // + + if ((BusType == (NDIS_INTERFACE_TYPE)-1) || + (BusNumber == (ULONG)-1)) { + + return; + + } + + + if (BusType != MicroChannel) { + + return; + + } + + *ChannelNumber = 0; + + // + // Find the PosId for this board. + // + + NdisConfiguration.KeyQueryTable[1].Name = PosIdString; + NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue; + + // + // Get the value from the registry; this chains it on to the + // parameter list at NdisConfiguration. + // + + NtStatus = RtlQueryRegistryValues( + RTL_REGISTRY_SERVICES, + NdisConfiguration.KeyQueryTable[3].Name, + NdisConfiguration.KeyQueryTable, + &NdisConfiguration, // context + NULL); + + if (NtStatus != NDIS_STATUS_SUCCESS) { + PosId = 0xffff; + } else if (ParameterValue->ParameterType != NdisParameterInteger) { + PosId = 0xffff; + } else { + PosId = (USHORT)(ParameterValue->ParameterData.IntegerData); + } + + RtlInitUnicodeString( + &RootName, + McaPath + ); + + InitializeObjectAttributes( + &ObjectAttributes, + &RootName, + OBJ_CASE_INSENSITIVE, + (HANDLE)NULL, + NULL + ); + + // + // Open the root. + // + + NtStatus = ZwOpenKey( + &McaHandle, + KEY_READ, + &ObjectAttributes + ); + + if (!NT_SUCCESS(NtStatus)) { + + return; + + } + + Index = 0; + + while (TRUE) { + + // + // Enumerate through keys, searching for the proper bus number + // + + NtStatus = ZwEnumerateKey( + McaHandle, + Index, + KeyBasicInformation, + NULL, + 0, + &BytesNeeded + ); + + // + // That should fail! + // + + if (BytesNeeded == 0) { + + Index++; + continue; + + } + + BasicInformation = (PKEY_BASIC_INFORMATION)ExAllocatePoolWithTag( + NonPagedPool, + BytesNeeded, + ' DN' + ); + + if (BasicInformation == NULL) { + + ZwClose(McaHandle); + + return; + } + + NtStatus = ZwEnumerateKey( + McaHandle, + Index, + KeyBasicInformation, + BasicInformation, + BytesNeeded, + &BytesWritten + ); + + if (!NT_SUCCESS(NtStatus)) { + + ExFreePool(BasicInformation); + + ZwClose(McaHandle); + + return; + } + + + // + // Init the BusName String + // + + BusName.MaximumLength = (USHORT)BasicInformation->NameLength; + BusName.Length = (USHORT)BasicInformation->NameLength; + BusName.Buffer = BasicInformation->Name; + + // + // Now try to find Configuration Data within this Key + // + + InitializeObjectAttributes( + &BusObjectAttributes, + &BusName, + OBJ_CASE_INSENSITIVE, + (HANDLE)McaHandle, + NULL + ); + + // + // Open the MCA root + Bus Number + // + + NtStatus = ZwOpenKey( + &BusHandle, + KEY_READ, + &BusObjectAttributes + ); + + ExFreePool(BasicInformation); + + if (!NT_SUCCESS(NtStatus)) { + + Index++; + + continue; + + } + + // + // opening the configuration data. This first call tells us how + // much memory we need to allocate + // + + RtlInitUnicodeString( + &ConfigDataName, + ConfigData + ); + + // + // This should fail + // + + NtStatus = ZwQueryValueKey( + BusHandle, + &ConfigDataName, + KeyValueFullInformation, + NULL, + 0, + &BytesNeeded + ); + + + ValueInformation = (PKEY_VALUE_FULL_INFORMATION)ExAllocatePoolWithTag( + NonPagedPool, + BytesNeeded, + ' DN' + ); + + + if (ValueInformation == NULL) { + + Index++; + + ZwClose(BusHandle); + + continue; + + } + + NtStatus = ZwQueryValueKey( + BusHandle, + &ConfigDataName, + KeyValueFullInformation, + ValueInformation, + BytesNeeded, + &BytesWritten + ); + + if (!NT_SUCCESS(NtStatus)) { + + Index++; + + ExFreePool(ValueInformation); + + ZwClose(BusHandle); + + continue; + + } + + // + // Search for our bus number and type + // + + + // + // What we got back from the registry is actually a blob of data that + // looks like this + // + // ------------------------------------------ + // |FULL |PAR |PAR |MCA |MCA |MCA | + // |RES. |RES |RES |POS |POS |POS | . . . + // |DESC |LIST|DESC|DATA|DATA|DATA| + // ------------------------------------------ + // slot 0 1 2 . . . + // + // Out of this mess we need to grovel a pointer to the first block + // of MCA_POS_DATA, then we can just index by slot number. + // + + BufferPointer = ((PUCHAR)ValueInformation) + ValueInformation->DataOffset; + FullResource = (PCM_FULL_RESOURCE_DESCRIPTOR) BufferPointer; + + if (FullResource->InterfaceType != MicroChannel) { + + // + // Get next key + // + + ExFreePool(ValueInformation); + + Index++; + + ZwClose(BusHandle); + + continue; + + } + + if (FullResource->BusNumber != BusNumber) { + + // + // Get next key + // + + ExFreePool(ValueInformation); + + Index++; + + ZwClose(BusHandle); + + continue; + + } + + + // + // Found it!! + // + + ResourceList = &FullResource->PartialResourceList; + + // + // Find the device-specific information, which is where the POS data is. + // + + for (i=0; i<ResourceList->Count; i++) { + if (ResourceList->PartialDescriptors[i].Type == CmResourceTypeDeviceSpecific) { + break; + } + } + + if (i == ResourceList->Count) { + // + // Couldn't find device-specific information. + // + +#if DBG + DbgPrint("NDIS: couldn't find POS data in registry\n"); +#endif + + ExFreePool(ValueInformation); + *Status = NDIS_STATUS_ADAPTER_NOT_FOUND; + return; + + } + + // + // Was there a buffer already there? + // + + if (NdisConfiguration.KeyQueryTable[3].DefaultData != NULL) { + + // + // Free it + // + + ExFreePool(NdisConfiguration.KeyQueryTable[3].DefaultData); + + } + + // + // Now read the slot number + // + + NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString; + NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue; + + // + // Get the value from the registry; this chains it on to the + // parameter list at NdisConfiguration. + // + + NtStatus = RtlQueryRegistryValues( + RTL_REGISTRY_SERVICES, + NdisConfiguration.KeyQueryTable[3].Name, + NdisConfiguration.KeyQueryTable, + &NdisConfiguration, // context + NULL); + + if ((NtStatus == NDIS_STATUS_SUCCESS) && + (ParameterValue->ParameterType == NdisParameterInteger)) { + + *ChannelNumber = ParameterValue->ParameterData.IntegerData; + + } else { + + *Status = NDIS_STATUS_FAILURE; + return; + + } + + // + // Store buffer + // + + NdisConfiguration.KeyQueryTable[3].DefaultData = ValueInformation; + + McaBlockPointer = (PNDIS_MCA_POS_DATA)(&ResourceList->PartialDescriptors[i+1]); + MaxSlotNumber = ResourceList->PartialDescriptors[i].u.DeviceSpecificData.DataSize / + sizeof(NDIS_MCA_POS_DATA); + + *McaData = *(McaBlockPointer + (*ChannelNumber) - 1); + + if ((PosId != 0xFFFF) && + (McaData->AdapterId != PosId)) { + + // + // The card seems to have been moved on us. Now we search for it. + // + + SearchSlotNumber = 1; + Found = FALSE; + + while (SearchSlotNumber <= MaxSlotNumber) { + + *McaData = *(McaBlockPointer + (SearchSlotNumber - 1)); + + if (McaData->AdapterId == PosId) { + + // + // Found one! + // + + if (Found) { + + // + // Uh-oh, found two of them! Fail + // + *Status = NDIS_STATUS_FAILURE; + return; + + } + + Found = TRUE; + FoundSlotNumber = SearchSlotNumber; + + } + + SearchSlotNumber++; + + } + + if (!Found) { + // + // No card found + // + *Status = NDIS_STATUS_FAILURE; + return; + + } + + // + // Find the SlotNumber parameter in the registry. + // + + *ChannelNumber = FoundSlotNumber; + + NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString; + NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue; + + Length = wcslen(NdisConfiguration.KeyQueryTable[3].Name); + + PathName = ExAllocatePoolWithTag(NonPagedPool, + sizeof(L"\\Parameters") + + (Length * sizeof(WCHAR)) + + sizeof(WCHAR), + ' DN' + ); + + if (PathName != NULL) { + + NdisZeroMemory(PathName, sizeof(L"\\Parameters") + + (Length * sizeof(WCHAR)) + + sizeof(WCHAR) + ); + + NdisMoveMemory(PathName, + NdisConfiguration.KeyQueryTable[3].Name, + Length * sizeof(WCHAR) + ); + + NdisMoveMemory(PathName + Length, Parameters, sizeof(L"\\Parameters")); + + // + // Update the value + // + + NtStatus = RtlWriteRegistryValue( + RTL_REGISTRY_SERVICES, + PathName, + SlotNumberString, + REG_DWORD, + &FoundSlotNumber, + sizeof(FoundSlotNumber) + ); + + ExFreePool(PathName); + + } + + // + // Update the value + // + NtStatus = RtlWriteRegistryValue( + RTL_REGISTRY_SERVICES, + NdisConfiguration.KeyQueryTable[3].Name, + SlotNumberString, + REG_DWORD, + &FoundSlotNumber, + sizeof(FoundSlotNumber) + ); + + // + // Get the new information + // + + *McaData = *(McaBlockPointer + (FoundSlotNumber - 1)); + + } + + *Status = NDIS_STATUS_SUCCESS; + + ZwClose(McaHandle); + + return; + + } + +} + +#if !defined(BUILD_FOR_3_1) + +NDIS_STATUS +NdisPciAssignResources( + IN NDIS_HANDLE NdisMacHandle, + IN NDIS_HANDLE NdisWrapperHandle, + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG SlotNumber, + OUT PNDIS_RESOURCE_LIST *AssignedResources + ) +/*++ + +Routine Description: + + This routine uses the Hal to assign a set of resources to a PCI + device. + +Arguments: + + NdisMacHandle - Handle returned from NdisRegisterMac. + + NdisWrapperHandle - Handle returned from NdisInitializeWrapper. + + WrapperConfigurationContext - Handle passed to MacAddAdapter. + + SlotNumber - Slot number of the device. + + AssignedResources - The returned resources. + +Return Value: + + Status of the operation + +--*/ +{ + NTSTATUS NtStatus; + ULONG BusNumber; + NDIS_INTERFACE_TYPE BusType; + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable; + PCM_RESOURCE_LIST AllocatedResources = NULL; + PNDIS_WRAPPER_HANDLE NdisMacInfo = (PNDIS_WRAPPER_HANDLE)NdisWrapperHandle; + + // + // Get the BusNumber and the BusType from the Context here!! + // + + KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + + BusType = (NDIS_INTERFACE_TYPE)KeyQueryTable[3].DefaultType; + + BusNumber = KeyQueryTable[3].DefaultLength; + + NtStatus = HalAssignSlotResources ( + (PUNICODE_STRING)(NdisMacInfo->NdisWrapperConfigurationHandle), + NULL, + NdisMacInfo->NdisWrapperDriver, + NULL, + BusType, + BusNumber, + SlotNumber, + &AllocatedResources + ); + + if (NtStatus != STATUS_SUCCESS) { + *AssignedResources = NULL; + return(NDIS_STATUS_FAILURE); + } + + // + // Store resources into the driver wide block + // + ((PNDIS_MAC_BLOCK)NdisMacHandle)->PciAssignedResources = AllocatedResources; + + *AssignedResources = &(AllocatedResources->List[0].PartialResourceList); + + return(NDIS_STATUS_SUCCESS); + +} + + + +ULONG +NdisReadPciSlotInformation( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG SlotNumber, + IN ULONG Offset, + IN PVOID Buffer, + IN ULONG Length + ) +/*++ + +Routine Description: + + This routine reads from the PCI configuration space a specified + length of bytes at a certain offset. + +Arguments: + + NdisAdapterHandle - Adapter we are talking about. + + SlotNumber - The slot number of the device. + + Offset - Offset to read from + + Buffer - Place to store the bytes + + Length - Number of bytes to read + +Return Value: + + Returns the number of bytes read. + +--*/ +{ + PNDIS_ADAPTER_BLOCK Adapter = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle; + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle; + ULONG DataLength; + + if (Adapter->DeviceObject == NULL) { + + // + // This is a mini-port + // + +#if DBG + ASSERT(Miniport->BusType == NdisInterfacePci); +#endif + + DataLength = HalGetBusDataByOffset( + PCIConfiguration, + Miniport->BusNumber, + SlotNumber, + Buffer, + Offset, + Length + ); + + return(DataLength); + + } else { + +#if DBG + ASSERT(Adapter->BusType == NdisInterfacePci); +#endif + + DataLength = HalGetBusDataByOffset( + PCIConfiguration, + Adapter->BusNumber, + SlotNumber, + Buffer, + Offset, + Length + ); + + return(DataLength); + + } + +} + +ULONG +NdisWritePciSlotInformation( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG SlotNumber, + IN ULONG Offset, + IN PVOID Buffer, + IN ULONG Length + ) +/*++ + +Routine Description: + + This routine writes to the PCI configuration space a specified + length of bytes at a certain offset. + +Arguments: + + NdisAdapterHandle - Adapter we are talking about. + + SlotNumber - The slot number of the device. + + Offset - Offset to read from + + Buffer - Place to store the bytes + + Length - Number of bytes to read + +Return Value: + + Returns the number of bytes written. + +--*/ +{ + PNDIS_ADAPTER_BLOCK Adapter = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle; + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle; + ULONG DataLength; + + if (Adapter->DeviceObject == NULL) { + + // + // This is a mini-port + // + +#if DBG + ASSERT(Miniport->BusType == NdisInterfacePci); +#endif + + DataLength = HalSetBusDataByOffset( + PCIConfiguration, + Miniport->BusNumber, + SlotNumber, + Buffer, + Offset, + Length + ); + + return(DataLength); + + } else { + +#if DBG + ASSERT(Adapter->BusType == NdisInterfacePci); +#endif + + DataLength = HalSetBusDataByOffset( + PCIConfiguration, + Adapter->BusNumber, + SlotNumber, + Buffer, + Offset, + Length + ); + + return(DataLength); + + } + +} + +#else // !defined(BUILD_FOR_3_1) + +NDIS_STATUS +NdisPciAssignResources( + IN NDIS_HANDLE NdisMacHandle, + IN NDIS_HANDLE NdisWrapperHandle, + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG SlotNumber, + OUT PNDIS_RESOURCE_LIST *AssignedResources + ) +{ + return NDIS_STATUS_FAILURE; +} + +ULONG +NdisReadPciSlotInformation( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG SlotNumber, + IN ULONG Offset, + IN PVOID Buffer, + IN ULONG Length + ) +{ + return 0; +} + +ULONG +NdisWritePciSlotInformation( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG SlotNumber, + IN ULONG Offset, + IN PVOID Buffer, + IN ULONG Length + ) +{ + return 0; +} + +#endif // else !defined(BUILD_FOR_3_1) + + +VOID +NdisOpenFile( + OUT PNDIS_STATUS Status, + OUT PNDIS_HANDLE FileHandle, + OUT PUINT FileLength, + IN PNDIS_STRING FileName, + IN NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress + ) + +/*++ + +Routine Description: + + This routine opens a file for future mapping and reads its contents + into allocated memory. + +Arguments: + + Status - The status of the operation + + FileHandle - A handle to be associated with this open + + FileLength - Returns the length of the file + + FileName - The name of the file + + HighestAcceptableAddress - The highest physical address at which + the memory for the file can be allocated. + +Return Value: + + None. + +--*/ +{ + NTSTATUS NtStatus; + IO_STATUS_BLOCK IoStatus; + HANDLE NtFileHandle; + OBJECT_ATTRIBUTES ObjectAttributes; + ULONG LengthOfFile; + WCHAR PathPrefix[] = L"\\SystemRoot\\system32\\drivers\\"; + NDIS_STRING FullFileName; + ULONG FullFileNameLength; + PNDIS_FILE_DESCRIPTOR FileDescriptor; + PVOID FileImage; + + // + // This structure represents the data from the + // NtQueryInformationFile API with an information + // class of FileStandardInformation. + // + + FILE_STANDARD_INFORMATION StandardInfo; + + + // + // Insert the correct path prefix. + // + + FullFileNameLength = sizeof(PathPrefix) + FileName->MaximumLength; + FullFileName.Buffer = ExAllocatePoolWithTag (NonPagedPool, FullFileNameLength, ' DN'); + + if (FullFileName.Buffer == NULL) { + *Status = NDIS_STATUS_RESOURCES; + return; + } + FullFileName.Length = sizeof (PathPrefix) - sizeof(WCHAR); + FullFileName.MaximumLength = (USHORT)FullFileNameLength; + RtlCopyMemory (FullFileName.Buffer, PathPrefix, sizeof(PathPrefix)); + + RtlAppendUnicodeStringToString (&FullFileName, FileName); + +#if DBG + DbgPrint ("NDIS: Attempting to open %Z\n", &FullFileName); +#endif + + InitializeObjectAttributes ( + &ObjectAttributes, + &FullFileName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + NtStatus = ZwCreateFile( + &NtFileHandle, + SYNCHRONIZE | FILE_READ_DATA, + &ObjectAttributes, + &IoStatus, + NULL, + 0, + FILE_SHARE_READ, + FILE_OPEN, + FILE_SYNCHRONOUS_IO_NONALERT, + NULL, + 0 + ); + + if (!NT_SUCCESS(NtStatus)) { +#if DBG + DbgPrint ("Error opening file %x\n", NtStatus); +#endif + ExFreePool (FullFileName.Buffer); + *Status = NDIS_STATUS_FILE_NOT_FOUND; + return; + } + + ExFreePool (FullFileName.Buffer); + + // + // Query the object to determine its length. + // + + NtStatus = ZwQueryInformationFile( + NtFileHandle, + &IoStatus, + &StandardInfo, + sizeof(FILE_STANDARD_INFORMATION), + FileStandardInformation + ); + + if (!NT_SUCCESS(NtStatus)) { +#if DBG + DbgPrint ("Error querying info on file %x\n", NtStatus); +#endif + ZwClose(NtFileHandle); + *Status = NDIS_STATUS_ERROR_READING_FILE; + return; + } + + LengthOfFile = StandardInfo.EndOfFile.LowPart; + +#if DBG + DbgPrint ("File length is %d\n", LengthOfFile); +#endif + + // + // Might be corrupted. + // + + if (LengthOfFile < 1) { +#if DBG + DbgPrint ("Bad file length %d\n", LengthOfFile); +#endif + ZwClose(NtFileHandle); + *Status = NDIS_STATUS_ERROR_READING_FILE; + return; + } + + // + // Allocate buffer for this file + // + + FileImage = ExAllocatePoolWithTag(NonPagedPool, LengthOfFile, ' DN'); + + if (FileImage == NULL) { + +#if DBG + DbgPrint ("Could not allocate buffer\n"); +#endif + ZwClose(NtFileHandle); + *Status = NDIS_STATUS_ERROR_READING_FILE; + return; + + } + + // + // Read the file into our buffer. + // + + NtStatus = ZwReadFile( + NtFileHandle, + NULL, + NULL, + NULL, + &IoStatus, + FileImage, + LengthOfFile, + NULL, + NULL + ); + + ZwClose(NtFileHandle); + + if ((!NT_SUCCESS(NtStatus)) || (IoStatus.Information != LengthOfFile)) { +#if DBG + DbgPrint ("error reading file %x\n", NtStatus); +#endif + *Status = NDIS_STATUS_ERROR_READING_FILE; + ExFreePool(FileImage); + return; + } + + // + // Allocate a structure to describe the file. + // + + FileDescriptor = ExAllocatePoolWithTag (NonPagedPool, sizeof(NDIS_FILE_DESCRIPTOR), ' DN'); + + if (FileDescriptor == NULL) { + *Status = NDIS_STATUS_RESOURCES; + ExFreePool(FileImage); + return; + } + + + FileDescriptor->Data = FileImage; + NdisAllocateSpinLock (&FileDescriptor->Lock); + FileDescriptor->Mapped = FALSE; + + *FileHandle = (NDIS_HANDLE)FileDescriptor; + *FileLength = LengthOfFile; + *Status = STATUS_SUCCESS; + +} + + +VOID +NdisCloseFile( + IN NDIS_HANDLE FileHandle + ) + +/*++ + +Routine Description: + + This routine closes a file previously opened with NdisOpenFile. + The file is unmapped if needed and the memory is freed. + +Arguments: + + FileHandle - The handle returned by NdisOpenFile + +Return Value: + + None. + +--*/ +{ + PNDIS_FILE_DESCRIPTOR FileDescriptor = (PNDIS_FILE_DESCRIPTOR)FileHandle; + + ExFreePool (FileDescriptor->Data); + ExFreePool (FileDescriptor); + +} + + +VOID +NdisMapFile( + OUT PNDIS_STATUS Status, + OUT PVOID * MappedBuffer, + IN NDIS_HANDLE FileHandle + ) + +/*++ + +Routine Description: + + This routine maps an open file, so that the contents can be accessed. + Files can only have one active mapping at any time. + +Arguments: + + Status - The status of the operation + + MappedBuffer - Returns the virtual address of the mapping. + + FileHandle - The handle returned by NdisOpenFile. + +Return Value: + + None. + +--*/ +{ + PNDIS_FILE_DESCRIPTOR FileDescriptor = (PNDIS_FILE_DESCRIPTOR)FileHandle; + + ACQUIRE_SPIN_LOCK(&FileDescriptor->Lock); + + if (FileDescriptor->Mapped == TRUE) { + *Status = NDIS_STATUS_ALREADY_MAPPED; + RELEASE_SPIN_LOCK (&FileDescriptor->Lock); + return; + } + + FileDescriptor->Mapped = TRUE; + RELEASE_SPIN_LOCK (&FileDescriptor->Lock); + + *MappedBuffer = FileDescriptor->Data; + *Status = STATUS_SUCCESS; + +} + + +VOID +NdisUnmapFile( + IN NDIS_HANDLE FileHandle + ) + +/*++ + +Routine Description: + + This routine unmaps a file previously mapped with NdisOpenFile. + The file is unmapped if needed and the memory is freed. + +Arguments: + + FileHandle - The handle returned by NdisOpenFile + +Return Value: + + None. + +--*/ + +{ + PNDIS_FILE_DESCRIPTOR FileDescriptor = (PNDIS_FILE_DESCRIPTOR)FileHandle; + + FileDescriptor->Mapped = FALSE; + +} + + +#if defined(_ALPHA_) +VOID +NdisCreateLookaheadBufferFromSharedMemory( + IN PVOID pSharedMemory, + IN UINT LookaheadLength, + OUT PVOID *pLookaheadBuffer + ) +/*++ + +Routine Description: + + This routine creates a lookahead buffer from a pointer to shared + RAM because some architectures (like ALPHA) do not allow access + through a pointer to shared ram. + +Arguments: + + pSharedMemory - Pointer to shared ram space. + + LookaheadLength - Amount of Lookahead to copy. + + pLookaheadBuffer - Pointer to host memory space with a copy of the + stuff in pSharedMemory. + +Return Value: + + None. + +--*/ +{ + PNDIS_LOOKAHEAD_ELEMENT TmpElement; + + ACQUIRE_SPIN_LOCK(&NdisLookaheadBufferLock); + + if (NdisLookaheadBufferLength < (LookaheadLength + + sizeof(NDIS_LOOKAHEAD_ELEMENT))) { + + // + // Free current list + // + while (NdisLookaheadBufferList != NULL) { + + TmpElement = NdisLookaheadBufferList; + NdisLookaheadBufferList = NdisLookaheadBufferList->Next; + + ExFreePool ( TmpElement ) ; + + } + + NdisLookaheadBufferLength = LookaheadLength + + sizeof(NDIS_LOOKAHEAD_ELEMENT); + + } + + if (NdisLookaheadBufferList == NULL) { + + NdisLookaheadBufferList = (PNDIS_LOOKAHEAD_ELEMENT)ExAllocatePoolWithTag( + NonPagedPool, + NdisLookaheadBufferLength, + 'blDN' + ); + + if (NdisLookaheadBufferList == NULL) { + + *pLookaheadBuffer = NULL; + RELEASE_SPIN_LOCK(&NdisLookaheadBufferLock); + return; + + } + + NdisLookaheadBufferList->Next = NULL; + NdisLookaheadBufferList->Length = NdisLookaheadBufferLength; + + } + + + // + // Get the buffer + // + + *pLookaheadBuffer = (PVOID)(NdisLookaheadBufferList + 1); + NdisLookaheadBufferList = NdisLookaheadBufferList->Next; + + RELEASE_SPIN_LOCK(&NdisLookaheadBufferLock); + + // + // Copy the stuff across + // + + READ_REGISTER_BUFFER_UCHAR(pSharedMemory, *pLookaheadBuffer, LookaheadLength); + +} + + +VOID +NdisDestroyLookaheadBufferFromSharedMemory( + IN PVOID pLookaheadBuffer + ) +/*++ + +Routine Description: + + This routine returns resources associated with a lookahead buffer. + +Arguments: + + pLookaheadBuffer - Lookahead buffer created by + CreateLookaheadBufferFromSharedMemory. + +Return Value: + + None. + +--*/ + +{ + PNDIS_LOOKAHEAD_ELEMENT Element = (PNDIS_LOOKAHEAD_ELEMENT)pLookaheadBuffer; + + Element--; + + if (Element->Length != NdisLookaheadBufferLength) { + + ExFreePool(Element); + + } else { + + ACQUIRE_SPIN_LOCK(&NdisLookaheadBufferLock); + + Element->Next = NdisLookaheadBufferList; + NdisLookaheadBufferList = Element; + + RELEASE_SPIN_LOCK(&NdisLookaheadBufferLock); + + } + +} + +#endif // _ALPHA_ + + +BOOLEAN CheckPortUsage( + IN INTERFACE_TYPE InterfaceType, + IN ULONG BusNumber, + IN ULONG PortNumber, + IN ULONG Length, + IN PDRIVER_OBJECT DriverObject +) +/*++ + +Routine Description: + + This routine checks if a port is currently in use somewhere in the + system via IoReportUsage -- which fails if there is a conflict. + +Arguments: + + InterfaceType - The bus type (ISA, EISA) + BusNumber - Bus number in the system + PortNumber - Address of the port to access. + Length - Number of ports from the base address to access. + +Return Value: + + FALSE if there is a conflict, else TRUE + +--*/ + +{ + NTSTATUS NtStatus; + BOOLEAN Conflict; + NTSTATUS FirstNtStatus; + BOOLEAN FirstConflict; + PCM_RESOURCE_LIST Resources; + + // + // Allocate space for resources + // + + Resources = (PCM_RESOURCE_LIST)ExAllocatePool( + NonPagedPool, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) + ); + + if (Resources == NULL) { + + // + // Error out + // + + return(FALSE); + + } + + Resources->Count = 1; + Resources->List[0].InterfaceType = InterfaceType; + Resources->List[0].BusNumber = BusNumber; + Resources->List[0].PartialResourceList.Version = 0; + Resources->List[0].PartialResourceList.Revision = 0; + Resources->List[0].PartialResourceList.Count = 1; + + // + // Setup port + // + Resources->List[0].PartialResourceList.PartialDescriptors[0].Type = CmResourceTypePort; + Resources->List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition = CmResourceShareDriverExclusive; + Resources->List[0].PartialResourceList.PartialDescriptors[0].Flags = + (InterfaceType == Internal)? + CM_RESOURCE_PORT_MEMORY : + CM_RESOURCE_PORT_IO; +#if !defined(BUILD_FOR_3_1) + Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start.QuadPart = PortNumber; +#else + Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start = + RtlConvertUlongToLargeInteger((ULONG)(PortNumber)); +#endif + Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Length = + Length; + + // + // Submit Resources + // + + FirstNtStatus = IoReportResourceUsage( + NULL, + DriverObject, + Resources, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR), + NULL, + NULL, + 0, + TRUE, + &FirstConflict + ); + + // + // Now clear it out + // + Resources->List[0].PartialResourceList.Count = 0; + + NtStatus = IoReportResourceUsage( + NULL, + DriverObject, + Resources, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR), + NULL, + NULL, + 0, + TRUE, + &Conflict + ); + + ExFreePool(Resources); + + // + // Check for conflict. + // + + if (FirstConflict || (FirstNtStatus != STATUS_SUCCESS)) { + + return(FALSE); + } + + return(TRUE); +} + +NTSTATUS +StartMapping( + IN INTERFACE_TYPE InterfaceType, + IN ULONG BusNumber, + IN ULONG InitialAddress, + IN ULONG Length, + OUT PVOID *InitialMapping, + OUT PBOOLEAN Mapped + ) + +/*++ + +Routine Description: + + This routine initialize the mapping of a address into virtual + space dependent on the bus number, etc. + +Arguments: + + InterfaceType - The bus type (ISA, EISA) + BusNumber - Bus number in the system + InitialAddress - Address to access. + Length - Number of bytes from the base address to access. + InitialMapping - The virtual address space to use when accessing the + address. + Mapped - Did an MmMapIoSpace() take place. + +Return Value: + + The function value is the status of the operation. + +--*/ +{ + PHYSICAL_ADDRESS Address; + PHYSICAL_ADDRESS InitialPhysAddress; + ULONG addressSpace; + + // + // Get the system physical address for this card. The card uses + // I/O space, except for "internal" Jazz devices which use + // memory space. + // + + *Mapped = FALSE; + + addressSpace = (InterfaceType == Internal) ? 0 : 1; + + InitialPhysAddress.LowPart = InitialAddress; + + InitialPhysAddress.HighPart = 0; + + if ( !HalTranslateBusAddress( + InterfaceType, // InterfaceType + BusNumber, // BusNumber + InitialPhysAddress, // Bus Address + &addressSpace, // AddressSpace + &Address // Translated address + ) ) { + + // + // It would be nice to return a better status here, but we only get + // TRUE/FALSE back from HalTranslateBusAddress. + // + + return NDIS_STATUS_FAILURE; + } + + if (addressSpace == 0) { + + // + // memory space + // + + *InitialMapping = MmMapIoSpace( + Address, + Length, + FALSE + ); + + if (*InitialMapping == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + *Mapped = TRUE; + + } else { + + // + // I/O space + // + + *InitialMapping = (PVOID)Address.LowPart; + + } + + return(STATUS_SUCCESS); + +} + + +NTSTATUS +EndMapping( + IN PVOID InitialMapping, + IN ULONG Length, + IN BOOLEAN Mapped + ) + +/*++ + +Routine Description: + + This routine undoes the mapping of an address into virtual + space dependent on the bus number, etc. + +Arguments: + + InitialMapping - The virtual address space to use when accessing the + address. + Length - Number of bytes from the base address to access. + Mapped - Do we need to call MmUnmapIoSpace. + +Return Value: + + The function value is the status of the operation. + +--*/ +{ + + if (Mapped) { + + // + // memory space + // + + MmUnmapIoSpace(InitialMapping, Length); + + } + + return(STATUS_SUCCESS); + +} + + +VOID +NdisImmediateReadPortUchar( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG Port, + OUT PUCHAR Data + ) +/*++ + +Routine Description: + + This routine reads from a port a UCHAR. It does all the mapping, + etc, to do the read here. + +Arguments: + + WrapperConfigurationContext - The handle used to call NdisOpenConfig. + + Port - Port number to read from. + + Data - Pointer to place to store the result. + +Return Value: + + None. + +--*/ + +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject; + BOOLEAN Mapped; + PVOID PortMapping; + NDIS_INTERFACE_TYPE BusType; + ULONG BusNumber; + NTSTATUS Status; + + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + BusNumber = KeyQueryTable[3].DefaultLength; + + // + // Check that the port is available. + // + if (CheckPortUsage( + BusType, + BusNumber, + Port, + sizeof(UCHAR), + DriverObject + ) == FALSE) { + + *Data = (UCHAR)0xFF; + return; + + } + + // + // Map the space + // + + Status = StartMapping( + BusType, + BusNumber, + Port, + sizeof(UCHAR), + &PortMapping, + &Mapped + ); + + if (!NT_SUCCESS(Status)) { + + *Data = (UCHAR)0xFF; + return; + + } + + // + // Read from the port + // + + *Data = READ_PORT_UCHAR((PUCHAR)PortMapping); + + // + // End port mapping + // + + EndMapping( + PortMapping, + sizeof(UCHAR), + Mapped + ); + +} + +VOID +NdisImmediateReadPortUshort( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG Port, + OUT PUSHORT Data + ) +/*++ + +Routine Description: + + This routine reads from a port a USHORT. It does all the mapping, + etc, to do the read here. + +Arguments: + + WrapperConfigurationContext - The handle used to call NdisOpenConfig. + + Port - Port number to read from. + + Data - Pointer to place to store the result. + +Return Value: + + None. + +--*/ + +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject; + BOOLEAN Mapped; + PVOID PortMapping; + NDIS_INTERFACE_TYPE BusType; + ULONG BusNumber; + NTSTATUS Status; + + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + BusNumber = KeyQueryTable[3].DefaultLength; + + // + // Check that the port is available. + // + if (CheckPortUsage( + BusType, + BusNumber, + Port, + sizeof(USHORT), + DriverObject + ) == FALSE) { + + *Data = (USHORT)0xFFFF; + return; + + } + + // + // Map the space + // + + Status = StartMapping( + BusType, + BusNumber, + Port, + sizeof(USHORT), + &PortMapping, + &Mapped + ); + + if (!NT_SUCCESS(Status)) { + + *Data = (USHORT)0xFFFF; + return; + + } + + // + // Read from the port + // + + *Data = READ_PORT_USHORT((PUSHORT)PortMapping); + + // + // End port mapping + // + + EndMapping( + PortMapping, + sizeof(USHORT), + Mapped + ); + +} + +VOID +NdisImmediateReadPortUlong( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG Port, + OUT PULONG Data + ) +/*++ + +Routine Description: + + This routine reads from a port a ULONG. It does all the mapping, + etc, to do the read here. + +Arguments: + + WrapperConfigurationContext - The handle used to call NdisOpenConfig. + + Port - Port number to read from. + + Data - Pointer to place to store the result. + +Return Value: + + None. + +--*/ + +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject; + BOOLEAN Mapped; + PVOID PortMapping; + NDIS_INTERFACE_TYPE BusType; + ULONG BusNumber; + NTSTATUS Status; + + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + BusNumber = KeyQueryTable[3].DefaultLength; + + // + // Check that the port is available. + // + if (CheckPortUsage( + BusType, + BusNumber, + Port, + sizeof(ULONG), + DriverObject + ) == FALSE) { + + *Data = (ULONG)0xFFFFFFFF; + return; + + } + + // + // Map the space + // + + Status = StartMapping( + BusType, + BusNumber, + Port, + sizeof(ULONG), + &PortMapping, + &Mapped + ); + + if (!NT_SUCCESS(Status)) { + + *Data = (ULONG)0xFFFFFFFF; + return; + + } + + // + // Read from the port + // + + *Data = READ_PORT_ULONG((PULONG)PortMapping); + + // + // End port mapping + // + + EndMapping( + PortMapping, + sizeof(ULONG), + Mapped + ); + +} + +VOID +NdisImmediateWritePortUchar( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG Port, + IN UCHAR Data + ) +/*++ + +Routine Description: + + This routine writes to a port a UCHAR. It does all the mapping, + etc, to do the write here. + +Arguments: + + WrapperConfigurationContext - The handle used to call NdisOpenConfig. + + Port - Port number to read from. + + Data - Pointer to place to store the result. + +Return Value: + + None. + +--*/ + +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject; + BOOLEAN Mapped; + PVOID PortMapping; + NDIS_INTERFACE_TYPE BusType; + ULONG BusNumber; + NTSTATUS Status; + + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + BusNumber = KeyQueryTable[3].DefaultLength; + + // + // Check that the port is available. + // + if (CheckPortUsage( + BusType, + BusNumber, + Port, + sizeof(UCHAR), + DriverObject + ) == FALSE) { + + return; + + } + + // + // Map the space + // + + Status = StartMapping( + BusType, + BusNumber, + Port, + sizeof(UCHAR), + &PortMapping, + &Mapped + ); + + if (!NT_SUCCESS(Status)) { + + return; + + } + + // + // Read from the port + // + + WRITE_PORT_UCHAR((PUCHAR)PortMapping, Data); + + // + // End port mapping + // + + EndMapping( + PortMapping, + sizeof(UCHAR), + Mapped + ); + +} + +VOID +NdisImmediateWritePortUshort( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG Port, + IN USHORT Data + ) +/*++ + +Routine Description: + + This routine writes to a port a USHORT. It does all the mapping, + etc, to do the write here. + +Arguments: + + WrapperConfigurationContext - The handle used to call NdisOpenConfig. + + Port - Port number to read from. + + Data - Pointer to place to store the result. + +Return Value: + + None. + +--*/ + +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject; + BOOLEAN Mapped; + PVOID PortMapping; + NDIS_INTERFACE_TYPE BusType; + ULONG BusNumber; + NTSTATUS Status; + + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + BusNumber = KeyQueryTable[3].DefaultLength; + + // + // Check that the port is available. + // + if (CheckPortUsage( + BusType, + BusNumber, + Port, + sizeof(USHORT), + DriverObject + ) == FALSE) { + + return; + + } + + // + // Map the space + // + + Status = StartMapping( + BusType, + BusNumber, + Port, + sizeof(USHORT), + &PortMapping, + &Mapped + ); + + if (!NT_SUCCESS(Status)) { + + return; + + } + + // + // Read from the port + // + + WRITE_PORT_USHORT((PUSHORT)PortMapping, Data); + + // + // End port mapping + // + + EndMapping( + PortMapping, + sizeof(USHORT), + Mapped + ); + +} + +VOID +NdisImmediateWritePortUlong( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG Port, + IN ULONG Data + ) +/*++ + +Routine Description: + + This routine writes to a port a ULONG. It does all the mapping, + etc, to do the write here. + +Arguments: + + WrapperConfigurationContext - The handle used to call NdisOpenConfig. + + Port - Port number to read from. + + Data - Pointer to place to store the result. + +Return Value: + + None. + +--*/ + +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject; + BOOLEAN Mapped; + PVOID PortMapping; + NDIS_INTERFACE_TYPE BusType; + ULONG BusNumber; + NTSTATUS Status; + + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + BusNumber = KeyQueryTable[3].DefaultLength; + + // + // Check that the port is available. + // + if (CheckPortUsage( + BusType, + BusNumber, + Port, + sizeof(ULONG), + DriverObject + ) == FALSE) { + + return; + + } + + // + // Map the space + // + + Status = StartMapping( + BusType, + BusNumber, + Port, + sizeof(ULONG), + &PortMapping, + &Mapped + ); + + if (!NT_SUCCESS(Status)) { + + return; + + } + + // + // Read from the port + // + + WRITE_PORT_ULONG((PULONG)PortMapping, Data); + + // + // End port mapping + // + + EndMapping( + PortMapping, + sizeof(ULONG), + Mapped + ); + +} + +BOOLEAN CheckMemoryUsage( + IN INTERFACE_TYPE InterfaceType, + IN ULONG BusNumber, + IN ULONG Address, + IN ULONG Length, + IN PDRIVER_OBJECT DriverObject +) +/*++ +Routine Description: + + This routine checks if a range of memory is currently in use somewhere + in the system via IoReportUsage -- which fails if there is a conflict. + +Arguments: + + InterfaceType - The bus type (ISA, EISA) + BusNumber - Bus number in the system + Address - Starting Address of the memory to access. + Length - Length of memory from the base address to access. + +Return Value: + + FALSE if there is a conflict, else TRUE + +--*/ +{ + NTSTATUS NtStatus; + BOOLEAN Conflict; + NTSTATUS FirstNtStatus; + BOOLEAN FirstConflict; + PCM_RESOURCE_LIST Resources; + + // + // Allocate space for resources + // + + Resources = (PCM_RESOURCE_LIST)ExAllocatePool( + NonPagedPool, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) + ); + + if (Resources == NULL) { + + // + // Error out + // + + return(FALSE); + + } + + Resources->Count = 1; + Resources->List[0].InterfaceType = InterfaceType; + Resources->List[0].BusNumber = BusNumber; + Resources->List[0].PartialResourceList.Version = 0; + Resources->List[0].PartialResourceList.Revision = 0; + Resources->List[0].PartialResourceList.Count = 1; + + // + // Setup memory + // + + Resources->List[0].PartialResourceList.PartialDescriptors[0].Type = + CmResourceTypeMemory; + Resources->List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition = + CmResourceShareDriverExclusive; + Resources->List[0].PartialResourceList.PartialDescriptors[0].Flags = + CM_RESOURCE_MEMORY_READ_WRITE; +#if !defined(BUILD_FOR_3_1) + Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Memory.Start.QuadPart = Address; +#else + Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Memory.Start = + RtlConvertUlongToLargeInteger((ULONG)(Address)); +#endif + Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Memory.Length = + Length; + + + // + // Submit Resources + // + + FirstNtStatus = IoReportResourceUsage( + NULL, + DriverObject, + Resources, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR), + NULL, + NULL, + 0, + TRUE, + &FirstConflict + ); + + // + // Now clear it out + // + Resources->List[0].PartialResourceList.Count = 0; + + NtStatus = IoReportResourceUsage( + NULL, + DriverObject, + Resources, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR), + NULL, + NULL, + 0, + TRUE, + &Conflict + ); + + ExFreePool(Resources); + + // + // Check for conflict. + // + + if (FirstConflict || (FirstNtStatus != STATUS_SUCCESS)) { + + return(FALSE); + } + + return(TRUE); +} + +VOID +NdisImmediateReadSharedMemory( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG SharedMemoryAddress, + OUT PUCHAR Buffer, + IN ULONG Length + ) +/*++ + +Routine Description: + + This routine read into a buffer from shared ram. It does all the mapping, + etc, to do the read here. + +Arguments: + + WrapperConfigurationContext - The handle used to call NdisOpenConfig. + + SharedMemoryAddress - The physical address to read from. + + Buffer - The buffer to read into. + + Length - Length of the buffer in bytes. + +Return Value: + + None. + +--*/ + +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject; + BOOLEAN Mapped; + PVOID MemoryMapping; + NDIS_INTERFACE_TYPE BusType; + ULONG BusNumber; + NTSTATUS Status; + + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + BusNumber = KeyQueryTable[3].DefaultLength; + + // + // Check that the memory is available. + // + if (CheckMemoryUsage( + BusType, + BusNumber, + SharedMemoryAddress, + Length, + DriverObject + ) == FALSE) { + + return; + + } + + // + // Map the space + // + + Status = StartMapping( + BusType, + BusNumber, + SharedMemoryAddress, + Length, + &MemoryMapping, + &Mapped + ); + + if (!NT_SUCCESS(Status)) { + + return; + + } + + // + // Read from memory + // + +#ifdef _M_IX86 + + memcpy(Buffer, MemoryMapping, Length); + +#else + + READ_REGISTER_BUFFER_UCHAR(MemoryMapping,Buffer,Length); + +#endif + + // + // End mapping + // + + EndMapping( + MemoryMapping, + Length, + Mapped + ); + +} + +VOID +NdisImmediateWriteSharedMemory( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG SharedMemoryAddress, + IN PUCHAR Buffer, + IN ULONG Length + ) +/*++ + +Routine Description: + + This routine writes a buffer to shared ram. It does all the mapping, + etc, to do the write here. + +Arguments: + + WrapperConfigurationContext - The handle used to call NdisOpenConfig. + + SharedMemoryAddress - The physical address to write to. + + Buffer - The buffer to write. + + Length - Length of the buffer in bytes. + +Return Value: + + None. + +--*/ + +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject; + BOOLEAN Mapped; + PVOID MemoryMapping; + NDIS_INTERFACE_TYPE BusType; + ULONG BusNumber; + NTSTATUS Status; + + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + BusNumber = KeyQueryTable[3].DefaultLength; + + // + // Check that the memory is available. + // + if (CheckMemoryUsage( + BusType, + BusNumber, + SharedMemoryAddress, + Length, + DriverObject + ) == FALSE) { + + return; + + } + + // + // Map the space + // + + Status = StartMapping( + BusType, + BusNumber, + SharedMemoryAddress, + Length, + &MemoryMapping, + &Mapped + ); + + if (!NT_SUCCESS(Status)) { + + return; + + } + + // + // Write to memory + // + +#ifdef _M_IX86 + + memcpy(MemoryMapping, Buffer, Length); + +#else + + WRITE_REGISTER_BUFFER_UCHAR(MemoryMapping,Buffer,Length); + +#endif + + // + // End mapping + // + + EndMapping( + MemoryMapping, + Length, + Mapped + ); + +} + +#if !defined(BUILD_FOR_3_1) + +ULONG +NdisImmediateReadPciSlotInformation( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG SlotNumber, + IN ULONG Offset, + IN PVOID Buffer, + IN ULONG Length + ) +/*++ + +Routine Description: + + This routine reads from the PCI configuration space a specified + length of bytes at a certain offset. + +Arguments: + + WrapperConfigurationContext - Context passed to MacAddAdapter. + + SlotNumber - The slot number of the device. + + Offset - Offset to read from + + Buffer - Place to store the bytes + + Length - Number of bytes to read + +Return Value: + + Returns the number of bytes read. + +--*/ +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + ULONG BusNumber; + ULONG DataLength; + + BusNumber = KeyQueryTable[3].DefaultLength; + +#if DBG + { + NDIS_INTERFACE_TYPE BusType; + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + ASSERT(BusType == NdisInterfacePci); + } +#endif + + DataLength = HalGetBusDataByOffset( + PCIConfiguration, + BusNumber, + SlotNumber, + Buffer, + Offset, + Length + ); + + return(DataLength); +} + +ULONG +NdisImmediateWritePciSlotInformation( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG SlotNumber, + IN ULONG Offset, + IN PVOID Buffer, + IN ULONG Length + ) +/*++ + +Routine Description: + + This routine writes to the PCI configuration space a specified + length of bytes at a certain offset. + +Arguments: + + WrapperConfigurationContext - Context passed to MacAddAdapter. + + SlotNumber - The slot number of the device. + + Offset - Offset to read from + + Buffer - Place to store the bytes + + Length - Number of bytes to read + +Return Value: + + Returns the number of bytes written. + +--*/ +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + ULONG BusNumber; + ULONG DataLength; + + BusNumber = KeyQueryTable[3].DefaultLength; + +#if DBG + { + NDIS_INTERFACE_TYPE BusType; + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + ASSERT(BusType == NdisInterfacePci); + } +#endif + + DataLength = HalSetBusDataByOffset( + PCIConfiguration, + BusNumber, + SlotNumber, + Buffer, + Offset, + Length + ); + + return(DataLength); +} + +#else // !defined(BUILD_FOR_3_1) + +ULONG +NdisImmediateReadPciSlotInformation( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG SlotNumber, + IN ULONG Offset, + IN PVOID Buffer, + IN ULONG Length + ) +{ + return 0; +} + +ULONG +NdisImmediateWritePciSlotInformation( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG SlotNumber, + IN ULONG Offset, + IN PVOID Buffer, + IN ULONG Length + ) +{ + return 0; +} + +#endif // !defined(BUILD_FOR_3_1) + + +CCHAR +NdisSystemProcessorCount( + VOID + ) +{ + return *KeNumberProcessors; +} + + +VOID +NdisOverrideBusNumber( + IN NDIS_HANDLE WrapperConfigurationContext, + IN NDIS_HANDLE MiniportAdapterHandle OPTIONAL, + IN ULONG BusNumber + ) + +/*++ + +Routine Description: + + This routine is used to override the BusNumber value retrieved + from the registry. It is expected to be used by PCI drivers + that discover that their adapter's bus number has changed. + +Arguments: + + WrapperConfigurationContext - a handle pointing to an RTL_QUERY_REGISTRY_TABLE + that is set up for this driver's parameters. + + MiniportAdapterHandle - points to the adapter block, if the calling + driver is a miniport. If the calling driver is a full MAC, this + parameter must be NULL. + + BusNumber - the new bus number. + +Return Value: + + None. + +--*/ + +{ + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle; + + ((PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext)[3].DefaultLength = BusNumber; + + if (Miniport != NULL) { + Miniport->BusNumber = BusNumber; + } + + return; +} + diff --git a/private/ntos/ndis/ndis30/wrapper.h b/private/ntos/ndis/ndis30/wrapper.h new file mode 100644 index 000000000..8885bd800 --- /dev/null +++ b/private/ntos/ndis/ndis30/wrapper.h @@ -0,0 +1,473 @@ +#include <ntddk.h> +#include <ndismain.h> +#include <ndismac.h> +#include <ndismini.h> + + +#if defined(BUILD_FOR_3_5) || defined(BUILD_FOR_3_1) + +#define Increment(a,b) ExInterlockedIncrementLong(a,b) +#define Decrement(a,b) ExInterlockedDecrementLong(a,b) + +#else + +#define Increment(a,b) InterlockedIncrement(a) +#define Decrement(a,b) InterlockedDecrement(a) + +#endif + +#if defined(BUILD_FOR_3_1) + +#define FASTCALL + +#define MmLockPagableImageSection(a) NULL +#define MmUnlockPagableImageSection(a) + +#define COMPUTE_PAGES_SPANNED(Va, Size) \ + ((((ULONG)Va & (PAGE_SIZE -1)) + (Size) + (PAGE_SIZE - 1)) >> PAGE_SHIFT) + +#define Int32x32To64(a,b) RtlEnlargedIntegerMultiply((a),(b)).QuadPart + +#define ExAllocatePoolWithTag(a,b,c) ExAllocatePool((a),(b)) + +NTSTATUS +NTAPI +RtlCharToInteger ( + PCSZ String, + ULONG Base, + PULONG Value + ); + +#endif + +#if defined(BUILD_FOR_3_5) +#define MmLockPagableCodeSection(x) MmLockPagableImageSection(x) +#endif + +#define ACQUIRE_SPIN_LOCK(_SpinLock) KeAcquireSpinLock(&(_SpinLock)->SpinLock, &(_SpinLock)->OldIrql) +#define RELEASE_SPIN_LOCK(_SpinLock) KeReleaseSpinLock(&(_SpinLock)->SpinLock, (_SpinLock)->OldIrql) +#define ACQUIRE_SPIN_LOCK_DPC(_SpinLock) KeAcquireSpinLockAtDpcLevel(&(_SpinLock)->SpinLock) +#define RELEASE_SPIN_LOCK_DPC(_SpinLock) KeReleaseSpinLockFromDpcLevel(&(_SpinLock)->SpinLock) + + +#if DBG +#define NDISDBG 0 +#endif +#if !defined(NDISDBG) +#define NDISDBG 0 +#endif + +#if NDISDBG + +#if defined(MEMPRINT) +#include "memprint.h" //DavidTr's memprint program at ntos\srv +#endif // MEMPRINT + +extern int NdisMsgLevel; +extern BOOLEAN NdisChkErrorFlag; + +#define TRACE_NONE 0x0000 +#define TRACE_IMPT 0x0001 +#define TRACE_ALL 0x0002 + +#define IF_TRACE(level) if ( NdisMsgLevel >= (level) ) //for tracing + +#define IF_ERROR_CHK if (NdisChkErrorFlag) // for parameter checking + +#define DbgIsNonPaged(_Address) \ + ( MmIsNonPagedSystemAddressValid((PVOID)(_Address)) ) + +#define DbgIsPacket(_Packet) \ + ( ((_Packet)->Private.Pool->PacketLength) > sizeof(_Packet) ) + +#define DbgIsNull(_Ptr) ( ((PVOID)(_Ptr)) == NULL ) + +#define NdisPrint1(fmt) DbgPrint(fmt) +#define NdisPrint2(fmt,v1) DbgPrint(fmt,v1) +#define NdisPrint3(fmt,v1,v2) DbgPrint(fmt,v1,v2) +#define NdisPrint4(fmt,v1,v2,v3) DbgPrint(fmt,v1,v2,v3) +#define NdisPrint5(fmt,v1,v2,v3,v4) DbgPrint(fmt,v1,v2,v3,v4) + +#else // NDISDBG + +#define IF_TRACE(level) if (FALSE) +#define IF_ERROR_CHK if (FALSE) + +#define DbgIsNonPaged(_Address) TRUE +#define DbgIsPacket(_Packet) TRUE +#define DbgIsNull(_Ptr) FALSE + +#define NdisPrint1(fmt) +#define NdisPrint2(fmt,v1) +#define NdisPrint3(fmt,v1,v2) +#define NdisPrint4(fmt,v1,v2,v3) +#define NdisPrint5(fmt,v1,v2,v3,v4) + +#endif // NDISDBG + + +#if DBG +#define MINIPORT_AT_DPC_LEVEL (KeGetCurrentIrql() == DISPATCH_LEVEL) +#else +#define MINIPORT_AT_DPC_LEVEL 1 +#endif + + +// +// This is the number of extra OIDs that ARCnet with Ethernet encapsulation +// supports. +// +#define ARC_NUMBER_OF_EXTRA_OIDS 2 + + + +// +// Internal wrapper data structures. +// + +// +// NDIS_WRAPPER_CONTEXT +// +// This data structure contains internal data items for use by the wrapper. +// + +typedef struct _NDIS_WRAPPER_CONTEXT { + + // + // Mac/miniport defined shutdown context. + // + + PVOID ShutdownContext; + + // + // Mac/miniport registered shutdown handler. + // + + ADAPTER_SHUTDOWN_HANDLER ShutdownHandler; + +#if !defined(BUILD_FOR_3_1) + // + // Kernel bugcheck record for bugcheck handling. + // + + KBUGCHECK_CALLBACK_RECORD BugcheckCallbackRecord; +#endif + + // + // Miniport assigned resources for PCI, PCMCIA, EISA, etc. + // + + PCM_RESOURCE_LIST AssignedSlotResources; + + // + // HAL common buffer cache. + // + + PVOID SharedMemoryPage[2]; + ULONG SharedMemoryLeft[2]; + NDIS_PHYSICAL_ADDRESS SharedMemoryAddress[2]; + +} NDIS_WRAPPER_CONTEXT, *PNDIS_WRAPPER_CONTEXT; + +// +// Lock/unlock miniport macros. +// + +#define LOCK_MINIPORT(_M_, _L) \ +{ \ + if (_M_->LockAcquired) { \ + _L = FALSE; \ + } else { \ + _L = TRUE; \ + _M_->LockAcquired = TRUE; \ + } \ +} + +#define UNLOCK_MINIPORT(_M_, _L) \ +{ \ + if (_L) { \ + _M_->LockAcquired = FALSE; \ + } \ +} + + +NDIS_STATUS +NdisInitialInit( + PDRIVER_OBJECT Driver OPTIONAL + ); + +VOID +FASTCALL +MiniportProcessDeferred( + PNDIS_MINIPORT_BLOCK Miniport + ); + +NDIS_STATUS +NdisMTransferDataSync( + IN NDIS_HANDLE NdisBindingHandle, + IN NDIS_HANDLE MacReceiveContext, + IN UINT ByteOffset, + IN UINT BytesToTransfer, + IN OUT PNDIS_PACKET Packet, + OUT PUINT BytesTransferred + ); + +#define MINIPORT_DISABLE_INTERRUPT(_M_) \ +{ \ + ASSERT(_M_->DriverHandle->MiniportCharacteristics.DisableInterruptHandler != NULL); \ + (_M_->DriverHandle->MiniportCharacteristics.DisableInterruptHandler)( \ + _M_->MiniportAdapterContext \ + ); \ +} + +#define MINIPORT_SYNC_DISABLE_INTERRUPT(_M_) \ +{ \ + if (_M_->DriverHandle->MiniportCharacteristics.DisableInterruptHandler != NULL) { \ + KeSynchronizeExecution( \ + (_M_)->Interrupt->InterruptObject, \ + (PKSYNCHRONIZE_ROUTINE)(_M_->DriverHandle->MiniportCharacteristics.DisableInterruptHandler),\ + _M_->MiniportAdapterContext \ + ); \ + } \ +} + +#define CHECK_FOR_NORMAL_INTERRUPTS(_Miniport) \ + _Miniport->NormalInterrupts = (BOOLEAN)(!_Miniport->HaltingMiniport && \ + !_Miniport->InInitialize && \ + (_Miniport->Interrupt != NULL) && \ + !_Miniport->Interrupt->IsrRequested && \ + !_Miniport->Interrupt->SharedInterrupt) + +// +// general reference/dereference functions +// + +BOOLEAN +NdisReferenceRef( + IN PREFERENCE RefP + ); + + +BOOLEAN +NdisDereferenceRef( + PREFERENCE RefP + ); + + +VOID +NdisInitializeRef( + PREFERENCE RefP + ); + + +BOOLEAN +NdisCloseRef( + PREFERENCE RefP + ); + + +/*++ +BOOLEAN +NdisReferenceProtocol( + IN PNDIS_PROTOCOL_BLOCK ProtP + ); +--*/ + +#define NdisReferenceProtocol(ProtP) \ + NdisReferenceRef(&(ProtP)->Ref) + + + +BOOLEAN +QueueOpenOnProtocol( + IN PNDIS_OPEN_BLOCK OpenP, + IN PNDIS_PROTOCOL_BLOCK ProtP + ); + + +/*++ +VOID +NdisDereferenceProtocol( + PNDIS_PROTOCOL_BLOCK ProtP + ); +--*/ +#define NdisDereferenceProtocol(ProtP) { \ + if (NdisDereferenceRef(&(ProtP)->Ref)) { \ + ExFreePool((PVOID)(ProtP)); \ + } \ +} + + + +VOID +NdisDeQueueOpenOnProtocol( + PNDIS_OPEN_BLOCK OpenP, + PNDIS_PROTOCOL_BLOCK ProtP + ); + + +BOOLEAN +NdisFinishOpen( + PNDIS_OPEN_BLOCK OpenP + ); + + +VOID +NdisKillOpenAndNotifyProtocol( + PNDIS_OPEN_BLOCK OldOpenP + ); + + +BOOLEAN +NdisKillOpen( + PNDIS_OPEN_BLOCK OldOpenP + ); + +/*++ +BOOLEAN +NdisReferenceMac( + IN PNDIS_MAC_BLOCK MacP + ); +--*/ +#define NdisReferenceMac(MacP) \ + NdisReferenceRef(&(MacP)->Ref) + +static +VOID +NdisDereferenceMac( + PNDIS_MAC_BLOCK MacP + ); + +BOOLEAN +NdisQueueAdapterOnMac( + PNDIS_ADAPTER_BLOCK AdaptP, + PNDIS_MAC_BLOCK MacP + ); + +VOID +NdisDeQueueAdapterOnMac( + PNDIS_ADAPTER_BLOCK AdaptP, + PNDIS_MAC_BLOCK MacP + ); + +/*++ +BOOLEAN +NdisReferenceAdapter( + IN PNDIS_ADAPTER_BLOCK AdaptP + ); +--*/ +#define NdisReferenceAdapter(AdaptP) \ + NdisReferenceRef(&(AdaptP)->Ref) + + +BOOLEAN +NdisQueueOpenOnAdapter( + PNDIS_OPEN_BLOCK OpenP, + PNDIS_ADAPTER_BLOCK AdaptP + ); + +VOID +NdisKillAdapter( + PNDIS_ADAPTER_BLOCK OldAdaptP + ); + +VOID +NdisDereferenceAdapter( + PNDIS_ADAPTER_BLOCK AdaptP + ); + +VOID +NdisDeQueueOpenOnAdapter( + PNDIS_OPEN_BLOCK OpenP, + PNDIS_ADAPTER_BLOCK AdaptP + ); + +NDIS_STATUS +NdisCallDriverAddAdapter( + IN PNDIS_MAC_BLOCK NewMacP + ); + +/*++ +BOOLEAN +NdisReferenceDriver( + IN PNDIS_M_DRIVER_BLOCK DriverP + ); +--*/ +#define NdisReferenceDriver(DriverP) \ + NdisReferenceRef(&(DriverP)->Ref) + + +VOID +NdisDereferenceDriver( + PNDIS_M_DRIVER_BLOCK DriverP + ); + +BOOLEAN +NdisQueueMiniportOnDriver( + PNDIS_MINIPORT_BLOCK MiniportP, + PNDIS_M_DRIVER_BLOCK DriverP + ); + +VOID +NdisDequeueMiniportOnDriver( + PNDIS_MINIPORT_BLOCK MiniportP, + PNDIS_M_DRIVER_BLOCK DriverP + ); + +BOOLEAN +NdisQueueOpenOnMiniport( + PNDIS_M_OPEN_BLOCK OpenP, + PNDIS_MINIPORT_BLOCK MiniportP + ); + +VOID +NdisKillMiniport( + PNDIS_MINIPORT_BLOCK OldMiniportP + ); + +/*++ +BOOLEAN +NdisReferenceMiniport( + IN PNDIS_MINIPORT_BLOCK MiniportP + ); +--*/ +#define NdisReferenceMiniport(MiniportP) \ + NdisReferenceRef(&(MiniportP)->Ref) + +VOID +NdisDereferenceMiniport( + PNDIS_MINIPORT_BLOCK MiniportP + ); + +VOID +NdisDeQueueOpenOnMiniport( + PNDIS_M_OPEN_BLOCK OpenP, + PNDIS_MINIPORT_BLOCK MiniportP + ); + +VOID +MiniportInitializePackage( + VOID + ); + +VOID +MiniportReferencePackage( + VOID + ); + +VOID +MiniportDereferencePackage( + VOID + ); + +NDIS_STATUS ArcConvertOidListToEthernet( + IN PNDIS_OID pOidList, + IN PULONG pcbOidList, + IN PNDIS_OID pTmpBuffer +); + +VOID +NdisBugcheckHandler( + IN PNDIS_WRAPPER_CONTEXT WrapperContext, + IN ULONG Size + ); diff --git a/private/ntos/ndis/ndis30/wrapper.txt b/private/ntos/ndis/ndis30/wrapper.txt new file mode 100644 index 000000000..2e52189f0 --- /dev/null +++ b/private/ntos/ndis/ndis30/wrapper.txt @@ -0,0 +1,120 @@ +Debug Wrapper + +Johnson Apacible (johnsona) +3-11-91 + + + +The debug version of the wrapper allows developers to +1. turn on/off error checking +2. control level of tracing. There are currently 2 levels of tracing: +Level 2 tracing turns on tracing on all wrapper functions; while level +1 tracing turns on tracing only on the more interesting functions. +Level 1 and 2 functions are enumerated below: + + +Level 1 Tracing enables tracing on the following functions: + + NdisInitializePacketPool + NdisTerminatePacketPool + + NdisRegisterProtocol + NdisDeregisterProtocol + + NdisOpenAdapter + NdisCloseAdapter + FinishOpen + + KillOpenAndNotifyProtocol + KillOpen + + NdisInitializeWrapper + NdisTerminateWrapper + + NdisRegisterMac + NdisDeregisterMac + DeQueueAdapterOnMac + QueueAdapterOnMac + + QueueOpenOnProtocol + DeQueueOpenOnProtocol + NdisRegisterAdapter + NdisDeregisterAdapter + KillAdapter + QueueAdapterOnAdapter + DeQueueAdapterOnAdapter + NdisSetPacketFilter + NdisAddMulticastAddress + NdisDeleteMulticastAddress + NdisSend + NdisTransferData + NdisQueryInformation + NdisSetInformation + NdisReset + NdisTest + NdisCompleteRequest + NdisCompleteSend + NdisCompleteTransferData + NdisIndicateStatus + NdisIndicateStatusComplete + + +Level 2 tracing enables tracing the functions listedbelow in addition +to all Level 1 functions: + + NdisQueryBuffer + NdisAllocatePacket + NdisDeallocatePacket + NdisReinitializePacket + NdisChainBufferAtFront + NdisChainBufferAtBack + NdisUnchainBufferAtFront + NdisUnchainBufferAtBack + NdisQueryPacket + NdisGetNextBuffer + ReferenceRef + DereferenceRef + InitializeRef + CloseRef + ReferenceProtocol + DereferenceProtocol + NdisSuccessIrplHandler + ReferencMac + ReferenceAdapter + DereferenceAdapter + + NdisIndicateReceive + NdisIndicateReceiveComplete + + + +Turning on/off error checking + +Error checking may be turned on/off during run-time by changing the +value of the flag NdisChkErrorFlag. A zero value turns off error +checking and a non-zero value turn it on. This flag is turned on +by default. + + +Controlling level of messages + +Message level may by specified by changing the NdisMsgLevel variable. + + Value of NdisMsgLevel Meaning + 0x000 Turn off all messages + 0x001 Turn on tracing on Level 1 functions + 0x002 Turn on all tracing + +NdisMsgLevel is set to 0 by default + + + +The debug code will be included only if the NDISDBG flag is turned on (== 1). + +If you do change this flag, be sure to delete (1) all nbf .obj files, +(2) ntos\dd\init\obj\i386\ddinit.obj, (3) ntos\init\obj\i386\init.obj, and +(4) recompile everything under ndis, since this flag will change a lot +of goings on inside ndis.h + + +
\ No newline at end of file |