--- /dev/null
+/*
+ * 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"
+
+#include <ntifs.h>
+#include <receive.h>
+#include <wait.h>
+
+UINT TransferDataCalled = 0;
+UINT TransferDataCompleteCalled = 0;
+
+#define CCS_ROOT L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet"
+#define TCPIP_GUID L"{4D36E972-E325-11CE-BFC1-08002BE10318}"
+
+typedef struct _LAN_WQ_ITEM {
+ LIST_ENTRY ListEntry;
+ PNDIS_PACKET Packet;
+ PLAN_ADAPTER Adapter;
+ UINT BytesTransferred;
+ BOOLEAN LegacyReceive;
+} LAN_WQ_ITEM, *PLAN_WQ_ITEM;
+
+typedef struct _RECONFIGURE_CONTEXT {
+ ULONG State;
+ PLAN_ADAPTER Adapter;
+} RECONFIGURE_CONTEXT, *PRECONFIGURE_CONTEXT;
+
+NDIS_HANDLE NdisProtocolHandle = (NDIS_HANDLE)NULL;
+BOOLEAN ProtocolRegistered = FALSE;
+LIST_ENTRY AdapterListHead;
+KSPIN_LOCK AdapterListLock;
+
+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;
+}
+
+/* Used by legacy ProtocolReceive for packet type */
+NDIS_STATUS
+GetPacketTypeFromHeaderBuffer(PLAN_ADAPTER Adapter,
+ PVOID HeaderBuffer,
+ ULONG HeaderBufferSize,
+ PULONG PacketType)
+{
+ PETH_HEADER EthHeader = HeaderBuffer;
+
+ if (HeaderBufferSize < Adapter->HeaderSize)
+ {
+ TI_DbgPrint(DEBUG_DATALINK, ("Runt frame (size %d).\n", HeaderBufferSize));
+ return NDIS_STATUS_NOT_ACCEPTED;
+ }
+
+ switch (Adapter->Media)
+ {
+ case NdisMedium802_3:
+ /* Ethernet and IEEE 802.3 frames can be distinguished 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 */
+
+ *PacketType = EthHeader->EType;
+ break;
+
+ default:
+ TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
+
+ /* FIXME: Support other medias */
+ return NDIS_STATUS_NOT_ACCEPTED;
+ }
+
+ TI_DbgPrint(DEBUG_DATALINK, ("EtherType (0x%X).\n", *PacketType));
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+/* Used by ProtocolReceivePacket for packet type */
+NDIS_STATUS
+GetPacketTypeFromNdisPacket(PLAN_ADAPTER Adapter,
+ PNDIS_PACKET NdisPacket,
+ PULONG PacketType)
+{
+ PVOID HeaderBuffer;
+ ULONG BytesCopied;
+ NDIS_STATUS Status;
+
+ HeaderBuffer = ExAllocatePoolWithTag(NonPagedPool,
+ Adapter->HeaderSize,
+ HEADER_TAG);
+ if (!HeaderBuffer)
+ return NDIS_STATUS_RESOURCES;
+
+ /* Copy the media header */
+ BytesCopied = CopyPacketToBuffer(HeaderBuffer,
+ NdisPacket,
+ 0,
+ Adapter->HeaderSize);
+ if (BytesCopied != Adapter->HeaderSize)
+ {
+ /* Runt frame */
+ ExFreePoolWithTag(HeaderBuffer, HEADER_TAG);
+ TI_DbgPrint(DEBUG_DATALINK, ("Runt frame (size %d).\n", BytesCopied));
+ return NDIS_STATUS_NOT_ACCEPTED;
+ }
+
+ Status = GetPacketTypeFromHeaderBuffer(Adapter,
+ HeaderBuffer,
+ BytesCopied,
+ PacketType);
+
+ ExFreePoolWithTag(HeaderBuffer, HEADER_TAG);
+
+ return Status;
+}
+
+
+VOID FreeAdapter(
+ PLAN_ADAPTER Adapter)
+/*
+ * FUNCTION: Frees memory for a LAN_ADAPTER structure
+ * ARGUMENTS:
+ * Adapter = Pointer to LAN_ADAPTER structure to free
+ */
+{
+ ExFreePoolWithTag(Adapter, LAN_ADAPTER_TAG);
+}
+
+
+NTSTATUS TcpipLanGetDwordOid
+( PIP_INTERFACE Interface,
+ NDIS_OID Oid,
+ PULONG Result ) {
+ /* Get maximum frame size */
+ if( Interface->Context ) {
+ return NDISCall((PLAN_ADAPTER)Interface->Context,
+ NdisRequestQueryInformation,
+ Oid,
+ Result,
+ sizeof(ULONG));
+ } else switch( Oid ) { /* Loopback Case */
+ case OID_GEN_HARDWARE_STATUS:
+ *Result = NdisHardwareStatusReady;
+ return STATUS_SUCCESS;
+ case OID_GEN_MEDIA_CONNECT_STATUS:
+ *Result = NdisMediaStateConnected;
+ return STATUS_SUCCESS;
+ default:
+ return STATUS_INVALID_PARAMETER;
+ }
+}
+
+
+VOID NTAPI 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"));
+
+ Adapter->NdisStatus = Status;
+
+ KeSetEvent(&Adapter->Event, 0, FALSE);
+}
+
+
+VOID NTAPI 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 NTAPI 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
+ */
+{
+ PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
+
+ TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+
+ Adapter->NdisStatus = Status;
+
+ KeSetEvent(&Adapter->Event, 0, FALSE);
+}
+
+
+VOID NTAPI 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 NTAPI 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
+ */
+{
+ FreeNdisPacket(Packet);
+}
+
+VOID LanReceiveWorker( PVOID Context ) {
+ ULONG PacketType;
+ PLAN_WQ_ITEM WorkItem = (PLAN_WQ_ITEM)Context;
+ PNDIS_PACKET Packet;
+ PLAN_ADAPTER Adapter;
+ UINT BytesTransferred;
+ IP_PACKET IPPacket;
+ BOOLEAN LegacyReceive;
+ PIP_INTERFACE Interface;
+
+ TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+
+ Packet = WorkItem->Packet;
+ Adapter = WorkItem->Adapter;
+ BytesTransferred = WorkItem->BytesTransferred;
+ LegacyReceive = WorkItem->LegacyReceive;
+
+ ExFreePoolWithTag(WorkItem, WQ_CONTEXT_TAG);
+
+ Interface = Adapter->Context;
+
+ IPInitializePacket(&IPPacket, 0);
+
+ IPPacket.NdisPacket = Packet;
+ IPPacket.ReturnPacket = !LegacyReceive;
+
+ if (LegacyReceive)
+ {
+ /* Packet type is precomputed */
+ PacketType = PC(IPPacket.NdisPacket)->PacketType;
+
+ /* Data is at position 0 */
+ IPPacket.Position = 0;
+
+ /* Packet size is determined by bytes transferred */
+ IPPacket.TotalSize = BytesTransferred;
+ }
+ else
+ {
+ /* Determine packet type from media header */
+ if (GetPacketTypeFromNdisPacket(Adapter,
+ IPPacket.NdisPacket,
+ &PacketType) != NDIS_STATUS_SUCCESS)
+ {
+ /* Bad packet */
+ IPPacket.Free(&IPPacket);
+ return;
+ }
+
+ /* Data is at the end of the media header */
+ IPPacket.Position = Adapter->HeaderSize;
+
+ /* Calculate packet size (excluding media header) */
+ NdisQueryPacketLength(IPPacket.NdisPacket, &IPPacket.TotalSize);
+ }
+
+ TI_DbgPrint
+ (DEBUG_DATALINK,
+ ("Ether Type = %x Total = %d\n",
+ PacketType, IPPacket.TotalSize));
+
+ /* Update interface stats */
+ Interface->Stats.InBytes += IPPacket.TotalSize + Adapter->HeaderSize;
+
+ /* NDIS packet is freed in all of these cases */
+ 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);
+ break;
+ default:
+ IPPacket.Free(&IPPacket);
+ break;
+ }
+}
+
+VOID LanSubmitReceiveWork(
+ NDIS_HANDLE BindingContext,
+ PNDIS_PACKET Packet,
+ UINT BytesTransferred,
+ BOOLEAN LegacyReceive) {
+ PLAN_WQ_ITEM WQItem = ExAllocatePoolWithTag(NonPagedPool, sizeof(LAN_WQ_ITEM),
+ WQ_CONTEXT_TAG);
+ PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
+
+ TI_DbgPrint(DEBUG_DATALINK,("called\n"));
+
+ if (!WQItem) return;
+
+ WQItem->Packet = Packet;
+ WQItem->Adapter = Adapter;
+ WQItem->BytesTransferred = BytesTransferred;
+ WQItem->LegacyReceive = LegacyReceive;
+
+ if (!ChewCreate( LanReceiveWorker, WQItem ))
+ ExFreePoolWithTag(WQItem, WQ_CONTEXT_TAG);
+}
+
+VOID NTAPI 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,
+ BytesTransferred,
+ TRUE);
+}
+
+INT NTAPI ProtocolReceivePacket(
+ NDIS_HANDLE BindingContext,
+ PNDIS_PACKET NdisPacket)
+{
+ PLAN_ADAPTER Adapter = BindingContext;
+
+ if (Adapter->State != LAN_STATE_STARTED) {
+ TI_DbgPrint(DEBUG_DATALINK, ("Adapter is stopped.\n"));
+ return 0;
+ }
+
+ LanSubmitReceiveWork(BindingContext,
+ NdisPacket,
+ 0, /* Unused */
+ FALSE);
+
+ /* Hold 1 reference on this packet */
+ return 1;
+}
+
+NDIS_STATUS NTAPI 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
+ */
+{
+ ULONG PacketType;
+ UINT BytesTransferred;
+ PCHAR BufferData;
+ NDIS_STATUS NdisStatus;
+ PNDIS_PACKET NdisPacket;
+ PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
+
+ 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;
+ }
+
+ NdisStatus = GetPacketTypeFromHeaderBuffer(Adapter,
+ HeaderBuffer,
+ HeaderBufferSize,
+ &PacketType);
+ if (NdisStatus != NDIS_STATUS_SUCCESS)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ TI_DbgPrint(DEBUG_DATALINK, ("Adapter: %x (MTU %d)\n",
+ Adapter, Adapter->MTU));
+
+ /* Get a transfer data packet */
+ NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL,
+ PacketSize );
+ if( NdisStatus != NDIS_STATUS_SUCCESS ) {
+ return NDIS_STATUS_NOT_ACCEPTED;
+ }
+
+ PC(NdisPacket)->PacketType = PacketType;
+
+ TI_DbgPrint(DEBUG_DATALINK, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize,PacketSize));
+
+ GetDataPtr( NdisPacket, 0, &BufferData, &PacketSize );
+
+ TransferDataCalled++;
+
+ if (LookaheadBufferSize == PacketSize)
+ {
+ /* Optimized code path for packets that are fully contained in
+ * the lookahead buffer. */
+ NdisCopyLookaheadData(BufferData,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ Adapter->MacOptions);
+ }
+ else
+ {
+ NdisTransferData(&NdisStatus, Adapter->NdisHandle,
+ MacReceiveContext, 0, PacketSize,
+ NdisPacket, &BytesTransferred);
+ }
+ TI_DbgPrint(DEBUG_DATALINK, ("Calling complete\n"));
+
+ if (NdisStatus != NDIS_STATUS_PENDING)
+ ProtocolTransferDataComplete(BindingContext,
+ NdisPacket,
+ NdisStatus,
+ PacketSize);
+
+ TI_DbgPrint(DEBUG_DATALINK, ("leaving\n"));
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+VOID NTAPI 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(DEBUG_DATALINK, ("Called.\n"));
+}
+
+BOOLEAN ReadIpConfiguration(PIP_INTERFACE Interface)
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE ParameterHandle;
+ PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
+ WCHAR Buffer[150];
+ UNICODE_STRING IPAddress = RTL_CONSTANT_STRING(L"IPAddress");
+ UNICODE_STRING Netmask = RTL_CONSTANT_STRING(L"SubnetMask");
+ UNICODE_STRING Gateway = RTL_CONSTANT_STRING(L"DefaultGateway");
+ UNICODE_STRING EnableDhcp = RTL_CONSTANT_STRING(L"EnableDHCP");
+ UNICODE_STRING Prefix = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\");
+ UNICODE_STRING TcpipRegistryPath;
+ UNICODE_STRING RegistryDataU;
+ ANSI_STRING RegistryDataA;
+ ULONG Unused;
+ NTSTATUS Status;
+ IP_ADDRESS DefaultMask, Router;
+
+ AddrInitIPv4(&DefaultMask, 0);
+
+ TcpipRegistryPath.MaximumLength = sizeof(WCHAR) * 150;
+ TcpipRegistryPath.Length = 0;
+ TcpipRegistryPath.Buffer = Buffer;
+
+ /* Build the registry path */
+ RtlAppendUnicodeStringToString(&TcpipRegistryPath, &Prefix);
+ RtlAppendUnicodeStringToString(&TcpipRegistryPath, &Interface->Name);
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ &TcpipRegistryPath,
+ OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+ 0,
+ NULL);
+
+ /* Open a handle to the adapter parameters */
+ Status = ZwOpenKey(&ParameterHandle, KEY_READ, &ObjectAttributes);
+
+ if (!NT_SUCCESS(Status))
+ {
+ return FALSE;
+ }
+ else
+ {
+ KeyValueInfo = ExAllocatePoolWithTag(PagedPool, sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 16 * sizeof(WCHAR), KEY_VALUE_TAG);
+ if (!KeyValueInfo)
+ {
+ ZwClose(ParameterHandle);
+ return FALSE;
+ }
+
+ /* Read the EnableDHCP entry */
+ Status = ZwQueryValueKey(ParameterHandle,
+ &EnableDhcp,
+ KeyValuePartialInformation,
+ KeyValueInfo,
+ sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG),
+ &Unused);
+ if (NT_SUCCESS(Status) && KeyValueInfo->DataLength == sizeof(ULONG) && (*(PULONG)KeyValueInfo->Data) == 0)
+ {
+ RegistryDataU.MaximumLength = 16 + sizeof(WCHAR);
+ RegistryDataU.Buffer = (PWCHAR)KeyValueInfo->Data;
+
+ /* Read the IP address */
+ Status = ZwQueryValueKey(ParameterHandle,
+ &IPAddress,
+ KeyValuePartialInformation,
+ KeyValueInfo,
+ sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 16 * sizeof(WCHAR),
+ &Unused);
+ if (NT_SUCCESS(Status))
+ {
+ RegistryDataU.Length = KeyValueInfo->DataLength;
+
+ RtlUnicodeStringToAnsiString(&RegistryDataA,
+ &RegistryDataU,
+ TRUE);
+
+ AddrInitIPv4(&Interface->Unicast, inet_addr(RegistryDataA.Buffer));
+
+ RtlFreeAnsiString(&RegistryDataA);
+ }
+
+ Status = ZwQueryValueKey(ParameterHandle,
+ &Netmask,
+ KeyValuePartialInformation,
+ KeyValueInfo,
+ sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 16 * sizeof(WCHAR),
+ &Unused);
+ if (NT_SUCCESS(Status))
+ {
+ RegistryDataU.Length = KeyValueInfo->DataLength;
+
+ RtlUnicodeStringToAnsiString(&RegistryDataA,
+ &RegistryDataU,
+ TRUE);
+
+ AddrInitIPv4(&Interface->Netmask, inet_addr(RegistryDataA.Buffer));
+
+ RtlFreeAnsiString(&RegistryDataA);
+ }
+
+ /* We have to wait until both IP address and subnet mask
+ * are read to add the interface route, but we must do it
+ * before we add the default gateway */
+ if (!AddrIsUnspecified(&Interface->Unicast) &&
+ !AddrIsUnspecified(&Interface->Netmask))
+ IPAddInterfaceRoute(Interface);
+
+ /* Read default gateway info */
+ Status = ZwQueryValueKey(ParameterHandle,
+ &Gateway,
+ KeyValuePartialInformation,
+ KeyValueInfo,
+ sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 16 * sizeof(WCHAR),
+ &Unused);
+ if (NT_SUCCESS(Status))
+ {
+ RegistryDataU.Length = KeyValueInfo->DataLength;
+
+ RtlUnicodeStringToAnsiString(&RegistryDataA,
+ &RegistryDataU,
+ TRUE);
+
+ AddrInitIPv4(&Router, inet_addr(RegistryDataA.Buffer));
+
+ if (!AddrIsUnspecified(&Router))
+ RouterCreateRoute(&DefaultMask, &DefaultMask, &Router, Interface, 1);
+
+ RtlFreeAnsiString(&RegistryDataA);
+ }
+ }
+
+ ExFreePoolWithTag(KeyValueInfo, KEY_VALUE_TAG);
+ ZwClose(ParameterHandle);
+ }
+
+ return TRUE;
+}
+
+BOOLEAN ReconfigureAdapter(PRECONFIGURE_CONTEXT Context)
+{
+ PLAN_ADAPTER Adapter = Context->Adapter;
+ PIP_INTERFACE Interface = Adapter->Context;
+ //NDIS_STATUS NdisStatus;
+ IP_ADDRESS DefaultMask;
+
+ /* Initialize the default unspecified address (0.0.0.0) */
+ AddrInitIPv4(&DefaultMask, 0);
+ if (Context->State == LAN_STATE_STARTED &&
+ !Context->Adapter->CompletingReset)
+ {
+ /* Read the IP configuration */
+ ReadIpConfiguration(Interface);
+
+ /* Compute the broadcast address */
+ Interface->Broadcast.Type = IP_ADDRESS_V4;
+ Interface->Broadcast.Address.IPv4Address = Interface->Unicast.Address.IPv4Address |
+ ~Interface->Netmask.Address.IPv4Address;
+ }
+ else if (!Context->Adapter->CompletingReset)
+ {
+ /* Clear IP configuration */
+ Interface->Unicast = DefaultMask;
+ Interface->Netmask = DefaultMask;
+ Interface->Broadcast = DefaultMask;
+
+ /* Remove all interface routes */
+ RouterRemoveRoutesForInterface(Interface);
+
+ /* Destroy all cached neighbors */
+ NBDestroyNeighborsForInterface(Interface);
+ }
+
+ Context->Adapter->CompletingReset = FALSE;
+
+ /* Update the IP and link status information cached in TCP */
+ TCPUpdateInterfaceIPInformation(Interface);
+ TCPUpdateInterfaceLinkStatus(Interface);
+
+ /* We're done here if the adapter isn't connected */
+ if (Context->State != LAN_STATE_STARTED)
+ {
+ Adapter->State = Context->State;
+ return TRUE;
+ }
+
+ /* NDIS Bug! */
+#if 0
+ /* Get maximum link speed */
+ NdisStatus = NDISCall(Adapter,
+ NdisRequestQueryInformation,
+ OID_GEN_LINK_SPEED,
+ &Interface->Speed,
+ sizeof(UINT));
+
+ if (!NT_SUCCESS(NdisStatus))
+ Interface->Speed = IP_DEFAULT_LINK_SPEED;
+
+ Adapter->Speed = Interface->Speed * 100L;
+
+ /* Get maximum frame size */
+ NdisStatus = NDISCall(Adapter,
+ NdisRequestQueryInformation,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ &Adapter->MTU,
+ sizeof(UINT));
+ if (NdisStatus != NDIS_STATUS_SUCCESS)
+ return FALSE;
+
+ Interface->MTU = Adapter->MTU;
+
+ /* Get maximum packet size */
+ NdisStatus = NDISCall(Adapter,
+ NdisRequestQueryInformation,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ &Adapter->MaxPacketSize,
+ sizeof(UINT));
+ if (NdisStatus != NDIS_STATUS_SUCCESS)
+ return FALSE;
+#endif
+
+ Adapter->State = Context->State;
+
+ return TRUE;
+}
+
+VOID ReconfigureAdapterWorker(PVOID Context)
+{
+ PRECONFIGURE_CONTEXT ReconfigureContext = Context;
+
+ /* Complete the reconfiguration asynchronously */
+ ReconfigureAdapter(ReconfigureContext);
+
+ /* Free the context */
+ ExFreePool(ReconfigureContext);
+}
+
+VOID NTAPI ProtocolStatus(
+ NDIS_HANDLE BindingContext,
+ NDIS_STATUS GeneralStatus,
+ PVOID StatusBuffer,
+ UINT StatusBufferSize)
+/*
+ * FUNCTION: Called by NDIS when the underlying driver has changed state
+ * ARGUMENTS:
+ * BindingContext = Pointer to a device context (LAN_ADAPTER)
+ * GeneralStatus = A general status code
+ * StatusBuffer = Pointer to a buffer with medium-specific data
+ * StatusBufferSize = Number of bytes in StatusBuffer
+ */
+{
+ PLAN_ADAPTER Adapter = BindingContext;
+ PRECONFIGURE_CONTEXT Context;
+
+ TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+
+ /* Ignore the status indication if we have no context yet. We'll get another later */
+ if (!Adapter->Context)
+ return;
+
+ Context = ExAllocatePoolWithTag(NonPagedPool, sizeof(RECONFIGURE_CONTEXT), CONTEXT_TAG);
+ if (!Context)
+ return;
+
+ Context->Adapter = Adapter;
+
+ switch(GeneralStatus)
+ {
+ case NDIS_STATUS_MEDIA_CONNECT:
+ DbgPrint("NDIS_STATUS_MEDIA_CONNECT\n");
+
+ if (Adapter->State == LAN_STATE_STARTED)
+ {
+ ExFreePoolWithTag(Context, CONTEXT_TAG);
+ return;
+ }
+
+ Context->State = LAN_STATE_STARTED;
+ break;
+
+ case NDIS_STATUS_MEDIA_DISCONNECT:
+ DbgPrint("NDIS_STATUS_MEDIA_DISCONNECT\n");
+
+ if (Adapter->State == LAN_STATE_STOPPED)
+ {
+ ExFreePoolWithTag(Context, CONTEXT_TAG);
+ return;
+ }
+
+ Context->State = LAN_STATE_STOPPED;
+ break;
+
+ case NDIS_STATUS_RESET_START:
+ Adapter->OldState = Adapter->State;
+ Adapter->State = LAN_STATE_RESETTING;
+ /* Nothing else to do here */
+ ExFreePoolWithTag(Context, CONTEXT_TAG);
+ return;
+
+ case NDIS_STATUS_RESET_END:
+ Adapter->CompletingReset = TRUE;
+ Context->State = Adapter->OldState;
+ break;
+
+ default:
+ DbgPrint("Unhandled status: %x", GeneralStatus);
+ ExFreePoolWithTag(Context, CONTEXT_TAG);
+ return;
+ }
+
+ /* Queue the work item */
+ if (!ChewCreate(ReconfigureAdapterWorker, Context))
+ ExFreePoolWithTag(Context, CONTEXT_TAG);
+}
+
+VOID NTAPI 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(DEBUG_DATALINK, ("Called.\n"));
+}
+
+NDIS_STATUS NTAPI
+ProtocolPnPEvent(
+ NDIS_HANDLE NdisBindingContext,
+ PNET_PNP_EVENT PnPEvent)
+{
+ switch(PnPEvent->NetEvent)
+ {
+ case NetEventSetPower:
+ DbgPrint("Device transitioned to power state %ld\n", PnPEvent->Buffer);
+ return NDIS_STATUS_SUCCESS;
+
+ case NetEventQueryPower:
+ DbgPrint("Device wants to go into power state %ld\n", PnPEvent->Buffer);
+ return NDIS_STATUS_SUCCESS;
+
+ case NetEventQueryRemoveDevice:
+ DbgPrint("Device is about to be removed\n");
+ return NDIS_STATUS_SUCCESS;
+
+ case NetEventCancelRemoveDevice:
+ DbgPrint("Device removal cancelled\n");
+ return NDIS_STATUS_SUCCESS;
+
+ default:
+ DbgPrint("Unhandled event type: %ld\n", PnPEvent->NetEvent);
+ return NDIS_STATUS_SUCCESS;
+ }
+}
+
+VOID NTAPI ProtocolBindAdapter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE BindContext,
+ IN PNDIS_STRING DeviceName,
+ IN PVOID SystemSpecific1,
+ IN PVOID SystemSpecific2)
+/*
+ * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
+ * bindings, and periodically thereafter as new adapters come online
+ * ARGUMENTS:
+ * Status: Return value to NDIS
+ * BindContext: Handle provided by NDIS to track pending binding operations
+ * DeviceName: Name of the miniport device to bind to
+ * SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
+ * SystemSpecific2: Unused & must not be touched
+ */
+{
+ TI_DbgPrint(DEBUG_DATALINK, ("Called with registry path %wZ for %wZ\n", SystemSpecific1, DeviceName));
+ *Status = LANRegisterAdapter(DeviceName, SystemSpecific1);
+}
+
+
+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;
+ PCHAR Data, OldData;
+ UINT Size, OldSize;
+ PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context;
+ KIRQL OldIrql;
+ PNDIS_PACKET XmitPacket;
+ PIP_INTERFACE Interface = Adapter->Context;
+
+ TI_DbgPrint(DEBUG_DATALINK,
+ ("Called( NdisPacket %x, Offset %d, Adapter %x )\n",
+ NdisPacket, Offset, Adapter));
+
+ if (Adapter->State != LAN_STATE_STARTED) {
+ (*PC(NdisPacket)->DLComplete)(PC(NdisPacket)->Context, NdisPacket, NDIS_STATUS_NOT_ACCEPTED);
+ return;
+ }
+
+ TI_DbgPrint(DEBUG_DATALINK,
+ ("Adapter Address [%02x %02x %02x %02x %02x %02x]\n",
+ Adapter->HWAddress[0] & 0xff,
+ Adapter->HWAddress[1] & 0xff,
+ Adapter->HWAddress[2] & 0xff,
+ Adapter->HWAddress[3] & 0xff,
+ Adapter->HWAddress[4] & 0xff,
+ Adapter->HWAddress[5] & 0xff));
+
+ GetDataPtr( NdisPacket, 0, &OldData, &OldSize );
+
+ NdisStatus = AllocatePacketWithBuffer(&XmitPacket, NULL, OldSize + Adapter->HeaderSize);
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ (*PC(NdisPacket)->DLComplete)(PC(NdisPacket)->Context, NdisPacket, NDIS_STATUS_RESOURCES);
+ return;
+ }
+
+ GetDataPtr(XmitPacket, 0, &Data, &Size);
+
+ RtlCopyMemory(Data + Adapter->HeaderSize, OldData, OldSize);
+
+ (*PC(NdisPacket)->DLComplete)(PC(NdisPacket)->Context, NdisPacket, NDIS_STATUS_SUCCESS);
+
+ 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:
+ ASSERT(FALSE);
+ return;
+ }
+ break;
+
+ default:
+ /* FIXME: Support other medias */
+ break;
+ }
+
+ TI_DbgPrint( MID_TRACE, ("LinkAddress: %x\n", LinkAddress));
+ if( LinkAddress ) {
+ TI_DbgPrint
+ ( MID_TRACE,
+ ("Link Address [%02x %02x %02x %02x %02x %02x]\n",
+ ((PCHAR)LinkAddress)[0] & 0xff,
+ ((PCHAR)LinkAddress)[1] & 0xff,
+ ((PCHAR)LinkAddress)[2] & 0xff,
+ ((PCHAR)LinkAddress)[3] & 0xff,
+ ((PCHAR)LinkAddress)[4] & 0xff,
+ ((PCHAR)LinkAddress)[5] & 0xff));
+ }
+
+ if (Adapter->MTU < Size) {
+ /* This is NOT a pointer. MSDN explicitly says so. */
+ NDIS_PER_PACKET_INFO_FROM_PACKET(NdisPacket,
+ TcpLargeSendPacketInfo) = (PVOID)((ULONG_PTR)Adapter->MTU);
+ }
+
+ /* Update interface stats */
+ Interface->Stats.OutBytes += Size;
+
+ TcpipAcquireSpinLock( &Adapter->Lock, &OldIrql );
+ TI_DbgPrint(MID_TRACE, ("NdisSend\n"));
+ NdisSend(&NdisStatus, Adapter->NdisHandle, XmitPacket);
+ TI_DbgPrint(MID_TRACE, ("NdisSend %s\n",
+ NdisStatus == NDIS_STATUS_PENDING ?
+ "Pending" : "Complete"));
+ TcpipReleaseSpinLock( &Adapter->Lock, OldIrql );
+
+ /* I had a talk with vizzini: these really ought to be here.
+ * we're supposed to see these completed by ndis *only* when
+ * status_pending is returned. Note that this is different from
+ * the situation with IRPs. */
+ if (NdisStatus != NDIS_STATUS_PENDING)
+ ProtocolSendComplete((NDIS_HANDLE)Context, XmitPacket, NdisStatus);
+}
+
+static NTSTATUS
+OpenRegistryKey( PNDIS_STRING RegistryPath, PHANDLE RegHandle ) {
+ OBJECT_ATTRIBUTES Attributes;
+ NTSTATUS Status;
+
+ InitializeObjectAttributes(&Attributes, RegistryPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, 0);
+ Status = ZwOpenKey(RegHandle, KEY_ALL_ACCESS, &Attributes);
+ return Status;
+}
+
+static NTSTATUS ReadStringFromRegistry( HANDLE RegHandle,
+ PWCHAR RegistryValue,
+ PUNICODE_STRING String ) {
+ UNICODE_STRING ValueName;
+ UNICODE_STRING UnicodeString;
+ NTSTATUS Status;
+ ULONG ResultLength;
+ UCHAR buf[1024];
+ PKEY_VALUE_PARTIAL_INFORMATION Information = (PKEY_VALUE_PARTIAL_INFORMATION)buf;
+
+ RtlInitUnicodeString(&ValueName, RegistryValue);
+ Status =
+ ZwQueryValueKey(RegHandle,
+ &ValueName,
+ KeyValuePartialInformation,
+ Information,
+ sizeof(buf),
+ &ResultLength);
+
+ if (!NT_SUCCESS(Status))
+ return Status;
+ /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
+ TI_DbgPrint(MIN_TRACE, ("Information DataLength: 0x%x\n", Information->DataLength));
+
+ UnicodeString.Buffer = (PWCHAR)&Information->Data;
+ UnicodeString.Length = Information->DataLength - sizeof(WCHAR);
+ UnicodeString.MaximumLength = Information->DataLength;
+
+ String->Buffer =
+ (PWCHAR)ExAllocatePoolWithTag( NonPagedPool,
+ UnicodeString.MaximumLength + sizeof(WCHAR), REG_STR_TAG );
+
+ if( !String->Buffer ) return STATUS_NO_MEMORY;
+
+ String->MaximumLength = UnicodeString.MaximumLength;
+ RtlCopyUnicodeString( String, &UnicodeString );
+
+ return STATUS_SUCCESS;
+}
+
+/*
+ * Utility to copy and append two unicode strings.
+ *
+ * IN OUT PUNICODE_STRING ResultFirst -> First string and result
+ * IN PUNICODE_STRING Second -> Second string to append
+ * IN BOOL Deallocate -> TRUE: Deallocate First string before
+ * overwriting.
+ *
+ * Returns NTSTATUS.
+ */
+
+NTSTATUS NTAPI AppendUnicodeString(PUNICODE_STRING ResultFirst,
+ PUNICODE_STRING Second,
+ BOOLEAN Deallocate) {
+ NTSTATUS Status;
+ UNICODE_STRING Ustr = *ResultFirst;
+ PWSTR new_string = ExAllocatePoolWithTag
+ (PagedPool,
+ (ResultFirst->Length + Second->Length + sizeof(WCHAR)), TEMP_STRING_TAG);
+ if( !new_string ) {
+ return STATUS_NO_MEMORY;
+ }
+ memcpy( new_string, ResultFirst->Buffer, ResultFirst->Length );
+ memcpy( new_string + ResultFirst->Length / sizeof(WCHAR),
+ Second->Buffer, Second->Length );
+ if( Deallocate ) RtlFreeUnicodeString(ResultFirst);
+ ResultFirst->Length = Ustr.Length + Second->Length;
+ ResultFirst->MaximumLength = ResultFirst->Length;
+ new_string[ResultFirst->Length / sizeof(WCHAR)] = 0;
+ Status = RtlCreateUnicodeString(ResultFirst,new_string) ?
+ STATUS_SUCCESS : STATUS_NO_MEMORY;
+ ExFreePoolWithTag(new_string, TEMP_STRING_TAG);
+ return Status;
+}
+
+static NTSTATUS CheckForDeviceDesc( PUNICODE_STRING EnumKeyName,
+ PUNICODE_STRING TargetKeyName,
+ PUNICODE_STRING Name,
+ PUNICODE_STRING DeviceDesc ) {
+ UNICODE_STRING RootDevice = { 0, 0, NULL }, LinkageKeyName = { 0, 0, NULL };
+ UNICODE_STRING DescKeyName = { 0, 0, NULL }, Linkage = { 0, 0, NULL };
+ UNICODE_STRING BackSlash = { 0, 0, NULL };
+ HANDLE DescKey = NULL, LinkageKey = NULL;
+ NTSTATUS Status;
+
+ TI_DbgPrint(DEBUG_DATALINK,("EnumKeyName %wZ\n", EnumKeyName));
+
+ RtlInitUnicodeString(&BackSlash, L"\\");
+ RtlInitUnicodeString(&Linkage, L"\\Linkage");
+
+ RtlInitUnicodeString(&DescKeyName, L"");
+ AppendUnicodeString( &DescKeyName, EnumKeyName, FALSE );
+ AppendUnicodeString( &DescKeyName, &BackSlash, TRUE );
+ AppendUnicodeString( &DescKeyName, TargetKeyName, TRUE );
+
+ RtlInitUnicodeString(&LinkageKeyName, L"");
+ AppendUnicodeString( &LinkageKeyName, &DescKeyName, FALSE );
+ AppendUnicodeString( &LinkageKeyName, &Linkage, TRUE );
+
+ Status = OpenRegistryKey( &LinkageKeyName, &LinkageKey );
+ if( !NT_SUCCESS(Status) ) goto cleanup;
+
+ Status = ReadStringFromRegistry( LinkageKey, L"RootDevice", &RootDevice );
+ if( !NT_SUCCESS(Status) ) goto cleanup;
+
+ if( RtlCompareUnicodeString( &RootDevice, Name, TRUE ) == 0 ) {
+ Status = OpenRegistryKey( &DescKeyName, &DescKey );
+ if( !NT_SUCCESS(Status) ) goto cleanup;
+
+ Status = ReadStringFromRegistry( DescKey, L"DriverDesc", DeviceDesc );
+ if( !NT_SUCCESS(Status) ) goto cleanup;
+
+ TI_DbgPrint(DEBUG_DATALINK,("ADAPTER DESC: %wZ\n", DeviceDesc));
+ } else Status = STATUS_UNSUCCESSFUL;
+
+cleanup:
+ RtlFreeUnicodeString( &RootDevice );
+ RtlFreeUnicodeString( &LinkageKeyName );
+ RtlFreeUnicodeString( &DescKeyName );
+ if( LinkageKey ) ZwClose( LinkageKey );
+ if( DescKey ) ZwClose( DescKey );
+
+ TI_DbgPrint(DEBUG_DATALINK,("Returning %x\n", Status));
+
+ return Status;
+}
+
+static NTSTATUS FindDeviceDescForAdapter( PUNICODE_STRING Name,
+ PUNICODE_STRING DeviceDesc ) {
+ UNICODE_STRING EnumKeyName, TargetKeyName;
+ HANDLE EnumKey;
+ NTSTATUS Status;
+ ULONG i;
+ KEY_BASIC_INFORMATION *Kbio =
+ ExAllocatePoolWithTag(NonPagedPool, sizeof(KEY_BASIC_INFORMATION), KBIO_TAG);
+ ULONG KbioLength = sizeof(KEY_BASIC_INFORMATION), ResultLength;
+
+ RtlInitUnicodeString( DeviceDesc, NULL );
+
+ if( !Kbio ) return STATUS_INSUFFICIENT_RESOURCES;
+
+ RtlInitUnicodeString
+ (&EnumKeyName, CCS_ROOT L"\\Control\\Class\\" TCPIP_GUID);
+
+ Status = OpenRegistryKey( &EnumKeyName, &EnumKey );
+
+ if( !NT_SUCCESS(Status) ) {
+ TI_DbgPrint(DEBUG_DATALINK,("Couldn't open Enum key %wZ: %x\n",
+ &EnumKeyName, Status));
+ ExFreePoolWithTag( Kbio, KBIO_TAG );
+ return Status;
+ }
+
+ for( i = 0; NT_SUCCESS(Status); i++ ) {
+ Status = ZwEnumerateKey( EnumKey, i, KeyBasicInformation,
+ Kbio, KbioLength, &ResultLength );
+
+ if( Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW ) {
+ ExFreePoolWithTag( Kbio, KBIO_TAG );
+ KbioLength = ResultLength;
+ Kbio = ExAllocatePoolWithTag( NonPagedPool, KbioLength, KBIO_TAG );
+ if( !Kbio ) {
+ TI_DbgPrint(DEBUG_DATALINK,("Failed to allocate memory\n"));
+ ZwClose( EnumKey );
+ return STATUS_NO_MEMORY;
+ }
+
+ Status = ZwEnumerateKey( EnumKey, i, KeyBasicInformation,
+ Kbio, KbioLength, &ResultLength );
+
+ if( !NT_SUCCESS(Status) ) {
+ TI_DbgPrint(DEBUG_DATALINK,("Couldn't enum key child %d\n", i));
+ ZwClose( EnumKey );
+ ExFreePoolWithTag( Kbio, KBIO_TAG );
+ return Status;
+ }
+ }
+
+ if( NT_SUCCESS(Status) ) {
+ TargetKeyName.Length = TargetKeyName.MaximumLength =
+ Kbio->NameLength;
+ TargetKeyName.Buffer = Kbio->Name;
+
+ Status = CheckForDeviceDesc
+ ( &EnumKeyName, &TargetKeyName, Name, DeviceDesc );
+ if( NT_SUCCESS(Status) ) {
+ ZwClose( EnumKey );
+ ExFreePoolWithTag( Kbio, KBIO_TAG );
+ return Status;
+ } else Status = STATUS_SUCCESS;
+ }
+ }
+
+ ZwClose( EnumKey );
+ ExFreePoolWithTag( Kbio, KBIO_TAG );
+ return STATUS_UNSUCCESSFUL;
+}
+
+VOID GetName( PUNICODE_STRING RegistryKey,
+ PUNICODE_STRING OutName ) {
+ PWCHAR Ptr;
+ UNICODE_STRING PartialRegistryKey;
+
+ PartialRegistryKey.Buffer =
+ RegistryKey->Buffer + wcslen(CCS_ROOT L"\\Services\\");
+ Ptr = PartialRegistryKey.Buffer;
+
+ while( *Ptr != L'\\' &&
+ ((PCHAR)Ptr) < ((PCHAR)RegistryKey->Buffer) + RegistryKey->Length )
+ Ptr++;
+
+ PartialRegistryKey.Length = PartialRegistryKey.MaximumLength =
+ (Ptr - PartialRegistryKey.Buffer) * sizeof(WCHAR);
+
+ RtlInitUnicodeString( OutName, L"" );
+ AppendUnicodeString( OutName, &PartialRegistryKey, FALSE );
+}
+
+BOOLEAN BindAdapter(
+ PLAN_ADAPTER Adapter,
+ PNDIS_STRING RegistryPath)
+/*
+ * 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
+ */
+{
+ PIP_INTERFACE IF;
+ NDIS_STATUS NdisStatus;
+ LLIP_BIND_INFO BindInfo;
+ ULONG Lookahead = LOOKAHEAD_SIZE;
+ NTSTATUS Status;
+ NDIS_MEDIA_STATE MediaState;
+
+ TI_DbgPrint(DEBUG_DATALINK, ("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(DEBUG_DATALINK, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus));
+ return FALSE;
+ }
+
+ /* Bind the adapter to IP layer */
+ BindInfo.Context = Adapter;
+ BindInfo.HeaderSize = Adapter->HeaderSize;
+ BindInfo.MinFrameSize = Adapter->MinFrameSize;
+ BindInfo.Address = (PUCHAR)&Adapter->HWAddress;
+ BindInfo.AddressLength = Adapter->HWAddressLength;
+ BindInfo.Transmit = LANTransmit;
+
+ IF = IPCreateInterface(&BindInfo);
+
+ if (!IF) {
+ TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+ return FALSE;
+ }
+
+ /*
+ * Query per-adapter configuration from the registry
+ * In case anyone is curious: there *is* an Ndis configuration api
+ * for this sort of thing, but it doesn't really support things like
+ * REG_MULTI_SZ very well, and there is a note in the DDK that says that
+ * protocol drivers developed for win2k and above just use the native
+ * services (ZwOpenKey, etc).
+ */
+
+ GetName( RegistryPath, &IF->Name );
+
+ Status = FindDeviceDescForAdapter( &IF->Name, &IF->Description );
+ if (!NT_SUCCESS(Status)) {
+ TI_DbgPrint(MIN_TRACE, ("Failed to get device description.\n"));
+ IPDestroyInterface(IF);
+ return FALSE;
+ }
+
+ TI_DbgPrint(DEBUG_DATALINK,("Adapter Description: %wZ\n",
+ &IF->Description));
+
+ /* Get maximum link speed */
+ NdisStatus = NDISCall(Adapter,
+ NdisRequestQueryInformation,
+ OID_GEN_LINK_SPEED,
+ &IF->Speed,
+ sizeof(UINT));
+
+ if (!NT_SUCCESS(NdisStatus))
+ IF->Speed = IP_DEFAULT_LINK_SPEED;
+
+ Adapter->Speed = IF->Speed * 100L;
+
+ /* Get maximum frame size */
+ NdisStatus = NDISCall(Adapter,
+ NdisRequestQueryInformation,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ &Adapter->MTU,
+ sizeof(UINT));
+ if (NdisStatus != NDIS_STATUS_SUCCESS)
+ return FALSE;
+
+ IF->MTU = Adapter->MTU;
+
+ /* Get maximum packet size */
+ NdisStatus = NDISCall(Adapter,
+ NdisRequestQueryInformation,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ &Adapter->MaxPacketSize,
+ sizeof(UINT));
+ if (NdisStatus != NDIS_STATUS_SUCCESS)
+ return FALSE;
+
+ /* Register interface with IP layer */
+ IPRegisterInterface(IF);
+
+ /* Store adapter context */
+ Adapter->Context = IF;
+
+ /* Get the media state */
+ NdisStatus = NDISCall(Adapter,
+ NdisRequestQueryInformation,
+ OID_GEN_MEDIA_CONNECT_STATUS,
+ &MediaState,
+ sizeof(MediaState));
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ TI_DbgPrint(DEBUG_DATALINK, ("Could not query media status (0x%X).\n", NdisStatus));
+ IPUnregisterInterface(IF);
+ IPDestroyInterface(IF);
+ return FALSE;
+ }
+
+ /* Indicate the current media state */
+ ProtocolStatus(Adapter,
+ (MediaState == NdisMediaStateConnected) ? NDIS_STATUS_MEDIA_CONNECT : NDIS_STATUS_MEDIA_DISCONNECT,
+ NULL, 0);
+
+ /* 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(DEBUG_DATALINK, ("Could not set packet filter (0x%X).\n", NdisStatus));
+ IPUnregisterInterface(IF);
+ IPDestroyInterface(IF);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+VOID UnbindAdapter(
+ PLAN_ADAPTER Adapter)
+/*
+ * FUNCTION: Unbinds a LAN adapter from IP layer
+ * ARGUMENTS:
+ * Adapter = Pointer to LAN_ADAPTER structure
+ */
+{
+ TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+
+ if (Adapter->State == LAN_STATE_STARTED) {
+ PIP_INTERFACE IF = Adapter->Context;
+
+ IPUnregisterInterface(IF);
+
+ IPDestroyInterface(IF);
+ }
+}
+
+
+NDIS_STATUS LANRegisterAdapter(
+ PNDIS_STRING AdapterName,
+ PNDIS_STRING RegistryPath)
+/*
+ * 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;
+
+ TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+
+ IF = ExAllocatePoolWithTag(NonPagedPool, sizeof(LAN_ADAPTER), LAN_ADAPTER_TAG);
+ if (!IF) {
+ TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+ 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;
+
+ TI_DbgPrint(DEBUG_DATALINK,("opening adapter %wZ\n", AdapterName));
+ /* 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) {
+ TI_DbgPrint(DEBUG_DATALINK,("denying adapter %wZ\n", AdapterName));
+ ExFreePoolWithTag(IF, LAN_ADAPTER_TAG);
+ 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"));
+ ExFreePoolWithTag(IF, LAN_ADAPTER_TAG);
+ return NDIS_STATUS_NOT_SUPPORTED;
+ }
+
+ /* 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"));
+ ExFreePoolWithTag(IF, LAN_ADAPTER_TAG);
+ return NdisStatus;
+ }
+
+ /* Bind adapter to IP layer */
+ if( !BindAdapter(IF, RegistryPath) ) {
+ TI_DbgPrint(DEBUG_DATALINK,("denying adapter %wZ (BindAdapter)\n", AdapterName));
+ ExFreePoolWithTag(IF, LAN_ADAPTER_TAG);
+ return NDIS_STATUS_NOT_ACCEPTED;
+ }
+
+ /* Add adapter to the adapter list */
+ ExInterlockedInsertTailList(&AdapterListHead,
+ &IF->ListEntry,
+ &AdapterListLock);
+
+ TI_DbgPrint(DEBUG_DATALINK, ("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;
+ NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
+
+ TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+
+ /* Unlink the adapter from the list */
+ RemoveEntryList(&Adapter->ListEntry);
+
+ /* Unbind adapter from IP layer */
+ UnbindAdapter(Adapter);
+
+ TcpipAcquireSpinLock(&Adapter->Lock, &OldIrql);
+ NdisHandle = Adapter->NdisHandle;
+ if (NdisHandle) {
+ Adapter->NdisHandle = NULL;
+ TcpipReleaseSpinLock(&Adapter->Lock, OldIrql);
+
+ NdisCloseAdapter(&NdisStatus, NdisHandle);
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+ TcpipWaitForSingleObject(&Adapter->Event,
+ UserRequest,
+ KernelMode,
+ FALSE,
+ NULL);
+ NdisStatus = Adapter->NdisStatus;
+ }
+ } else
+ TcpipReleaseSpinLock(&Adapter->Lock, OldIrql);
+
+ FreeAdapter(Adapter);
+
+ return NdisStatus;
+}
+
+VOID
+NTAPI
+LANUnregisterProtocol(VOID)
+/*
+ * FUNCTION: Unregisters this protocol driver with NDIS
+ * NOTES: Does not care wether we are already registered
+ */
+{
+ TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+
+ if (ProtocolRegistered) {
+ NDIS_STATUS NdisStatus;
+ PLIST_ENTRY CurrentEntry;
+ PLIST_ENTRY NextEntry;
+ PLAN_ADAPTER Current;
+ KIRQL OldIrql;
+
+ TcpipAcquireSpinLock(&AdapterListLock, &OldIrql);
+
+ /* Search the list and remove every adapter we find */
+ CurrentEntry = AdapterListHead.Flink;
+ while (CurrentEntry != &AdapterListHead) {
+ NextEntry = CurrentEntry->Flink;
+ Current = CONTAINING_RECORD(CurrentEntry, LAN_ADAPTER, ListEntry);
+ /* Unregister it */
+ LANUnregisterAdapter(Current);
+ CurrentEntry = NextEntry;
+ }
+
+ TcpipReleaseSpinLock(&AdapterListLock, OldIrql);
+
+ NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle);
+ ProtocolRegistered = FALSE;
+ }
+}
+
+VOID
+NTAPI
+ProtocolUnbindAdapter(
+ PNDIS_STATUS Status,
+ NDIS_HANDLE ProtocolBindingContext,
+ NDIS_HANDLE UnbindContext)
+{
+ /* We don't pend any unbinding so we can just ignore UnbindContext */
+ *Status = LANUnregisterAdapter((PLAN_ADAPTER)ProtocolBindingContext);
+}
+
+NTSTATUS LANRegisterProtocol(
+ PNDIS_STRING 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;
+
+ TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+
+ InitializeListHead(&AdapterListHead);
+ KeInitializeSpinLock(&AdapterListLock);
+
+ /* 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 = Name->Buffer;
+ ProtChars.Name.MaximumLength = Name->MaximumLength;
+ ProtChars.OpenAdapterCompleteHandler = ProtocolOpenAdapterComplete;
+ ProtChars.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete;
+ ProtChars.ResetCompleteHandler = ProtocolResetComplete;
+ ProtChars.RequestCompleteHandler = ProtocolRequestComplete;
+ ProtChars.SendCompleteHandler = ProtocolSendComplete;
+ ProtChars.TransferDataCompleteHandler = ProtocolTransferDataComplete;
+ ProtChars.ReceivePacketHandler = ProtocolReceivePacket;
+ ProtChars.ReceiveHandler = ProtocolReceive;
+ ProtChars.ReceiveCompleteHandler = ProtocolReceiveComplete;
+ ProtChars.StatusHandler = ProtocolStatus;
+ ProtChars.StatusCompleteHandler = ProtocolStatusComplete;
+ ProtChars.BindAdapterHandler = ProtocolBindAdapter;
+ ProtChars.PnPEventHandler = ProtocolPnPEvent;
+ ProtChars.UnbindAdapterHandler = ProtocolUnbindAdapter;
+ ProtChars.UnloadHandler = LANUnregisterProtocol;
+
+ /* Try to register protocol */
+ NdisRegisterProtocol(&NdisStatus,
+ &NdisProtocolHandle,
+ &ProtChars,
+ sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
+ if (NdisStatus != NDIS_STATUS_SUCCESS)
+ {
+ TI_DbgPrint(DEBUG_DATALINK, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus));
+ return (NTSTATUS)NdisStatus;
+ }
+
+ ProtocolRegistered = TRUE;
+
+ return STATUS_SUCCESS;
+}
+
+/* EOF */