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
Diff: resolve/ar4.c
- Revision:
- 116:60521b29e4c9
- Parent:
- 93:580fc113d9e9
- Child:
- 132:db2174b36a6d
diff -r 5c003909bcf3 -r 60521b29e4c9 resolve/ar4.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/resolve/ar4.c Fri Jan 25 17:37:51 2019 +0000 @@ -0,0 +1,240 @@ +#include <stdint.h> +#include <stdbool.h> +#include "log.h" +#include "net.h" +#include "mac.h" +#include "ip4addr.h" +#include "arp.h" +#include "http.h" +#include "mstimer.h" + +bool Ar4Trace = false; + +#define CACHE_TIMEOUT_MS 3600 * 1000 +#define FREEZE_TIMEOUT_MS 1800 * 1000 +#define REPLY_TIMEOUT_MS 1 * 1000 +#define SEND_ATTEMPTS 3 +#define RECORDS_COUNT 20 + +#define STATE_EMPTY 0 +#define STATE_WANT 1 +#define STATE_SENT 2 +#define STATE_VALID 3 + +struct record +{ + uint32_t elapsed; + uint32_t ip; + uint8_t state; + uint8_t tries; + char mac[6]; +}; +static struct record records[RECORDS_COUNT]; +static int getExistingIp(uint32_t ip) +{ + for (int i = 0; i < RECORDS_COUNT; i++) + { + if (records[i].state && records[i].ip == ip) return i; + } + return -1; +} +static int getOldest() +{ + int iOldest = 0; + uint32_t ageOldest = 0; + for (int i = 0; i < RECORDS_COUNT; i++) + { + if (!records[i].state) return i; //Found an empty slot so just return it + uint32_t age = MsTimerCount - records[i].elapsed; + if (age >= ageOldest) + { + ageOldest = age; + iOldest = i; + } + } + return iOldest; //Otherwise return the oldest +} +void Ar4MakeRequestForMacFromIp(uint32_t ip) +{ + //Don't treat non ips + if (!ip) return; + int i; + + //If a record already exists then request an update + i = getExistingIp(ip); + if (i > -1) + { + if (!MsTimerHasElapsed(records[i].elapsed, FREEZE_TIMEOUT_MS)) return; + if (Ar4Trace) + { + LogTimeF("AR4 Updated request for MAC of "); + Ip4AddressLog(ip); + Log("\r\n"); + } + records[i].state = STATE_WANT; + records[i].tries = 0; + records[i].elapsed = MsTimerCount; + return; + } + + //If a record does not exist then find the first empty slot and add the IP and date + if (Ar4Trace) + { + LogTimeF("AR4 Made request for MAC of "); + Ip4AddressLog(ip); + Log("\r\n"); + } + i = getOldest(); + records[i].ip = ip; + records[i].state = STATE_WANT; + records[i].tries = 0; + records[i].elapsed = MsTimerCount; + MacClear(records[i].mac); +} +int Ar4AddIpRecord(void (*traceback)(void), char* mac, uint32_t ip) +{ + //Don't treat non ips + if (!ip) + { + if (Ar4Trace) + { + LogTime("Ar4AddIpRecord had blank ip\r\n"); + if (NetTraceStack) traceback(); + } + return -1; + } + if (MacIsEmpty(mac)) + { + if (Ar4Trace) + { + LogTime("Ar4AddIpRecord had blank mac\r\n"); + if (NetTraceStack) traceback(); + } + return -1; + } + int i; + + //See if any record corresponds to the IP and, if so, update the MAC and time + i = getExistingIp(ip); + if (i > -1) + { + records[i].elapsed = MsTimerCount; + records[i].state = STATE_VALID; + MacCopy(records[i].mac, mac); + return i; + } + + //Otherwise find the first empty slot and add the IP, MAC, and date + i = getOldest(); + records[i].ip = ip; + records[i].elapsed = MsTimerCount; + records[i].state = STATE_VALID; + MacCopy(records[i].mac, mac); + return i; +} +void Ar4IpToMac(uint32_t ip, char* mac) +{ + for (int i = 0; i < RECORDS_COUNT; i++) + { + if (records[i].state == STATE_VALID && records[i].ip == ip) + { + MacCopy(mac, records[i].mac); + return; + } + } + MacClear(mac); +} +bool Ar4HaveMacForIp(uint32_t ip) +{ + for (int i = 0; i < RECORDS_COUNT; i++) + { + if (records[i].state == STATE_VALID && records[i].ip == ip) return true; + } + return false; +} +uint32_t Ar4IndexToIp(int i) +{ + return records[i].ip; +} +void Ar4SendHttp() +{ + for (int i = 0; i < RECORDS_COUNT; i++) + { + if (records[i].state) + { + HttpAddF("%4u ", (MsTimerCount - records[i].elapsed) / 1000 / 60); + + int ipLen = Ip4AddressHttp(records[i].ip); + HttpFillChar(' ', 40 - ipLen); + + MacHttp(records[i].mac); + + HttpAddChar('\r'); + HttpAddChar('\n'); + } + } +} +static void clear(struct record* pr) +{ + pr->state = STATE_EMPTY; +} +static void clearCache(struct record* pr) +{ + if (MsTimerHasElapsed(pr->elapsed, CACHE_TIMEOUT_MS)) clear(pr); +} +static void retry(struct record* pr) +{ + if (pr->state == STATE_SENT && MsTimerHasElapsed(pr->elapsed, REPLY_TIMEOUT_MS)) + { + if (pr->tries < SEND_ATTEMPTS) + { + pr->state = STATE_WANT; + pr->elapsed = MsTimerCount; + pr->tries++; + } + else + { + clear(pr); + } + } +} +static void sendRequest(struct record* pr) +{ + if (!ArpResolveRequestFlag) + { + if (pr->state == STATE_WANT) + { + if (Ar4Trace) + { + LogTimeF("AR4 Send request for MAC from IP4 "); + Ip4AddressLog(pr->ip); + Log("\r\n"); + } + ArpAddressToResolve = pr->ip; + ArpResolveRequestFlag = true; + pr->state = STATE_SENT; + pr->elapsed = MsTimerCount; + return; + } + } +} +void Ar4Main() +{ + static int i = -1; + i++; + if (i >= RECORDS_COUNT) i = 0; + + struct record* pr = &records[i]; + + clearCache (pr); + retry (pr); + sendRequest(pr); +} +void Ar4Init() +{ + for (int i = 0; i < RECORDS_COUNT; i++) + { + struct record* pr = &records[i]; + clear(pr); + } +}