[IP][LWIP][TCPIP] Move ip and lwip libraries to drivers/network/tcpip
[reactos.git] / drivers / network / tcpip / ip / transport / rawip / rawip.c
diff --git a/drivers/network/tcpip/ip/transport/rawip/rawip.c b/drivers/network/tcpip/ip/transport/rawip/rawip.c
new file mode 100644 (file)
index 0000000..ca98530
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        transport/rawip/rawip.c
+ * PURPOSE:     User Datagram Protocol routines
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ *   CSH 01/08-2000 Created
+ */
+
+#include "precomp.h"
+
+NTSTATUS AddGenericHeaderIPv4(
+    PADDRESS_FILE AddrFile,
+    PIP_ADDRESS RemoteAddress,
+    USHORT RemotePort,
+    PIP_ADDRESS LocalAddress,
+    USHORT LocalPort,
+    PIP_PACKET IPPacket,
+    UINT DataLength,
+    UINT Protocol,
+    UINT ExtraLength,
+    PVOID *NextHeader )
+/*
+ * FUNCTION: Adds an IPv4 and RawIp header to an IP packet
+ * ARGUMENTS:
+ *     SendRequest  = Pointer to send request
+ *     LocalAddress = Pointer to our local address
+ *     LocalPort    = The port we send this datagram from
+ *     IPPacket     = Pointer to IP packet
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    PIPv4_HEADER IPHeader;
+    ULONG BufferSize;
+
+    TI_DbgPrint(MID_TRACE, ("Packet: %x NdisPacket %x\n",
+                           IPPacket, IPPacket->NdisPacket));
+
+    BufferSize = sizeof(IPv4_HEADER) + ExtraLength;
+
+    GetDataPtr( IPPacket->NdisPacket,
+               0,
+               (PCHAR *)&IPPacket->Header,
+               &IPPacket->TotalSize );
+    IPPacket->MappedHeader = TRUE;
+
+    IPPacket->HeaderSize = sizeof(IPv4_HEADER);
+
+    TI_DbgPrint(MAX_TRACE, ("Allocated %d bytes for headers at 0x%X.\n",
+                           BufferSize, IPPacket->Header));
+    TI_DbgPrint(MAX_TRACE, ("Packet total length %d\n", IPPacket->TotalSize));
+
+    /* Build IPv4 header */
+    IPHeader = (PIPv4_HEADER)IPPacket->Header;
+    /* Version = 4, Length = 5 DWORDs */
+    IPHeader->VerIHL = 0x45;
+    /* Normal Type-of-Service */
+    IPHeader->Tos = 0;
+    /* Length of header and data */
+    IPHeader->TotalLength = WH2N((USHORT)IPPacket->TotalSize);
+    /* Identification */
+    IPHeader->Id = (USHORT)Random();
+    /* One fragment at offset 0 */
+    IPHeader->FlagsFragOfs = 0;
+    /* Time-to-Live */
+    IPHeader->Ttl = AddrFile->TTL;
+    /* Protocol */
+    IPHeader->Protocol = Protocol;
+    /* Checksum is 0 (for later calculation of this) */
+    IPHeader->Checksum = 0;
+    /* Source address */
+    IPHeader->SrcAddr = LocalAddress->Address.IPv4Address;
+    /* Destination address. FIXME: IPv4 only */
+    IPHeader->DstAddr = RemoteAddress->Address.IPv4Address;
+
+    /* Build RawIp header */
+    *NextHeader = (((PCHAR)IPHeader) + sizeof(IPv4_HEADER));
+    IPPacket->Data = ((PCHAR)*NextHeader) + ExtraLength;
+
+    return STATUS_SUCCESS;
+}
+
+
+NTSTATUS BuildRawIpPacket(
+    PADDRESS_FILE AddrFile,
+    PIP_PACKET Packet,
+    PIP_ADDRESS RemoteAddress,
+    USHORT RemotePort,
+    PIP_ADDRESS LocalAddress,
+    USHORT LocalPort,
+    PCHAR DataBuffer,
+    UINT DataLen )
+/*
+ * FUNCTION: Builds an RawIp packet
+ * ARGUMENTS:
+ *     Context      = Pointer to context information (DATAGRAM_SEND_REQUEST)
+ *     LocalAddress = Pointer to our local address
+ *     LocalPort    = The port we send this datagram from
+ *     IPPacket     = Address of pointer to IP packet
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    NTSTATUS Status;
+    PCHAR Payload;
+
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    /* FIXME: Assumes IPv4 */
+    IPInitializePacket(Packet, IP_ADDRESS_V4);
+
+    Packet->TotalSize = sizeof(IPv4_HEADER) + DataLen;
+
+    /* Prepare packet */
+    Status = AllocatePacketWithBuffer( &Packet->NdisPacket,
+                                      NULL,
+                                      Packet->TotalSize );
+
+    if( !NT_SUCCESS(Status) ) return Status;
+
+    TI_DbgPrint(MID_TRACE, ("Allocated packet: %x\n", Packet->NdisPacket));
+    TI_DbgPrint(MID_TRACE, ("Local Addr : %s\n", A2S(LocalAddress)));
+    TI_DbgPrint(MID_TRACE, ("Remote Addr: %s\n", A2S(RemoteAddress)));
+
+    switch (RemoteAddress->Type) {
+    case IP_ADDRESS_V4:
+       Status = AddGenericHeaderIPv4
+            (AddrFile, RemoteAddress, RemotePort,
+             LocalAddress, LocalPort, Packet, DataLen,
+             AddrFile->Protocol,
+             0, (PVOID *)&Payload );
+       break;
+    case IP_ADDRESS_V6:
+       /* FIXME: Support IPv6 */
+        Status = STATUS_UNSUCCESSFUL;
+       TI_DbgPrint(MIN_TRACE, ("IPv6 RawIp datagrams are not supported.\n"));
+        break;
+
+    default:
+       Status = STATUS_UNSUCCESSFUL;
+        TI_DbgPrint(MIN_TRACE, ("Bad Address Type %d\n", RemoteAddress->Type));
+       break;
+    }
+
+    if( !NT_SUCCESS(Status) ) {
+        TI_DbgPrint(MIN_TRACE, ("Cannot add header. Status = (0x%X)\n",
+                                Status));
+        Packet->Free(Packet);
+        return Status;
+    }
+
+    TI_DbgPrint(MID_TRACE, ("Copying data (hdr %x data %x (%d))\n",
+                           Packet->Header, Packet->Data,
+                           (PCHAR)Packet->Data - (PCHAR)Packet->Header));
+
+    RtlCopyMemory( Packet->Data, DataBuffer, DataLen );
+
+    Packet->Flags |= IP_PACKET_FLAG_RAW;
+
+    TI_DbgPrint(MID_TRACE, ("Displaying packet\n"));
+
+    DISPLAY_IP_PACKET(Packet);
+
+    TI_DbgPrint(MID_TRACE, ("Leaving\n"));
+
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS RawIPSendDatagram(
+    PADDRESS_FILE AddrFile,
+    PTDI_CONNECTION_INFORMATION ConnInfo,
+    PCHAR BufferData,
+    ULONG DataSize,
+    PULONG DataUsed )
+/*
+ * FUNCTION: Sends an RawIp datagram to a remote address
+ * ARGUMENTS:
+ *     Request   = Pointer to TDI request
+ *     ConnInfo  = Pointer to connection information
+ *     Buffer    = Pointer to NDIS buffer with data
+ *     DataSize  = Size in bytes of data to be sent
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    IP_PACKET Packet;
+    PTA_IP_ADDRESS RemoteAddressTa = (PTA_IP_ADDRESS)ConnInfo->RemoteAddress;
+    IP_ADDRESS RemoteAddress,  LocalAddress;
+    USHORT RemotePort;
+    NTSTATUS Status;
+    PNEIGHBOR_CACHE_ENTRY NCE;
+
+    LockObject(AddrFile);
+
+    TI_DbgPrint(MID_TRACE,("Sending Datagram(%x %x %x %d)\n",
+                          AddrFile, ConnInfo, BufferData, DataSize));
+    TI_DbgPrint(MID_TRACE,("RemoteAddressTa: %x\n", RemoteAddressTa));
+
+    switch( RemoteAddressTa->Address[0].AddressType ) {
+        case TDI_ADDRESS_TYPE_IP:
+            RemoteAddress.Type = IP_ADDRESS_V4;
+            RemoteAddress.Address.IPv4Address =
+            RemoteAddressTa->Address[0].Address[0].in_addr;
+            RemotePort = RemoteAddressTa->Address[0].Address[0].sin_port;
+            break;
+
+        default:
+            UnlockObject(AddrFile);
+            return STATUS_UNSUCCESSFUL;
+    }
+
+    TI_DbgPrint(MID_TRACE,("About to get route to destination\n"));
+
+    LocalAddress = AddrFile->Address;
+    if (AddrIsUnspecified(&LocalAddress))
+    {
+        /* If the local address is unspecified (0),
+         * then use the unicast address of the
+         * interface we're sending over
+         */
+        if(!(NCE = RouteGetRouteToDestination( &RemoteAddress ))) {
+            UnlockObject(AddrFile);
+            return STATUS_NETWORK_UNREACHABLE;
+        }
+
+        LocalAddress = NCE->Interface->Unicast;
+    }
+    else
+    {
+        if(!(NCE = NBLocateNeighbor( &LocalAddress, NULL ))) {
+            UnlockObject(AddrFile);
+            return STATUS_INVALID_PARAMETER;
+        }
+    }
+
+    Status = BuildRawIpPacket( AddrFile,
+                               &Packet,
+                               &RemoteAddress,
+                               RemotePort,
+                               &LocalAddress,
+                               AddrFile->Port,
+                               BufferData,
+                               DataSize );
+
+    UnlockObject(AddrFile);
+
+    if( !NT_SUCCESS(Status) )
+        return Status;
+
+    TI_DbgPrint(MID_TRACE,("About to send datagram\n"));
+
+    Status = IPSendDatagram(&Packet, NCE);
+    if (!NT_SUCCESS(Status))
+        return Status;
+
+    *DataUsed = DataSize;
+
+    TI_DbgPrint(MID_TRACE,("Leaving\n"));
+
+    return STATUS_SUCCESS;
+}
+
+
+VOID RawIpReceive(PIP_INTERFACE Interface, PIP_PACKET IPPacket)
+/*
+ * FUNCTION: Receives and queues a RawIp datagram
+ * ARGUMENTS:
+ *     NTE      = Pointer to net table entry which the packet was received on
+*     IPPacket = Pointer to an IP packet that was received
+* NOTES:
+*     This is the low level interface for receiving RawIp datagrams. It strips
+*     the RawIp header from a packet and delivers the data to anyone that wants it
+*/
+{
+  AF_SEARCH SearchContext;
+  PIPv4_HEADER IPv4Header;
+  PADDRESS_FILE AddrFile;
+  PIP_ADDRESS DstAddress, SrcAddress;
+  UINT DataSize;
+
+  TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+  switch (IPPacket->Type) {
+  /* IPv4 packet */
+  case IP_ADDRESS_V4:
+    IPv4Header = IPPacket->Header;
+    DstAddress = &IPPacket->DstAddr;
+    SrcAddress = &IPPacket->SrcAddr;
+    DataSize = IPPacket->TotalSize;
+    break;
+
+  /* IPv6 packet */
+  case IP_ADDRESS_V6:
+    TI_DbgPrint(MIN_TRACE, ("Discarded IPv6 datagram (%i bytes).\n", IPPacket->TotalSize));
+
+    /* FIXME: IPv6 is not supported */
+    return;
+
+  default:
+    return;
+  }
+
+  /* Locate a receive request on destination address file object
+     and deliver the packet if one is found. If there is no receive
+     request on the address file object, call the associated receive
+     handler. If no receive handler is registered, drop the packet */
+
+  AddrFile = AddrSearchFirst(DstAddress,
+                             0,
+                             IPv4Header->Protocol,
+                             &SearchContext);
+  if (AddrFile) {
+    do {
+      DGDeliverData(AddrFile,
+                   SrcAddress,
+                    DstAddress,
+                    0,
+                    0,
+                    IPPacket,
+                    DataSize);
+      DereferenceObject(AddrFile);
+    } while ((AddrFile = AddrSearchNext(&SearchContext)) != NULL);
+  } else {
+    /* There are no open address files that will take this datagram */
+    /* FIXME: IPv4 only */
+    TI_DbgPrint(MID_TRACE, ("Cannot deliver IPv4 raw datagram to address (0x%X).\n",
+                            DN2H(DstAddress->Address.IPv4Address)));
+
+    /* FIXME: Send ICMP reply */
+  }
+  TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+}
+
+
+NTSTATUS RawIPStartup(VOID)
+/*
+ * FUNCTION: Initializes the UDP subsystem
+ * RETURNS:
+ *     Status of operation
+ */
+{
+  RtlZeroMemory(&UDPStats, sizeof(UDP_STATISTICS));
+
+  /* Register this protocol with IP layer */
+  IPRegisterProtocol(IPPROTO_RAW, RawIpReceive);
+
+  return STATUS_SUCCESS;
+}
+
+
+NTSTATUS RawIPShutdown(VOID)
+/*
+ * FUNCTION: Shuts down the UDP subsystem
+ * RETURNS:
+ *     Status of operation
+ */
+{
+  /* Deregister this protocol with IP layer */
+  IPRegisterProtocol(IPPROTO_RAW, NULL);
+
+  return STATUS_SUCCESS;
+}
+
+/* EOF */