Andrew Boyson / net

Dependents:   oldheating gps motorhome heating

Revision:
61:aad055f1b0d1
Parent:
59:e0e556c8bd46
Child:
71:736a5747ade1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ip4/ip4.c	Thu Jan 11 17:38:21 2018 +0000
@@ -0,0 +1,265 @@
+#include <stdint.h>
+#include <stdbool.h>
+
+#include     "log.h"
+#include     "net.h"
+#include  "action.h"
+#include   "icmp4.h"
+#include "udptcp4.h"
+#include     "ar4.h"
+#include     "nr4.h"
+#include    "dhcp.h"
+#include     "eth.h"
+#include      "ip.h"
+#include "ip4addr.h"
+#include     "ntp.h"
+#include     "mac.h"
+
+bool Ip4Trace = true;
+
+#define OFF_LINK_TTL 64
+
+__packed struct header
+{
+    uint8_t  versionIhl;
+    uint8_t  tos;
+    uint16_t length;
+    uint16_t id;
+    uint16_t flagsOffset;
+    uint8_t  ttl;
+    uint8_t  protocol;
+    uint16_t checksum;
+    uint32_t src;
+    uint32_t dst;
+};
+
+//Header variables
+static uint8_t      version;
+static int     headerLength;
+static uint8_t          tos;
+static uint16_t totalLength;
+static uint16_t          id;
+static bool    dontFragment;
+static bool    moreFragments;
+static uint16_t      offset;
+static uint8_t          ttl;
+static uint8_t     protocol;
+static uint16_t    checksum;
+static uint16_t     calcsum;
+static uint32_t       srcIp;
+static uint32_t       dstIp;
+
+static void readHeader(struct header * pHeader)
+{
+             version       =             pHeader->versionIhl >> 4;
+    uint8_t  ihl           =             pHeader->versionIhl & 0xF;
+             headerLength  =             ihl * 4;
+             tos           =             pHeader->tos;
+             totalLength   = NetToHost16(pHeader->length);
+             id            = NetToHost16(pHeader->id);
+    uint16_t flagsOffset   = NetToHost16(pHeader->flagsOffset);
+             dontFragment  =             flagsOffset & 0x4000;
+             moreFragments =             flagsOffset & 0x8000;
+             offset        =             flagsOffset & 0x1FFF;
+             ttl           =             pHeader->ttl;
+             protocol      =             pHeader->protocol;
+             checksum      = NetToHost16(pHeader->checksum);
+             calcsum       = NetCheckSum(headerLength, pHeader);
+             srcIp         =             pHeader->src;
+             dstIp         =             pHeader->dst;
+}
+static void writeHeader(struct header * pHeader)
+{
+    uint16_t flagsOffset = offset;
+    if (dontFragment)  flagsOffset |= 0x4000;
+    if (moreFragments) flagsOffset |= 0x8000;
+
+    uint8_t ihl          = headerLength >> 2;
+    pHeader->versionIhl  = (version << 4) + ihl;
+    pHeader->tos         = tos;
+    pHeader->id          = NetToHost16(id);
+    pHeader->flagsOffset = NetToHost16(flagsOffset);
+    pHeader->ttl         = ttl;
+    pHeader->protocol    = protocol;
+    
+    pHeader->dst         = dstIp;
+    pHeader->src         = srcIp;
+    pHeader->length      = NetToHost16(totalLength);
+    pHeader->checksum    = 0;
+    pHeader->checksum    = NetCheckSum(headerLength, pHeader);
+    calcsum              = 0;
+}
+
+static void logHeader()
+{
+    if (NetTraceVerbose)
+    {
+        Log ("IP4 header\r\n");
+        LogF("  Version           %d\r\n", version);
+        LogF("  Header length     %d\r\n", headerLength);
+        LogF("  Type of service   %d\r\n", tos);
+        LogF("  Total length      %d\r\n", totalLength);
+        LogF("  Identification    %d\r\n", id);
+        if (dontFragment)  LogF("  Don't fragment\r\n");
+        else               LogF("  Do fragment\r\n");
+        if (moreFragments) LogF("  More fragments\r\n");
+        else               LogF("  No more fragments\r\n");
+        LogF("  Offset            %d\r\n", offset);
+        LogF("  Time to live      %d\r\n", ttl);
+        LogF("  Protocol          "); IpProtocolLog(protocol); Log("\r\n");
+        LogF("  Checksum (hex)    %04hX\r\n", checksum);
+        LogF("  Calculated (hex)  %04hX\r\n",  calcsum);
+        LogF("  Source IP         "); Ip4AddressLog(srcIp); Log("\r\n");
+        LogF("  Destination IP    "); Ip4AddressLog(dstIp); Log("\r\n");
+    }
+    else
+    {
+        Log ("IP4   header ");
+        IpProtocolLog(protocol);
+        Log(" ");
+        Ip4AddressLog(srcIp);
+        Log(" >>> ");
+        Ip4AddressLog(dstIp);
+        Log("\r\n");
+    }
+}
+static void (*pTraceBack)(void);
+static void trace()
+{
+    pTraceBack();
+    logHeader();
+}
+int Ip4HandleReceivedPacket(void (*traceback)(void), void* pPacketRx, int sizeRx, void* pPacketTx, int* pSizeTx, char* macRemote)
+{
+    pTraceBack = traceback;
+    struct header * pHeaderRx = (struct header*)pPacketRx;
+    struct header * pHeaderTx = (struct header*)pPacketTx;
+    
+    char* pDataRx = (char*)pHeaderRx + headerLength;
+    char* pDataTx = (char*)pHeaderTx + headerLength;
+    
+    readHeader(pHeaderRx);
+    if (totalLength < sizeRx) sizeRx = totalLength;
+    int dataLengthRx = sizeRx - headerLength;
+    int dataLengthTx = *pSizeTx - sizeof(struct header);
+    
+    bool isMe             = dstIp ==  DhcpLocalIp;
+    bool isLocalBroadcast = dstIp == (DhcpLocalIp | 0xFF000000); // dstIp == 192.168.1.255; '|' is lower precendence than '=='
+    bool isBroadcast      = dstIp ==  IP4_BROADCAST_ADDRESS;     // dstIp == 255.255.255.255
+    bool isMulticast      = (dstIp & 0xE0) == 0xE0; //224.x.x.x == 1110 0000 == E0.xx.xx.xx == xx.xx.xx.E0 in little endian
+    
+    bool doIt = isMe || isLocalBroadcast || isBroadcast || isMulticast;
+    if (!doIt)
+    {
+        if (Ip4Trace);
+        {
+            LogTimeF("IP4 filtered out ip "); Ip4AddressLog(dstIp); 
+            Log(" from ");
+            Ip4AddressLog(srcIp);
+            Log("\r\n");
+        }
+        return DO_NOTHING;
+    }
+    
+    if (srcIp)
+    {
+        Ar4AddIpRecord(trace, macRemote, srcIp);
+        Nr4MakeRequestForNameFromIp(srcIp);
+    }
+    
+    int action = DO_NOTHING;
+    switch (protocol)
+    {
+        case ICMP:   action = Icmp4HandleReceivedPacket(trace, pDataRx, dataLengthRx, pDataTx, &dataLengthTx, &srcIp, &dstIp); break;
+        case IGMP:                                                                                                             break;
+        case UDP:    action =  Udp4HandleReceivedPacket(trace, pDataRx, dataLengthRx, pDataTx, &dataLengthTx, &srcIp, &dstIp); break;
+        case TCP:    action =  Tcp4HandleReceivedPacket(trace, pDataRx, dataLengthRx, pDataTx, &dataLengthTx, &srcIp, &dstIp); break;
+        case IP6IN4:                                                                                                           break;
+        default:
+            LogTimeF("IP4 received packet unknown protocol %d\r\n");
+            return DO_NOTHING;
+    }
+    if (!action) return DO_NOTHING;
+    
+    if (DhcpIpNeedsToBeRouted(dstIp))
+    {
+        Ar4IpToMac(DhcpRouter, macRemote);  //Send back to the router
+        ttl = OFF_LINK_TTL;
+    }
+    else
+    {
+        ttl = 255;
+    }
+
+    totalLength = sizeof(struct header) + dataLengthTx;
+    headerLength = sizeof(struct header);
+
+    writeHeader(pHeaderTx);
+    
+    *pSizeTx = totalLength;
+    
+    if (ActionGetTracePart(action)) logHeader();
+
+    return action;
+}
+int Ip4PollForPacketToSend(void* pPacket, int* pSize, char* pDstMac)
+{    
+    headerLength  = sizeof(struct header);
+    char* pData   = (char*)pPacket + headerLength;
+    version       = 4;
+    tos           = 0;
+    id            = 0;
+    dontFragment  = true;
+    moreFragments = false;
+    offset        = 0;
+    protocol      = UDP;
+    
+    int dataLength = *pSize - sizeof(struct header);
+    
+    int action  = DO_NOTHING;
+    if (!action) action = Udp4PollForPacketToSend(pData, &dataLength, &srcIp, &dstIp);
+    if (!action) return DO_NOTHING;
+    int dest = ActionGetDestPart(action);
+    switch (dest)
+    {
+        case UNICAST:
+        case UNICAST_DNS:
+        case UNICAST_DHCP:
+        case UNICAST_NTP:
+        case UNICAST_TFTP:
+            if (DhcpIpNeedsToBeRouted(dstIp))
+            {
+                Ar4IpToMac(DhcpRouter, pDstMac); //send via router
+                ttl = OFF_LINK_TTL;
+            }
+            else
+            {
+                Ar4IpToMac(dstIp,      pDstMac); //Send direct
+                ttl = 255;
+            }
+            break;
+        case MULTICAST_NODE:
+        case MULTICAST_ROUTER:
+        case MULTICAST_MDNS:
+        case MULTICAST_LLMNR:
+        case BROADCAST:
+            ttl = 255;
+            break;
+        default:
+            LogTimeF("Ip4PollForPacketToSend - undefined destination %d\r\n", dest);
+            return DO_NOTHING;
+    }
+
+    struct header* pHeader = (struct header*)pPacket;
+
+    totalLength = sizeof(struct header) + dataLength;
+    headerLength = sizeof(struct header);
+
+    writeHeader(pHeader);
+    
+    *pSize = totalLength;
+    
+    if (ActionGetTracePart(action)) logHeader();
+
+    return action;
+}