📄 lan.c
字号:
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS TCP/IP protocol driver
* FILE: datalink/lan.c
* PURPOSE: Local Area Network media routines
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
* REVISIONS:
* CSH 01/08-2000 Created
*/
#include "precomp.h"
/* Define this to bugcheck on double complete */
/* #define BREAK_ON_DOUBLE_COMPLETE */
UINT TransferDataCalled = 0;
UINT TransferDataCompleteCalled = 0;
UINT LanReceiveWorkerCalled = 0;
BOOLEAN LanReceiveWorkerBusy = FALSE;
#define CCS_ROOT L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet"
#define TCPIP_GUID L"{4D36E972-E325-11CE-BFC1-08002BE10318}"
#define NGFP(_Packet) \
{ \
PVOID _Header; \
ULONG _ContigSize, _TotalSize; \
PNDIS_BUFFER _NdisBuffer; \
\
TI_DbgPrint(MID_TRACE,("Checking Packet %x\n", _Packet)); \
NdisGetFirstBufferFromPacket(_Packet, \
&_NdisBuffer, \
&_Header, \
&_ContigSize, \
&_TotalSize); \
TI_DbgPrint(MID_TRACE,("NdisBuffer: %x\n", _NdisBuffer)); \
TI_DbgPrint(MID_TRACE,("Header : %x\n", _Header)); \
TI_DbgPrint(MID_TRACE,("ContigSize: %x\n", _ContigSize)); \
TI_DbgPrint(MID_TRACE,("TotalSize : %x\n", _TotalSize)); \
}
typedef struct _LAN_WQ_ITEM {
LIST_ENTRY ListEntry;
PNDIS_PACKET Packet;
PLAN_ADAPTER Adapter;
UINT BytesTransferred;
} LAN_WQ_ITEM, *PLAN_WQ_ITEM;
NDIS_HANDLE NdisProtocolHandle = (NDIS_HANDLE)NULL;
BOOLEAN ProtocolRegistered = FALSE;
LIST_ENTRY AdapterListHead;
KSPIN_LOCK AdapterListLock;
/* Double complete protection */
KSPIN_LOCK LanSendCompleteLock;
LIST_ENTRY LanSendCompleteList;
VOID LanChainCompletion( PLAN_ADAPTER Adapter, PNDIS_PACKET NdisPacket ) {
PLAN_WQ_ITEM PendingCompletion =
ExAllocatePool( NonPagedPool, sizeof(LAN_WQ_ITEM) );
if( !PendingCompletion ) return;
PendingCompletion->Packet = NdisPacket;
PendingCompletion->Adapter = Adapter;
ExInterlockedInsertTailList( &LanSendCompleteList,
&PendingCompletion->ListEntry,
&LanSendCompleteLock );
}
BOOLEAN LanShouldComplete( PLAN_ADAPTER Adapter, PNDIS_PACKET NdisPacket ) {
PLIST_ENTRY ListEntry;
PLAN_WQ_ITEM CompleteEntry;
KIRQL OldIrql;
KeAcquireSpinLock( &LanSendCompleteLock, &OldIrql );
for( ListEntry = LanSendCompleteList.Flink;
ListEntry != &LanSendCompleteList;
ListEntry = ListEntry->Flink ) {
CompleteEntry = CONTAINING_RECORD(ListEntry, LAN_WQ_ITEM, ListEntry);
if( CompleteEntry->Adapter == Adapter &&
CompleteEntry->Packet == NdisPacket ) {
RemoveEntryList( ListEntry );
KeReleaseSpinLock( &LanSendCompleteLock, OldIrql );
ExFreePool( CompleteEntry );
return TRUE;
}
}
KeReleaseSpinLock( &LanSendCompleteLock, OldIrql );
DbgPrint("NDIS completed the same send packet twice "
"(Adapter %x Packet %x)!!\n", Adapter, NdisPacket);
#ifdef BREAK_ON_DOUBLE_COMPLETE
KeBugCheck(0);
#endif
return FALSE;
}
NDIS_STATUS NDISCall(
PLAN_ADAPTER Adapter,
NDIS_REQUEST_TYPE Type,
NDIS_OID OID,
PVOID Buffer,
UINT Length)
/*
* FUNCTION: Send a request to NDIS
* ARGUMENTS:
* Adapter = Pointer to a LAN_ADAPTER structure
* Type = Type of request (Set or Query)
* OID = Value to be set/queried for
* Buffer = Pointer to a buffer to use
* Length = Number of bytes in Buffer
* RETURNS:
* Status of operation
*/
{
NDIS_REQUEST Request;
NDIS_STATUS NdisStatus;
Request.RequestType = Type;
if (Type == NdisRequestSetInformation) {
Request.DATA.SET_INFORMATION.Oid = OID;
Request.DATA.SET_INFORMATION.InformationBuffer = Buffer;
Request.DATA.SET_INFORMATION.InformationBufferLength = Length;
} else {
Request.DATA.QUERY_INFORMATION.Oid = OID;
Request.DATA.QUERY_INFORMATION.InformationBuffer = Buffer;
Request.DATA.QUERY_INFORMATION.InformationBufferLength = Length;
}
if (Adapter->State != LAN_STATE_RESETTING) {
NdisRequest(&NdisStatus, Adapter->NdisHandle, &Request);
} else {
NdisStatus = NDIS_STATUS_NOT_ACCEPTED;
}
/* Wait for NDIS to complete the request */
if (NdisStatus == NDIS_STATUS_PENDING) {
KeWaitForSingleObject(&Adapter->Event,
UserRequest,
KernelMode,
FALSE,
NULL);
NdisStatus = Adapter->NdisStatus;
}
return NdisStatus;
}
VOID FreeAdapter(
PLAN_ADAPTER Adapter)
/*
* FUNCTION: Frees memory for a LAN_ADAPTER structure
* ARGUMENTS:
* Adapter = Pointer to LAN_ADAPTER structure to free
*/
{
exFreePool(Adapter);
}
NTSTATUS TcpipLanGetDwordOid
( PIP_INTERFACE Interface,
NDIS_OID Oid,
PDWORD Result ) {
/* Get maximum frame size */
if( Interface->Context ) {
return NDISCall((PLAN_ADAPTER)Interface->Context,
NdisRequestQueryInformation,
Oid,
Result,
sizeof(DWORD));
} else switch( Oid ) { /* Loopback Case */
case OID_GEN_HARDWARE_STATUS:
*Result = NdisHardwareStatusReady;
return STATUS_SUCCESS;
default:
return STATUS_INVALID_PARAMETER;
}
}
VOID STDCALL ProtocolOpenAdapterComplete(
NDIS_HANDLE BindingContext,
NDIS_STATUS Status,
NDIS_STATUS OpenErrorStatus)
/*
* FUNCTION: Called by NDIS to complete opening of an adapter
* ARGUMENTS:
* BindingContext = Pointer to a device context (LAN_ADAPTER)
* Status = Status of the operation
* OpenErrorStatus = Additional status information
*/
{
PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
KeSetEvent(&Adapter->Event, 0, FALSE);
}
VOID STDCALL ProtocolCloseAdapterComplete(
NDIS_HANDLE BindingContext,
NDIS_STATUS Status)
/*
* FUNCTION: Called by NDIS to complete closing an adapter
* ARGUMENTS:
* BindingContext = Pointer to a device context (LAN_ADAPTER)
* Status = Status of the operation
*/
{
PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
Adapter->NdisStatus = Status;
KeSetEvent(&Adapter->Event, 0, FALSE);
}
VOID STDCALL ProtocolResetComplete(
NDIS_HANDLE BindingContext,
NDIS_STATUS Status)
/*
* FUNCTION: Called by NDIS to complete resetting an adapter
* ARGUMENTS:
* BindingContext = Pointer to a device context (LAN_ADAPTER)
* Status = Status of the operation
*/
{
TI_DbgPrint(MID_TRACE, ("Called.\n"));
}
VOID STDCALL ProtocolRequestComplete(
NDIS_HANDLE BindingContext,
PNDIS_REQUEST NdisRequest,
NDIS_STATUS Status)
/*
* FUNCTION: Called by NDIS to complete a request
* ARGUMENTS:
* BindingContext = Pointer to a device context (LAN_ADAPTER)
* NdisRequest = Pointer to an object describing the request
* Status = Status of the operation
*/
{
PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
/* Save status of request and signal an event */
Adapter->NdisStatus = Status;
KeSetEvent(&Adapter->Event, 0, FALSE);
}
VOID STDCALL ProtocolSendComplete(
NDIS_HANDLE BindingContext,
PNDIS_PACKET Packet,
NDIS_STATUS Status)
/*
* FUNCTION: Called by NDIS to complete sending process
* ARGUMENTS:
* BindingContext = Pointer to a device context (LAN_ADAPTER)
* Packet = Pointer to a packet descriptor
* Status = Status of the operation
*/
{
TI_DbgPrint(DEBUG_DATALINK, ("Calling completion routine\n"));
if( LanShouldComplete( (PLAN_ADAPTER)BindingContext, Packet ) ) {
ASSERT_KM_POINTER(Packet);
ASSERT_KM_POINTER(PC(Packet));
ASSERT_KM_POINTER(PC(Packet)->DLComplete);
(*PC(Packet)->DLComplete)( PC(Packet)->Context, Packet, Status);
TI_DbgPrint(DEBUG_DATALINK, ("Finished\n"));
}
}
VOID LanReceiveWorker( PVOID Context ) {
UINT PacketType;
PLAN_WQ_ITEM WorkItem = (PLAN_WQ_ITEM)Context;
PNDIS_PACKET Packet;
PLAN_ADAPTER Adapter;
UINT BytesTransferred;
PNDIS_BUFFER NdisBuffer;
IP_PACKET IPPacket;
TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
Packet = WorkItem->Packet;
Adapter = WorkItem->Adapter;
BytesTransferred = WorkItem->BytesTransferred;
IPPacket.NdisPacket = Packet;
NdisGetFirstBufferFromPacket(Packet,
&NdisBuffer,
&IPPacket.Header,
&IPPacket.ContigSize,
&IPPacket.TotalSize);
IPPacket.ContigSize = IPPacket.TotalSize = BytesTransferred;
/* Determine which upper layer protocol that should receive
this packet and pass it to the correct receive handler */
TI_DbgPrint(MID_TRACE,
("ContigSize: %d, TotalSize: %d, BytesTransferred: %d\n",
IPPacket.ContigSize, IPPacket.TotalSize,
BytesTransferred));
PacketType = PC(IPPacket.NdisPacket)->PacketType;
IPPacket.Position = 0;
TI_DbgPrint
(DEBUG_DATALINK,
("Ether Type = %x ContigSize = %d Total = %d\n",
PacketType, IPPacket.ContigSize, IPPacket.TotalSize));
switch (PacketType) {
case ETYPE_IPv4:
case ETYPE_IPv6:
TI_DbgPrint(MID_TRACE,("Received IP Packet\n"));
IPReceive(Adapter->Context, &IPPacket);
break;
case ETYPE_ARP:
TI_DbgPrint(MID_TRACE,("Received ARP Packet\n"));
ARPReceive(Adapter->Context, &IPPacket);
default:
break;
}
FreeNdisPacket( Packet );
}
VOID LanSubmitReceiveWork(
NDIS_HANDLE BindingContext,
PNDIS_PACKET Packet,
NDIS_STATUS Status,
UINT BytesTransferred) {
LAN_WQ_ITEM WQItem;
PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
PVOID LanWorkItem;
TI_DbgPrint(DEBUG_DATALINK,("called\n"));
WQItem.Packet = Packet;
WQItem.Adapter = Adapter;
WQItem.BytesTransferred = BytesTransferred;
if( !ChewCreate
( &LanWorkItem, sizeof(LAN_WQ_ITEM), LanReceiveWorker, &WQItem ) )
ASSERT(0);
}
VOID STDCALL ProtocolTransferDataComplete(
NDIS_HANDLE BindingContext,
PNDIS_PACKET Packet,
NDIS_STATUS Status,
UINT BytesTransferred)
/*
* FUNCTION: Called by NDIS to complete reception of data
* ARGUMENTS:
* BindingContext = Pointer to a device context (LAN_ADAPTER)
* Packet = Pointer to a packet descriptor
* Status = Status of the operation
* BytesTransferred = Number of bytes transferred
* NOTES:
* If the packet was successfully received, determine the protocol
* type and pass it to the correct receive handler
*/
{
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
TI_DbgPrint(DEBUG_DATALINK,("called\n"));
TransferDataCompleteCalled++;
ASSERT(TransferDataCompleteCalled <= TransferDataCalled);
if( Status != NDIS_STATUS_SUCCESS ) return;
LanSubmitReceiveWork( BindingContext, Packet, Status, BytesTransferred );
}
NDIS_STATUS STDCALL ProtocolReceive(
NDIS_HANDLE BindingContext,
NDIS_HANDLE MacReceiveContext,
PVOID HeaderBuffer,
UINT HeaderBufferSize,
PVOID LookaheadBuffer,
UINT LookaheadBufferSize,
UINT PacketSize)
/*
* FUNCTION: Called by NDIS when a packet has been received on the physical link
* ARGUMENTS:
* BindingContext = Pointer to a device context (LAN_ADAPTER)
* MacReceiveContext = Handle used by underlying NIC driver
* HeaderBuffer = Pointer to a buffer containing the packet header
* HeaderBufferSize = Number of bytes in HeaderBuffer
* LookaheadBuffer = Pointer to a buffer containing buffered packet data
* LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
* PacketSize = Overall size of the packet (not including header)
* RETURNS:
* Status of operation
*/
{
USHORT EType;
UINT PacketType, BytesTransferred;
UINT temp;
IP_PACKET IPPacket;
PCHAR BufferData;
NDIS_STATUS NdisStatus;
PNDIS_PACKET NdisPacket;
PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
PETH_HEADER EHeader = (PETH_HEADER)HeaderBuffer;
TI_DbgPrint(DEBUG_DATALINK, ("Called. (packetsize %d)\n",PacketSize));
if (Adapter->State != LAN_STATE_STARTED) {
TI_DbgPrint(DEBUG_DATALINK, ("Adapter is stopped.\n"));
return NDIS_STATUS_NOT_ACCEPTED;
}
if (HeaderBufferSize < Adapter->HeaderSize) {
TI_DbgPrint(DEBUG_DATALINK, ("Runt frame received.\n"));
return NDIS_STATUS_NOT_ACCEPTED;
}
if (Adapter->Media == NdisMedium802_3) {
/* Ethernet and IEEE 802.3 frames can be destinguished by
looking at the IEEE 802.3 length field. This field is
less than or equal to 1500 for a valid IEEE 802.3 frame
and larger than 1500 is it's a valid EtherType value.
See RFC 1122, section 2.3.3 for more information */
/* FIXME: Test for Ethernet and IEEE 802.3 frame */
if (((EType = EHeader->EType) != ETYPE_IPv4) && (EType != ETYPE_ARP)) {
TI_DbgPrint(DEBUG_DATALINK, ("Not IP or ARP frame. EtherType (0x%X).\n", EType));
return NDIS_STATUS_NOT_ACCEPTED;
}
/* We use EtherType constants to destinguish packet types */
PacketType = EType;
} else {
TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
/* FIXME: Support other medias */
return NDIS_STATUS_NOT_ACCEPTED;
}
/* Get a transfer data packet */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -