[TCPIP]
[reactos.git] / reactos / drivers / network / tcpip / datalink / lan.c
index 890330e..90c730e 100644 (file)
 
 UINT TransferDataCalled = 0;
 UINT TransferDataCompleteCalled = 0;
-UINT LanReceiveWorkerCalled = 0;
-BOOLEAN LanReceiveWorkerBusy = FALSE;
 
 #define CCS_ROOT L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet"
 #define TCPIP_GUID L"{4D36E972-E325-11CE-BFC1-08002BE10318}"
 
-#define NGFP(_Packet)                                             \
-    {                                                             \
-        PVOID _Header;                                            \
-        ULONG _ContigSize, _TotalSize;                            \
-        PNDIS_BUFFER _NdisBuffer;                                 \
-                                                                  \
-        TI_DbgPrint(MID_TRACE,("Checking Packet %x\n", _Packet)); \
-       NdisGetFirstBufferFromPacket(_Packet,                     \
-                                    &_NdisBuffer,                \
-                                    &_Header,                    \
-                                    &_ContigSize,                \
-                                    &_TotalSize);                \
-        TI_DbgPrint(MID_TRACE,("NdisBuffer: %x\n", _NdisBuffer)); \
-        TI_DbgPrint(MID_TRACE,("Header    : %x\n", _Header));     \
-        TI_DbgPrint(MID_TRACE,("ContigSize: %x\n", _ContigSize)); \
-        TI_DbgPrint(MID_TRACE,("TotalSize : %x\n", _TotalSize));  \
-    }
-
 typedef struct _LAN_WQ_ITEM {
     LIST_ENTRY ListEntry;
     PNDIS_PACKET Packet;
     PLAN_ADAPTER Adapter;
     UINT BytesTransferred;
+    BOOLEAN LegacyReceive;
 } LAN_WQ_ITEM, *PLAN_WQ_ITEM;
 
 NDIS_HANDLE NdisProtocolHandle = (NDIS_HANDLE)NULL;
@@ -99,6 +80,83 @@ NDIS_STATUS NDISCall(
     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 destinguished by
+               looking at the IEEE 802.3 length field. This field is
+               less than or equal to 1500 for a valid IEEE 802.3 frame
+               and larger than 1500 is it's a valid EtherType value.
+               See RFC 1122, section 2.3.3 for more information */
+
+            *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 = ExAllocatePool(NonPagedPool,
+                                  Adapter->HeaderSize);
+    if (!HeaderBuffer)
+        return NDIS_STATUS_RESOURCES;
+    
+    /* Copy the media header */
+    BytesCopied = CopyPacketToBuffer(HeaderBuffer,
+                                     NdisPacket,
+                                     0,
+                                     Adapter->HeaderSize);
+    if (BytesCopied != Adapter->HeaderSize)
+    {
+        /* Runt frame */
+        ExFreePool(HeaderBuffer);
+        TI_DbgPrint(DEBUG_DATALINK, ("Runt frame (size %d).\n", BytesCopied));
+        return NDIS_STATUS_NOT_ACCEPTED;
+    }
+
+    Status = GetPacketTypeFromHeaderBuffer(Adapter,
+                                           HeaderBuffer,
+                                           BytesCopied,
+                                           PacketType);
+    
+    ExFreePool(HeaderBuffer);
+    
+    return Status;
+}
+
 
 VOID FreeAdapter(
     PLAN_ADAPTER Adapter)
@@ -235,71 +293,90 @@ VOID NTAPI ProtocolSendComplete(
 }
 
 VOID LanReceiveWorker( PVOID Context ) {
-    UINT PacketType;
+    ULONG PacketType;
     PLAN_WQ_ITEM WorkItem = (PLAN_WQ_ITEM)Context;
     PNDIS_PACKET Packet;
     PLAN_ADAPTER Adapter;
     UINT BytesTransferred;
-    PNDIS_BUFFER NdisBuffer;
     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;
 
-    NdisGetFirstBufferFromPacket(Packet,
-                                &NdisBuffer,
-                                &IPPacket.Header,
-                                &IPPacket.ContigSize,
-                                &IPPacket.TotalSize);
+    if (LegacyReceive)
+    {
+        /* Packet type is precomputed */
+        PacketType = PC(IPPacket.NdisPacket)->PacketType;
+
+        /* Data is at position 0 */
+        IPPacket.Position = 0;
 
-    IPPacket.ContigSize = IPPacket.TotalSize = BytesTransferred;
-    /* Determine which upper layer protocol that should receive
-       this packet and pass it to the correct receive handler */
+        /* 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;
+        }
 
-    TI_DbgPrint(MID_TRACE,
-               ("ContigSize: %d, TotalSize: %d, BytesTransferred: %d\n",
-                IPPacket.ContigSize, IPPacket.TotalSize,
-                BytesTransferred));
+        /* Data is at the end of the media header */
+        IPPacket.Position = Adapter->HeaderSize;
 
-    PacketType = PC(IPPacket.NdisPacket)->PacketType;
-    IPPacket.Position = 0;
+        /* Calculate packet size (excluding media header) */
+        NdisQueryPacketLength(IPPacket.NdisPacket, &IPPacket.TotalSize);
+    }
 
     TI_DbgPrint
        (DEBUG_DATALINK,
-        ("Ether Type = %x ContigSize = %d Total = %d\n",
-         PacketType, IPPacket.ContigSize, IPPacket.TotalSize));
+        ("Ether Type = %x Total = %d\n",
+         PacketType, IPPacket.TotalSize));
+
+    Interface->Stats.InBytes += IPPacket.TotalSize;
 
+    /* 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);
-    default:
-        IPPacket.Free(&IPPacket);
-       break;
+        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;
     }
-
-    FreeNdisPacket( Packet );
 }
 
 VOID LanSubmitReceiveWork(
     NDIS_HANDLE BindingContext,
     PNDIS_PACKET Packet,
-    NDIS_STATUS Status,
-    UINT BytesTransferred) {
+    UINT BytesTransferred,
+    BOOLEAN LegacyReceive) {
     PLAN_WQ_ITEM WQItem = ExAllocatePoolWithTag(NonPagedPool, sizeof(LAN_WQ_ITEM),
                                                 WQ_CONTEXT_TAG);
     PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
@@ -311,6 +388,7 @@ VOID LanSubmitReceiveWork(
     WQItem->Packet = Packet;
     WQItem->Adapter = Adapter;
     WQItem->BytesTransferred = BytesTransferred;
+    WQItem->LegacyReceive = LegacyReceive;
 
     if (!ChewCreate( LanReceiveWorker, WQItem ))
         ExFreePoolWithTag(WQItem, WQ_CONTEXT_TAG);
@@ -342,7 +420,30 @@ VOID NTAPI ProtocolTransferDataComplete(
 
     if( Status != NDIS_STATUS_SUCCESS ) return;
 
-    LanSubmitReceiveWork( BindingContext, Packet, Status, BytesTransferred );
+    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(
@@ -367,15 +468,12 @@ NDIS_STATUS NTAPI ProtocolReceive(
  *     Status of operation
  */
 {
-    USHORT EType;
-    UINT PacketType, BytesTransferred;
-    UINT temp;
-    IP_PACKET IPPacket;
+    ULONG PacketType;
+    UINT BytesTransferred;
     PCHAR BufferData;
     NDIS_STATUS NdisStatus;
     PNDIS_PACKET NdisPacket;
     PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
-    PETH_HEADER EHeader  = (PETH_HEADER)HeaderBuffer;
 
     TI_DbgPrint(DEBUG_DATALINK, ("Called. (packetsize %d)\n",PacketSize));
 
@@ -389,30 +487,17 @@ NDIS_STATUS NTAPI ProtocolReceive(
         return NDIS_STATUS_NOT_ACCEPTED;
     }
 
-    if (Adapter->Media == NdisMedium802_3) {
-        /* Ethernet and IEEE 802.3 frames can be destinguished by
-           looking at the IEEE 802.3 length field. This field is
-           less than or equal to 1500 for a valid IEEE 802.3 frame
-           and larger than 1500 is it's a valid EtherType value.
-           See RFC 1122, section 2.3.3 for more information */
-        /* FIXME: Test for Ethernet and IEEE 802.3 frame */
-        if (((EType = EHeader->EType) != ETYPE_IPv4) && (EType != ETYPE_ARP)) {
-            TI_DbgPrint(DEBUG_DATALINK, ("Not IP or ARP frame. EtherType (0x%X).\n", EType));
-            return NDIS_STATUS_NOT_ACCEPTED;
-        }
-        /* We use EtherType constants to destinguish packet types */
-        PacketType = EType;
-    } else {
-        TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
-        /* FIXME: Support other medias */
+    NdisStatus = GetPacketTypeFromHeaderBuffer(Adapter,
+                                               HeaderBuffer,
+                                               HeaderBufferSize,
+                                               &PacketType);
+    if (NdisStatus != NDIS_STATUS_SUCCESS)
         return NDIS_STATUS_NOT_ACCEPTED;
-    }
-
-    /* Get a transfer data packet */
 
     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 ) {
@@ -423,10 +508,7 @@ NDIS_STATUS NTAPI ProtocolReceive(
 
     TI_DbgPrint(DEBUG_DATALINK, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize,PacketSize));
 
-    GetDataPtr( NdisPacket, 0, &BufferData, &temp );
-
-    IPPacket.NdisPacket = NdisPacket;
-    IPPacket.Position = 0;
+    GetDataPtr( NdisPacket, 0, &BufferData, &PacketSize );
 
     TransferDataCalled++;
 
@@ -569,9 +651,7 @@ VOID NTAPI ProtocolBindAdapter(
  *     SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
  *     SystemSpecific2: Unused & must not be touched
  */
-{
-    /* XXX confirm that this is still true, or re-word the following comment */
-    /* we get to ignore BindContext because we will never pend an operation with NDIS */
+{    
     TI_DbgPrint(DEBUG_DATALINK, ("Called with registry path %wZ for %wZ\n", SystemSpecific1, DeviceName));
     *Status = LANRegisterAdapter(DeviceName, SystemSpecific1);
 }
@@ -946,9 +1026,21 @@ BOOLEAN BindAdapter(
     PIP_INTERFACE IF;
     NDIS_STATUS NdisStatus;
     LLIP_BIND_INFO BindInfo;
-    IP_ADDRESS DefaultMask;
-    ULONG Lookahead = LOOKAHEAD_SIZE;
+    IP_ADDRESS DefaultMask, Router;
+    ULONG Lookahead = LOOKAHEAD_SIZE, Unused;
     NTSTATUS Status;
+    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;
 
     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
 
@@ -1000,11 +1092,129 @@ BOOLEAN BindAdapter(
 
     TI_DbgPrint(DEBUG_DATALINK,("Adapter Description: %wZ\n",
                 &IF->Description));
+    
+    TcpipRegistryPath.MaximumLength = sizeof(WCHAR) * 150;
+    TcpipRegistryPath.Length = 0;
+    TcpipRegistryPath.Buffer = Buffer;
+    
+    RtlAppendUnicodeStringToString(&TcpipRegistryPath,
+                                   &Prefix);
+    
+    RtlAppendUnicodeStringToString(&TcpipRegistryPath,
+                                   &IF->Name);
+
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &TcpipRegistryPath,
+                               OBJ_CASE_INSENSITIVE,
+                               0,
+                               NULL);
 
     AddrInitIPv4(&DefaultMask, 0);
 
-    IF->Unicast = DefaultMask;
-    IF->Netmask = DefaultMask;
+    Status = ZwOpenKey(&ParameterHandle, KEY_READ, &ObjectAttributes);
+
+    if (!NT_SUCCESS(Status))
+    {
+        IF->Unicast = DefaultMask;
+        IF->Netmask = DefaultMask;
+    }
+    else
+    {
+        KeyValueInfo = ExAllocatePool(PagedPool, sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 16 * sizeof(WCHAR));
+        if (!KeyValueInfo)
+        {
+            ZwClose(ParameterHandle);
+            IPDestroyInterface(IF);
+            return FALSE;
+        }
+
+        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;
+
+            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(&IF->Unicast, inet_addr(RegistryDataA.Buffer));
+
+                RtlFreeAnsiString(&RegistryDataA);
+
+            }
+            else
+            {
+                IF->Unicast = DefaultMask;
+            }
+
+            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(&IF->Netmask, inet_addr(RegistryDataA.Buffer));
+
+                RtlFreeAnsiString(&RegistryDataA);
+            }
+            else
+            {
+                IF->Netmask = DefaultMask;
+            }
+
+            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));
+
+                RtlFreeAnsiString(&RegistryDataA);
+
+                if (!AddrIsUnspecified(&Router)) RouterCreateRoute(&DefaultMask, &DefaultMask, &Router, IF, 1);
+            }
+        }
+        else
+        {
+            IF->Unicast = DefaultMask;
+            IF->Netmask = DefaultMask;
+        }
+
+        ZwClose(ParameterHandle);
+    }
 
     IF->Broadcast.Type = IP_ADDRESS_V4;
     IF->Broadcast.Address.IPv4Address =
@@ -1358,6 +1568,7 @@ NTSTATUS LANRegisterProtocol(
     ProtChars.RequestCompleteHandler         = ProtocolRequestComplete;
     ProtChars.SendCompleteHandler            = ProtocolSendComplete;
     ProtChars.TransferDataCompleteHandler    = ProtocolTransferDataComplete;
+    ProtChars.ReceivePacketHandler           = ProtocolReceivePacket;
     ProtChars.ReceiveHandler                 = ProtocolReceive;
     ProtChars.ReceiveCompleteHandler         = ProtocolReceiveComplete;
     ProtChars.StatusHandler                  = ProtocolStatus;