mirror of
https://github.com/reactos/reactos.git
synced 2024-10-08 10:24:06 +00:00
1368 lines
42 KiB
C
1368 lines
42 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS NDIS library
|
|
* FILE: ndis/protocol.c
|
|
* PURPOSE: Routines used by NDIS protocol drivers
|
|
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
|
* Vizzini (vizzini@plasmic.com)
|
|
* REVISIONS:
|
|
* CSH 01/08-2000 Created
|
|
* 09-13-2003 Vizzini Updates for SendPackets support
|
|
*/
|
|
|
|
#include "ndissys.h"
|
|
|
|
#define SERVICES_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"
|
|
#define LINKAGE_KEY L"\\Linkage"
|
|
#define PARAMETERS_KEY L"\\Parameters\\"
|
|
|
|
LIST_ENTRY ProtocolListHead;
|
|
KSPIN_LOCK ProtocolListLock;
|
|
|
|
#define WORKER_TEST 0
|
|
|
|
typedef struct _DMA_CONTEXT {
|
|
PLOGICAL_ADAPTER Adapter;
|
|
PNDIS_PACKET Packet;
|
|
} DMA_CONTEXT, *PDMA_CONTEXT;
|
|
|
|
PNET_PNP_EVENT
|
|
ProSetupPnPEvent(
|
|
NET_PNP_EVENT_CODE EventCode,
|
|
PVOID EventBuffer,
|
|
ULONG EventBufferLength)
|
|
{
|
|
PNET_PNP_EVENT PnPEvent;
|
|
|
|
PnPEvent = ExAllocatePool(PagedPool, sizeof(NET_PNP_EVENT));
|
|
if (!PnPEvent) {
|
|
NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n"));
|
|
return NULL;
|
|
}
|
|
|
|
RtlZeroMemory(PnPEvent, sizeof(NET_PNP_EVENT));
|
|
|
|
PnPEvent->NetEvent = EventCode;
|
|
|
|
if (EventBuffer != NULL)
|
|
{
|
|
PnPEvent->Buffer = ExAllocatePool(PagedPool, EventBufferLength);
|
|
if (!PnPEvent->Buffer)
|
|
{
|
|
NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n"));
|
|
ExFreePool(PnPEvent);
|
|
return NULL;
|
|
}
|
|
|
|
PnPEvent->BufferLength = EventBufferLength;
|
|
|
|
RtlCopyMemory(PnPEvent->Buffer, EventBuffer, PnPEvent->BufferLength);
|
|
}
|
|
|
|
return PnPEvent;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ProSendAndFreePnPEvent(
|
|
PLOGICAL_ADAPTER Adapter,
|
|
PNET_PNP_EVENT PnPEvent,
|
|
PIRP Irp)
|
|
{
|
|
PLIST_ENTRY CurrentEntry;
|
|
NDIS_STATUS Status;
|
|
PADAPTER_BINDING AdapterBinding;
|
|
|
|
CurrentEntry = Adapter->ProtocolListHead.Flink;
|
|
|
|
while (CurrentEntry != &Adapter->ProtocolListHead)
|
|
{
|
|
AdapterBinding = CONTAINING_RECORD(CurrentEntry, ADAPTER_BINDING, AdapterListEntry);
|
|
|
|
Status = (*AdapterBinding->ProtocolBinding->Chars.PnPEventHandler)(
|
|
AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
|
|
PnPEvent);
|
|
|
|
if (Status == NDIS_STATUS_PENDING)
|
|
{
|
|
IoMarkIrpPending(Irp);
|
|
/* Yes, I know this is stupid */
|
|
PnPEvent->NdisReserved[0] = (ULONG_PTR)Irp;
|
|
PnPEvent->NdisReserved[1] = (ULONG_PTR)CurrentEntry->Flink;
|
|
return NDIS_STATUS_PENDING;
|
|
}
|
|
else if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
if (PnPEvent->Buffer) ExFreePool(PnPEvent->Buffer);
|
|
ExFreePool(PnPEvent);
|
|
return Status;
|
|
}
|
|
|
|
CurrentEntry = CurrentEntry->Flink;
|
|
}
|
|
|
|
if (PnPEvent->Buffer) ExFreePool(PnPEvent->Buffer);
|
|
ExFreePool(PnPEvent);
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
NdisIPwrSetPower(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp)
|
|
{
|
|
PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
|
|
PNET_PNP_EVENT PnPEvent;
|
|
PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
ASSERT(Stack->Parameters.Power.Type == DevicePowerState);
|
|
|
|
PnPEvent = ProSetupPnPEvent(NetEventSetPower, &Stack->Parameters.Power.State, sizeof(NDIS_DEVICE_POWER_STATE));
|
|
if (!PnPEvent) {
|
|
NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n"));
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
return ProSendAndFreePnPEvent(Adapter, PnPEvent, Irp);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
NdisIPwrQueryPower(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp)
|
|
{
|
|
PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
|
|
PNET_PNP_EVENT PnPEvent;
|
|
PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
ASSERT(Stack->Parameters.Power.Type == DevicePowerState);
|
|
|
|
PnPEvent = ProSetupPnPEvent(NetEventQueryPower, &Stack->Parameters.Power.State, sizeof(NDIS_DEVICE_POWER_STATE));
|
|
if (!PnPEvent) {
|
|
NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n"));
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
return ProSendAndFreePnPEvent(Adapter, PnPEvent, Irp);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
NdisIPnPQueryStopDevice(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp)
|
|
{
|
|
PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
|
|
PNET_PNP_EVENT PnPEvent;
|
|
|
|
PnPEvent = ProSetupPnPEvent(NetEventQueryRemoveDevice, NULL, 0);
|
|
if (!PnPEvent) {
|
|
NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n"));
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
return ProSendAndFreePnPEvent(Adapter, PnPEvent, Irp);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
NdisIPnPCancelStopDevice(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp)
|
|
{
|
|
PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
|
|
PNET_PNP_EVENT PnPEvent;
|
|
|
|
PnPEvent = ProSetupPnPEvent(NetEventCancelRemoveDevice, NULL, 0);
|
|
if (!PnPEvent) {
|
|
NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n"));
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
return ProSendAndFreePnPEvent(Adapter, PnPEvent, Irp);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
EXPORT
|
|
NdisCompleteBindAdapter(
|
|
IN NDIS_HANDLE BindAdapterContext,
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_STATUS OpenStatus)
|
|
/*
|
|
* FUNCTION: Indicates a packet to bound protocols
|
|
* ARGUMENTS:
|
|
* Adapter = Pointer to logical adapter
|
|
* Packet = Pointer to packet to indicate
|
|
* RETURNS:
|
|
* Status of operation
|
|
* NOTES:
|
|
* - FIXME: partially-implemented
|
|
*/
|
|
{
|
|
PROTOCOL_BINDING *Protocol = (PROTOCOL_BINDING *)BindAdapterContext;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
NDIS_DbgPrint(MIN_TRACE, ("Binding failed (%x)\n", Status));
|
|
return;
|
|
}
|
|
|
|
/* Put protocol binding struct on global list */
|
|
ExInterlockedInsertTailList(&ProtocolListHead, &Protocol->ListEntry, &ProtocolListLock);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
EXPORT
|
|
NdisCompleteUnbindAdapter(
|
|
IN NDIS_HANDLE UnbindAdapterContext,
|
|
IN NDIS_STATUS Status)
|
|
{
|
|
/* We probably need to do more here but for now we just do
|
|
* the opposite of what NdisCompleteBindAdapter does
|
|
*/
|
|
|
|
PROTOCOL_BINDING *Protocol = (PROTOCOL_BINDING *)UnbindAdapterContext;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
NDIS_DbgPrint(MIN_TRACE, ("Unbinding failed (%x)\n", Status));
|
|
return;
|
|
}
|
|
|
|
ExInterlockedRemoveEntryList(&Protocol->ListEntry, &ProtocolListLock);
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ProIndicatePacket(
|
|
PLOGICAL_ADAPTER Adapter,
|
|
PNDIS_PACKET Packet)
|
|
/*
|
|
* FUNCTION: Indicates a packet to bound protocols
|
|
* ARGUMENTS:
|
|
* Adapter = Pointer to logical adapter
|
|
* Packet = Pointer to packet to indicate
|
|
* RETURNS:
|
|
* STATUS_SUCCESS in all cases
|
|
* NOTES:
|
|
* - XXX ATM, this only handles loopback packets - is that its designed function?
|
|
*/
|
|
{
|
|
UINT BufferedLength;
|
|
UINT PacketLength;
|
|
KIRQL OldIrql;
|
|
PUCHAR LookaheadBuffer;
|
|
|
|
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
|
|
|
|
#if DBG
|
|
MiniDisplayPacket(Packet);
|
|
#endif
|
|
|
|
NdisQueryPacket(Packet, NULL, NULL, NULL, &PacketLength);
|
|
|
|
LookaheadBuffer = ExAllocatePool(NonPagedPool, PacketLength);
|
|
if (!LookaheadBuffer) {
|
|
NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n"));
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
NDIS_DbgPrint(MAX_TRACE, ("acquiring miniport block lock\n"));
|
|
KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
|
|
{
|
|
BufferedLength = CopyPacketToBuffer(LookaheadBuffer, Packet, 0, PacketLength);
|
|
Adapter->NdisMiniportBlock.IndicatedPacket[KeGetCurrentProcessorNumber()] = Packet;
|
|
}
|
|
KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
|
|
|
|
if (BufferedLength > Adapter->MediumHeaderSize)
|
|
{
|
|
/* XXX Change this to call SendPackets so we don't have to duplicate this wacky logic */
|
|
MiniIndicateData(Adapter, NULL, LookaheadBuffer, Adapter->MediumHeaderSize,
|
|
&LookaheadBuffer[Adapter->MediumHeaderSize], BufferedLength - Adapter->MediumHeaderSize,
|
|
PacketLength - Adapter->MediumHeaderSize);
|
|
}
|
|
else
|
|
{
|
|
MiniIndicateData(Adapter, NULL, LookaheadBuffer, Adapter->MediumHeaderSize, NULL, 0, 0);
|
|
}
|
|
|
|
ExFreePool(LookaheadBuffer);
|
|
|
|
KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
|
|
{
|
|
Adapter->NdisMiniportBlock.IndicatedPacket[KeGetCurrentProcessorNumber()] = NULL;
|
|
}
|
|
KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
NDIS_STATUS NTAPI
|
|
ProRequest(
|
|
IN NDIS_HANDLE MacBindingHandle,
|
|
IN PNDIS_REQUEST NdisRequest)
|
|
/*
|
|
* FUNCTION: Forwards a request to an NDIS miniport
|
|
* ARGUMENTS:
|
|
* MacBindingHandle = Adapter binding handle
|
|
* NdisRequest = Pointer to request to perform
|
|
* RETURNS:
|
|
* Status of operation
|
|
*/
|
|
{
|
|
PADAPTER_BINDING AdapterBinding;
|
|
PLOGICAL_ADAPTER Adapter;
|
|
PNDIS_REQUEST_MAC_BLOCK MacBlock = (PNDIS_REQUEST_MAC_BLOCK)NdisRequest->MacReserved;
|
|
|
|
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
|
|
|
|
ASSERT(MacBindingHandle);
|
|
AdapterBinding = GET_ADAPTER_BINDING(MacBindingHandle);
|
|
|
|
ASSERT(AdapterBinding->Adapter);
|
|
Adapter = AdapterBinding->Adapter;
|
|
|
|
MacBlock->Binding = &AdapterBinding->NdisOpenBlock;
|
|
|
|
#if WORKER_TEST
|
|
MiniQueueWorkItem(Adapter, NdisWorkItemRequest, NdisRequest, FALSE);
|
|
return NDIS_STATUS_PENDING;
|
|
#else
|
|
if (MiniIsBusy(Adapter, NdisWorkItemRequest)) {
|
|
MiniQueueWorkItem(Adapter, NdisWorkItemRequest, NdisRequest, FALSE);
|
|
return NDIS_STATUS_PENDING;
|
|
}
|
|
|
|
return MiniDoRequest(Adapter, NdisRequest);
|
|
#endif
|
|
}
|
|
|
|
|
|
NDIS_STATUS NTAPI
|
|
ProReset(
|
|
IN NDIS_HANDLE MacBindingHandle)
|
|
{
|
|
PADAPTER_BINDING AdapterBinding = MacBindingHandle;
|
|
|
|
/* FIXME: Wait for all packets to be sent */
|
|
|
|
return MiniReset(AdapterBinding->Adapter);
|
|
}
|
|
|
|
VOID NTAPI
|
|
ScatterGatherSendPacket(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PSCATTER_GATHER_LIST ScatterGather,
|
|
IN PVOID Context)
|
|
{
|
|
PDMA_CONTEXT DmaContext = Context;
|
|
PLOGICAL_ADAPTER Adapter = DmaContext->Adapter;
|
|
PNDIS_PACKET Packet = DmaContext->Packet;
|
|
NDIS_STATUS Status;
|
|
|
|
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
|
|
|
|
NDIS_PER_PACKET_INFO_FROM_PACKET(Packet,
|
|
ScatterGatherListPacketInfo) = ScatterGather;
|
|
|
|
Status = proSendPacketToMiniport(Adapter, Packet);
|
|
|
|
if (Status != NDIS_STATUS_PENDING) {
|
|
NDIS_DbgPrint(MAX_TRACE, ("Completing packet.\n"));
|
|
MiniSendComplete(Adapter,
|
|
Packet,
|
|
Status);
|
|
}
|
|
|
|
ExFreePool(DmaContext);
|
|
}
|
|
|
|
NDIS_STATUS
|
|
proSendPacketToMiniport(PLOGICAL_ADAPTER Adapter, PNDIS_PACKET Packet)
|
|
{
|
|
#if WORKER_TEST
|
|
MiniQueueWorkItem(Adapter, NdisWorkItemSend, Packet, FALSE);
|
|
return NDIS_STATUS_PENDING;
|
|
#else
|
|
KIRQL RaiseOldIrql;
|
|
NDIS_STATUS NdisStatus;
|
|
|
|
if(MiniIsBusy(Adapter, NdisWorkItemSend)) {
|
|
MiniQueueWorkItem(Adapter, NdisWorkItemSend, Packet, FALSE);
|
|
return NDIS_STATUS_PENDING;
|
|
}
|
|
|
|
if(Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)
|
|
{
|
|
if(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_DESERIALIZE)
|
|
{
|
|
NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's SendPackets handler\n"));
|
|
(*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)(
|
|
Adapter->NdisMiniportBlock.MiniportAdapterContext, &Packet, 1);
|
|
NdisStatus = NDIS_STATUS_PENDING;
|
|
} else {
|
|
/* SendPackets is called at DISPATCH_LEVEL for all serialized miniports */
|
|
KeRaiseIrql(DISPATCH_LEVEL, &RaiseOldIrql);
|
|
{
|
|
NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's SendPackets handler\n"));
|
|
(*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)(
|
|
Adapter->NdisMiniportBlock.MiniportAdapterContext, &Packet, 1);
|
|
}
|
|
KeLowerIrql(RaiseOldIrql);
|
|
|
|
NdisStatus = NDIS_GET_PACKET_STATUS(Packet);
|
|
if (NdisStatus == NDIS_STATUS_RESOURCES) {
|
|
MiniQueueWorkItem(Adapter, NdisWorkItemSend, Packet, TRUE);
|
|
NdisStatus = NDIS_STATUS_PENDING;
|
|
}
|
|
}
|
|
|
|
if (NdisStatus != NDIS_STATUS_PENDING) {
|
|
MiniWorkItemComplete(Adapter, NdisWorkItemSend);
|
|
}
|
|
|
|
return NdisStatus;
|
|
} else {
|
|
if(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_DESERIALIZE)
|
|
{
|
|
NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's Send handler\n"));
|
|
NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendHandler)(
|
|
Adapter->NdisMiniportBlock.MiniportAdapterContext, Packet, Packet->Private.Flags);
|
|
NDIS_DbgPrint(MAX_TRACE, ("back from miniport's send handler\n"));
|
|
} else {
|
|
/* Send is called at DISPATCH_LEVEL for all serialized miniports */
|
|
KeRaiseIrql(DISPATCH_LEVEL, &RaiseOldIrql);
|
|
NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's Send handler\n"));
|
|
NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendHandler)(
|
|
Adapter->NdisMiniportBlock.MiniportAdapterContext, Packet, Packet->Private.Flags);
|
|
NDIS_DbgPrint(MAX_TRACE, ("back from miniport's send handler\n"));
|
|
KeLowerIrql(RaiseOldIrql);
|
|
|
|
if (NdisStatus == NDIS_STATUS_RESOURCES) {
|
|
MiniQueueWorkItem(Adapter, NdisWorkItemSend, Packet, TRUE);
|
|
NdisStatus = NDIS_STATUS_PENDING;
|
|
}
|
|
}
|
|
|
|
if (NdisStatus != NDIS_STATUS_PENDING) {
|
|
MiniWorkItemComplete(Adapter, NdisWorkItemSend);
|
|
}
|
|
|
|
return NdisStatus;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
NDIS_STATUS NTAPI
|
|
ProSend(
|
|
IN NDIS_HANDLE MacBindingHandle,
|
|
IN PNDIS_PACKET Packet)
|
|
/*
|
|
* FUNCTION: Forwards a request to send a packet to an NDIS miniport
|
|
* ARGUMENTS:
|
|
* MacBindingHandle = Adapter binding handle
|
|
* Packet = Pointer to NDIS packet descriptor
|
|
* RETURNS:
|
|
* NDIS_STATUS_SUCCESS if the packet was successfully sent
|
|
* NDIS_STATUS_PENDING if the miniport was busy or a serialized miniport returned NDIS_STATUS_RESOURCES
|
|
*/
|
|
{
|
|
PADAPTER_BINDING AdapterBinding;
|
|
PLOGICAL_ADAPTER Adapter;
|
|
PNDIS_BUFFER NdisBuffer;
|
|
PDMA_CONTEXT Context;
|
|
NDIS_STATUS NdisStatus;
|
|
UINT PacketLength;
|
|
KIRQL OldIrql;
|
|
|
|
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
|
|
|
|
ASSERT(MacBindingHandle);
|
|
AdapterBinding = GET_ADAPTER_BINDING(MacBindingHandle);
|
|
|
|
ASSERT(AdapterBinding);
|
|
Adapter = AdapterBinding->Adapter;
|
|
|
|
ASSERT(Adapter);
|
|
|
|
/* if the following is not true, KeRaiseIrql() below will break */
|
|
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
|
|
|
|
/* XXX what is this crazy black magic? */
|
|
Packet->Reserved[1] = (ULONG_PTR)MacBindingHandle;
|
|
|
|
/*
|
|
* Test the packet to see if it is a MAC loopback.
|
|
*
|
|
* We may have to loop this packet if miniport cannot.
|
|
* If dest MAC address of packet == MAC address of adapter,
|
|
* this is a loopback frame.
|
|
*/
|
|
|
|
if ((Adapter->NdisMiniportBlock.MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) &&
|
|
MiniAdapterHasAddress(Adapter, Packet))
|
|
{
|
|
#if WORKER_TEST
|
|
MiniQueueWorkItem(Adapter, NdisWorkItemSendLoopback, Packet, FALSE);
|
|
return NDIS_STATUS_PENDING;
|
|
#else
|
|
return ProIndicatePacket(Adapter, Packet);
|
|
#endif
|
|
} else {
|
|
if (Adapter->NdisMiniportBlock.ScatterGatherListSize != 0)
|
|
{
|
|
NDIS_DbgPrint(MID_TRACE, ("Using Scatter/Gather DMA\n"));
|
|
|
|
NdisQueryPacket(Packet,
|
|
NULL,
|
|
NULL,
|
|
&NdisBuffer,
|
|
&PacketLength);
|
|
|
|
Context = ExAllocatePool(NonPagedPool, sizeof(DMA_CONTEXT));
|
|
if (!Context) {
|
|
NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n"));
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
Context->Adapter = Adapter;
|
|
Context->Packet = Packet;
|
|
|
|
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
|
|
|
|
KeFlushIoBuffers(NdisBuffer, FALSE, TRUE);
|
|
|
|
NdisStatus = Adapter->NdisMiniportBlock.SystemAdapterObject->DmaOperations->GetScatterGatherList(
|
|
Adapter->NdisMiniportBlock.SystemAdapterObject,
|
|
Adapter->NdisMiniportBlock.PhysicalDeviceObject,
|
|
NdisBuffer,
|
|
MmGetMdlVirtualAddress(NdisBuffer),
|
|
PacketLength,
|
|
ScatterGatherSendPacket,
|
|
Context,
|
|
TRUE);
|
|
|
|
KeLowerIrql(OldIrql);
|
|
|
|
if (!NT_SUCCESS(NdisStatus)) {
|
|
NDIS_DbgPrint(MIN_TRACE, ("GetScatterGatherList failed! (%x)\n", NdisStatus));
|
|
return NdisStatus;
|
|
}
|
|
|
|
return NDIS_STATUS_PENDING;
|
|
}
|
|
|
|
|
|
return proSendPacketToMiniport(Adapter, Packet);
|
|
}
|
|
}
|
|
|
|
VOID NTAPI
|
|
ProSendPackets(
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
IN PPNDIS_PACKET PacketArray,
|
|
IN UINT NumberOfPackets)
|
|
{
|
|
PADAPTER_BINDING AdapterBinding = NdisBindingHandle;
|
|
PLOGICAL_ADAPTER Adapter = AdapterBinding->Adapter;
|
|
KIRQL RaiseOldIrql;
|
|
NDIS_STATUS NdisStatus;
|
|
UINT i;
|
|
|
|
if(Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)
|
|
{
|
|
if(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_DESERIALIZE)
|
|
{
|
|
(*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)(
|
|
Adapter->NdisMiniportBlock.MiniportAdapterContext, PacketArray, NumberOfPackets);
|
|
}
|
|
else
|
|
{
|
|
/* SendPackets is called at DISPATCH_LEVEL for all serialized miniports */
|
|
KeRaiseIrql(DISPATCH_LEVEL, &RaiseOldIrql);
|
|
(*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)(
|
|
Adapter->NdisMiniportBlock.MiniportAdapterContext, PacketArray, NumberOfPackets);
|
|
KeLowerIrql(RaiseOldIrql);
|
|
for (i = 0; i < NumberOfPackets; i++)
|
|
{
|
|
NdisStatus = NDIS_GET_PACKET_STATUS(PacketArray[i]);
|
|
if (NdisStatus != NDIS_STATUS_PENDING)
|
|
MiniSendComplete(Adapter, PacketArray[i], NdisStatus);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_DESERIALIZE)
|
|
{
|
|
for (i = 0; i < NumberOfPackets; i++)
|
|
{
|
|
NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendHandler)(
|
|
Adapter->NdisMiniportBlock.MiniportAdapterContext, PacketArray[i], PacketArray[i]->Private.Flags);
|
|
if (NdisStatus != NDIS_STATUS_PENDING)
|
|
MiniSendComplete(Adapter, PacketArray[i], NdisStatus);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Send is called at DISPATCH_LEVEL for all serialized miniports */
|
|
KeRaiseIrql(DISPATCH_LEVEL, &RaiseOldIrql);
|
|
for (i = 0; i < NumberOfPackets; i++)
|
|
{
|
|
NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendHandler)(
|
|
Adapter->NdisMiniportBlock.MiniportAdapterContext, PacketArray[i], PacketArray[i]->Private.Flags);
|
|
if (NdisStatus != NDIS_STATUS_PENDING)
|
|
MiniSendComplete(Adapter, PacketArray[i], NdisStatus);
|
|
}
|
|
KeLowerIrql(RaiseOldIrql);
|
|
}
|
|
}
|
|
}
|
|
|
|
NDIS_STATUS NTAPI
|
|
ProTransferData(
|
|
IN NDIS_HANDLE MacBindingHandle,
|
|
IN NDIS_HANDLE MacReceiveContext,
|
|
IN UINT ByteOffset,
|
|
IN UINT BytesToTransfer,
|
|
IN OUT PNDIS_PACKET Packet,
|
|
OUT PUINT BytesTransferred)
|
|
/*
|
|
* FUNCTION: Forwards a request to copy received data into a protocol-supplied packet
|
|
* ARGUMENTS:
|
|
* MacBindingHandle = Adapter binding handle
|
|
* MacReceiveContext = MAC receive context
|
|
* ByteOffset = Offset in packet to place data
|
|
* BytesToTransfer = Number of bytes to copy into packet
|
|
* Packet = Pointer to NDIS packet descriptor
|
|
* BytesTransferred = Address of buffer to place number of bytes copied
|
|
*/
|
|
{
|
|
PADAPTER_BINDING AdapterBinding = GET_ADAPTER_BINDING(MacBindingHandle);
|
|
PLOGICAL_ADAPTER Adapter = AdapterBinding->Adapter;
|
|
NDIS_STATUS Status;
|
|
KIRQL OldIrql;
|
|
|
|
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
|
|
|
|
/* FIXME: Interrupts must be disabled for adapter */
|
|
/* XXX sd - why is that true? */
|
|
|
|
if (Adapter->NdisMiniportBlock.IndicatedPacket[KeGetCurrentProcessorNumber()]) {
|
|
NDIS_DbgPrint(MAX_TRACE, ("LoopPacket\n"));
|
|
/* NDIS is responsible for looping this packet */
|
|
NdisCopyFromPacketToPacket(Packet,
|
|
ByteOffset + Adapter->MediumHeaderSize,
|
|
BytesToTransfer + Adapter->MediumHeaderSize,
|
|
Adapter->NdisMiniportBlock.IndicatedPacket[KeGetCurrentProcessorNumber()],
|
|
0,
|
|
BytesTransferred);
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
ASSERT(Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.TransferDataHandler);
|
|
|
|
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
|
|
|
|
Status = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.TransferDataHandler)(
|
|
Packet,
|
|
BytesTransferred,
|
|
Adapter->NdisMiniportBlock.MiniportAdapterContext,
|
|
MacReceiveContext,
|
|
ByteOffset,
|
|
BytesToTransfer);
|
|
|
|
KeLowerIrql(OldIrql);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
EXPORT
|
|
NdisCloseAdapter(
|
|
OUT PNDIS_STATUS Status,
|
|
IN NDIS_HANDLE NdisBindingHandle)
|
|
/*
|
|
* FUNCTION: Closes an adapter opened with NdisOpenAdapter
|
|
* ARGUMENTS:
|
|
* Status = Address of buffer for status information
|
|
* NdisBindingHandle = Handle returned by NdisOpenAdapter
|
|
*/
|
|
{
|
|
PADAPTER_BINDING AdapterBinding = GET_ADAPTER_BINDING(NdisBindingHandle);
|
|
|
|
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
|
|
|
|
/* Remove from protocol's bound adapters list */
|
|
ExInterlockedRemoveEntryList(&AdapterBinding->ProtocolListEntry, &AdapterBinding->ProtocolBinding->Lock);
|
|
|
|
/* Remove protocol from adapter's bound protocols list */
|
|
ExInterlockedRemoveEntryList(&AdapterBinding->AdapterListEntry, &AdapterBinding->Adapter->NdisMiniportBlock.Lock);
|
|
|
|
ExFreePool(AdapterBinding);
|
|
|
|
*Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
EXPORT
|
|
NdisDeregisterProtocol(
|
|
OUT PNDIS_STATUS Status,
|
|
IN NDIS_HANDLE NdisProtocolHandle)
|
|
/*
|
|
* FUNCTION: Releases the resources allocated by NdisRegisterProtocol
|
|
* ARGUMENTS:
|
|
* Status = Address of buffer for status information
|
|
* NdisProtocolHandle = Handle returned by NdisRegisterProtocol
|
|
*/
|
|
{
|
|
PPROTOCOL_BINDING Protocol = GET_PROTOCOL_BINDING(NdisProtocolHandle);
|
|
|
|
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
|
|
|
|
/* FIXME: Make sure no adapter bindings exist */
|
|
|
|
/* Remove protocol from global list */
|
|
ExInterlockedRemoveEntryList(&Protocol->ListEntry, &ProtocolListLock);
|
|
|
|
ExFreePool(Protocol);
|
|
|
|
*Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
EXPORT
|
|
NdisOpenAdapter(
|
|
OUT PNDIS_STATUS Status,
|
|
OUT PNDIS_STATUS OpenErrorStatus,
|
|
OUT PNDIS_HANDLE NdisBindingHandle,
|
|
OUT PUINT SelectedMediumIndex,
|
|
IN PNDIS_MEDIUM MediumArray,
|
|
IN UINT MediumArraySize,
|
|
IN NDIS_HANDLE NdisProtocolHandle,
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN PNDIS_STRING AdapterName,
|
|
IN UINT OpenOptions,
|
|
IN PSTRING AddressingInformation OPTIONAL)
|
|
/*
|
|
* FUNCTION: Opens an adapter for communication
|
|
* ARGUMENTS:
|
|
* Status = Address of buffer for status information
|
|
* OpenErrorStatus = Address of buffer for secondary error code
|
|
* NdisBindingHandle = Address of buffer for adapter binding handle
|
|
* SelectedMediumIndex = Address of buffer for selected medium
|
|
* MediumArray = Pointer to an array of NDIS_MEDIUMs called can support
|
|
* MediumArraySize = Number of elements in MediumArray
|
|
* NdisProtocolHandle = Handle returned by NdisRegisterProtocol
|
|
* ProtocolBindingContext = Pointer to caller supplied context area
|
|
* AdapterName = Pointer to buffer with name of adapter
|
|
* OpenOptions = Bitmask with flags passed to next-lower driver
|
|
* AddressingInformation = Optional pointer to buffer with NIC specific information
|
|
*/
|
|
{
|
|
UINT i;
|
|
BOOLEAN Found;
|
|
PLOGICAL_ADAPTER Adapter;
|
|
PADAPTER_BINDING AdapterBinding;
|
|
PPROTOCOL_BINDING Protocol = GET_PROTOCOL_BINDING(NdisProtocolHandle);
|
|
|
|
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
|
|
|
|
if(!NdisProtocolHandle)
|
|
{
|
|
NDIS_DbgPrint(MIN_TRACE, ("NdisProtocolHandle is NULL\n"));
|
|
*OpenErrorStatus = *Status = NDIS_STATUS_FAILURE;
|
|
return;
|
|
}
|
|
|
|
Adapter = MiniLocateDevice(AdapterName);
|
|
if (!Adapter)
|
|
{
|
|
NDIS_DbgPrint(MIN_TRACE, ("Adapter not found.\n"));
|
|
*Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
|
|
return;
|
|
}
|
|
|
|
/* Find the media type in the list provided by the protocol driver */
|
|
Found = FALSE;
|
|
for (i = 0; i < MediumArraySize; i++)
|
|
{
|
|
if (Adapter->NdisMiniportBlock.MediaType == MediumArray[i])
|
|
{
|
|
*SelectedMediumIndex = i;
|
|
Found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!Found)
|
|
{
|
|
NDIS_DbgPrint(MIN_TRACE, ("Medium is not supported.\n"));
|
|
*Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
|
|
return;
|
|
}
|
|
|
|
/* Now that we have confirmed that the adapter can be opened, create a binding */
|
|
|
|
AdapterBinding = ExAllocatePool(NonPagedPool, sizeof(ADAPTER_BINDING));
|
|
if (!AdapterBinding)
|
|
{
|
|
NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
|
|
*Status = NDIS_STATUS_RESOURCES;
|
|
return;
|
|
}
|
|
|
|
RtlZeroMemory(AdapterBinding, sizeof(ADAPTER_BINDING));
|
|
|
|
AdapterBinding->ProtocolBinding = Protocol;
|
|
AdapterBinding->Adapter = Adapter;
|
|
AdapterBinding->NdisOpenBlock.ProtocolBindingContext = ProtocolBindingContext;
|
|
|
|
/* Set fields required by some NDIS macros */
|
|
AdapterBinding->NdisOpenBlock.BindingHandle = (NDIS_HANDLE)AdapterBinding;
|
|
|
|
/* Set handlers (some NDIS macros require these) */
|
|
|
|
AdapterBinding->NdisOpenBlock.RequestHandler = ProRequest;
|
|
AdapterBinding->NdisOpenBlock.ResetHandler = ProReset;
|
|
AdapterBinding->NdisOpenBlock.SendHandler = ProSend;
|
|
AdapterBinding->NdisOpenBlock.SendPacketsHandler = ProSendPackets;
|
|
AdapterBinding->NdisOpenBlock.TransferDataHandler = ProTransferData;
|
|
|
|
AdapterBinding->NdisOpenBlock.RequestCompleteHandler =
|
|
Protocol->Chars.RequestCompleteHandler;
|
|
|
|
/* Put on protocol's bound adapters list */
|
|
ExInterlockedInsertTailList(&Protocol->AdapterListHead, &AdapterBinding->ProtocolListEntry, &Protocol->Lock);
|
|
|
|
/* Put protocol on adapter's bound protocols list */
|
|
NDIS_DbgPrint(MAX_TRACE, ("acquiring miniport block lock\n"));
|
|
ExInterlockedInsertTailList(&Adapter->ProtocolListHead, &AdapterBinding->AdapterListEntry, &Adapter->NdisMiniportBlock.Lock);
|
|
|
|
*NdisBindingHandle = (NDIS_HANDLE)AdapterBinding;
|
|
|
|
*Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
PADAPTER_BINDING
|
|
NTAPI
|
|
LocateAdapterBindingByName(IN PPROTOCOL_BINDING ProtocolBinding, IN PNDIS_STRING AdapterName)
|
|
{
|
|
PLIST_ENTRY CurrentEntry;
|
|
PADAPTER_BINDING AdapterBinding;
|
|
KIRQL OldIrql;
|
|
|
|
KeAcquireSpinLock(&ProtocolBinding->Lock, &OldIrql);
|
|
|
|
CurrentEntry = ProtocolBinding->AdapterListHead.Flink;
|
|
|
|
while (CurrentEntry != &ProtocolBinding->AdapterListHead)
|
|
{
|
|
AdapterBinding = CONTAINING_RECORD(CurrentEntry, ADAPTER_BINDING, ProtocolListEntry);
|
|
|
|
if (RtlCompareUnicodeString(AdapterName, &AdapterBinding->Adapter->NdisMiniportBlock.MiniportName, TRUE) == 0)
|
|
{
|
|
KeReleaseSpinLock(&ProtocolBinding->Lock, OldIrql);
|
|
return AdapterBinding;
|
|
}
|
|
|
|
CurrentEntry = CurrentEntry->Flink;
|
|
}
|
|
|
|
KeReleaseSpinLock(&ProtocolBinding->Lock, OldIrql);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
ndisBindMiniportsToProtocol(OUT PNDIS_STATUS Status, IN PPROTOCOL_BINDING Protocol)
|
|
{
|
|
/*
|
|
* bind the protocol to all of its miniports
|
|
*
|
|
* open registry path
|
|
* get list of devices from Bind key
|
|
* call BindAdapterHandler for each
|
|
*/
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING RegistryPath;
|
|
WCHAR *RegistryPathStr, *DataPtr = NULL;
|
|
NTSTATUS NtStatus;
|
|
HANDLE DriverKeyHandle = NULL;
|
|
PKEY_VALUE_PARTIAL_INFORMATION KeyInformation = NULL;
|
|
PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics = &Protocol->Chars;
|
|
UNICODE_STRING ValueName;
|
|
ULONG ResultLength;
|
|
PLIST_ENTRY CurrentEntry = NULL;
|
|
|
|
RegistryPathStr = ExAllocatePoolWithTag(PagedPool, sizeof(SERVICES_KEY) + ProtocolCharacteristics->Name.Length + sizeof(LINKAGE_KEY), NDIS_TAG + __LINE__);
|
|
if(!RegistryPathStr)
|
|
{
|
|
NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
|
|
*Status = NDIS_STATUS_RESOURCES;
|
|
return;
|
|
}
|
|
|
|
wcscpy(RegistryPathStr, SERVICES_KEY);
|
|
wcsncat(RegistryPathStr, ((WCHAR *)ProtocolCharacteristics->Name.Buffer), ProtocolCharacteristics->Name.Length / sizeof(WCHAR));
|
|
RegistryPathStr[wcslen(SERVICES_KEY)+ProtocolCharacteristics->Name.Length/sizeof(WCHAR)] = 0;
|
|
wcscat(RegistryPathStr, LINKAGE_KEY);
|
|
|
|
RtlInitUnicodeString(&RegistryPath, RegistryPathStr);
|
|
NDIS_DbgPrint(MAX_TRACE, ("Opening configuration key: %wZ\n", &RegistryPath));
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes, &RegistryPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
|
|
NtStatus = ZwOpenKey(&DriverKeyHandle, KEY_READ, &ObjectAttributes);
|
|
|
|
ExFreePool(RegistryPathStr);
|
|
|
|
if(NT_SUCCESS(NtStatus))
|
|
{
|
|
NDIS_DbgPrint(MAX_TRACE, ("Successfully opened the registry configuration\n"));
|
|
|
|
RtlInitUnicodeString(&ValueName, L"Bind");
|
|
|
|
NtStatus = ZwQueryValueKey(DriverKeyHandle, &ValueName, KeyValuePartialInformation, NULL, 0, &ResultLength);
|
|
if(NtStatus != STATUS_BUFFER_OVERFLOW && NtStatus != STATUS_BUFFER_TOO_SMALL && NtStatus != STATUS_SUCCESS)
|
|
{
|
|
NDIS_DbgPrint(MIN_TRACE, ("Unable to query the Bind value for size\n"));
|
|
ZwClose(DriverKeyHandle);
|
|
}
|
|
else
|
|
{
|
|
KeyInformation = ExAllocatePoolWithTag(PagedPool, sizeof(KEY_VALUE_PARTIAL_INFORMATION) + ResultLength, NDIS_TAG + __LINE__);
|
|
if(!KeyInformation)
|
|
{
|
|
NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
|
|
ZwClose(DriverKeyHandle);
|
|
NtStatus = STATUS_NO_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
NtStatus = ZwQueryValueKey(DriverKeyHandle, &ValueName, KeyValuePartialInformation, KeyInformation,
|
|
sizeof(KEY_VALUE_PARTIAL_INFORMATION) + ResultLength, &ResultLength);
|
|
|
|
ZwClose(DriverKeyHandle);
|
|
|
|
if(!NT_SUCCESS(NtStatus))
|
|
{
|
|
NDIS_DbgPrint(MIN_TRACE, ("Unable to query the Bind value\n"));
|
|
ExFreePool(KeyInformation);
|
|
KeyInformation = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
NDIS_DbgPrint(MID_TRACE, ("Performing global bind for protocol '%wZ'\n", &ProtocolCharacteristics->Name));
|
|
KeyInformation = NULL;
|
|
|
|
CurrentEntry = AdapterListHead.Flink;
|
|
}
|
|
else
|
|
{
|
|
NDIS_DbgPrint(MID_TRACE, ("Performing standard bind for protocol '%wZ'\n", &ProtocolCharacteristics->Name));
|
|
|
|
DataPtr = (WCHAR*)KeyInformation->Data;
|
|
}
|
|
|
|
/* Assume success for now */
|
|
*Status = NDIS_STATUS_SUCCESS;
|
|
|
|
while (TRUE)
|
|
{
|
|
/* BindContext is for tracking pending binding operations */
|
|
VOID *BindContext = 0;
|
|
NDIS_STRING DeviceName;
|
|
NDIS_STRING RegistryPath;
|
|
WCHAR *RegistryPathStr = NULL;
|
|
ULONG PathLength = 0;
|
|
PLOGICAL_ADAPTER Adapter;
|
|
|
|
if (KeyInformation)
|
|
{
|
|
/* Parse the REG_MULTI_SZ entry for device names */
|
|
if (!(*DataPtr))
|
|
break;
|
|
|
|
RtlInitUnicodeString(&DeviceName, DataPtr);
|
|
}
|
|
else
|
|
{
|
|
/* Use the device name from the global adapter list */
|
|
if (CurrentEntry == &AdapterListHead)
|
|
break;
|
|
|
|
Adapter = CONTAINING_RECORD(CurrentEntry, LOGICAL_ADAPTER, ListEntry);
|
|
|
|
DeviceName = Adapter->NdisMiniportBlock.MiniportName;
|
|
}
|
|
|
|
/* Make sure the adapter has started */
|
|
if (!MiniLocateDevice(&DeviceName))
|
|
{
|
|
/* It wasn't in the global miniport list, so skip the bind entry */
|
|
goto next;
|
|
}
|
|
|
|
/* Make sure this device isn't already bound to this protocol */
|
|
if (LocateAdapterBindingByName(Protocol, &DeviceName))
|
|
{
|
|
/* It was already in this protocol's bound adapter list, so skip the bind entry */
|
|
goto next;
|
|
}
|
|
|
|
/*
|
|
* RegistryPath should be:
|
|
* \Registry\Machine\System\CurrentControlSet\Services\Nic1\Parameters\Tcpip
|
|
*
|
|
* This is constructed as follows:
|
|
* SERVICES_KEY + extracted device name + Protocol name from characteristics
|
|
*/
|
|
|
|
PathLength = sizeof(SERVICES_KEY) + /* \Registry\Machine\System\CurrentControlSet\Services\ */
|
|
wcslen( DeviceName.Buffer + 8 ) * sizeof(WCHAR) + /* Adapter1 (extracted from \Device\Adapter1) */
|
|
sizeof(PARAMETERS_KEY) + /* \Parameters\ */
|
|
ProtocolCharacteristics->Name.Length + sizeof(WCHAR); /* Tcpip */
|
|
|
|
RegistryPathStr = ExAllocatePool(PagedPool, PathLength);
|
|
if(!RegistryPathStr)
|
|
{
|
|
NDIS_DbgPrint(MIN_TRACE, ("insufficient resources.\n"));
|
|
*Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
wcscpy(RegistryPathStr, SERVICES_KEY);
|
|
wcscat(RegistryPathStr, DeviceName.Buffer + 8 );
|
|
wcscat(RegistryPathStr, PARAMETERS_KEY);
|
|
wcsncat(RegistryPathStr, ProtocolCharacteristics->Name.Buffer, ProtocolCharacteristics->Name.Length / sizeof(WCHAR) );
|
|
|
|
RegistryPathStr[PathLength/sizeof(WCHAR) - 1] = 0;
|
|
|
|
RtlInitUnicodeString(&RegistryPath, RegistryPathStr);
|
|
|
|
NDIS_DbgPrint(MAX_TRACE, ("Calling protocol's BindAdapter handler with DeviceName %wZ and RegistryPath %wZ\n",
|
|
&DeviceName, &RegistryPath));
|
|
|
|
{
|
|
BIND_HANDLER BindHandler = ProtocolCharacteristics->BindAdapterHandler;
|
|
if(BindHandler)
|
|
{
|
|
BindHandler(Status, BindContext, &DeviceName, &RegistryPath, 0);
|
|
NDIS_DbgPrint(MID_TRACE, ("%wZ's BindAdapter handler returned 0x%x for %wZ\n", &ProtocolCharacteristics->Name, *Status, &DeviceName));
|
|
}
|
|
else
|
|
NDIS_DbgPrint(MID_TRACE, ("No protocol bind handler specified\n"));
|
|
}
|
|
|
|
next:
|
|
if (KeyInformation)
|
|
{
|
|
/* Advance to the next adapter in the REG_MULTI_SZ */
|
|
DataPtr += (DeviceName.Length / sizeof(WCHAR)) + 1;
|
|
}
|
|
else
|
|
{
|
|
/* Advance to the next adapter in the global list */
|
|
CurrentEntry = CurrentEntry->Flink;
|
|
}
|
|
}
|
|
|
|
if (KeyInformation)
|
|
{
|
|
ExFreePool(KeyInformation);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
EXPORT
|
|
NdisRegisterProtocol(
|
|
OUT PNDIS_STATUS Status,
|
|
OUT PNDIS_HANDLE NdisProtocolHandle,
|
|
IN PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics,
|
|
IN UINT CharacteristicsLength)
|
|
/*
|
|
* FUNCTION: Registers an NDIS driver's ProtocolXxx entry points
|
|
* ARGUMENTS:
|
|
* Status = Address of buffer for status information
|
|
* NdisProtocolHandle = Address of buffer for handle used to identify the driver
|
|
* ProtocolCharacteristics = Pointer to NDIS_PROTOCOL_CHARACTERISTICS structure
|
|
* CharacteristicsLength = Size of structure which ProtocolCharacteristics targets
|
|
* NOTES:
|
|
* - you *must* set NdisProtocolHandle before doing anything that could wind up
|
|
* getting BindAdapterHandler, as it will probably call OpenAdapter with this handle
|
|
* - the above implies that the initialization of the protocol block must be complete
|
|
* by then
|
|
* TODO:
|
|
* - break this function up - probably do a 'ndisRefreshProtocolBindings' function
|
|
* - make this thing able to handle >1 protocol
|
|
*/
|
|
{
|
|
PPROTOCOL_BINDING Protocol;
|
|
NTSTATUS NtStatus;
|
|
UINT MinSize;
|
|
PNET_PNP_EVENT PnPEvent;
|
|
|
|
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
|
|
|
|
*NdisProtocolHandle = NULL;
|
|
|
|
/* first validate the PROTOCOL_CHARACTERISTICS */
|
|
switch (ProtocolCharacteristics->MajorNdisVersion)
|
|
{
|
|
case 0x03:
|
|
/* we don't really want to support ndis3 drivers - so we complain for now */
|
|
NDIS_DbgPrint(MID_TRACE, ("NDIS 3 protocol attempting to register\n"));
|
|
MinSize = sizeof(NDIS30_PROTOCOL_CHARACTERISTICS);
|
|
break;
|
|
|
|
case 0x04:
|
|
MinSize = sizeof(NDIS40_PROTOCOL_CHARACTERISTICS);
|
|
break;
|
|
|
|
case 0x05:
|
|
MinSize = sizeof(NDIS50_PROTOCOL_CHARACTERISTICS);
|
|
break;
|
|
|
|
default:
|
|
*Status = NDIS_STATUS_BAD_VERSION;
|
|
NDIS_DbgPrint(MIN_TRACE, ("Incorrect characteristics size\n"));
|
|
return;
|
|
}
|
|
|
|
if (CharacteristicsLength < MinSize)
|
|
{
|
|
NDIS_DbgPrint(MIN_TRACE, ("Bad protocol characteristics.\n"));
|
|
*Status = NDIS_STATUS_BAD_CHARACTERISTICS;
|
|
return;
|
|
}
|
|
|
|
/* set up the protocol block */
|
|
Protocol = ExAllocatePool(NonPagedPool, sizeof(PROTOCOL_BINDING));
|
|
if (!Protocol)
|
|
{
|
|
NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
|
|
*Status = NDIS_STATUS_RESOURCES;
|
|
return;
|
|
}
|
|
|
|
RtlZeroMemory(Protocol, sizeof(PROTOCOL_BINDING));
|
|
RtlCopyMemory(&Protocol->Chars, ProtocolCharacteristics, MinSize);
|
|
|
|
NtStatus = RtlUpcaseUnicodeString(&Protocol->Chars.Name, &ProtocolCharacteristics->Name, TRUE);
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
|
|
ExFreePool(Protocol);
|
|
*Status = NDIS_STATUS_RESOURCES;
|
|
return;
|
|
}
|
|
|
|
KeInitializeSpinLock(&Protocol->Lock);
|
|
|
|
InitializeListHead(&Protocol->AdapterListHead);
|
|
|
|
/* We must set this before the call to ndisBindMiniportsToProtocol because the protocol's
|
|
* BindAdapter handler might need it */
|
|
|
|
*NdisProtocolHandle = Protocol;
|
|
|
|
ndisBindMiniportsToProtocol(Status, Protocol);
|
|
|
|
/* Should we only send this if ndisBindMiniportsToProtocol succeeds? */
|
|
PnPEvent = ProSetupPnPEvent(NetEventBindsComplete, NULL, 0);
|
|
if (PnPEvent)
|
|
{
|
|
if (Protocol->Chars.PnPEventHandler)
|
|
{
|
|
/* We call this with a NULL binding context because it affects all bindings */
|
|
NtStatus = (*Protocol->Chars.PnPEventHandler)(NULL,
|
|
PnPEvent);
|
|
|
|
/* FIXME: We don't support this yet */
|
|
ASSERT(NtStatus != NDIS_STATUS_PENDING);
|
|
}
|
|
|
|
ExFreePool(PnPEvent);
|
|
}
|
|
|
|
if (*Status == NDIS_STATUS_SUCCESS) {
|
|
ExInterlockedInsertTailList(&ProtocolListHead, &Protocol->ListEntry, &ProtocolListLock);
|
|
} else {
|
|
NDIS_DbgPrint(MIN_TRACE, ("Binding failed (%x)\n", *Status));
|
|
ExFreePool(Protocol);
|
|
*NdisProtocolHandle = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
EXPORT
|
|
NdisRequest(
|
|
OUT PNDIS_STATUS Status,
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
IN PNDIS_REQUEST NdisRequest)
|
|
/*
|
|
* FUNCTION: Forwards a request to an NDIS driver
|
|
* ARGUMENTS:
|
|
* Status = Address of buffer for status information
|
|
* NdisBindingHandle = Adapter binding handle
|
|
* NdisRequest = Pointer to request to perform
|
|
*/
|
|
{
|
|
*Status = ProRequest(NdisBindingHandle, NdisRequest);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
EXPORT
|
|
NdisReset(
|
|
OUT PNDIS_STATUS Status,
|
|
IN NDIS_HANDLE NdisBindingHandle)
|
|
{
|
|
*Status = ProReset(NdisBindingHandle);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
#undef NdisSend
|
|
VOID
|
|
EXPORT
|
|
NdisSend(
|
|
OUT PNDIS_STATUS Status,
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
IN PNDIS_PACKET Packet)
|
|
/*
|
|
* FUNCTION: Forwards a request to send a packet
|
|
* ARGUMENTS:
|
|
* Status = Address of buffer for status information
|
|
* NdisBindingHandle = Adapter binding handle
|
|
* Packet = Pointer to NDIS packet descriptor
|
|
*/
|
|
{
|
|
*Status = ProSend(NdisBindingHandle, Packet);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
#undef NdisSendPackets
|
|
VOID
|
|
EXPORT
|
|
NdisSendPackets(
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
IN PPNDIS_PACKET PacketArray,
|
|
IN UINT NumberOfPackets)
|
|
{
|
|
ProSendPackets(NdisBindingHandle, PacketArray, NumberOfPackets);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
#undef NdisTransferData
|
|
VOID
|
|
EXPORT
|
|
NdisTransferData(
|
|
OUT PNDIS_STATUS Status,
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
IN NDIS_HANDLE MacReceiveContext,
|
|
IN UINT ByteOffset,
|
|
IN UINT BytesToTransfer,
|
|
IN OUT PNDIS_PACKET Packet,
|
|
OUT PUINT BytesTransferred)
|
|
/*
|
|
* FUNCTION: Forwards a request to copy received data into a protocol-supplied packet
|
|
* ARGUMENTS:
|
|
* Status = Address of buffer for status information
|
|
* NdisBindingHandle = Adapter binding handle
|
|
* MacReceiveContext = MAC receive context
|
|
* ByteOffset = Offset in packet to place data
|
|
* BytesToTransfer = Number of bytes to copy into packet
|
|
* Packet = Pointer to NDIS packet descriptor
|
|
* BytesTransferred = Address of buffer to place number of bytes copied
|
|
*/
|
|
{
|
|
*Status = ProTransferData(NdisBindingHandle,
|
|
MacReceiveContext,
|
|
ByteOffset,
|
|
BytesToTransfer,
|
|
Packet,
|
|
BytesTransferred);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
NdisReEnumerateProtocolBindings(IN NDIS_HANDLE NdisProtocolHandle)
|
|
{
|
|
NDIS_STATUS NdisStatus;
|
|
|
|
ndisBindMiniportsToProtocol(&NdisStatus, NdisProtocolHandle);
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
EXPORT
|
|
NdisGetDriverHandle(
|
|
IN PNDIS_HANDLE NdisBindingHandle,
|
|
OUT PNDIS_HANDLE NdisDriverHandle)
|
|
/*
|
|
* FUNCTION:
|
|
* ARGUMENTS:
|
|
* NOTES:
|
|
* NDIS 5.0
|
|
*/
|
|
{
|
|
PADAPTER_BINDING Binding = (PADAPTER_BINDING)NdisBindingHandle;
|
|
|
|
if (!Binding)
|
|
{
|
|
NDIS_DbgPrint(MIN_TRACE, ("Bad binding handle\n"));
|
|
*NdisDriverHandle = NULL;
|
|
return;
|
|
}
|
|
|
|
*NdisDriverHandle = Binding->Adapter->NdisMiniportBlock.DriverHandle;
|
|
}
|
|
|
|
/* EOF */
|