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: udp/dhcp/dhcp.c
- Revision:
- 184:ad80a63e3002
- Parent:
- 183:ee809769bf89
- Child:
- 185:e8f516e142c4
--- 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