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 ar4.c Source File

ar4.c

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