-/*\r
- * COPYRIGHT: See COPYING in the top level directory\r
- * PROJECT: ReactOS TCP/IP protocol driver\r
- * FILE: datalink/lan.c\r
- * PURPOSE: Local Area Network media routines\r
- * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)\r
- * REVISIONS:\r
- * CSH 01/08-2000 Created\r
- */\r
-#include <tcpip.h>\r
-#include <lan.h>\r
-#include <address.h>\r
-#include <routines.h>\r
-#include <transmit.h>\r
-#include <receive.h>\r
-#include <arp.h>\r
-\r
-\r
-NDIS_HANDLE NdisProtocolHandle = (NDIS_HANDLE)NULL;\r
-BOOLEAN ProtocolRegistered = FALSE;\r
-PLAN_ADAPTER Adapters = NULL;\r
-\r
-\r
-NDIS_STATUS NDISCall(\r
- PLAN_ADAPTER Adapter,\r
- NDIS_REQUEST_TYPE Type,\r
- NDIS_OID OID,\r
- PVOID Buffer,\r
- UINT Length)\r
-/*\r
- * FUNCTION: Send a request to NDIS\r
- * ARGUMENTS:\r
- * Adapter = Pointer to a LAN_ADAPTER structure\r
- * Type = Type of request (Set or Query)\r
- * OID = Value to be set/queried for\r
- * Buffer = Pointer to a buffer to use\r
- * Length = Number of bytes in Buffer\r
- * RETURNS:\r
- * Status of operation\r
- */\r
-{\r
- NDIS_REQUEST Request;\r
- NDIS_STATUS NdisStatus;\r
-\r
- Request.RequestType = Type;\r
- if (Type == NdisRequestSetInformation) {\r
- Request.DATA.SET_INFORMATION.Oid = OID;\r
- Request.DATA.SET_INFORMATION.InformationBuffer = Buffer;\r
- Request.DATA.SET_INFORMATION.InformationBufferLength = Length;\r
- } else {\r
- Request.DATA.QUERY_INFORMATION.Oid = OID;\r
- Request.DATA.QUERY_INFORMATION.InformationBuffer = Buffer;\r
- Request.DATA.QUERY_INFORMATION.InformationBufferLength = Length;\r
- }\r
-\r
- if (Adapter->State != LAN_STATE_RESETTING) {\r
- NdisRequest(&NdisStatus, Adapter->NdisHandle, &Request);\r
- } else\r
- NdisStatus = NDIS_STATUS_NOT_ACCEPTED;\r
-\r
- /* Wait for NDIS to complete the request */\r
- if (NdisStatus == NDIS_STATUS_PENDING) {\r
- KeWaitForSingleObject(&Adapter->Event, UserRequest, KernelMode, FALSE, NULL);\r
- NdisStatus = Adapter->NdisStatus;\r
- }\r
-\r
- return NdisStatus;\r
-}\r
-\r
-\r
-PNDIS_PACKET AllocateTDPacket(\r
- PLAN_ADAPTER Adapter)\r
-/*\r
- * FUNCTION: Allocates an NDIS packet for NdisTransferData\r
- * ARGUMENTS:\r
- * Adapter = Pointer to LAN_ADAPTER structure\r
- * RETURNS:\r
- * Pointer to NDIS packet or NULL if there was not enough free\r
- * non-paged memory\r
- */\r
-{\r
- NDIS_STATUS NdisStatus;\r
- PNDIS_PACKET NdisPacket;\r
- PNDIS_BUFFER Buffer;\r
- PVOID Data;\r
-\r
- NdisAllocatePacket(&NdisStatus, &NdisPacket, GlobalPacketPool);\r
- if (NdisStatus != NDIS_STATUS_SUCCESS)\r
- return NULL;\r
-\r
- Data = ExAllocatePool(NonPagedPool, Adapter->MTU);\r
- if (!Data) {\r
- NdisFreePacket(NdisPacket);\r
- return NULL;\r
- }\r
- \r
- NdisAllocateBuffer(&NdisStatus, &Buffer, GlobalBufferPool, Data, Adapter->MTU);\r
- if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
- NdisFreePacket(NdisPacket);\r
- ExFreePool(Data);\r
- return NULL;\r
- }\r
-\r
- NdisChainBufferAtFront(NdisPacket, Buffer);\r
-\r
- PC(NdisPacket)->Context = NULL; /* End of list */\r
-\r
- return NdisPacket;\r
-}\r
-\r
-\r
-VOID FreeTDPackets(\r
- PLAN_ADAPTER Adapter)\r
-/*\r
- * FUNCTION: Frees transfer data packets\r
- * ARGUMENTS:\r
- * Adapter = Pointer to LAN_ADAPTER structure\r
- */\r
-{\r
- PNDIS_PACKET NdisPacket, Next;\r
-\r
- /* Release transfer data packets */\r
- NdisPacket = Adapter->TDPackets;\r
- while (NdisPacket) {\r
- Next = PC(NdisPacket)->Context;\r
- FreeNdisPacket(NdisPacket);\r
- NdisPacket = Next;\r
- }\r
- Adapter->TDPackets = NULL;\r
-}\r
-\r
-\r
-VOID FreeAdapter(\r
- PLAN_ADAPTER Adapter)\r
-/*\r
- * FUNCTION: Frees memory for a LAN_ADAPTER structure\r
- * ARGUMENTS:\r
- * Adapter = Pointer to LAN_ADAPTER structure to free\r
- */\r
-{\r
- FreeTDPackets(Adapter);\r
- ExFreePool(Adapter);\r
-}\r
-\r
-\r
-VOID ProtocolOpenAdapterComplete(\r
- NDIS_HANDLE BindingContext,\r
- NDIS_STATUS Status,\r
- NDIS_STATUS OpenErrorStatus)\r
-/*\r
- * FUNCTION: Called by NDIS to complete opening of an adapter\r
- * ARGUMENTS:\r
- * BindingContext = Pointer to a device context (LAN_ADAPTER)\r
- * Status = Status of the operation\r
- * OpenErrorStatus = Additional status information\r
- */\r
-{\r
- PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;\r
-\r
- TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
-\r
- KeSetEvent(&Adapter->Event, 0, FALSE);\r
-}\r
-\r
-\r
-VOID ProtocolCloseAdapterComplete(\r
- NDIS_HANDLE BindingContext,\r
- NDIS_STATUS Status)\r
-/*\r
- * FUNCTION: Called by NDIS to complete closing an adapter\r
- * ARGUMENTS:\r
- * BindingContext = Pointer to a device context (LAN_ADAPTER)\r
- * Status = Status of the operation\r
- */\r
-{\r
- PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;\r
-\r
- TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
-\r
- Adapter->NdisStatus = Status;\r
-\r
- KeSetEvent(&Adapter->Event, 0, FALSE);\r
-}\r
-\r
-\r
-VOID ProtocolResetComplete(\r
- NDIS_HANDLE BindingContext,\r
- NDIS_STATUS Status)\r
-/*\r
- * FUNCTION: Called by NDIS to complete resetting an adapter\r
- * ARGUMENTS:\r
- * BindingContext = Pointer to a device context (LAN_ADAPTER)\r
- * Status = Status of the operation\r
- */\r
-{\r
- TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
-}\r
-\r
-\r
-VOID ProtocolRequestComplete(\r
- NDIS_HANDLE BindingContext,\r
- PNDIS_REQUEST NdisRequest,\r
- NDIS_STATUS Status)\r
-/*\r
- * FUNCTION: Called by NDIS to complete a request\r
- * ARGUMENTS:\r
- * BindingContext = Pointer to a device context (LAN_ADAPTER)\r
- * NdisRequest = Pointer to an object describing the request\r
- * Status = Status of the operation\r
- */\r
-{\r
- PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;\r
-\r
- /* Save status of request and signal an event */\r
- Adapter->NdisStatus = Status;\r
-\r
- KeSetEvent(&Adapter->Event, 0, FALSE);\r
-}\r
-\r
-\r
-VOID ProtocolSendComplete(\r
- NDIS_HANDLE BindingContext,\r
- PNDIS_PACKET Packet,\r
- NDIS_STATUS Status)\r
-/*\r
- * FUNCTION: Called by NDIS to complete sending process\r
- * ARGUMENTS:\r
- * BindingContext = Pointer to a device context (LAN_ADAPTER)\r
- * Packet = Pointer to a packet descriptor\r
- * Status = Status of the operation\r
- */\r
-{\r
- PLAN_ADAPTER Adapter = BindingContext;\r
-\r
- TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
-\r
- AdjustPacket(Packet, Adapter->HeaderSize, PC(Packet)->DLOffset);\r
-\r
- (*PC(Packet)->DLComplete)(Adapter->Context, Packet, Status);\r
-}\r
-\r
-\r
-VOID ProtocolTransferDataComplete(\r
- NDIS_HANDLE BindingContext,\r
- PNDIS_PACKET Packet,\r
- NDIS_STATUS Status,\r
- UINT BytesTransferred)\r
-/*\r
- * FUNCTION: Called by NDIS to complete reception of data\r
- * ARGUMENTS:\r
- * BindingContext = Pointer to a device context (LAN_ADAPTER)\r
- * Packet = Pointer to a packet descriptor\r
- * Status = Status of the operation\r
- * BytesTransferred = Number of bytes transferred\r
- * NOTES:\r
- * If the packet was successfully received, determine the protocol\r
- * type and pass it to the correct receive handler\r
- */\r
-{\r
- UINT PacketType;\r
- PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;\r
-\r
- if (Status == NDIS_STATUS_SUCCESS) {\r
- PNDIS_BUFFER NdisBuffer;\r
- IP_PACKET IPPacket;\r
-\r
- NdisGetFirstBufferFromPacket(\r
- Packet, &NdisBuffer, &IPPacket.Header,\r
- &IPPacket.ContigSize, &IPPacket.TotalSize);\r
-\r
- /* Determine which upper layer protocol that should receive\r
- this packet and pass it to the correct receive handler */\r
- PacketType = ((PETH_HEADER)IPPacket.Header)->EType;\r
- switch (PacketType) {\r
- case ETYPE_IPv4:\r
- case ETYPE_IPv6:\r
- IPReceive(Adapter->Context, &IPPacket);\r
- break;\r
- case ETYPE_ARP:\r
- ARPReceive(Adapter->Context, &IPPacket);\r
- default:\r
- break;\r
- }\r
- }\r
-\r
- /* Release the packet descriptor */\r
- KeAcquireSpinLockAtDpcLevel(&Adapter->Lock);\r
-\r
- PC(Packet)->Context = Adapter->TDPackets;\r
- Adapter->TDPackets = Packet;\r
-\r
- KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);\r
-}\r
-\r
-\r
-NDIS_STATUS ProtocolReceive(\r
- NDIS_HANDLE BindingContext,\r
- NDIS_HANDLE MacReceiveContext,\r
- PVOID HeaderBuffer,\r
- UINT HeaderBufferSize,\r
- PVOID LookaheadBuffer,\r
- UINT LookaheadBufferSize,\r
- UINT PacketSize)\r
-/*\r
- * FUNCTION: Called by NDIS when a packet has been received on the physical link\r
- * ARGUMENTS:\r
- * BindingContext = Pointer to a device context (LAN_ADAPTER)\r
- * MacReceiveContext = Handle used by underlying NIC driver\r
- * HeaderBuffer = Pointer to a buffer containing the packet header\r
- * HeaderBufferSize = Number of bytes in HeaderBuffer\r
- * LookaheadBuffer = Pointer to a buffer containing buffered packet data\r
- * LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for\r
- * PacketSize = Overall size of the packet (not including header)\r
- * RETURNS:\r
- * Status of operation\r
- */\r
-{\r
- USHORT EType;\r
- UINT PacketType;\r
- IP_PACKET IPPacket;\r
- PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;\r
- PETH_HEADER EHeader = (PETH_HEADER)HeaderBuffer;\r
-\r
- TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
-\r
- if ((Adapter->State != LAN_STATE_STARTED) ||\r
- HeaderBufferSize < Adapter->HeaderSize)\r
- /* Adapter is not started or the header was too small */\r
- return NDIS_STATUS_NOT_ACCEPTED;\r
-\r
- if (Adapter->Media == NdisMedium802_3) {\r
- /* Ethernet and IEEE 802.3 frames can be destinguished by\r
- looking at the IEEE 802.3 length field. This field is\r
- less than or equal to 1500 for a valid IEEE 802.3 frame\r
- and larger than 1500 is it's a valid Ether-Type value.\r
- See RFC 1122, section 2.3.3 for more information */\r
- if (((EType = EHeader->EType) != ETYPE_IPv4) && (EType != ETYPE_ARP))\r
- return NDIS_STATUS_NOT_ACCEPTED;\r
- /* We use Ether-Type constants to destinguish packets */\r
- PacketType = EType;\r
- } else\r
- /* FIXME: Support other medias */\r
- return NDIS_STATUS_NOT_ACCEPTED;\r
-\r
- if (LookaheadBufferSize < PacketSize) {\r
- NDIS_STATUS NdisStatus;\r
- PNDIS_PACKET NdisPacket;\r
- UINT BytesTransferred;\r
- \r
- /* Get transfer data packet */\r
-\r
- KeAcquireSpinLockAtDpcLevel(&Adapter->Lock);\r
-\r
- NdisPacket = Adapter->TDPackets;\r
- if (NdisPacket == (PNDIS_PACKET)NULL) {\r
- /* We don't have a free packet descriptor. Drop the packet */\r
- KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);\r
- return NDIS_STATUS_SUCCESS;\r
- }\r
- Adapter->TDPackets = PC(NdisPacket)->Context;\r
-\r
- KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);\r
-\r
- /* Get the data */\r
- NdisTransferData(&NdisStatus, Adapter->NdisHandle,\r
- MacReceiveContext, 0, PacketSize,\r
- NdisPacket, &BytesTransferred);\r
- if (NdisStatus != NDIS_STATUS_PENDING)\r
- ProtocolTransferDataComplete(BindingContext,\r
- NdisPacket, NdisStatus, BytesTransferred);\r
-\r
- return NDIS_STATUS_SUCCESS;\r
- }\r
-\r
- /* We got all the data in the lookahead buffer */\r
- RtlZeroMemory(&IPPacket, sizeof(IPPacket));\r
- IPPacket.Header = LookaheadBuffer;\r
- IPPacket.TotalSize = PacketSize;\r
-\r
- switch (PacketType) {\r
- case ETYPE_IPv4:\r
- case ETYPE_IPv6:\r
- IPReceive(Adapter->Context, &IPPacket);\r
- break;\r
- case ETYPE_ARP:\r
- ARPReceive(Adapter->Context, &IPPacket);\r
- break;\r
- default:\r
- break;\r
- }\r
-\r
- return NDIS_STATUS_SUCCESS;\r
-}\r
-\r
-\r
-VOID ProtocolReceiveComplete(\r
- NDIS_HANDLE BindingContext)\r
-/*\r
- * FUNCTION: Called by NDIS when we're done receiving data\r
- * ARGUMENTS:\r
- * BindingContext = Pointer to a device context (LAN_ADAPTER)\r
- */\r
-{\r
- TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
-}\r
-\r
-\r
-VOID ProtocolStatus(\r
- NDIS_HANDLE BindingContext,\r
- NDIS_STATUS GenerelStatus,\r
- PVOID StatusBuffer,\r
- UINT StatusBufferSize)\r
-/*\r
- * FUNCTION: Called by NDIS when the underlying driver has changed state\r
- * ARGUMENTS:\r
- * BindingContext = Pointer to a device context (LAN_ADAPTER)\r
- * GenerelStatus = A generel status code\r
- * StatusBuffer = Pointer to a buffer with medium-specific data\r
- * StatusBufferSize = Number of bytes in StatusBuffer\r
- */\r
-{\r
- TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
-}\r
-\r
-\r
-VOID ProtocolStatusComplete(\r
- NDIS_HANDLE NdisBindingContext)\r
-/*\r
- * FUNCTION: Called by NDIS when a status-change has occurred\r
- * ARGUMENTS:\r
- * BindingContext = Pointer to a device context (LAN_ADAPTER)\r
- */\r
-{\r
- TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
-}\r
-\r
-\r
-VOID LANTransmit(\r
- PVOID Context,\r
- PNDIS_PACKET NdisPacket,\r
- UINT Offset,\r
- PVOID LinkAddress,\r
- USHORT Type)\r
-/*\r
- * FUNCTION: Transmits a packet\r
- * ARGUMENTS:\r
- * Context = Pointer to context information (LAN_ADAPTER)\r
- * NdisPacket = Pointer to NDIS packet to send\r
- * Offset = Offset in packet where data starts\r
- * LinkAddress = Pointer to link address of destination (NULL = broadcast)\r
- * Type = LAN protocol type (LAN_PROTO_*)\r
- */\r
-{\r
- NDIS_STATUS NdisStatus;\r
- PETH_HEADER EHeader;\r
- PVOID Data;\r
- PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context;\r
-\r
- TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
-\r
- /* NDIS send routines don't have an offset argument so we\r
- must offset the data in upper layers and adjust the\r
- packet here. We save the offset in the packet context\r
- area so it can be undone before we release the packet */\r
- Data = AdjustPacket(NdisPacket, Offset, Adapter->HeaderSize);\r
- PC(NdisPacket)->DLOffset = Offset;\r
-\r
- if (Adapter->State == LAN_STATE_STARTED) {\r
- switch (Adapter->Media) {\r
- case NdisMedium802_3:\r
- EHeader = (PETH_HEADER)Data;\r
- \r
- if (LinkAddress)\r
- /* Unicast address */\r
- RtlCopyMemory(EHeader->DstAddr, LinkAddress, IEEE_802_ADDR_LENGTH);\r
- else\r
- /* Broadcast address */\r
- RtlFillMemory(EHeader->DstAddr, IEEE_802_ADDR_LENGTH, 0xFF);\r
-\r
- RtlCopyMemory(EHeader->SrcAddr, Adapter->HWAddress, IEEE_802_ADDR_LENGTH);\r
-\r
- switch (Type) {\r
- case LAN_PROTO_IPv4:\r
- EHeader->EType = ETYPE_IPv4;\r
- break;\r
- case LAN_PROTO_ARP:\r
- EHeader->EType = ETYPE_ARP;\r
- break;\r
- case LAN_PROTO_IPv6:\r
- EHeader->EType = ETYPE_IPv6;\r
- break;\r
- default:\r
-#if DBG\r
- /* Should not happen */\r
- TI_DbgPrint(MIN_TRACE, ("Unknown LAN protocol.\n"));\r
-\r
- ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NDIS_STATUS_FAILURE);\r
-#endif\r
- return;\r
- }\r
- break;\r
-\r
- default:\r
- /* FIXME: Support other medias */\r
- break;\r
- }\r
- \r
- NdisSend(&NdisStatus, Adapter->NdisHandle, NdisPacket);\r
- if (NdisStatus != NDIS_STATUS_PENDING)\r
- ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NdisStatus);\r
- } else\r
- ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NDIS_STATUS_CLOSED);\r
-}\r
-\r
-\r
-VOID BindAdapter(\r
- PLAN_ADAPTER Adapter)\r
-/*\r
- * FUNCTION: Binds a LAN adapter to IP layer\r
- * ARGUMENTS:\r
- * Adapter = Pointer to LAN_ADAPTER structure\r
- * NOTES:\r
- * We set the lookahead buffer size, set the packet filter and\r
- * bind the adapter to IP layer\r
- */\r
-{\r
- INT i;\r
- PIP_INTERFACE IF;\r
- PIP_ADDRESS Address;\r
- PNDIS_PACKET Packet;\r
- NDIS_STATUS NdisStatus;\r
- LLIP_BIND_INFO BindInfo;\r
- ULONG Lookahead = LOOKAHEAD_SIZE;\r
-\r
- TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
-\r
- Adapter->State = LAN_STATE_OPENING;\r
-\r
- NdisStatus = NDISCall(Adapter, NdisRequestSetInformation,\r
- OID_GEN_CURRENT_LOOKAHEAD, &Lookahead, sizeof(ULONG));\r
- if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
- TI_DbgPrint(MID_TRACE, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus));\r
- return;\r
- }\r
-\r
- /* Allocate packets for NdisTransferData */\r
- /* FIXME: How many should we allocate? */\r
- Adapter->TDPackets = NULL;\r
- for (i = 0; i < 2; i++) {\r
- Packet = AllocateTDPacket(Adapter);\r
- PC(Packet)->Context = Adapter->TDPackets;\r
- Adapter->TDPackets = Packet;\r
- if (!Packet) {\r
- TI_DbgPrint(MID_TRACE, ("Could not allocate transfer data packet (out of resources).\n"));\r
- FreeTDPackets(Adapter);\r
- return;\r
- }\r
- }\r
-\r
- /* Bind the adapter to IP layer */\r
- BindInfo.Context = Adapter;\r
- BindInfo.HeaderSize = Adapter->HeaderSize;\r
- BindInfo.MinFrameSize = Adapter->MinFrameSize;\r
- BindInfo.MTU = Adapter->MTU;\r
- BindInfo.Address = (PUCHAR)&Adapter->HWAddress;\r
- BindInfo.AddressLength = Adapter->HWAddressLength;\r
- BindInfo.Transmit = LANTransmit;\r
-\r
- IF = IPCreateInterface(&BindInfo);\r
- if (!IF) {\r
- TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
- FreeTDPackets(Adapter);\r
- return;\r
- }\r
-\r
- /* FIXME: Get address from registry.\r
- For now just use a private address, eg. 10.0.0.10 */\r
- Address = AddrBuildIPv4(0x0A00000A);\r
- if (!Address) {\r
- TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
- FreeTDPackets(Adapter);\r
- IPDestroyInterface(Adapter->Context);\r
- return;\r
- }\r
- /* Create a net table entry for this interface */\r
- if (!IPCreateNTE(IF, Address, 8)) {\r
- TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
- FreeTDPackets(Adapter);\r
- IPDestroyInterface(IF);\r
- return;\r
- }\r
-\r
- /* Reference the interface for the NTE. The reference for\r
- the address is just passed on to the NTE */\r
- ReferenceObject(IF);\r
-\r
- /* Register interface with IP layer */\r
- IPRegisterInterface(IF);\r
-\r
- /* Set packet filter so we can send and receive packets */\r
- NdisStatus = NDISCall(Adapter, NdisRequestSetInformation,\r
- OID_GEN_CURRENT_PACKET_FILTER, &Adapter->PacketFilter, sizeof(UINT));\r
- if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
- TI_DbgPrint(MID_TRACE, ("Could not set packet filter (0x%X).\n", NdisStatus));\r
- FreeTDPackets(Adapter);\r
- IPDestroyInterface(IF);\r
- return;\r
- }\r
-\r
- Adapter->Context = IF;\r
-\r
- Adapter->State = LAN_STATE_STARTED;\r
-}\r
-\r
-\r
-VOID UnbindAdapter(\r
- PLAN_ADAPTER Adapter)\r
-/*\r
- * FUNCTION: Unbinds a LAN adapter from IP layer\r
- * ARGUMENTS:\r
- * Adapter = Pointer to LAN_ADAPTER structure\r
- */\r
-{\r
- TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
-\r
- if (Adapter->State == LAN_STATE_STARTED) {\r
- PIP_INTERFACE IF = Adapter->Context;\r
-\r
- IPUnregisterInterface(IF);\r
-\r
- IPDestroyInterface(IF);\r
-\r
- /* Free transfer data packets */\r
- FreeTDPackets(Adapter);\r
- }\r
-}\r
-\r
-\r
-NDIS_STATUS LANRegisterAdapter(\r
- PNDIS_STRING AdapterName,\r
- PLAN_ADAPTER *Adapter)\r
-/*\r
- * FUNCTION: Registers protocol with an NDIS adapter\r
- * ARGUMENTS:\r
- * AdapterName = Pointer to string with name of adapter to register\r
- * Adapter = Address of pointer to a LAN_ADAPTER structure\r
- * RETURNS:\r
- * Status of operation\r
- */\r
-{\r
- PLAN_ADAPTER IF;\r
- NDIS_STATUS NdisStatus;\r
- NDIS_STATUS OpenStatus;\r
- UINT MediaIndex;\r
- NDIS_MEDIUM MediaArray[MAX_MEDIA];\r
- UINT AddressOID;\r
- UINT Speed;\r
-\r
- TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
-\r
- IF = ExAllocatePool(NonPagedPool, sizeof(LAN_ADAPTER));\r
- if (!IF)\r
- return NDIS_STATUS_RESOURCES;\r
-\r
- RtlZeroMemory(IF, sizeof(LAN_ADAPTER));\r
-\r
- /* Put adapter in stopped state */\r
- IF->State = LAN_STATE_STOPPED;\r
-\r
- /* Initialize protecting spin lock */\r
- KeInitializeSpinLock(&IF->Lock);\r
-\r
- KeInitializeEvent(&IF->Event, SynchronizationEvent, FALSE);\r
-\r
- /* Initialize array with media IDs we support */\r
- MediaArray[MEDIA_ETH] = NdisMedium802_3;\r
-\r
- /* Open the adapter. */\r
- NdisOpenAdapter(&NdisStatus, &OpenStatus, &IF->NdisHandle, &MediaIndex,\r
- MediaArray, MAX_MEDIA, NdisProtocolHandle, IF, AdapterName, 0, NULL);\r
-\r
- /* Wait until the adapter is opened */\r
- if (NdisStatus == NDIS_STATUS_PENDING)\r
- KeWaitForSingleObject(&IF->Event, UserRequest, KernelMode, FALSE, NULL);\r
- else if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
- ExFreePool(IF);\r
- return NdisStatus;\r
- }\r
-\r
- IF->Media = MediaArray[MediaIndex];\r
-\r
- /* Fill LAN_ADAPTER structure with some adapter specific information */\r
- switch (IF->Media) {\r
- case NdisMedium802_3:\r
- IF->HWAddressLength = IEEE_802_ADDR_LENGTH;\r
- IF->BCastMask = BCAST_ETH_MASK;\r
- IF->BCastCheck = BCAST_ETH_CHECK;\r
- IF->BCastOffset = BCAST_ETH_OFFSET;\r
- IF->HeaderSize = sizeof(ETH_HEADER);\r
- IF->MinFrameSize = 60;\r
- AddressOID = OID_802_3_CURRENT_ADDRESS;\r
- IF->PacketFilter = \r
- NDIS_PACKET_TYPE_BROADCAST |\r
- NDIS_PACKET_TYPE_DIRECTED |\r
- NDIS_PACKET_TYPE_MULTICAST;\r
- break;\r
-\r
- default:\r
- /* Unsupported media */\r
- TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));\r
- ExFreePool(IF);\r
- return NDIS_STATUS_NOT_SUPPORTED;\r
- }\r
-\r
- /* Get maximum frame size */\r
- NdisStatus = NDISCall(IF, NdisRequestQueryInformation,\r
- OID_GEN_MAXIMUM_FRAME_SIZE, &IF->MTU, sizeof(UINT));\r
- if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
- ExFreePool(IF);\r
- return NdisStatus;\r
- }\r
-\r
- /* Get maximum packet size */\r
- NdisStatus = NDISCall(IF, NdisRequestQueryInformation,\r
- OID_GEN_MAXIMUM_TOTAL_SIZE, &IF->MaxPacketSize, sizeof(UINT));\r
- if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
- TI_DbgPrint(MIN_TRACE, ("Query for maximum packet size failed.\n"));\r
- ExFreePool(IF);\r
- return NdisStatus;\r
- }\r
-\r
- /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */\r
- NdisStatus = NDISCall(IF, NdisRequestQueryInformation,\r
- OID_GEN_MAXIMUM_SEND_PACKETS, &IF->MaxSendPackets, sizeof(UINT));\r
- if (NdisStatus != NDIS_STATUS_SUCCESS)\r
- /* Legacy NIC drivers may not support this query, if it fails we\r
- assume it can send at least one packet per call to NdisSend(Packets) */\r
- IF->MaxSendPackets = 1;\r
-\r
- /* Get current hardware address */\r
- NdisStatus = NDISCall(IF, NdisRequestQueryInformation, AddressOID,\r
- IF->HWAddress, IF->HWAddressLength);\r
- if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
- TI_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n"));\r
- ExFreePool(IF);\r
- return NdisStatus;\r
- }\r
-\r
- /* Get maximum link speed */\r
- NdisStatus = NDISCall(IF, NdisRequestQueryInformation,\r
- OID_GEN_LINK_SPEED, &Speed, sizeof(UINT));\r
- if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
- TI_DbgPrint(MIN_TRACE, ("Query for maximum link speed failed.\n"));\r
- ExFreePool(IF);\r
- return NdisStatus;\r
- }\r
-\r
- /* Convert returned link speed to bps (it is in 100bps increments) */\r
- IF->Speed = Speed * 100L;\r
-\r
- *Adapter = IF;\r
-\r
- /* Add adapter to the adapter list */\r
- IF->Next = Adapters;\r
- Adapters = IF;\r
-\r
- /* Bind adapter to IP layer */\r
- BindAdapter(IF);\r
-\r
- TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));\r
-\r
- return NDIS_STATUS_SUCCESS;\r
-}\r
-\r
-\r
-NDIS_STATUS LANUnregisterAdapter(\r
- PLAN_ADAPTER Adapter)\r
-/*\r
- * FUNCTION: Unregisters protocol with NDIS adapter\r
- * ARGUMENTS:\r
- * Adapter = Pointer to a LAN_ADAPTER structure\r
- * RETURNS:\r
- * Status of operation\r
- */\r
-{\r
- KIRQL OldIrql;\r
- NDIS_HANDLE NdisHandle;\r
- PLAN_ADAPTER IF, PrevIF;\r
- BOOLEAN Found = FALSE;\r
- NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;\r
-\r
- TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
-\r
- /* Search the adapter list for the specified adapter and remove it */\r
- IF = Adapters;\r
- if (IF) {\r
- if (Adapter != Adapters) {\r
- PrevIF = IF;\r
- while ((IF) && (!Found)) {\r
- if (IF == Adapter) {\r
- /* We've found the adapter, now remove it from the list */\r
- PrevIF->Next = IF->Next;\r
- Found = TRUE;\r
- }\r
- PrevIF = IF;\r
- IF = IF->Next;\r
- }\r
- } else {\r
- Adapters = NULL;\r
- Found = TRUE;\r
- }\r
- }\r
- if (!Found) {\r
- TI_DbgPrint(MIN_TRACE, ("Leaving (adapter was not in list).\n"));\r
- return NDIS_STATUS_ADAPTER_NOT_FOUND;\r
- }\r
-\r
- /* Unbind adapter from IP layer */\r
- UnbindAdapter(Adapter);\r
-\r
- KeAcquireSpinLock(&Adapter->Lock, &OldIrql);\r
- NdisHandle = Adapter->NdisHandle;\r
- if (NdisHandle) {\r
- Adapter->NdisHandle = NULL;\r
- KeReleaseSpinLock(&Adapter->Lock, OldIrql);\r
-\r
- NdisCloseAdapter(&NdisStatus, NdisHandle);\r
- if (NdisStatus == NDIS_STATUS_PENDING) {\r
- KeWaitForSingleObject(&Adapter->Event,\r
- UserRequest, KernelMode, FALSE, NULL);\r
- NdisStatus = Adapter->NdisStatus;\r
- }\r
- } else\r
- KeReleaseSpinLock(&Adapter->Lock, OldIrql);\r
-\r
- FreeAdapter(Adapter);\r
-\r
- return NDIS_STATUS_SUCCESS;\r
-}\r
-\r
-\r
-NTSTATUS LANRegisterProtocol(\r
- PSTRING Name)\r
-/*\r
- * FUNCTION: Registers this protocol driver with NDIS\r
- * ARGUMENTS:\r
- * Name = Name of this protocol driver\r
- * RETURNS:\r
- * Status of operation\r
- */\r
-{\r
- NDIS_STATUS NdisStatus;\r
- NDIS_PROTOCOL_CHARACTERISTICS ProtChars;\r
-\r
- /* Set up protocol characteristics */\r
- RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));\r
- ProtChars.MajorNdisVersion = NDIS_VERSION_MAJOR;\r
- ProtChars.MinorNdisVersion = NDIS_VERSION_MINOR;\r
- ProtChars.Name.Length = Name->Length;\r
- ProtChars.Name.Buffer = (PVOID)Name->Buffer;\r
- ProtChars.OpenAdapterCompleteHandler = ProtocolOpenAdapterComplete;\r
- ProtChars.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete;\r
- ProtChars.ResetCompleteHandler = ProtocolResetComplete;\r
- ProtChars.RequestCompleteHandler = ProtocolRequestComplete;\r
- ProtChars.SendCompleteHandler = ProtocolSendComplete;\r
- ProtChars.TransferDataCompleteHandler = ProtocolTransferDataComplete;\r
- ProtChars.ReceiveHandler = ProtocolReceive;\r
- ProtChars.ReceiveCompleteHandler = ProtocolReceiveComplete;\r
- ProtChars.StatusHandler = ProtocolStatus;\r
- ProtChars.StatusCompleteHandler = ProtocolStatusComplete;\r
-\r
- /* Try to register protocol */\r
- NdisRegisterProtocol(\r
- &NdisStatus, &NdisProtocolHandle, &ProtChars,\r
- sizeof(NDIS_PROTOCOL_CHARACTERISTICS) + Name->Length);\r
- if (NdisStatus != NDIS_STATUS_SUCCESS)\r
- return (NTSTATUS)NdisStatus;\r
-\r
- ProtocolRegistered = TRUE;\r
-\r
- return STATUS_SUCCESS;\r
-}\r
-\r
-\r
-VOID LANUnregisterProtocol(\r
- VOID)\r
-/*\r
- * FUNCTION: Unregisters this protocol driver with NDIS\r
- * NOTES: Does not care wether we are already registered\r
- */\r
-{\r
- if (ProtocolRegistered) {\r
- NDIS_STATUS NdisStatus;\r
-\r
- while (Adapters)\r
- NdisStatus = LANUnregisterAdapter(Adapters);\r
-\r
- NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle);\r
- ProtocolRegistered = FALSE;\r
- }\r
-}\r
-\r
-/* EOF */\r
+/*
+ * 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 <tcpip.h>
+#include <lan.h>
+#include <address.h>
+#include <routines.h>
+#include <transmit.h>
+#include <receive.h>
+#include <arp.h>
+
+
+NDIS_HANDLE NdisProtocolHandle = (NDIS_HANDLE)NULL;
+BOOLEAN ProtocolRegistered = FALSE;
+PLAN_ADAPTER Adapters = NULL;
+
+
+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;
+}
+
+
+PNDIS_PACKET AllocateTDPacket(
+ PLAN_ADAPTER Adapter)
+/*
+ * FUNCTION: Allocates an NDIS packet for NdisTransferData
+ * ARGUMENTS:
+ * Adapter = Pointer to LAN_ADAPTER structure
+ * RETURNS:
+ * Pointer to NDIS packet or NULL if there was not enough free
+ * non-paged memory
+ */
+{
+ NDIS_STATUS NdisStatus;
+ PNDIS_PACKET NdisPacket;
+ PNDIS_BUFFER Buffer;
+ PVOID Data;
+
+ NdisAllocatePacket(&NdisStatus, &NdisPacket, GlobalPacketPool);
+ if (NdisStatus != NDIS_STATUS_SUCCESS)
+ return NULL;
+
+ Data = ExAllocatePool(NonPagedPool, Adapter->MTU);
+ if (!Data) {
+ NdisFreePacket(NdisPacket);
+ return NULL;
+ }
+
+ NdisAllocateBuffer(&NdisStatus, &Buffer, GlobalBufferPool, Data, Adapter->MTU);
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NdisFreePacket(NdisPacket);
+ ExFreePool(Data);
+ return NULL;
+ }
+
+ NdisChainBufferAtFront(NdisPacket, Buffer);
+
+ PC(NdisPacket)->Context = NULL; /* End of list */
+
+ return NdisPacket;
+}
+
+
+VOID FreeTDPackets(
+ PLAN_ADAPTER Adapter)
+/*
+ * FUNCTION: Frees transfer data packets
+ * ARGUMENTS:
+ * Adapter = Pointer to LAN_ADAPTER structure
+ */
+{
+ PNDIS_PACKET NdisPacket, Next;
+
+ /* Release transfer data packets */
+ NdisPacket = Adapter->TDPackets;
+ while (NdisPacket) {
+ Next = PC(NdisPacket)->Context;
+ FreeNdisPacket(NdisPacket);
+ NdisPacket = Next;
+ }
+ Adapter->TDPackets = NULL;
+}
+
+
+VOID FreeAdapter(
+ PLAN_ADAPTER Adapter)
+/*
+ * FUNCTION: Frees memory for a LAN_ADAPTER structure
+ * ARGUMENTS:
+ * Adapter = Pointer to LAN_ADAPTER structure to free
+ */
+{
+ FreeTDPackets(Adapter);
+ ExFreePool(Adapter);
+}
+
+
+VOID 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(MID_TRACE, ("Called.\n"));
+
+ KeSetEvent(&Adapter->Event, 0, FALSE);
+}
+
+
+VOID 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(MID_TRACE, ("Called.\n"));
+
+ Adapter->NdisStatus = Status;
+
+ KeSetEvent(&Adapter->Event, 0, FALSE);
+}
+
+
+VOID 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 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;
+
+ /* Save status of request and signal an event */
+ Adapter->NdisStatus = Status;
+
+ KeSetEvent(&Adapter->Event, 0, FALSE);
+}
+
+
+VOID 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
+ */
+{
+ PLAN_ADAPTER Adapter = BindingContext;
+
+ TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+ AdjustPacket(Packet, Adapter->HeaderSize, PC(Packet)->DLOffset);
+
+ (*PC(Packet)->DLComplete)(Adapter->Context, Packet, Status);
+}
+
+
+VOID 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
+ */
+{
+ UINT PacketType;
+ PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+ PNDIS_BUFFER NdisBuffer;
+ IP_PACKET IPPacket;
+
+ NdisGetFirstBufferFromPacket(
+ Packet, &NdisBuffer, &IPPacket.Header,
+ &IPPacket.ContigSize, &IPPacket.TotalSize);
+
+ /* Determine which upper layer protocol that should receive
+ this packet and pass it to the correct receive handler */
+ PacketType = ((PETH_HEADER)IPPacket.Header)->EType;
+ switch (PacketType) {
+ case ETYPE_IPv4:
+ case ETYPE_IPv6:
+ IPReceive(Adapter->Context, &IPPacket);
+ break;
+ case ETYPE_ARP:
+ ARPReceive(Adapter->Context, &IPPacket);
+ default:
+ break;
+ }
+ }
+
+ /* Release the packet descriptor */
+ KeAcquireSpinLockAtDpcLevel(&Adapter->Lock);
+
+ PC(Packet)->Context = Adapter->TDPackets;
+ Adapter->TDPackets = Packet;
+
+ KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);
+}
+
+
+NDIS_STATUS 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;
+ IP_PACKET IPPacket;
+ PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
+ PETH_HEADER EHeader = (PETH_HEADER)HeaderBuffer;
+
+ TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+ if ((Adapter->State != LAN_STATE_STARTED) ||
+ HeaderBufferSize < Adapter->HeaderSize)
+ /* Adapter is not started or the header was too small */
+ 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 Ether-Type value.
+ See RFC 1122, section 2.3.3 for more information */
+ if (((EType = EHeader->EType) != ETYPE_IPv4) && (EType != ETYPE_ARP))
+ return NDIS_STATUS_NOT_ACCEPTED;
+ /* We use Ether-Type constants to destinguish packets */
+ PacketType = EType;
+ } else
+ /* FIXME: Support other medias */
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ if (LookaheadBufferSize < PacketSize) {
+ NDIS_STATUS NdisStatus;
+ PNDIS_PACKET NdisPacket;
+ UINT BytesTransferred;
+
+ /* Get transfer data packet */
+
+ KeAcquireSpinLockAtDpcLevel(&Adapter->Lock);
+
+ NdisPacket = Adapter->TDPackets;
+ if (NdisPacket == (PNDIS_PACKET)NULL) {
+ /* We don't have a free packet descriptor. Drop the packet */
+ KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);
+ return NDIS_STATUS_SUCCESS;
+ }
+ Adapter->TDPackets = PC(NdisPacket)->Context;
+
+ KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);
+
+ /* Get the data */
+ NdisTransferData(&NdisStatus, Adapter->NdisHandle,
+ MacReceiveContext, 0, PacketSize,
+ NdisPacket, &BytesTransferred);
+ if (NdisStatus != NDIS_STATUS_PENDING)
+ ProtocolTransferDataComplete(BindingContext,
+ NdisPacket, NdisStatus, BytesTransferred);
+
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ /* We got all the data in the lookahead buffer */
+ RtlZeroMemory(&IPPacket, sizeof(IPPacket));
+ IPPacket.Header = LookaheadBuffer;
+ IPPacket.TotalSize = PacketSize;
+
+ switch (PacketType) {
+ case ETYPE_IPv4:
+ case ETYPE_IPv6:
+ IPReceive(Adapter->Context, &IPPacket);
+ break;
+ case ETYPE_ARP:
+ ARPReceive(Adapter->Context, &IPPacket);
+ break;
+ default:
+ break;
+ }
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+VOID ProtocolReceiveComplete(
+ NDIS_HANDLE BindingContext)
+/*
+ * FUNCTION: Called by NDIS when we're done receiving data
+ * ARGUMENTS:
+ * BindingContext = Pointer to a device context (LAN_ADAPTER)
+ */
+{
+ TI_DbgPrint(MID_TRACE, ("Called.\n"));
+}
+
+
+VOID ProtocolStatus(
+ NDIS_HANDLE BindingContext,
+ NDIS_STATUS GenerelStatus,
+ PVOID StatusBuffer,
+ UINT StatusBufferSize)
+/*
+ * FUNCTION: Called by NDIS when the underlying driver has changed state
+ * ARGUMENTS:
+ * BindingContext = Pointer to a device context (LAN_ADAPTER)
+ * GenerelStatus = A generel status code
+ * StatusBuffer = Pointer to a buffer with medium-specific data
+ * StatusBufferSize = Number of bytes in StatusBuffer
+ */
+{
+ TI_DbgPrint(MID_TRACE, ("Called.\n"));
+}
+
+
+VOID ProtocolStatusComplete(
+ NDIS_HANDLE NdisBindingContext)
+/*
+ * FUNCTION: Called by NDIS when a status-change has occurred
+ * ARGUMENTS:
+ * BindingContext = Pointer to a device context (LAN_ADAPTER)
+ */
+{
+ TI_DbgPrint(MID_TRACE, ("Called.\n"));
+}
+
+
+VOID LANTransmit(
+ PVOID Context,
+ PNDIS_PACKET NdisPacket,
+ UINT Offset,
+ PVOID LinkAddress,
+ USHORT Type)
+/*
+ * FUNCTION: Transmits a packet
+ * ARGUMENTS:
+ * Context = Pointer to context information (LAN_ADAPTER)
+ * NdisPacket = Pointer to NDIS packet to send
+ * Offset = Offset in packet where data starts
+ * LinkAddress = Pointer to link address of destination (NULL = broadcast)
+ * Type = LAN protocol type (LAN_PROTO_*)
+ */
+{
+ NDIS_STATUS NdisStatus;
+ PETH_HEADER EHeader;
+ PVOID Data;
+ PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context;
+
+ TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+ /* NDIS send routines don't have an offset argument so we
+ must offset the data in upper layers and adjust the
+ packet here. We save the offset in the packet context
+ area so it can be undone before we release the packet */
+ Data = AdjustPacket(NdisPacket, Offset, Adapter->HeaderSize);
+ PC(NdisPacket)->DLOffset = Offset;
+
+ if (Adapter->State == LAN_STATE_STARTED) {
+ switch (Adapter->Media) {
+ case NdisMedium802_3:
+ EHeader = (PETH_HEADER)Data;
+
+ if (LinkAddress)
+ /* Unicast address */
+ RtlCopyMemory(EHeader->DstAddr, LinkAddress, IEEE_802_ADDR_LENGTH);
+ else
+ /* Broadcast address */
+ RtlFillMemory(EHeader->DstAddr, IEEE_802_ADDR_LENGTH, 0xFF);
+
+ RtlCopyMemory(EHeader->SrcAddr, Adapter->HWAddress, IEEE_802_ADDR_LENGTH);
+
+ switch (Type) {
+ case LAN_PROTO_IPv4:
+ EHeader->EType = ETYPE_IPv4;
+ break;
+ case LAN_PROTO_ARP:
+ EHeader->EType = ETYPE_ARP;
+ break;
+ case LAN_PROTO_IPv6:
+ EHeader->EType = ETYPE_IPv6;
+ break;
+ default:
+#if DBG
+ /* Should not happen */
+ TI_DbgPrint(MIN_TRACE, ("Unknown LAN protocol.\n"));
+
+ ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NDIS_STATUS_FAILURE);
+#endif
+ return;
+ }
+ break;
+
+ default:
+ /* FIXME: Support other medias */
+ break;
+ }
+
+ NdisSend(&NdisStatus, Adapter->NdisHandle, NdisPacket);
+ if (NdisStatus != NDIS_STATUS_PENDING)
+ ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NdisStatus);
+ } else
+ ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NDIS_STATUS_CLOSED);
+}
+
+
+VOID BindAdapter(
+ PLAN_ADAPTER Adapter)
+/*
+ * FUNCTION: Binds a LAN adapter to IP layer
+ * ARGUMENTS:
+ * Adapter = Pointer to LAN_ADAPTER structure
+ * NOTES:
+ * We set the lookahead buffer size, set the packet filter and
+ * bind the adapter to IP layer
+ */
+{
+ INT i;
+ PIP_INTERFACE IF;
+ PIP_ADDRESS Address;
+ PNDIS_PACKET Packet;
+ NDIS_STATUS NdisStatus;
+ LLIP_BIND_INFO BindInfo;
+ ULONG Lookahead = LOOKAHEAD_SIZE;
+
+ TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+ Adapter->State = LAN_STATE_OPENING;
+
+ NdisStatus = NDISCall(Adapter, NdisRequestSetInformation,
+ OID_GEN_CURRENT_LOOKAHEAD, &Lookahead, sizeof(ULONG));
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ TI_DbgPrint(MID_TRACE, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus));
+ return;
+ }
+
+ /* Allocate packets for NdisTransferData */
+ /* FIXME: How many should we allocate? */
+ Adapter->TDPackets = NULL;
+ for (i = 0; i < 2; i++) {
+ Packet = AllocateTDPacket(Adapter);
+ PC(Packet)->Context = Adapter->TDPackets;
+ Adapter->TDPackets = Packet;
+ if (!Packet) {
+ TI_DbgPrint(MID_TRACE, ("Could not allocate transfer data packet (out of resources).\n"));
+ FreeTDPackets(Adapter);
+ return;
+ }
+ }
+
+ /* Bind the adapter to IP layer */
+ BindInfo.Context = Adapter;
+ BindInfo.HeaderSize = Adapter->HeaderSize;
+ BindInfo.MinFrameSize = Adapter->MinFrameSize;
+ BindInfo.MTU = Adapter->MTU;
+ BindInfo.Address = (PUCHAR)&Adapter->HWAddress;
+ BindInfo.AddressLength = Adapter->HWAddressLength;
+ BindInfo.Transmit = LANTransmit;
+
+ IF = IPCreateInterface(&BindInfo);
+ if (!IF) {
+ TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+ FreeTDPackets(Adapter);
+ return;
+ }
+
+ /* FIXME: Get address from registry.
+ For now just use a private address, eg. 10.0.0.10 */
+ Address = AddrBuildIPv4(0x0A00000A);
+ if (!Address) {
+ TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+ FreeTDPackets(Adapter);
+ IPDestroyInterface(Adapter->Context);
+ return;
+ }
+ /* Create a net table entry for this interface */
+ if (!IPCreateNTE(IF, Address, 8)) {
+ TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+ FreeTDPackets(Adapter);
+ IPDestroyInterface(IF);
+ return;
+ }
+
+ /* Reference the interface for the NTE. The reference for
+ the address is just passed on to the NTE */
+ ReferenceObject(IF);
+
+ /* Register interface with IP layer */
+ IPRegisterInterface(IF);
+
+ /* Set packet filter so we can send and receive packets */
+ NdisStatus = NDISCall(Adapter, NdisRequestSetInformation,
+ OID_GEN_CURRENT_PACKET_FILTER, &Adapter->PacketFilter, sizeof(UINT));
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ TI_DbgPrint(MID_TRACE, ("Could not set packet filter (0x%X).\n", NdisStatus));
+ FreeTDPackets(Adapter);
+ IPDestroyInterface(IF);
+ return;
+ }
+
+ Adapter->Context = IF;
+
+ Adapter->State = LAN_STATE_STARTED;
+}
+
+
+VOID UnbindAdapter(
+ PLAN_ADAPTER Adapter)
+/*
+ * FUNCTION: Unbinds a LAN adapter from IP layer
+ * ARGUMENTS:
+ * Adapter = Pointer to LAN_ADAPTER structure
+ */
+{
+ TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+ if (Adapter->State == LAN_STATE_STARTED) {
+ PIP_INTERFACE IF = Adapter->Context;
+
+ IPUnregisterInterface(IF);
+
+ IPDestroyInterface(IF);
+
+ /* Free transfer data packets */
+ FreeTDPackets(Adapter);
+ }
+}
+
+
+NDIS_STATUS LANRegisterAdapter(
+ PNDIS_STRING AdapterName,
+ PLAN_ADAPTER *Adapter)
+/*
+ * FUNCTION: Registers protocol with an NDIS adapter
+ * ARGUMENTS:
+ * AdapterName = Pointer to string with name of adapter to register
+ * Adapter = Address of pointer to a LAN_ADAPTER structure
+ * RETURNS:
+ * Status of operation
+ */
+{
+ PLAN_ADAPTER IF;
+ NDIS_STATUS NdisStatus;
+ NDIS_STATUS OpenStatus;
+ UINT MediaIndex;
+ NDIS_MEDIUM MediaArray[MAX_MEDIA];
+ UINT AddressOID;
+ UINT Speed;
+
+ TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+ IF = ExAllocatePool(NonPagedPool, sizeof(LAN_ADAPTER));
+ if (!IF)
+ return NDIS_STATUS_RESOURCES;
+
+ RtlZeroMemory(IF, sizeof(LAN_ADAPTER));
+
+ /* Put adapter in stopped state */
+ IF->State = LAN_STATE_STOPPED;
+
+ /* Initialize protecting spin lock */
+ KeInitializeSpinLock(&IF->Lock);
+
+ KeInitializeEvent(&IF->Event, SynchronizationEvent, FALSE);
+
+ /* Initialize array with media IDs we support */
+ MediaArray[MEDIA_ETH] = NdisMedium802_3;
+
+ /* Open the adapter. */
+ NdisOpenAdapter(&NdisStatus, &OpenStatus, &IF->NdisHandle, &MediaIndex,
+ MediaArray, MAX_MEDIA, NdisProtocolHandle, IF, AdapterName, 0, NULL);
+
+ /* Wait until the adapter is opened */
+ if (NdisStatus == NDIS_STATUS_PENDING)
+ KeWaitForSingleObject(&IF->Event, UserRequest, KernelMode, FALSE, NULL);
+ else if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ ExFreePool(IF);
+ return NdisStatus;
+ }
+
+ IF->Media = MediaArray[MediaIndex];
+
+ /* Fill LAN_ADAPTER structure with some adapter specific information */
+ switch (IF->Media) {
+ case NdisMedium802_3:
+ IF->HWAddressLength = IEEE_802_ADDR_LENGTH;
+ IF->BCastMask = BCAST_ETH_MASK;
+ IF->BCastCheck = BCAST_ETH_CHECK;
+ IF->BCastOffset = BCAST_ETH_OFFSET;
+ IF->HeaderSize = sizeof(ETH_HEADER);
+ IF->MinFrameSize = 60;
+ AddressOID = OID_802_3_CURRENT_ADDRESS;
+ IF->PacketFilter =
+ NDIS_PACKET_TYPE_BROADCAST |
+ NDIS_PACKET_TYPE_DIRECTED |
+ NDIS_PACKET_TYPE_MULTICAST;
+ break;
+
+ default:
+ /* Unsupported media */
+ TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
+ ExFreePool(IF);
+ return NDIS_STATUS_NOT_SUPPORTED;
+ }
+
+ /* Get maximum frame size */
+ NdisStatus = NDISCall(IF, NdisRequestQueryInformation,
+ OID_GEN_MAXIMUM_FRAME_SIZE, &IF->MTU, sizeof(UINT));
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ ExFreePool(IF);
+ return NdisStatus;
+ }
+
+ /* Get maximum packet size */
+ NdisStatus = NDISCall(IF, NdisRequestQueryInformation,
+ OID_GEN_MAXIMUM_TOTAL_SIZE, &IF->MaxPacketSize, sizeof(UINT));
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ TI_DbgPrint(MIN_TRACE, ("Query for maximum packet size failed.\n"));
+ ExFreePool(IF);
+ return NdisStatus;
+ }
+
+ /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
+ NdisStatus = NDISCall(IF, NdisRequestQueryInformation,
+ OID_GEN_MAXIMUM_SEND_PACKETS, &IF->MaxSendPackets, sizeof(UINT));
+ if (NdisStatus != NDIS_STATUS_SUCCESS)
+ /* Legacy NIC drivers may not support this query, if it fails we
+ assume it can send at least one packet per call to NdisSend(Packets) */
+ IF->MaxSendPackets = 1;
+
+ /* Get current hardware address */
+ NdisStatus = NDISCall(IF, NdisRequestQueryInformation, AddressOID,
+ IF->HWAddress, IF->HWAddressLength);
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ TI_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n"));
+ ExFreePool(IF);
+ return NdisStatus;
+ }
+
+ /* Get maximum link speed */
+ NdisStatus = NDISCall(IF, NdisRequestQueryInformation,
+ OID_GEN_LINK_SPEED, &Speed, sizeof(UINT));
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ TI_DbgPrint(MIN_TRACE, ("Query for maximum link speed failed.\n"));
+ ExFreePool(IF);
+ return NdisStatus;
+ }
+
+ /* Convert returned link speed to bps (it is in 100bps increments) */
+ IF->Speed = Speed * 100L;
+
+ *Adapter = IF;
+
+ /* Add adapter to the adapter list */
+ IF->Next = Adapters;
+ Adapters = IF;
+
+ /* Bind adapter to IP layer */
+ BindAdapter(IF);
+
+ TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+NDIS_STATUS LANUnregisterAdapter(
+ PLAN_ADAPTER Adapter)
+/*
+ * FUNCTION: Unregisters protocol with NDIS adapter
+ * ARGUMENTS:
+ * Adapter = Pointer to a LAN_ADAPTER structure
+ * RETURNS:
+ * Status of operation
+ */
+{
+ KIRQL OldIrql;
+ NDIS_HANDLE NdisHandle;
+ PLAN_ADAPTER IF, PrevIF;
+ BOOLEAN Found = FALSE;
+ NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
+
+ TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+ /* Search the adapter list for the specified adapter and remove it */
+ IF = Adapters;
+ if (IF) {
+ if (Adapter != Adapters) {
+ PrevIF = IF;
+ while ((IF) && (!Found)) {
+ if (IF == Adapter) {
+ /* We've found the adapter, now remove it from the list */
+ PrevIF->Next = IF->Next;
+ Found = TRUE;
+ }
+ PrevIF = IF;
+ IF = IF->Next;
+ }
+ } else {
+ Adapters = NULL;
+ Found = TRUE;
+ }
+ }
+ if (!Found) {
+ TI_DbgPrint(MIN_TRACE, ("Leaving (adapter was not in list).\n"));
+ return NDIS_STATUS_ADAPTER_NOT_FOUND;
+ }
+
+ /* Unbind adapter from IP layer */
+ UnbindAdapter(Adapter);
+
+ KeAcquireSpinLock(&Adapter->Lock, &OldIrql);
+ NdisHandle = Adapter->NdisHandle;
+ if (NdisHandle) {
+ Adapter->NdisHandle = NULL;
+ KeReleaseSpinLock(&Adapter->Lock, OldIrql);
+
+ NdisCloseAdapter(&NdisStatus, NdisHandle);
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+ KeWaitForSingleObject(&Adapter->Event,
+ UserRequest, KernelMode, FALSE, NULL);
+ NdisStatus = Adapter->NdisStatus;
+ }
+ } else
+ KeReleaseSpinLock(&Adapter->Lock, OldIrql);
+
+ FreeAdapter(Adapter);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+NTSTATUS LANRegisterProtocol(
+ PSTRING Name)
+/*
+ * FUNCTION: Registers this protocol driver with NDIS
+ * ARGUMENTS:
+ * Name = Name of this protocol driver
+ * RETURNS:
+ * Status of operation
+ */
+{
+ NDIS_STATUS NdisStatus;
+ NDIS_PROTOCOL_CHARACTERISTICS ProtChars;
+
+ /* Set up protocol characteristics */
+ RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
+ ProtChars.MajorNdisVersion = NDIS_VERSION_MAJOR;
+ ProtChars.MinorNdisVersion = NDIS_VERSION_MINOR;
+ ProtChars.Name.Length = Name->Length;
+ ProtChars.Name.Buffer = (PVOID)Name->Buffer;
+ ProtChars.OpenAdapterCompleteHandler = ProtocolOpenAdapterComplete;
+ ProtChars.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete;
+ ProtChars.ResetCompleteHandler = ProtocolResetComplete;
+ ProtChars.RequestCompleteHandler = ProtocolRequestComplete;
+ ProtChars.SendCompleteHandler = ProtocolSendComplete;
+ ProtChars.TransferDataCompleteHandler = ProtocolTransferDataComplete;
+ ProtChars.ReceiveHandler = ProtocolReceive;
+ ProtChars.ReceiveCompleteHandler = ProtocolReceiveComplete;
+ ProtChars.StatusHandler = ProtocolStatus;
+ ProtChars.StatusCompleteHandler = ProtocolStatusComplete;
+
+ /* Try to register protocol */
+ NdisRegisterProtocol(
+ &NdisStatus, &NdisProtocolHandle, &ProtChars,
+ sizeof(NDIS_PROTOCOL_CHARACTERISTICS) + Name->Length);
+ if (NdisStatus != NDIS_STATUS_SUCCESS)
+ return (NTSTATUS)NdisStatus;
+
+ ProtocolRegistered = TRUE;
+
+ return STATUS_SUCCESS;
+}
+
+
+VOID LANUnregisterProtocol(
+ VOID)
+/*
+ * FUNCTION: Unregisters this protocol driver with NDIS
+ * NOTES: Does not care wether we are already registered
+ */
+{
+ if (ProtocolRegistered) {
+ NDIS_STATUS NdisStatus;
+
+ while (Adapters)
+ NdisStatus = LANUnregisterAdapter(Adapters);
+
+ NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle);
+ ProtocolRegistered = FALSE;
+ }
+}
+
+/* EOF */