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

Revision:
116:60521b29e4c9
Parent:
115:5c003909bcf3
Child:
119:8e1a7805b801
--- a/udp/dhcp/dhcp.c	Wed Jan 23 15:42:35 2019 +0000
+++ b/udp/dhcp/dhcp.c	Fri Jan 25 17:37:51 2019 +0000
@@ -10,6 +10,7 @@
 #include "ip4addr.h"
 #include     "mac.h"
 #include     "udp.h"
+#include     "dns.h"
 
 bool DhcpTrace = false;
 
@@ -53,29 +54,32 @@
     uint32_t cookie;
 };
 
-#define REPEAT_DELAY_TIME_MS 60 * 1000
-static uint32_t delayStartMs = 0; //Reset whenever a message is sent and blocks another send until count exceeds REPEAT_DELAY_TIME
-static uint32_t lifeStartMs  = 0; //Reset whenever an IP address request has been acknowledged 
+#define MAX_REPEAT_DELAY_TIME_MS 60000
+#define MIN_REPEAT_DELAY_TIME_MS  1000
+static uint32_t repeatDelayTimer = 0;               //Started whenever a message is sent and blocks another send until after the delay time
+static uint32_t delayMs = MIN_REPEAT_DELAY_TIME_MS; //Doubles on failure up to max; reset to min whenever an IP address request has been acknowledged
+
+static uint32_t elapsedLifeTimer  = 0;              //Started whenever an IP address request has been acknowledged 
 
 uint32_t DhcpGetElapsedLife()
 {
-    if (!lifeStartMs) return 0;
-    return (MsTimerCount - lifeStartMs) / 1000;
+    if (!elapsedLifeTimer) return 0;
+    return (MsTimerCount - elapsedLifeTimer) / 1000;
 }
 
 static uint8_t  dhcpMessageType = 0;
 uint32_t DhcpLeaseTime   = 0;
-uint32_t DhcpServer      = 0;
-uint32_t DhcpRouter      = 0;
+uint32_t DhcpServerIp    = 0;
+uint32_t DhcpRouterIp    = 0;
 uint32_t DhcpSubnetMask  = 0;
-uint32_t DhcpNtp         = 0;
+uint32_t DhcpNtpIp       = 0;
 uint32_t DhcpRenewalT1   = 0;
 uint32_t DhcpRenewalT2   = 0;
 uint32_t DhcpBroadcastIp = 0;
 uint32_t DhcpLocalIp     = 0;
-uint32_t DhcpDnsServer   = 0;
-char     DhcpDomainName[20];
-char     DhcpHostName[20];
+uint32_t DhcpDnsServerIp = 0;
+char     DhcpDomainName[DNS_MAX_LABEL_LENGTH];
+char     DhcpHostName  [DNS_MAX_LABEL_LENGTH];
 
 bool DhcpIpNeedsToBeRouted(uint32_t ip)
 {   
@@ -131,20 +135,20 @@
             case 0:                                                     break;  //NOP
             case 255:                                                   return; //End of options
             case 1:               DhcpSubnetMask  = readIp(&p);         break;  //Subnet Mask        
-            case 3:               DhcpRouter      = readIp(&p);         break;  //Router           
-            case 6:               DhcpDnsServer   = readIp(&p);         break;  //DNS server     
+            case 3:               DhcpRouterIp    = readIp(&p);         break;  //Router           
+            case 6:               DhcpDnsServerIp = readIp(&p);         break;  //DNS server     
             case 12:              readString(&p, DhcpHostName);         break;  //Host name
             case 15:              readString(&p, DhcpDomainName);       break;  //Domain name
             case 19:  len = *++p; p+= len;                              break;  //IP forwarding yes/no
             case 28:              DhcpBroadcastIp = readIp(&p);         break;  //Broadcast IP         
-            case 42:              DhcpNtp         = readIp(&p);         break;  //NTP          
+            case 42:              DhcpNtpIp       = readIp(&p);         break;  //NTP          
             case 44:  len = *++p; p+= len;                              break;  //NetBIOS name server
             case 45:  len = *++p; p+= len;                              break;  //NetBIOS datagram server
             case 46:  len = *++p; p+= len;                              break;  //NetBIOS node type
             case 47:  len = *++p; p+= len;                              break;  //NetBIOS scope
             case 53:  len = *++p; dhcpMessageType = *++p;               break;  //DHCP message type
             case 51:              DhcpLeaseTime   = readOption32(&p);   break;  //Address lease time
-            case 54:              DhcpServer      = readIp(&p);         break;  //DHCP server
+            case 54:              DhcpServerIp    = readIp(&p);         break;  //DHCP server
             case 58:              DhcpRenewalT1   = readOption32(&p);   break;  //T1
             case 59:              DhcpRenewalT2   = readOption32(&p);   break;  //T2
             default:
@@ -224,7 +228,6 @@
     
     *p++ = 255;                       //End of options
     
-    delayStartMs = MsTimerCount;
     return HEADER_LENGTH + p - pOptions;
 }
 int DhcpHandleResponse(void (*traceback)(void), int sizeRx, void* pPacketRx, int* pSizeTx, void* pPacketTx)
@@ -263,7 +266,8 @@
         case DHCPACK:
             if (DhcpTrace) { LogTime("DHCP <- ack ip ");   Ip4AddressLog(yiaddr); Log("\r\n"); }
             DhcpLocalIp = yiaddr;
-            lifeStartMs = MsTimerCount;
+            elapsedLifeTimer = MsTimerCount;    //Start the life timer
+            delayMs = MIN_REPEAT_DELAY_TIME_MS; //Set the delay time back to minimum
             break;
         case DHCPNAK:
             if (DhcpTrace) { LogTime("DHCP <- nack ip ");  Ip4AddressLog(yiaddr); Log("\r\n"); }
@@ -276,10 +280,13 @@
 }
 
 int DhcpPollForRequestToSend(void* pPacket, int* pSize)
-{    
-    if (delayStartMs && !MsTimerHasElapsed(delayStartMs, REPEAT_DELAY_TIME_MS)) return DO_NOTHING; //Don't retry within the delay time
+{
+    if (repeatDelayTimer && !MsTimerHasElapsed(repeatDelayTimer, delayMs)) return DO_NOTHING; //Don't retry within the delay time
+    delayMs <<= 1;                                                                            //Backoff (double) the delay time after each attempt
+    if (delayMs > MAX_REPEAT_DELAY_TIME_MS) delayMs = MAX_REPEAT_DELAY_TIME_MS;               //Don't go beyond a maximum
+    repeatDelayTimer = MsTimerCount;                                                          //Start the delay timer
     
-    uint32_t elapsedTimeMs = MsTimerCount - lifeStartMs;
+    uint32_t elapsedTimeMs = MsTimerCount - elapsedLifeTimer;
     uint32_t   leaseTimeMs = DhcpLeaseTime * 1000;
 
     if (DhcpLocalIp && elapsedTimeMs < (leaseTimeMs >> 1)) return 0; //Do nothing if have address and within T1
@@ -288,14 +295,14 @@
     int dest = DO_NOTHING;
     if (DhcpLocalIp && elapsedTimeMs <  leaseTimeMs)
     {
-        *pSize = sendRequest(pPacket, DHCPREQUEST, DhcpServer, DhcpLocalIp); //if within T2 then send request to the server - not broadcast
+        *pSize = sendRequest(pPacket, DHCPREQUEST, DhcpServerIp, DhcpLocalIp); //if within T2 then send request to the server - not broadcast
         dest = UNICAST_DHCP;
     }
     else
     {
         if (DhcpTrace) LogTimeF("DHCP lease has expired\r\n");
         DhcpLocalIp = 0;
-        DhcpServer = 0;
+        DhcpServerIp = 0;
         *pSize = sendRequest(pPacket, DHCPDISCOVER, 0, 0); //If outside T2 then start from scratch to do a full DHCP
         dest = BROADCAST;
     }