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:
184:ad80a63e3002
Parent:
183:ee809769bf89
Child:
185:e8f516e142c4
diff -r ee809769bf89 -r ad80a63e3002 udp/dhcp/dhcp.c
--- a/udp/dhcp/dhcp.c	Tue Jan 12 19:10:22 2021 +0000
+++ b/udp/dhcp/dhcp.c	Thu Jan 14 13:41:02 2021 +0000
@@ -30,8 +30,8 @@
 
 #define COOKIE 0x63825363
 
-#define MAX_REPEAT_DELAY_TIME_MS 60000
-#define MIN_REPEAT_DELAY_TIME_MS   900
+#define MAX_REPEAT_DELAY_TIME_MS 64000
+#define MIN_REPEAT_DELAY_TIME_MS  4000
 
 #define STATE_NONE     0
 #define STATE_DISCOVER 1
@@ -45,12 +45,9 @@
 static int          _state = STATE_NONE;
 static uint32_t _offeredIp = 0;
 static uint32_t  _serverId = 0;
-static bool _awaitResponse = false;
+static bool   _awaitingResponse = false;
 
-static uint32_t _repeatDelayMsTimer = (uint32_t)-MIN_REPEAT_DELAY_TIME_MS; //Initial value ensures no delay at startup
-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 _elapsedLifeMsTimer  = 0;              //Started whenever an IP address request has been acknowledged
+static uint32_t _elapsedLifeMsTimer  = 0;                       //Started whenever an IP address request has been acknowledged
 
 uint32_t DhcpGetElapsedLife()
 {
@@ -88,6 +85,7 @@
     DhcpHostName  [0] = 0;
     _offeredIp        = 0;
     _serverId         = 0;
+    _awaitingResponse = false;
 }
 
 bool DhcpIpNeedsToBeRouted(uint32_t ip)
@@ -243,49 +241,9 @@
     
     *pp += *pLength + 2;
 }
-int sendRequest(void* pPacket)
+int makeRequest(void* pPacket, uint8_t type, uint32_t ciaddr, uint32_t requestedIp, uint32_t serverId)
 {
-    uint8_t         type = 0;
-    uint32_t   currentIp = 0; //goes in ciaddr 
-    uint32_t requestedIp = 0; //goes in option 54
-    uint32_t    serverIp = 0; //goes in option 50 and is the server id for the accepted offer
-    
-    switch (_state)
-    {
-        case STATE_DISCOVER:
-            if (DhcpTrace) LogTimeF("DHCP -> discover\r\n");
-                   type = DHCPDISCOVER;
-              currentIp = 0;
-            requestedIp = 0;
-               serverIp = 0;
-            break;
-        case STATE_SELECT:
-            if (DhcpTrace) LogTimeF("DHCP -> select "); Ip4AddressLog(_offeredIp); Log(" from server "); Ip4AddressLog(_serverId); Log("\r\n");
-                   type = DHCPREQUEST;
-              currentIp = 0;
-            requestedIp = _offeredIp;
-               serverIp = _serverId;
-            break;
-        case STATE_RENEW:
-            if (DhcpTrace) LogTimeF("DHCP -> renew (T1)\r\n");
-                   type = DHCPREQUEST;
-              currentIp = DhcpLocalIp;
-            requestedIp = 0;
-               serverIp = 0;
-            break;
-        case STATE_REBIND:
-            if (DhcpTrace) LogTimeF("DHCP -> rebind (T2)\r\n");
-                   type = DHCPREQUEST;
-              currentIp = 0;
-            requestedIp = 0;
-               serverIp = 0;
-            break;
-        default:
-            LogTimeF("DHCP -> unknown state %d\r\n", _state);
-            return 0;
-    }
-
-    bool broadcast = currentIp == 0;
+    bool broadcast = ciaddr == 0;
     uint16_t flags = 0;
     if (broadcast) flags |= 0x8000;
     DhcpHdrSetOp    (pPacket, REQUEST            );
@@ -295,7 +253,7 @@
     DhcpHdrSetXid   (pPacket, _xid               ); //Randomly chosed transaction id used to associate messages to responses
     DhcpHdrSetSecs  (pPacket, 0                  ); //Seconds since started to boot
     DhcpHdrSetFlags (pPacket, flags              ); //Broadcast (1) Unicast (0)
-    DhcpHdrSetCiaddr(pPacket, currentIp          ); //'Client' address set by client or 0 if don't know address
+    DhcpHdrSetCiaddr(pPacket, ciaddr             ); //'Client' address set by client or 0 if don't know address
     DhcpHdrSetYiaddr(pPacket, 0                  ); //'Your' address returned by server
     DhcpHdrSetSiaddr(pPacket, 0                  ); //'Server' address to use if required
     DhcpHdrSetGiaddr(pPacket, 0                  ); //'Gateway' address
@@ -307,14 +265,9 @@
     char* p = pOptions;
     *p++ = 53; *p++ = 1; *p++ = type;                  //DHCP message type
     if (requestedIp) writeIp(50, requestedIp, &p);     //Requested IP
-    if (   serverIp) writeIp(54,    serverIp, &p);     //Server ip
+    if (   serverId) writeIp(54,    serverId, &p);     //Server ip
     writeText(12, NET_NAME, &p);                       //Host name
     *p++ = 255;                                        //End of options
-
-    _awaitResponse = true;
-    _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
-    _repeatDelayMsTimer = MsTimerCount;                                             //Start the delay timer
     
     return DHCP_HEADER_LENGTH + p - pOptions;
 }
@@ -347,8 +300,7 @@
                 _offeredIp = yiaddr;
                 readOptionServerId(sizeRx - DHCP_HEADER_LENGTH, pOptions);
                 if (DhcpTrace) { LogTime("DHCP <- offer  "); Ip4AddressLog(_offeredIp); Log(" from server "); Ip4AddressLog(_serverId); Log("\r\n"); }
-                _awaitResponse = false;
-                _delayMs = MIN_REPEAT_DELAY_TIME_MS; //Set the delay time back to minimum
+                _awaitingResponse = false;
             }
             else
             {
@@ -363,8 +315,7 @@
                 DhcpServerIp = _serverId;
                 if (DhcpTrace) { LogTime("DHCP <- ack    ");   Ip4AddressLog(DhcpLocalIp); Log(" from server "); Ip4AddressLog(_serverId); Log("\r\n"); }
                 _elapsedLifeMsTimer = MsTimerCount;  //Start the life timer
-                _awaitResponse = false;
-                _delayMs = MIN_REPEAT_DELAY_TIME_MS; //Set the delay time back to minimum
+                _awaitingResponse = false;
             }
             else
             {
@@ -377,8 +328,7 @@
                 readOptionServerId(sizeRx - DHCP_HEADER_LENGTH, pOptions);
                 if (DhcpTrace) { LogTime("DHCP <- nack   ");  Ip4AddressLog(yiaddr); Log(" from server "); Ip4AddressLog(_serverId); Log("\r\n"); }
                 clearAll();
-                _awaitResponse = false;
-                _delayMs = MIN_REPEAT_DELAY_TIME_MS; //Set the delay time back to minimum
+                _awaitingResponse = false;
             }
             else
             {
@@ -438,33 +388,94 @@
     bool stateHasChanged = _state != stateLastScan;
     stateLastScan = _state;
     
-    bool needToResendRequest = _awaitResponse && MsTimerRelative(_repeatDelayMsTimer, _delayMs);
+    static uint32_t delayMs;
+    static uint32_t repeatDelayMsTimer;
+    
+    bool responseTimeout = _awaitingResponse && MsTimerRelative(repeatDelayMsTimer, delayMs);
 
-    bool need = stateHasChanged || needToResendRequest;
+    bool send = stateHasChanged || responseTimeout;
     
-    if (!need) return DO_NOTHING;
+    if (!send) return DO_NOTHING;
+
+    int             dest = DO_NOTHING;
+    uint8_t         type = 0; //DISCOVER or REQUEST
+    uint32_t      ciaddr = 0; //goes in ciaddr only for BOUND/RENEW/REBIND
+    uint32_t requestedIp = 0; //goes in option 54 only for SELECTING
+    uint32_t    serverId = 0; //goes in option 50 and is the server id for the accepted offer
 
     //Send the renewal request
     *pSize = 0;
-    int dest = DO_NOTHING;
+
+
     switch (_state)
     {
-        case STATE_NONE:     clearAll();          return DO_NOTHING;
-        case STATE_DISCOVER: dest = BROADCAST;    break;
-        case STATE_SELECT:   dest = BROADCAST;    break;
-        case STATE_BOUND:                         return DO_NOTHING;
-        case STATE_RENEW:    dest = UNICAST_DHCP; break;
-        case STATE_REBIND:   dest = BROADCAST;    break;
-        case STATE_EXPIRED:
-            if (DhcpTrace) LogTimeF("DHCP lease has expired\r\n");
+        case STATE_NONE:
+            if (DhcpTrace) { LogTimeF("DHCP -- none\r\n"); }
             clearAll();
             return DO_NOTHING;
+            
+        case STATE_DISCOVER:
+            if (DhcpTrace) { LogTimeF("DHCP -> discover\r\n"); }
+            type = DHCPDISCOVER;
+            ciaddr = 0;
+            requestedIp = 0;
+            serverId = 0;
+            dest = BROADCAST;
+            break;
+            
+        case STATE_SELECT:
+            if (DhcpTrace) { LogTimeF("DHCP -> select "); Ip4AddressLog(_offeredIp); Log(" from server "); Ip4AddressLog(_serverId); Log("\r\n"); }
+            type = DHCPREQUEST;
+            ciaddr = 0;
+            requestedIp = _offeredIp;
+            serverId = _serverId;
+            dest = BROADCAST;
+            break;
+            
+        case STATE_BOUND:
+            if (DhcpTrace) { LogTimeF("DHCP -- bound  "); Ip4AddressLog(DhcpLocalIp); Log("\r\n"); }
+            return DO_NOTHING;
+            
+        case STATE_RENEW:
+            if (DhcpTrace) { LogTimeF("DHCP -> renew (T1) "); Ip4AddressLog(DhcpLocalIp); Log("\r\n"); }
+            type = DHCPREQUEST;
+            ciaddr = DhcpLocalIp;
+            requestedIp = 0;
+            serverId = 0;
+            dest = UNICAST_DHCP;
+            break;
+            
+        case STATE_REBIND:
+            if (DhcpTrace) { LogTimeF("DHCP -> rebind (T2) "); Ip4AddressLog(DhcpLocalIp); Log("\r\n"); }
+            type = DHCPREQUEST;
+            ciaddr = DhcpLocalIp;
+            requestedIp = 0;
+            serverId = 0;
+            dest = BROADCAST;
+            break;
+            
+        case STATE_EXPIRED:
+            if (DhcpTrace) { LogTimeF("DHCP -- expired "); Ip4AddressLog(DhcpLocalIp); Log("\r\n"); }
+            clearAll();
+            return DO_NOTHING;
+            
         default:
-            LogTimeF("DHCP -> unknown state %d", _state);
-            return DO_NOTHING;
+            LogTimeF("DHCP -- unknown state %d\r\n", _state);
+            return 0;
     }
     
-    *pSize = sendRequest(pPacket);
+    if (!_awaitingResponse)
+    {
+        delayMs = MIN_REPEAT_DELAY_TIME_MS;
+    }
+    else
+    {
+        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
+    }
+    _awaitingResponse = true;
+    repeatDelayMsTimer = MsTimerCount;                                                //Start the repeat delay timer
+    *pSize = makeRequest(pPacket, type, ciaddr, requestedIp, serverId);
     
     return ActionMakeFromDestAndTrace(dest, DhcpTrace && NetTraceStack);
 }
\ No newline at end of file