Andrew Boyson / net

Dependents:   oldheating gps motorhome heating

Revision:
61:aad055f1b0d1
Parent:
53:77f8a49adf89
Child:
65:37acccf2752f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ip6/icmp/ndp/ndp.c	Thu Jan 11 17:38:21 2018 +0000
@@ -0,0 +1,245 @@
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include "log.h"
+#include "net.h"
+#include "mac.h"
+#include "ip6addr.h"
+#include "slaac.h"
+#include "clock.h"
+#include "rs.h"
+
+int      NdpHopLimit             = 0;
+bool     NdpManagedConfiguration = false;
+bool     NdpOtherConfiguration   = false;
+int      NdpLifetime             = 0;
+
+char     NdpRouterMac[6];
+
+int      NdpPrefixLength            = 0;
+bool     NdpPrefixFlagL             = false;
+bool     NdpPrefixFlagA             = false;
+uint32_t NdpPrefixValidLifetime     = 0;
+uint32_t NdpPrefixPreferredLifetime = 0;
+char     NdpPrefix[16];
+
+uint32_t NdpDnsLifetime = 0;
+char     NdpDnsServer[16];
+
+int      NdpMtu = 0;
+
+uint32_t NdpElapsedTime = 0;         //Reset whenever an IP address request has been acknowledged 
+
+bool NdpIpNeedsToBeRouted(char* ip)
+{
+    //Check address is assigned to internet
+    if (*(ip + 0) != 0x20) return false;
+    if (*(ip + 1) != 0x00) return false;
+    
+    //Check it is not our own prefix
+    if (memcmp(ip, NdpPrefix, 8) == 0) return false;
+    
+    return true;
+}
+
+static uint32_t decodeUint32(char* p)
+{
+    uint32_t value = 0;
+    value |= *p++ << 24;
+    value |= *p++ << 12;
+    value |= *p++ <<  8;
+    value |= *p++ <<  0;
+    return value;
+}
+static int decodeOption(char* p, char* srcMac, char* dstMac)
+{
+    int type = *p++;
+    int size = *p++;
+    if (size == 0) return 0;
+    switch (type)
+    {
+        case 1:
+            if (srcMac) MacCopy(srcMac, p);
+            break;
+        case 2:
+            if (dstMac) MacCopy(dstMac, p);
+            break;
+        case 3:
+            NdpPrefixLength = *p;                                   p += 1;
+            NdpPrefixFlagL = *p & 0x80; NdpPrefixFlagA = *p & 0x40; p += 1;
+            NdpPrefixValidLifetime = decodeUint32(p);               p += 4;
+            NdpPrefixPreferredLifetime = decodeUint32(p);           p += 4;
+            /*Ignore the reserved2 field*/                          p += 4;
+            Ip6AddressCopy(NdpPrefix, p); SlaacMakeGlobal(NdpPrefix);
+            break;
+        case 5:
+            /*Ignore the reserved field*/                           p += 2;
+            NdpMtu = decodeUint32(p);
+            break;
+        case 25:
+            /*Ignore the reserved field*/                           p += 2;
+            NdpDnsLifetime = decodeUint32(p);                       p += 4;
+            Ip6AddressCopy(NdpDnsServer, p);
+            break;
+    }
+    return size * 8;
+}
+static void logFlagsLA(char flags)
+{
+    if (flags & 0x80) LogPush('L');
+    if (flags & 0x40) LogPush('A');
+}
+static int logOptionVerbose(char* p)
+{
+    uint32_t value;
+    int type = *p++;
+    int size = *p++;
+    if (size == 0)
+    {
+        LogF("    Size zero for option %d\r\n", type); 
+        return 0;
+    }
+    switch (type)
+    {
+        case 1:
+                                           Log("    Src MAC          "); MacLog(p);         Log("\r\n"); break;
+        case 2:
+                                           Log("    Tgt MAC          "); MacLog(p);         Log("\r\n"); break;
+        case 3:
+                                           Log("    Prefix length    "); LogF("%d", *p);    Log("\r\n"); p += 1;
+                                           Log("    Prefix flags     "); logFlagsLA(*p);    Log("\r\n"); p += 1;
+            value = decodeUint32(p);       Log("    Prefix valid     "); LogF("%u", value); Log("\r\n"); p += 4;
+            value = decodeUint32(p);       Log("    Prefix preferred "); LogF("%u", value); Log("\r\n"); p += 4;
+            /*Ignore the Reserved2 field*/                                                               p += 4; 
+                                           Log("    Prefix           "); Ip6AddressLog(p);  Log("\r\n"); break;
+        case 5:
+            /*Ignore the reserved field*/                                                                p += 2;
+            value = decodeUint32(p);       Log("    MTU              "); LogF("%u", value); Log("\r\n"); break;
+        case 25:
+            /*Ignore the reserved field*/                                                                p += 2;
+            value = decodeUint32(p);       Log("    DNS lifetime     "); LogF("%u", value); Log("\r\n"); p += 4;
+                                           Log("    DNS Server       "); Ip6AddressLog(p);  Log("\r\n"); break;
+        default:
+                                           Log("    Unknown option   "); LogF("%d", type);  Log("\r\n"); break;
+    }
+    return size * 8;
+}
+static int logOptionQuiet(char* p)
+{
+    uint32_t value;
+    int type = *p++;
+    int size = *p++;
+    if (size == 0) return 0;
+    switch (type)
+    {
+        case 1:
+            Log(" src ");
+            MacLog(p);
+            break;
+        case 2:
+            Log(" tgt ");
+            MacLog(p);
+            break;
+        case 3:
+            *p++; //Length
+            *p++; //LA
+            p += 4; //Valid lifetime
+            p += 4; //Preferred lifetime
+            p += 4; //Reserved 2
+            Log(" prefix ");
+            Ip6AddressLog(p); //IP6 address
+            break;
+        case 5:
+            p += 2; //Skip past the reserved field
+            value = decodeUint32(p);
+            p += 4;
+            LogF(" MTU %u", value);
+            break;
+        case 25:
+            p += 2; //Skip past the reserved field
+            p += 4; //DNS lifetime
+            Log(" DNS ");
+            Ip6AddressLog(p);
+            break;
+        default:
+            LogF(" ? %d", type);
+            break;
+    }
+    return size * 8;
+}
+void NdpDecodeOptions(char* pData, int dataLength, char* srcMac, char* dstMac)
+{
+    char* p = pData;
+    char* pE = pData + dataLength;
+    while(p < pE)
+    {
+        int size = decodeOption(p, srcMac, dstMac);
+        if (size == 0) break;
+        p += size;
+    }
+}
+void NdpLogOptionsVerbose(char* pData, int dataLength)
+{
+    char* p = pData;
+    char* pE = pData + dataLength;
+    while(p < pE)
+    {
+        int size = logOptionVerbose(p);
+        if (size == 0) break;
+        p += size;
+    }
+}
+void NdpLogOptionsQuiet(char* pData, int dataLength)
+{
+    char* p = pData;
+    char* pE = pData + dataLength;
+    while(p < pE)
+    {
+        int size = logOptionQuiet(p);
+        if (size == 0) break;
+        p += size;
+    }
+}
+int NdpAddOptionSourceMac(char* p, char* pMac)
+{
+    *p++ = 1; //Source MAC option
+    *p++ = 1; //8 bytes
+    MacCopy(p, pMac);
+    return 8;
+}
+int NdpAddOptionTargetMac(char* p, char* pMac)
+{
+    *p++ = 2; //Target MAC option
+    *p++ = 1; //8 bytes
+    MacCopy(p, pMac);
+    return 8;
+}
+
+#define INITIAL_DELAY 1
+#define REPEAT_DELAY 60
+static uint32_t delayTime = INITIAL_DELAY; //Set to REPEAT_DELAY_TIME whenever a message is sent and blocks another send until count is back at zero
+void NdpMain()
+{
+    if (ClockTicked)
+    {
+        NdpElapsedTime++;
+        if (delayTime > 0) delayTime--;
+    }
+    if (delayTime) return; //Don't retry within the delay time
+    
+    if (NdpLifetime && NdpElapsedTime < (NdpLifetime >> 1)) return; //Do nothing if within half the life
+    
+    if (!NdpLifetime || NdpElapsedTime >= NdpLifetime)
+    {
+        if (NetTraceNewLine) Log("\r\n");
+        LogTime("NDP lifetime has expired\r\n");
+        NdpLifetime = 0;
+        Ip6AddressClear(NdpPrefix);
+        SlaacMakeGlobal(NdpPrefix);
+        Ip6AddressClear(NdpDnsServer);
+    }
+    
+    delayTime = REPEAT_DELAY;
+    RsSendSolicitation = true;
+}