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
resolve/ar4.c
- Committer:
- andrewboyson
- Date:
- 2019-04-10
- Revision:
- 140:9000ea70b220
- Parent:
- 133:a37eb35a03f1
- Child:
- 159:3ebef2d02f7f
File content as of revision 140:9000ea70b220:
#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 (!MsTimerRelative(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'); } } } void Ar4SendAjax() { for (int i = 0; i < RECORDS_COUNT; i++) { if (records[i].state) { HttpAddInt32AsHex(MsTimerCount - records[i].elapsed); HttpAddInt32AsHex(records[i].ip); for (int b = 0; b < 6; b++) HttpAddByteAsHex(records[i].mac[b]); HttpAddChar('\n'); } } } static void clear(struct record* pr) { pr->state = STATE_EMPTY; } static void clearCache(struct record* pr) { if (MsTimerRelative(pr->elapsed, CACHE_TIMEOUT_MS)) clear(pr); } static void retry(struct record* pr) { if (pr->state == STATE_SENT && MsTimerRelative(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); } }