📄 protocol.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"
#include <buffer.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;
/*
* @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;
/* Put protocol binding struct on global list */
ExInterlockedInsertTailList(&ProtocolListHead, &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?
*/
{
KIRQL OldIrql;
UINT BufferedLength;
UINT PacketLength;
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
#ifdef DBG
MiniDisplayPacket(Packet);
#endif
NdisQueryPacket(Packet, NULL, NULL, NULL, &PacketLength);
NDIS_DbgPrint(MAX_TRACE, ("acquiring miniport block lock\n"));
KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
{
Adapter->NdisMiniportBlock.IndicatedPacket[KeGetCurrentProcessorNumber()] = Packet;
BufferedLength = CopyPacketToBuffer(Adapter->LookaheadBuffer, Packet, 0, Adapter->NdisMiniportBlock.CurrentLookahead);
}
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, Adapter->LookaheadBuffer, Adapter->MediumHeaderSize,
&Adapter->LookaheadBuffer[Adapter->MediumHeaderSize], BufferedLength - Adapter->MediumHeaderSize,
PacketLength - Adapter->MediumHeaderSize);
}
else
{
MiniIndicateData(Adapter, NULL, Adapter->LookaheadBuffer, Adapter->MediumHeaderSize, NULL, 0, 0);
}
NDIS_DbgPrint(MAX_TRACE, ("acquiring miniport block lock\n"));
KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
{
Adapter->NdisMiniportBlock.IndicatedPacket[KeGetCurrentProcessorNumber()] = NULL;
}
KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
return 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
*/
{
KIRQL OldIrql;
BOOLEAN QueueWorkItem = FALSE;
NDIS_STATUS NdisStatus;
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 the miniport is already busy, queue a workitem
*/
NDIS_DbgPrint(MAX_TRACE, ("acquiring miniport block lock\n"));
KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
{
if(Adapter->MiniportBusy)
QueueWorkItem = TRUE;
else
{
NDIS_DbgPrint(MAX_TRACE, ("Setting adapter 0x%x to busy\n"));
Adapter->MiniportBusy = TRUE;
}
}
/* MiniQueueWorkItem must be called at IRQL >= DISPATCH_LEVEL */
if (QueueWorkItem)
{
MiniQueueWorkItem(Adapter, NdisWorkItemRequest, (PVOID)NdisRequest);
KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
return NDIS_STATUS_PENDING;
}
KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
/* MiniportQueryInformation (called by MiniDoRequest) runs at DISPATCH_LEVEL */
/* TODO (?): move the irql raise into MiniDoRequest */
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
{
NdisStatus = MiniDoRequest(&Adapter->NdisMiniportBlock, NdisRequest);
NDIS_DbgPrint(MAX_TRACE, ("acquiring miniport block lock\n"));
KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
{
NDIS_DbgPrint(MAX_TRACE, ("Setting adapter 0x%x to free\n"));
Adapter->MiniportBusy = FALSE;
if (Adapter->WorkQueueHead)
KeInsertQueueDpc(&Adapter->NdisMiniportBlock.DeferredDpc, NULL, NULL);
}
KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
}
KeLowerIrql(OldIrql);
return NdisStatus;
}
NDIS_STATUS NTAPI
ProReset(
IN NDIS_HANDLE MacBindingHandle)
{
UNIMPLEMENTED
return NDIS_STATUS_FAILURE;
}
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 always
* NOTES:
* TODO:
* - Fix return values
* - Should queue packet if miniport returns NDIS_STATUS_RESOURCES
* - Queue packets directly on the adapters when possible (i.e.
* when miniports not busy)
* - Break this up
*/
{
KIRQL RaiseOldIrql, SpinOldIrql;
BOOLEAN QueueWorkItem = FALSE;
NDIS_STATUS NdisStatus;
PADAPTER_BINDING AdapterBinding;
PLOGICAL_ADAPTER Adapter;
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[0] = (ULONG_PTR)MacBindingHandle;
/*
* Acquire this lock in order to see if the miniport is busy.
* If it is not busy, we mark it as busy and release the lock.
* Else we don't do anything because we have to queue a workitem
* anyway.
*/
NDIS_DbgPrint(MAX_TRACE, ("acquiring miniport block lock\n"));
KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &SpinOldIrql);
{
/*
* if the miniport is marked as busy, we queue the packet as a work item,
* else we send the packet directly to the miniport. Sending to the miniport
* makes it busy.
*/
if (Adapter->MiniportBusy)
QueueWorkItem = TRUE;
else
{
NDIS_DbgPrint(MAX_TRACE, ("Setting adapter 0x%x to busy\n"));
Adapter->MiniportBusy = TRUE;
}
}
KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, SpinOldIrql);
/*
* 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))
{
NDIS_DbgPrint(MIN_TRACE, ("Looping packet.\n"));
if (QueueWorkItem)
{
MiniQueueWorkItem(Adapter, NdisWorkItemSendLoopback, (PVOID)Packet);
return NDIS_STATUS_PENDING;
}
KeRaiseIrql(DISPATCH_LEVEL, &RaiseOldIrql);
{
/*
* atm this *only* handles loopback packets - it calls MiniIndicateData to
* send back to the protocol. FIXME: this will need to be adjusted a bit.
* Also, I'm not sure you really have to be at dispatch level for this. It
* might use a ReceivePackets handler, which can run <= DISPATCH_LEVEL.
*/
NdisStatus = ProIndicatePacket(Adapter, Packet);
NDIS_DbgPrint(MAX_TRACE, ("acquiring miniport block lock\n"));
KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
{
NDIS_DbgPrint(MAX_TRACE, ("Setting adapter 0x%x to free\n"));
Adapter->MiniportBusy = FALSE;
if (Adapter->WorkQueueHead)
KeInsertQueueDpc(&Adapter->NdisMiniportBlock.DeferredDpc, NULL, NULL);
else
NDIS_DbgPrint(MID_TRACE,("Failed to insert packet into work queue\n"));
}
KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
}
KeLowerIrql(RaiseOldIrql);
return NdisStatus;
}
else
NDIS_DbgPrint(MID_TRACE,("Not a loopback packet\n"));
/* This is a normal send packet, not a loopback packet. */
if (QueueWorkItem)
{
MiniQueueWorkItem(Adapter, NdisWorkItemSend, (PVOID)Packet);
NDIS_DbgPrint(MAX_TRACE, ("Queued a work item and returning\n"));
return NDIS_STATUS_PENDING;
}
ASSERT(Adapter->NdisMiniportBlock.DriverHandle);
/*
* Call the appropriate send handler
*
* If a miniport provides a SendPackets handler, we always call it. If not, we call the
* Send handler.
*/
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);
}
else
{
/* SendPackets is called at DISPATCH_LEVEL for all serialized miniports */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -