Added networking code from Casper Hornstrup
[reactos.git] / reactos / drivers / net / tcpip / datalink / arp.c
index 83d2490..6121918 100644 (file)
-/*\r
- * COPYRIGHT:   See COPYING in the top level directory\r
- * PROJECT:     ReactOS TCP/IP protocol driver\r
- * FILE:        datalink/arp.c\r
- * PURPOSE:     Address Resolution Protocol 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 <arp.h>\r
-#include <routines.h>\r
-#include <neighbor.h>\r
-#include <address.h>\r
-#include <pool.h>\r
-#include <lan.h>\r
-\r
-\r
-PNDIS_PACKET PrepareARPPacket(\r
-    USHORT HardwareType,\r
-    USHORT ProtocolType,\r
-    UCHAR LinkAddressLength,\r
-    UCHAR ProtoAddressLength,\r
-    PVOID SenderLinkAddress,\r
-    PVOID SenderProtoAddress,\r
-    PVOID TargetLinkAddress,\r
-    PVOID TargetProtoAddress,\r
-    USHORT Opcode)\r
-/*\r
- * FUNCTION: Prepares an ARP packet\r
- * ARGUMENTS:\r
- *     HardwareType       = Hardware type (in network byte order)\r
- *     ProtocolType       = Protocol type (in network byte order)\r
- *     LinkAddressLength  = Length of link address fields\r
- *     ProtoAddressLength = Length of protocol address fields\r
- *     SenderLinkAddress  = Sender's link address\r
- *     SenderProtoAddress = Sender's protocol address\r
- *     TargetLinkAddress  = Target's link address (NULL if don't care)\r
- *     TargetProtoAddress = Target's protocol address\r
- *     Opcode             = ARP opcode (in network byte order)\r
- * RETURNS:\r
- *     Pointer to NDIS packet, NULL if there is not enough free resources\r
- */\r
-{\r
-    PNDIS_PACKET NdisPacket;\r
-    PNDIS_BUFFER NdisBuffer;\r
-    NDIS_STATUS NdisStatus;\r
-    PARP_HEADER Header;\r
-    PVOID DataBuffer;\r
-    ULONG Size;\r
-\r
-    TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
-\r
-    /* Prepare ARP packet */\r
-    Size = MaxLLHeaderSize + sizeof(ARP_HEADER) + \r
-        2 * LinkAddressLength + /* Hardware address length */\r
-        2 * ProtoAddressLength; /* Protocol address length */\r
-    Size = MAX(Size, MinLLFrameSize);\r
-\r
-    DataBuffer = ExAllocatePool(NonPagedPool, Size);\r
-    if (!DataBuffer)\r
-        return NULL;\r
-\r
-    /* Allocate NDIS packet */\r
-    NdisAllocatePacket(&NdisStatus, &NdisPacket, GlobalPacketPool);\r
-    if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
-        ExFreePool(DataBuffer);\r
-        return NULL;\r
-    }\r
-\r
-    /* Allocate NDIS buffer for maximum link level header and ARP packet */\r
-    NdisAllocateBuffer(&NdisStatus, &NdisBuffer, GlobalBufferPool,\r
-        DataBuffer, Size);\r
-    if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
-        NdisFreePacket(NdisPacket);\r
-        ExFreePool(DataBuffer);\r
-        return NULL;\r
-    }\r
-\r
-    /* Link NDIS buffer into packet */\r
-    NdisChainBufferAtFront(NdisPacket, NdisBuffer);\r
-    RtlZeroMemory(DataBuffer, Size);\r
-    Header = (PARP_HEADER)((ULONG_PTR)DataBuffer + MaxLLHeaderSize);\r
-    Header->HWType       = HardwareType;\r
-    Header->ProtoType    = ProtocolType;\r
-    Header->HWAddrLen    = LinkAddressLength;\r
-    Header->ProtoAddrLen = ProtoAddressLength;\r
-    Header->Opcode       = Opcode; /* Already swapped */\r
-    DataBuffer = (PVOID)((ULONG_PTR)Header + sizeof(ARP_HEADER));\r
-\r
-    /* Our hardware address */\r
-    RtlCopyMemory(DataBuffer, SenderLinkAddress, LinkAddressLength);\r
-    (ULONG_PTR)DataBuffer += LinkAddressLength;\r
-\r
-    /* Our protocol address */\r
-    RtlCopyMemory(DataBuffer, SenderProtoAddress, ProtoAddressLength);\r
-\r
-    if (TargetLinkAddress) {\r
-        (ULONG_PTR)DataBuffer += ProtoAddressLength;\r
-        /* Target hardware address */\r
-        RtlCopyMemory(DataBuffer, TargetLinkAddress, LinkAddressLength);\r
-        (ULONG_PTR)DataBuffer += LinkAddressLength;\r
-    } else\r
-        /* Don't care about target hardware address */\r
-        (ULONG_PTR)DataBuffer += (ProtoAddressLength + LinkAddressLength);\r
-\r
-    /* Target protocol address */\r
-    RtlCopyMemory(DataBuffer, TargetProtoAddress, ProtoAddressLength);\r
-\r
-    return NdisPacket;\r
-}\r
-\r
-\r
-VOID ARPTransmitComplete(\r
-    PVOID Context,\r
-    PNDIS_PACKET NdisPacket,\r
-    NDIS_STATUS NdisStatus)\r
-/*\r
- * FUNCTION: ARP request transmit completion handler\r
- * ARGUMENTS:\r
- *     Context    = Pointer to context information (IP_INTERFACE)\r
- *     Packet     = Pointer to NDIS packet that was sent\r
- *     NdisStatus = NDIS status of operation\r
- * NOTES:\r
- *    This routine is called when an ARP request has been sent\r
- */\r
-{\r
-    TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
-\r
-    FreeNdisPacket(NdisPacket);\r
-}\r
-\r
-\r
-BOOLEAN ARPTransmit(\r
-    PIP_ADDRESS Address,\r
-    PNET_TABLE_ENTRY NTE)\r
-/*\r
- * FUNCTION: Creates an ARP request and transmits it on a network\r
- * ARGUMENTS:\r
- *     Address = Pointer to IP address to resolve\r
- *     NTE     = Pointer to net table entru to use for transmitting request\r
- * RETURNS:\r
- *     TRUE if the request was successfully sent, FALSE if not\r
- */\r
-{\r
-    PIP_INTERFACE Interface;\r
-    PNDIS_PACKET NdisPacket;\r
-    UCHAR ProtoAddrLen;\r
-    USHORT ProtoType;\r
-\r
-    TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
-\r
-    Interface = NTE->Interface;\r
-\r
-    switch (Address->Type) {\r
-        case IP_ADDRESS_V4:\r
-            ProtoType    = (USHORT)ETYPE_IPv4; /* IPv4 */\r
-            ProtoAddrLen = 4;                  /* Length of IPv4 address */\r
-            break;\r
-        case IP_ADDRESS_V6:\r
-            ProtoType    = (USHORT)ETYPE_IPv6; /* IPv6 */\r
-            ProtoAddrLen = 16;                 /* Length of IPv6 address */\r
-            break;\r
-        default:\r
-            /* Should not happen */\r
-            return FALSE;\r
-    }\r
-\r
-    NdisPacket = PrepareARPPacket(\r
-        WN2H(0x0001),                    /* FIXME: Ethernet only */\r
-        ProtoType,                       /* Protocol type */\r
-        (UCHAR)Interface->AddressLength, /* Hardware address length */\r
-        (UCHAR)ProtoAddrLen,             /* Protocol address length */\r
-        Interface->Address,              /* Sender's (local) hardware address */\r
-        &NTE->Address->Address,          /* Sender's (local) protocol address */\r
-        NULL,                            /* Don't care */\r
-        &Address->Address,               /* Target's (remote) protocol address */\r
-        ARP_OPCODE_REQUEST);             /* ARP request */\r
-\r
-    PC(NdisPacket)->DLComplete = ARPTransmitComplete;\r
-\r
-    (*Interface->Transmit)(Interface->Context, NdisPacket,\r
-        MaxLLHeaderSize, NULL, LAN_PROTO_ARP);\r
-\r
-    return TRUE;\r
-}\r
-\r
-\r
-VOID ARPReceive(\r
-    PVOID Context,\r
-    PIP_PACKET Packet)\r
-/*\r
- * FUNCTION: Receives an ARP packet\r
- * ARGUMENTS:\r
- *     Context = Pointer to context information (IP_INTERFACE)\r
- *     Packet  = Pointer to packet\r
- */\r
-{\r
-    PARP_HEADER Header;\r
-    PIP_ADDRESS Address;\r
-    PVOID SenderHWAddress;\r
-    PVOID SenderProtoAddress;\r
-    PVOID TargetProtoAddress;\r
-    PADDRESS_ENTRY ADE;\r
-    PNEIGHBOR_CACHE_ENTRY NCE;\r
-    PNDIS_PACKET NdisPacket;\r
-    PIP_INTERFACE Interface = (PIP_INTERFACE)Context;\r
-\r
-    TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
-\r
-    Header = (PARP_HEADER)Packet->Header;\r
-\r
-    /* FIXME: Ethernet only */\r
-    if (WN2H(Header->HWType) != 1)\r
-        return;\r
-\r
-    /* Check protocol type */\r
-    if (Header->ProtoType != ETYPE_IPv4)\r
-        return;\r
-\r
-    SenderHWAddress    = (PVOID)((ULONG_PTR)Header + sizeof(ARP_HEADER));\r
-    SenderProtoAddress = (PVOID)((ULONG_PTR)SenderHWAddress + Header->HWAddrLen);\r
-\r
-    /* Check if we have the target protocol address */\r
-\r
-    TargetProtoAddress = (PVOID)((ULONG_PTR)SenderProtoAddress +\r
-        Header->ProtoAddrLen + Header->HWAddrLen);\r
-\r
-    Address = AddrBuildIPv4(*(PULONG)(TargetProtoAddress));\r
-    ADE = IPLocateADE(Address, ADE_UNICAST);\r
-    if (!ADE) {\r
-        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
-        return;\r
-    }\r
-\r
-    /* Check if we know the sender */\r
-\r
-    AddrInitIPv4(Address, *(PULONG)(SenderProtoAddress));\r
-    NCE = NBLocateNeighbor(Address);\r
-    if (NCE) {\r
-        DereferenceObject(Address);\r
-        /* We know the sender. Update the hardware address \r
-           and state in our neighbor address cache */\r
-        NBUpdateNeighbor(NCE, SenderHWAddress, NUD_REACHABLE);\r
-    } else {\r
-        /* The packet had our protocol address as target. The sender\r
-           may want to communicate with us soon, so add his address\r
-           to our address cache */\r
-        NCE = NBAddNeighbor(Interface, Address, SenderHWAddress,\r
-            Header->HWAddrLen, NUD_REACHABLE);\r
-    }\r
-    if (NCE)\r
-        DereferenceObject(NCE)\r
-\r
-    if (Header->Opcode != ARP_OPCODE_REQUEST)\r
-        return;\r
-    \r
-    /* This is a request for our address. Swap the addresses and\r
-       send an ARP reply back to the sender */\r
-    NdisPacket = PrepareARPPacket(\r
-        Header->HWType,                  /* Hardware type */\r
-        Header->ProtoType,               /* Protocol type */\r
-        (UCHAR)Interface->AddressLength, /* Hardware address length */\r
-        (UCHAR)Header->ProtoAddrLen,     /* Protocol address length */\r
-        Interface->Address,              /* Sender's (local) hardware address */\r
-        &ADE->Address->Address,          /* Sender's (local) protocol address */\r
-        SenderHWAddress,                 /* Target's (remote) hardware address */\r
-        SenderProtoAddress,              /* Target's (remote) protocol address */\r
-        ARP_OPCODE_REPLY);               /* ARP reply */\r
-    if (NdisPacket) {\r
-        PC(NdisPacket)->DLComplete = ARPTransmitComplete;\r
-        (*Interface->Transmit)(Interface->Context, NdisPacket,\r
-            MaxLLHeaderSize, SenderHWAddress, LAN_PROTO_ARP);\r
-    }\r
-}\r
-\r
-/* EOF */\r
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        datalink/arp.c
+ * PURPOSE:     Address Resolution Protocol routines
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ *   CSH 01/08-2000 Created
+ */
+#include <tcpip.h>
+#include <arp.h>
+#include <routines.h>
+#include <neighbor.h>
+#include <address.h>
+#include <pool.h>
+#include <lan.h>
+
+
+PNDIS_PACKET PrepareARPPacket(
+    USHORT HardwareType,
+    USHORT ProtocolType,
+    UCHAR LinkAddressLength,
+    UCHAR ProtoAddressLength,
+    PVOID SenderLinkAddress,
+    PVOID SenderProtoAddress,
+    PVOID TargetLinkAddress,
+    PVOID TargetProtoAddress,
+    USHORT Opcode)
+/*
+ * FUNCTION: Prepares an ARP packet
+ * ARGUMENTS:
+ *     HardwareType       = Hardware type (in network byte order)
+ *     ProtocolType       = Protocol type (in network byte order)
+ *     LinkAddressLength  = Length of link address fields
+ *     ProtoAddressLength = Length of protocol address fields
+ *     SenderLinkAddress  = Sender's link address
+ *     SenderProtoAddress = Sender's protocol address
+ *     TargetLinkAddress  = Target's link address (NULL if don't care)
+ *     TargetProtoAddress = Target's protocol address
+ *     Opcode             = ARP opcode (in network byte order)
+ * RETURNS:
+ *     Pointer to NDIS packet, NULL if there is not enough free resources
+ */
+{
+    PNDIS_PACKET NdisPacket;
+    PNDIS_BUFFER NdisBuffer;
+    NDIS_STATUS NdisStatus;
+    PARP_HEADER Header;
+    PVOID DataBuffer;
+    ULONG Size;
+
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+    /* Prepare ARP packet */
+    Size = MaxLLHeaderSize + sizeof(ARP_HEADER) + 
+        2 * LinkAddressLength + /* Hardware address length */
+        2 * ProtoAddressLength; /* Protocol address length */
+    Size = MAX(Size, MinLLFrameSize);
+
+    DataBuffer = ExAllocatePool(NonPagedPool, Size);
+    if (!DataBuffer)
+        return NULL;
+
+    /* Allocate NDIS packet */
+    NdisAllocatePacket(&NdisStatus, &NdisPacket, GlobalPacketPool);
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        ExFreePool(DataBuffer);
+        return NULL;
+    }
+
+    /* Allocate NDIS buffer for maximum link level header and ARP packet */
+    NdisAllocateBuffer(&NdisStatus, &NdisBuffer, GlobalBufferPool,
+        DataBuffer, Size);
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        NdisFreePacket(NdisPacket);
+        ExFreePool(DataBuffer);
+        return NULL;
+    }
+
+    /* Link NDIS buffer into packet */
+    NdisChainBufferAtFront(NdisPacket, NdisBuffer);
+    RtlZeroMemory(DataBuffer, Size);
+    Header = (PARP_HEADER)((ULONG_PTR)DataBuffer + MaxLLHeaderSize);
+    Header->HWType       = HardwareType;
+    Header->ProtoType    = ProtocolType;
+    Header->HWAddrLen    = LinkAddressLength;
+    Header->ProtoAddrLen = ProtoAddressLength;
+    Header->Opcode       = Opcode; /* Already swapped */
+    DataBuffer = (PVOID)((ULONG_PTR)Header + sizeof(ARP_HEADER));
+
+    /* Our hardware address */
+    RtlCopyMemory(DataBuffer, SenderLinkAddress, LinkAddressLength);
+    (ULONG_PTR)DataBuffer += LinkAddressLength;
+
+    /* Our protocol address */
+    RtlCopyMemory(DataBuffer, SenderProtoAddress, ProtoAddressLength);
+
+    if (TargetLinkAddress) {
+        (ULONG_PTR)DataBuffer += ProtoAddressLength;
+        /* Target hardware address */
+        RtlCopyMemory(DataBuffer, TargetLinkAddress, LinkAddressLength);
+        (ULONG_PTR)DataBuffer += LinkAddressLength;
+    } else
+        /* Don't care about target hardware address */
+        (ULONG_PTR)DataBuffer += (ProtoAddressLength + LinkAddressLength);
+
+    /* Target protocol address */
+    RtlCopyMemory(DataBuffer, TargetProtoAddress, ProtoAddressLength);
+
+    return NdisPacket;
+}
+
+
+VOID ARPTransmitComplete(
+    PVOID Context,
+    PNDIS_PACKET NdisPacket,
+    NDIS_STATUS NdisStatus)
+/*
+ * FUNCTION: ARP request transmit completion handler
+ * ARGUMENTS:
+ *     Context    = Pointer to context information (IP_INTERFACE)
+ *     Packet     = Pointer to NDIS packet that was sent
+ *     NdisStatus = NDIS status of operation
+ * NOTES:
+ *    This routine is called when an ARP request has been sent
+ */
+{
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+    FreeNdisPacket(NdisPacket);
+}
+
+
+BOOLEAN ARPTransmit(
+    PIP_ADDRESS Address,
+    PNET_TABLE_ENTRY NTE)
+/*
+ * FUNCTION: Creates an ARP request and transmits it on a network
+ * ARGUMENTS:
+ *     Address = Pointer to IP address to resolve
+ *     NTE     = Pointer to net table entru to use for transmitting request
+ * RETURNS:
+ *     TRUE if the request was successfully sent, FALSE if not
+ */
+{
+    PIP_INTERFACE Interface;
+    PNDIS_PACKET NdisPacket;
+    UCHAR ProtoAddrLen;
+    USHORT ProtoType;
+
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+    Interface = NTE->Interface;
+
+    switch (Address->Type) {
+        case IP_ADDRESS_V4:
+            ProtoType    = (USHORT)ETYPE_IPv4; /* IPv4 */
+            ProtoAddrLen = 4;                  /* Length of IPv4 address */
+            break;
+        case IP_ADDRESS_V6:
+            ProtoType    = (USHORT)ETYPE_IPv6; /* IPv6 */
+            ProtoAddrLen = 16;                 /* Length of IPv6 address */
+            break;
+        default:
+            /* Should not happen */
+            return FALSE;
+    }
+
+    NdisPacket = PrepareARPPacket(
+        WN2H(0x0001),                    /* FIXME: Ethernet only */
+        ProtoType,                       /* Protocol type */
+        (UCHAR)Interface->AddressLength, /* Hardware address length */
+        (UCHAR)ProtoAddrLen,             /* Protocol address length */
+        Interface->Address,              /* Sender's (local) hardware address */
+        &NTE->Address->Address,          /* Sender's (local) protocol address */
+        NULL,                            /* Don't care */
+        &Address->Address,               /* Target's (remote) protocol address */
+        ARP_OPCODE_REQUEST);             /* ARP request */
+
+    PC(NdisPacket)->DLComplete = ARPTransmitComplete;
+
+    (*Interface->Transmit)(Interface->Context, NdisPacket,
+        MaxLLHeaderSize, NULL, LAN_PROTO_ARP);
+
+    return TRUE;
+}
+
+
+VOID ARPReceive(
+    PVOID Context,
+    PIP_PACKET Packet)
+/*
+ * FUNCTION: Receives an ARP packet
+ * ARGUMENTS:
+ *     Context = Pointer to context information (IP_INTERFACE)
+ *     Packet  = Pointer to packet
+ */
+{
+    PARP_HEADER Header;
+    PIP_ADDRESS Address;
+    PVOID SenderHWAddress;
+    PVOID SenderProtoAddress;
+    PVOID TargetProtoAddress;
+    PADDRESS_ENTRY ADE;
+    PNEIGHBOR_CACHE_ENTRY NCE;
+    PNDIS_PACKET NdisPacket;
+    PIP_INTERFACE Interface = (PIP_INTERFACE)Context;
+
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+    Header = (PARP_HEADER)Packet->Header;
+
+    /* FIXME: Ethernet only */
+    if (WN2H(Header->HWType) != 1)
+        return;
+
+    /* Check protocol type */
+    if (Header->ProtoType != ETYPE_IPv4)
+        return;
+
+    SenderHWAddress    = (PVOID)((ULONG_PTR)Header + sizeof(ARP_HEADER));
+    SenderProtoAddress = (PVOID)((ULONG_PTR)SenderHWAddress + Header->HWAddrLen);
+
+    /* Check if we have the target protocol address */
+
+    TargetProtoAddress = (PVOID)((ULONG_PTR)SenderProtoAddress +
+        Header->ProtoAddrLen + Header->HWAddrLen);
+
+    Address = AddrBuildIPv4(*(PULONG)(TargetProtoAddress));
+    ADE = IPLocateADE(Address, ADE_UNICAST);
+    if (!ADE) {
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+        return;
+    }
+
+    /* Check if we know the sender */
+
+    AddrInitIPv4(Address, *(PULONG)(SenderProtoAddress));
+    NCE = NBLocateNeighbor(Address);
+    if (NCE) {
+        DereferenceObject(Address);
+        /* We know the sender. Update the hardware address 
+           and state in our neighbor address cache */
+        NBUpdateNeighbor(NCE, SenderHWAddress, NUD_REACHABLE);
+    } else {
+        /* The packet had our protocol address as target. The sender
+           may want to communicate with us soon, so add his address
+           to our address cache */
+        NCE = NBAddNeighbor(Interface, Address, SenderHWAddress,
+            Header->HWAddrLen, NUD_REACHABLE);
+    }
+    if (NCE)
+        DereferenceObject(NCE)
+
+    if (Header->Opcode != ARP_OPCODE_REQUEST)
+        return;
+    
+    /* This is a request for our address. Swap the addresses and
+       send an ARP reply back to the sender */
+    NdisPacket = PrepareARPPacket(
+        Header->HWType,                  /* Hardware type */
+        Header->ProtoType,               /* Protocol type */
+        (UCHAR)Interface->AddressLength, /* Hardware address length */
+        (UCHAR)Header->ProtoAddrLen,     /* Protocol address length */
+        Interface->Address,              /* Sender's (local) hardware address */
+        &ADE->Address->Address,          /* Sender's (local) protocol address */
+        SenderHWAddress,                 /* Target's (remote) hardware address */
+        SenderProtoAddress,              /* Target's (remote) protocol address */
+        ARP_OPCODE_REPLY);               /* ARP reply */
+    if (NdisPacket) {
+        PC(NdisPacket)->DLComplete = ARPTransmitComplete;
+        (*Interface->Transmit)(Interface->Context, NdisPacket,
+            MaxLLHeaderSize, SenderHWAddress, LAN_PROTO_ARP);
+    }
+}
+
+/* EOF */