A stack which works with or without an Mbed os library. Provides IPv4 or IPv6 with a full 1500 byte buffer.

Dependents:   oldheating gps motorhome heating

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ar6.c Source File

ar6.c

00001 #include    <stdint.h>
00002 #include <stdbool.h>
00003 
00004 #include     "log.h"
00005 #include "mstimer.h"
00006 #include     "net.h"
00007 #include     "mac.h"
00008 #include "ip6addr.h"
00009 #include      "ns.h"
00010 #include    "http.h"
00011 
00012 bool Ar6Trace = false;
00013 
00014 #define  CACHE_TIMEOUT_MS  3600 * 1000
00015 #define FREEZE_TIMEOUT_MS  1800 * 1000
00016 #define  REPLY_TIMEOUT_MS     1 * 1000
00017 #define SEND_ATTEMPTS      3
00018 #define RECORDS_COUNT     20
00019 
00020 #define STATE_EMPTY 0
00021 #define STATE_WANT  1
00022 #define STATE_SENT  2
00023 #define STATE_VALID 3
00024 
00025 struct record
00026 {
00027     uint32_t elapsed;
00028     char     ip[16];
00029     uint8_t  state;
00030     uint8_t  tries;
00031     char     mac[6];
00032 };
00033 static struct record records[RECORDS_COUNT];
00034 static int getExistingIp(char* ip)
00035 {
00036     for (int i = 0; i < RECORDS_COUNT; i++)
00037     {
00038         if (records[i].state && Ip6AddrIsSame(records[i].ip, ip)) return i;
00039     }
00040     return -1;
00041 }
00042 static int getOldest()
00043 {
00044     int        iOldest = 0;
00045     uint32_t ageOldest = 0;
00046     for (int i = 0; i < RECORDS_COUNT; i++)
00047     {
00048         if (!records[i].state) return i; //Found an empty slot so just return it
00049         uint32_t age = MsTimerCount - records[i].elapsed;
00050         if (age >= ageOldest)
00051         {
00052             ageOldest = age;
00053               iOldest = i;
00054         }
00055     }  
00056     return iOldest;                      //Otherwise return the oldest
00057 }
00058 void Ar6MakeRequestForMacFromIp(char* ip)
00059 {
00060     //Don't treat non ips
00061     if (!ip[0]) return;
00062     int i;
00063     
00064     //If a record already exists then request an update
00065     i = getExistingIp(ip);
00066     if (i > -1)
00067     {
00068         if (!MsTimerRelative(records[i].elapsed, FREEZE_TIMEOUT_MS)) return;
00069         if (Ar6Trace)
00070         {
00071             LogTime("AR6 Updated request for MAC of ");
00072             Ip6AddrLog(ip);
00073             Log("\r\n");
00074         }
00075         records[i].state    = STATE_WANT;
00076         records[i].tries    = 0;
00077         records[i].elapsed  = MsTimerCount;
00078         return;
00079     }
00080     
00081     //If a record does not exist then find the first empty slot and add the IP and date
00082     if (Ar6Trace)
00083     {
00084         LogTime("AR6 Made request for MAC of ");
00085         Ip6AddrLog(ip);
00086         Log("\r\n");
00087     }
00088     i = getOldest();
00089     Ip6AddrCopy(records[i].ip, ip);
00090     records[i].state    = STATE_WANT;
00091     records[i].tries    = 0;
00092     records[i].elapsed  = MsTimerCount;
00093     MacClear(records[i].mac);
00094 }
00095 int Ar6AddIpRecord(void (*traceback)(void), char* mac, char* ip)
00096 {
00097     //Don't treat non ips
00098     if (!ip[0])
00099     {
00100         if (Ar6Trace)
00101         {
00102             LogTime("Ar6AddIpRecord had blank ip\r\n");
00103             if (NetTraceStack) traceback();
00104         }
00105         return -1;
00106     }
00107     if (MacIsEmpty(mac))
00108     {
00109         if (Ar6Trace)
00110         {
00111             LogTime("Ar6AddIpRecord had blank mac\r\n");
00112             if (NetTraceStack) traceback();
00113         }
00114         return -1;
00115     }
00116     int i;
00117     
00118     //See if any record corresponds to the IP and, if so, update the MAC and time
00119     i = getExistingIp(ip);
00120     if (i > -1)
00121     {
00122         records[i].elapsed = MsTimerCount;
00123         records[i].state = STATE_VALID;
00124         MacCopy(records[i].mac, mac);
00125         return i;
00126     }
00127     
00128     //Otherwise find the first empty slot and add the MAC, IP and date
00129     i = getOldest();
00130     MacCopy(records[i].mac, mac);
00131     Ip6AddrCopy(records[i].ip, ip);
00132     records[i].elapsed   = MsTimerCount;
00133     records[i].state = STATE_VALID;
00134     return i;
00135 }
00136 void Ar6IpToMac(char* ip, char* mac)
00137 {
00138     for (int i = 0; i < RECORDS_COUNT; i++)
00139     {
00140         if (records[i].state == STATE_VALID && Ip6AddrIsSame(records[i].ip, ip))
00141         {
00142             MacCopy(mac, records[i].mac);
00143             return;
00144         }
00145     }
00146     MacClear(mac);
00147 }
00148 bool Ar6HaveMacForIp(char* ip)
00149 {
00150     for (int i = 0; i < RECORDS_COUNT; i++)
00151     {
00152         if (records[i].state == STATE_VALID && Ip6AddrIsSame(records[i].ip, ip)) return true;
00153     }
00154     return false;
00155 }
00156 bool Ar6CheckHaveMacAndFetchIfNot(char* ip)
00157 {
00158     if (!Ar6HaveMacForIp(ip))
00159     {
00160         Ar6MakeRequestForMacFromIp(ip); //The request is only repeated if made after a freeze time - call as often as you want.
00161         return false;
00162     }
00163     return true;
00164 }
00165 void Ar6IndexToIp(int i, char* ip)
00166 {
00167     Ip6AddrCopy(ip, records[i].ip);
00168 }
00169 void Ar6SendHttp()
00170 {
00171     for (int i = 0; i < RECORDS_COUNT; i++)
00172     {
00173         if (records[i].state)
00174         {
00175             HttpAddF("%4u ", (MsTimerCount - records[i].elapsed) / 1000 / 60);
00176             
00177             int ipLen = Ip6AddrHttp(records[i].ip);
00178             HttpAddFillChar(' ', 40 - ipLen);
00179             
00180             MacHttp(records[i].mac);
00181             
00182             HttpAddChar('\r');
00183             HttpAddChar('\n');
00184         }
00185     }
00186 }
00187 void Ar6SendAjax()
00188 {
00189     for (int i = 0; i < RECORDS_COUNT; i++)
00190     {
00191         if (records[i].state)
00192         {
00193             HttpAddByteAsHex(i);
00194             HttpAddChar('\t');
00195             HttpAddInt32AsHex(MsTimerCount - records[i].elapsed);
00196             HttpAddChar('\t');
00197             for (int b = 0; b < 16; b++) HttpAddByteAsHex(records[i].ip[b]);
00198             HttpAddChar('\t');
00199             for (int b = 0; b <  6; b++) HttpAddByteAsHex(records[i].mac[b]);
00200             HttpAddChar('\n');
00201         }
00202     }
00203 }
00204 static void clear(struct record* pr)
00205 {
00206     pr->state = STATE_EMPTY;
00207 }
00208 static void clearCache(struct record* pr)
00209 {
00210     if (MsTimerRelative(pr->elapsed, CACHE_TIMEOUT_MS)) clear(pr);
00211 }
00212 static void retry(struct record* pr)
00213 {
00214     if (pr->state == STATE_SENT && MsTimerRelative(pr->elapsed, REPLY_TIMEOUT_MS))
00215     {
00216         if (pr->tries < SEND_ATTEMPTS)
00217         {
00218             pr->state   = STATE_WANT;
00219             pr->elapsed = MsTimerCount;
00220             pr->tries++;
00221         }
00222         else
00223         {
00224             clear(pr);
00225         }
00226     }
00227 }
00228 static void sendRequest(struct record* pr)
00229 {
00230     if (!NsResolveRequestFlag)
00231     {
00232         if (pr->state == STATE_WANT)
00233         {
00234             if (Ar6Trace)
00235             {
00236                 LogTime("AR6 Send request for MAC from IP6 ");
00237                 Ip6AddrLog(pr->ip);
00238                 Log("\r\n");
00239             }
00240             Ip6AddrCopy(NsAddressToResolve, pr->ip);
00241             NsResolveRequestFlag = true;
00242             pr->state   = STATE_SENT;
00243             pr->elapsed = MsTimerCount;
00244             return;
00245         }
00246     }
00247 }
00248 void Ar6Main()
00249 {
00250     static int i = -1;
00251     i++;
00252     if (i >= RECORDS_COUNT) i = 0;
00253     
00254     struct record* pr = &records[i];
00255     
00256     clearCache (pr);
00257     retry      (pr);
00258     sendRequest(pr);
00259 }
00260 void Ar6Init()
00261 {
00262     for (int i = 0; i < RECORDS_COUNT; i++)
00263     {
00264     
00265         struct record* pr = &records[i];
00266         clear(pr);
00267     }
00268 }