Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: oldheating gps motorhome heating
Diff: eth/nr6.c
- Revision:
- 61:aad055f1b0d1
- Parent:
- 60:1d8c7a1e7483
- Child:
- 65:37acccf2752f
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/eth/nr6.c Thu Jan 11 17:38:21 2018 +0000
@@ -0,0 +1,375 @@
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include "log.h"
+#include "clock.h"
+#include "net.h"
+#include "mac.h"
+#include "ip6addr.h"
+#include "dns.h"
+#include "dhcp.h"
+#include "dnsquery.h"
+#include "http.h"
+
+bool Nr6Trace = false;
+
+#define NAME_MAX_LENGTH 20
+#define CACHE_TIMEOUT 3600
+#define FREEZE_TIMEOUT 1800
+#define REPLY_TIMEOUT 2
+
+#define RECORDS_COUNT 20
+
+#define STATE_EMPTY 0
+#define STATE_WANT 1
+#define STATE_SENT 2
+#define STATE_VALID 3
+
+#define TODO_NONE 0
+#define TODO_NAME_FROM_IP 1
+#define TODO_IP_FROM_NAME 2
+
+static uint32_t elapsed = 0;
+struct record
+{
+ uint32_t elapsed;
+ char ip[16];
+ uint8_t todo;
+ uint8_t state;
+ uint8_t protocol;
+ char name[NAME_MAX_LENGTH];
+};
+static struct record records[RECORDS_COUNT];
+
+static int getExistingIp(char* ip)
+{
+ for (int i = 0; i < RECORDS_COUNT; i++)
+ {
+ if (records[i].state == STATE_EMPTY) continue;
+ if (Ip6AddressIsSame(records[i].ip, ip)) return i;
+ }
+ return -1;
+}
+static int getExistingName(char* name)
+{
+ for (int i = 0; i < RECORDS_COUNT; i++)
+ {
+ if (records[i].state == STATE_EMPTY) continue;
+ if (DnsHostNamesEquate(records[i].name, name)) return i;
+ }
+ return -1;
+}
+static int getNameOnly(char* name)
+{
+ for (int i = 0; i < RECORDS_COUNT; i++)
+ {
+ if (records[i].state == STATE_EMPTY) continue;
+ if (!Ip6AddressIsEmpty(records[i].ip)) continue;
+ if (DnsHostNamesEquate(records[i].name, name)) return i;
+ }
+ return -1;
+}
+static int getOldest()
+{
+ int iN = 0;
+ uint32_t tN = 0xFFFFFFFF;
+ for (int i = 0; i < RECORDS_COUNT; i++)
+ {
+ if (records[i].state == STATE_EMPTY) return i; //Found an empty slot so just return it
+ if (records[i].elapsed < tN)
+ {
+ tN = records[i].elapsed;
+ iN = i;
+ }
+ }
+ return iN; //Otherwise return the oldest
+}
+void Nr6MakeRequestForNameFromIp(char* ip)
+{
+ //Don't treat non ips
+ if (!ip[0]) return;
+ int i;
+
+ //If a record already exists then request an update
+ i = getExistingIp(ip);
+ if (i > -1)
+ {
+ if (elapsed < records[i].elapsed + FREEZE_TIMEOUT) return;
+ if (Nr6Trace)
+ {
+ LogTimeF("NR - renew name of ");
+ Ip6AddressLog(ip);
+ Log("\r\n");
+ }
+ records[i].todo = TODO_NAME_FROM_IP;
+ records[i].state = STATE_WANT;
+ records[i].protocol = DnsGetNextProtocol6(DNS_PROTOCOL_NONE);
+ records[i].elapsed = elapsed;
+ return;
+ }
+
+ //If a record does not exist then find the first empty slot and add the IP and date
+ if (Nr6Trace)
+ {
+ LogTimeF("NR - request name of ");
+ Ip6AddressLog(ip);
+ Log("\r\n");
+ }
+ i = getOldest();
+ Ip6AddressCopy(records[i].ip, ip);
+ records[i].todo = TODO_NAME_FROM_IP;
+ records[i].state = STATE_WANT;
+ records[i].protocol = DnsGetNextProtocol6(DNS_PROTOCOL_NONE);
+ records[i].elapsed = elapsed;
+ records[i].name[0] = 0;
+}
+void Nr6MakeRequestForIpFromName(char* name)
+{
+ //Don't treat non names
+ if (!name[0]) return;
+ int i;
+
+ //If a record already exists then request an update
+ i = getExistingName(name);
+ if (i > -1)
+ {
+ if (elapsed < records[i].elapsed + FREEZE_TIMEOUT) return;
+ if (Nr6Trace)
+ {
+ LogTimeF("NR - renew IPv6 of %s\r\n", name);
+ }
+ records[i].todo = TODO_IP_FROM_NAME;
+ records[i].state = STATE_WANT;
+ records[i].protocol = DnsGetNextProtocol6(DNS_PROTOCOL_NONE);
+ records[i].elapsed = elapsed;
+ return;
+ }
+
+ //If a record does not exist then find the first empty slot and add the name and date
+ if (Nr6Trace)
+ {
+ LogTimeF("NR - request IPv6 of %s\r\n", name);
+ }
+ i = getOldest();
+ records[i].ip[0] = 0;
+ records[i].todo = TODO_IP_FROM_NAME;
+ records[i].state = STATE_WANT;
+ records[i].protocol = DnsGetNextProtocol6(DNS_PROTOCOL_NONE);
+ records[i].elapsed = elapsed;
+ strncpy(records[i].name, name, NAME_MAX_LENGTH);
+ records[i].name[NAME_MAX_LENGTH - 1] = 0;
+}
+static void addIpRecord(int i, char* ip, char* name, int protocol)
+{
+ records[i].todo = TODO_NONE;
+ records[i].elapsed = elapsed;
+ Ip6AddressCopy(records[i].ip, ip);
+ records[i].protocol = protocol;
+ records[i].state = STATE_VALID;
+ strncpy(records[i].name, name, NAME_MAX_LENGTH);
+ records[i].name[NAME_MAX_LENGTH - 1] = 0;
+}
+void Nr6AddIpRecord(char* ip, char* name, int protocol)
+{
+ int i;
+
+ //Get existing ip and, if found, add it then clear any name only entries
+ i = getExistingIp(ip);
+ if (i >= 0)
+ {
+ if (Nr6Trace)
+ {
+ if (DnsHostNamesEquate(name, records[i].name)) LogTimeF("NR - confirm existing ");
+ else LogTimeF("NR - replace name for existing ip ");
+ Ip6AddressLog(ip);
+ Log(" == '");
+ Log(name);
+ Log("'\r\n");
+ }
+ addIpRecord(i, ip, name, protocol);
+
+ i = getNameOnly(name);
+ if (i >= 0)
+ {
+ if (Nr6Trace) LogTimeF("NR - clear name '%s' with no ip\r\n", name);
+ records[i].state = STATE_EMPTY;
+ }
+ return;
+ }
+
+ //Get name only entry and, if found, add it
+ i = getNameOnly(name);
+ if (i >= 0)
+ {
+ if (Nr6Trace)
+ {
+ LogTimeF("NR - add ip for name ");
+ Ip6AddressLog(ip);
+ Log(" == '");
+ Log(name);
+ Log("'\r\n");
+ }
+ addIpRecord(i, ip, name, protocol);
+ return;
+ }
+
+ //No other entry exists so just add it to the next available space
+ i = getOldest();
+ if (Nr6Trace)
+ {
+ LogTimeF("NR - add ip for name %s ");
+ Ip6AddressLog(ip);
+ Log("== '");
+ Log(name);
+ Log("'\r\n");
+ }
+ addIpRecord(i, ip, name, protocol);
+}
+void Nr6IpToName(char* ip, char* name)
+{
+ for (int i = 0; i < RECORDS_COUNT; i++)
+ {
+ if (records[i].state == STATE_EMPTY) continue;
+ if (Ip6AddressIsSame(records[i].ip, ip))
+ {
+ strcpy(name, records[i].name);
+ return;
+ }
+ }
+ name[0] = 0;
+}
+void Nr6NameToIp(char* name, char* ip)
+{
+ int newest = 0;
+ Ip6AddressClear(ip);
+ for (int i = 0; i < RECORDS_COUNT; i++)
+ {
+ if (records[i].state == STATE_EMPTY) continue;
+ if(Ip6AddressIsEmpty(records[i].ip)) continue;
+ if (!DnsHostNamesEquate(records[i].name, name)) continue;
+ if (records[i].elapsed > newest)
+ {
+ newest = records[i].elapsed;
+ Ip6AddressCopy(ip, records[i].ip);
+ }
+ }
+}
+static char letterFromStateAndProtocol(uint8_t dnsState, uint8_t protocol)
+{
+ switch (dnsState)
+ {
+ case STATE_WANT:
+ case STATE_SENT: return '>';
+
+ case STATE_VALID:
+ switch (protocol)
+ {
+ case DNS_PROTOCOL_UDNS: return 'd';
+ case DNS_PROTOCOL_MDNS: return 'm';
+ case DNS_PROTOCOL_LLMNR: return 'l';
+ case DNS_PROTOCOL_NONE: return '-';
+ default: return '?';
+ }
+ default: return '~';
+ }
+}
+void Nr6SendHttp()
+{
+ for (int i = 0; i < RECORDS_COUNT; i++)
+ {
+ if (records[i].state == STATE_EMPTY) continue;
+ if (!Ip6AddressIsEmpty(records[i].ip) || records[i].name[0])
+ {
+ HttpAddF("%4u ", (elapsed - records[i].elapsed) / 60);
+
+ int ipLen = Ip6AddressHttp(records[i].ip);
+ HttpFillChar(' ', 40 - ipLen);
+
+ HttpAddChar(letterFromStateAndProtocol(records[i].state, records[i].protocol));
+
+ HttpAddChar(' ');
+
+ HttpAddText(records[i].name);
+
+ HttpAddChar('\r');
+ HttpAddChar('\n');
+ }
+ }
+}
+static void clearCache(struct record* pr)
+{
+ if (elapsed > pr->elapsed + CACHE_TIMEOUT) pr->state = STATE_EMPTY;
+}
+static void nextProtocol(struct record* pr)
+{
+ if (pr->state == STATE_SENT && elapsed > pr->elapsed + REPLY_TIMEOUT && pr->protocol)
+ {
+ pr->protocol = DnsGetNextProtocol6(pr->protocol);
+ if (pr->protocol)
+ {
+ pr->state = STATE_WANT;
+ }
+ else
+ {
+ if (pr->todo == TODO_NAME_FROM_IP) pr->name[0] = 0;
+ if (pr->todo == TODO_IP_FROM_NAME) Ip6AddressClear(pr->ip);
+ pr->state = STATE_VALID;
+ }
+ pr->elapsed = elapsed;
+ }
+}
+static void queryNameFromIp(struct record* pr)
+{
+ if (Nr6Trace)
+ {
+ LogTime("NR - send ");
+ DnsProtocolLog(pr->protocol);
+ Log(" request for name from IP6 ");
+ Ip6AddressLog(pr->ip);
+ Log("\r\n");
+ }
+ DnsQueryNameFromIp6(pr->ip, pr->protocol);
+}
+static void queryIpFromName(struct record* pr)
+{
+ if (Nr6Trace)
+ {
+ LogTime("NR - send ");
+ DnsProtocolLog(pr->protocol);
+ Log(" request for IP6 from name '");
+ Log(pr->name);
+ Log("'\r\n");
+ }
+ DnsQueryIp6FromName(pr->name, pr->protocol);
+}
+static void sendRequest(struct record* pr)
+{
+ if ( DnsQueryIsBusy ) return;
+ if ( pr->state != STATE_WANT) return;
+ if (!pr->protocol ) return;
+
+ if (pr->todo == TODO_NAME_FROM_IP) queryNameFromIp(pr);
+ if (pr->todo == TODO_IP_FROM_NAME) queryIpFromName(pr);
+
+ pr->state = STATE_SENT;
+ pr->elapsed = elapsed;
+}
+void Nr6Main()
+{
+ static int i = -1;
+ i++;
+ if (i >= RECORDS_COUNT) i = 0;
+
+ struct record* pr = &records[i];
+
+ clearCache (pr);
+ nextProtocol(pr);
+ sendRequest (pr);
+
+ if (ClockTicked) elapsed++;
+}
+void Nr6Init()
+{
+ for (int i = 0; i < RECORDS_COUNT; i++) records[i].state = STATE_EMPTY;
+}