mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
10214 lines
256 KiB
10214 lines
256 KiB
/*++
|
|
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;
|
|
}
|
|
|