⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lan.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * 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 + -