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

Committer:
andrewboyson
Date:
Thu Jan 14 13:41:02 2021 +0000
Revision:
184:ad80a63e3002
Parent:
183:ee809769bf89
Child:
185:e8f516e142c4
Modified TFTP to not start if the network wasn't ready in IPv4; Made changes to DHCP including making the first timeout 4 seconds rather than 1.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
andrewboyson 61:aad055f1b0d1 1 #include <stdint.h>
andrewboyson 61:aad055f1b0d1 2 #include <stdbool.h>
andrewboyson 61:aad055f1b0d1 3 #include <string.h>
andrewboyson 61:aad055f1b0d1 4
andrewboyson 128:79052cb4a41c 5 #include "log.h"
andrewboyson 128:79052cb4a41c 6 #include "mstimer.h"
andrewboyson 128:79052cb4a41c 7 #include "net.h"
andrewboyson 178:52714fef5ca1 8 #include "net-this.h"
andrewboyson 128:79052cb4a41c 9 #include "action.h"
andrewboyson 128:79052cb4a41c 10 #include "eth.h"
andrewboyson 128:79052cb4a41c 11 #include "ip4addr.h"
andrewboyson 128:79052cb4a41c 12 #include "mac.h"
andrewboyson 128:79052cb4a41c 13 #include "udp.h"
andrewboyson 128:79052cb4a41c 14 #include "dnslabel.h"
andrewboyson 136:8a65abb0dc63 15 #include "dhcphdr.h"
andrewboyson 10:f0854784e960 16
andrewboyson 37:793b39683406 17 bool DhcpTrace = false;
andrewboyson 10:f0854784e960 18
andrewboyson 10:f0854784e960 19 #define REQUEST 1
andrewboyson 10:f0854784e960 20 #define REPLY 2
andrewboyson 10:f0854784e960 21
andrewboyson 10:f0854784e960 22 #define DHCPDISCOVER 1
andrewboyson 10:f0854784e960 23 #define DHCPOFFER 2
andrewboyson 10:f0854784e960 24 #define DHCPREQUEST 3
andrewboyson 10:f0854784e960 25 #define DHCPDECLINE 4
andrewboyson 10:f0854784e960 26 #define DHCPACK 5
andrewboyson 10:f0854784e960 27 #define DHCPNAK 6
andrewboyson 10:f0854784e960 28 #define DHCPRELEASE 7
andrewboyson 10:f0854784e960 29 #define DHCPINFORM 8
andrewboyson 10:f0854784e960 30
andrewboyson 10:f0854784e960 31 #define COOKIE 0x63825363
andrewboyson 10:f0854784e960 32
andrewboyson 184:ad80a63e3002 33 #define MAX_REPEAT_DELAY_TIME_MS 64000
andrewboyson 184:ad80a63e3002 34 #define MIN_REPEAT_DELAY_TIME_MS 4000
andrewboyson 183:ee809769bf89 35
andrewboyson 183:ee809769bf89 36 #define STATE_NONE 0
andrewboyson 183:ee809769bf89 37 #define STATE_DISCOVER 1
andrewboyson 183:ee809769bf89 38 #define STATE_SELECT 2
andrewboyson 183:ee809769bf89 39 #define STATE_BOUND 3
andrewboyson 183:ee809769bf89 40 #define STATE_RENEW 4
andrewboyson 183:ee809769bf89 41 #define STATE_REBIND 5
andrewboyson 183:ee809769bf89 42 #define STATE_EXPIRED 6
andrewboyson 116:60521b29e4c9 43
andrewboyson 183:ee809769bf89 44 static uint32_t _xid = 0;
andrewboyson 183:ee809769bf89 45 static int _state = STATE_NONE;
andrewboyson 183:ee809769bf89 46 static uint32_t _offeredIp = 0;
andrewboyson 183:ee809769bf89 47 static uint32_t _serverId = 0;
andrewboyson 184:ad80a63e3002 48 static bool _awaitingResponse = false;
andrewboyson 183:ee809769bf89 49
andrewboyson 184:ad80a63e3002 50 static uint32_t _elapsedLifeMsTimer = 0; //Started whenever an IP address request has been acknowledged
andrewboyson 93:580fc113d9e9 51
andrewboyson 93:580fc113d9e9 52 uint32_t DhcpGetElapsedLife()
andrewboyson 10:f0854784e960 53 {
andrewboyson 183:ee809769bf89 54 if (!_elapsedLifeMsTimer) return 0;
andrewboyson 183:ee809769bf89 55 return (MsTimerCount - _elapsedLifeMsTimer) / 1000;
andrewboyson 10:f0854784e960 56 }
andrewboyson 10:f0854784e960 57
andrewboyson 183:ee809769bf89 58 static uint8_t _dhcpMessageType = 0;
andrewboyson 10:f0854784e960 59 uint32_t DhcpLeaseTime = 0;
andrewboyson 116:60521b29e4c9 60 uint32_t DhcpServerIp = 0;
andrewboyson 116:60521b29e4c9 61 uint32_t DhcpRouterIp = 0;
andrewboyson 10:f0854784e960 62 uint32_t DhcpSubnetMask = 0;
andrewboyson 116:60521b29e4c9 63 uint32_t DhcpNtpIp = 0;
andrewboyson 10:f0854784e960 64 uint32_t DhcpRenewalT1 = 0;
andrewboyson 10:f0854784e960 65 uint32_t DhcpRenewalT2 = 0;
andrewboyson 10:f0854784e960 66 uint32_t DhcpBroadcastIp = 0;
andrewboyson 10:f0854784e960 67 uint32_t DhcpLocalIp = 0;
andrewboyson 116:60521b29e4c9 68 uint32_t DhcpDnsServerIp = 0;
andrewboyson 128:79052cb4a41c 69 char DhcpDomainName[DNS_MAX_LABEL_LENGTH+1];
andrewboyson 128:79052cb4a41c 70 char DhcpHostName [DNS_MAX_LABEL_LENGTH+1];
andrewboyson 44:83ce5ace337b 71
andrewboyson 179:55342264fca1 72 static void clearAll()
andrewboyson 179:55342264fca1 73 {
andrewboyson 179:55342264fca1 74 DhcpLeaseTime = 0;
andrewboyson 179:55342264fca1 75 DhcpServerIp = 0;
andrewboyson 179:55342264fca1 76 DhcpRouterIp = 0;
andrewboyson 179:55342264fca1 77 DhcpSubnetMask = 0;
andrewboyson 179:55342264fca1 78 DhcpNtpIp = 0;
andrewboyson 179:55342264fca1 79 DhcpRenewalT1 = 0;
andrewboyson 179:55342264fca1 80 DhcpRenewalT2 = 0;
andrewboyson 179:55342264fca1 81 DhcpBroadcastIp = 0;
andrewboyson 179:55342264fca1 82 DhcpLocalIp = 0;
andrewboyson 179:55342264fca1 83 DhcpDnsServerIp = 0;
andrewboyson 179:55342264fca1 84 DhcpDomainName[0] = 0;
andrewboyson 179:55342264fca1 85 DhcpHostName [0] = 0;
andrewboyson 183:ee809769bf89 86 _offeredIp = 0;
andrewboyson 183:ee809769bf89 87 _serverId = 0;
andrewboyson 184:ad80a63e3002 88 _awaitingResponse = false;
andrewboyson 179:55342264fca1 89 }
andrewboyson 179:55342264fca1 90
andrewboyson 44:83ce5ace337b 91 bool DhcpIpNeedsToBeRouted(uint32_t ip)
andrewboyson 174:60e5ab296671 92 {
andrewboyson 174:60e5ab296671 93 if ((ip & 0x000000FF) == 0xFF) return false; //Broadcast 255.xxx.xxx.xxx
andrewboyson 174:60e5ab296671 94 if ((ip & 0x000000FF) == 0xE0) return false; //Multicast 224.xxx.xxx.xxx
andrewboyson 174:60e5ab296671 95 if (ip == (DhcpLocalIp | 0xFF000000)) return false; //Local broadcast ip == 192.168.0.255
andrewboyson 174:60e5ab296671 96
andrewboyson 174:60e5ab296671 97 return (ip & DhcpSubnetMask) != (DhcpLocalIp & DhcpSubnetMask); //ip != 192.168.0.xxx
andrewboyson 44:83ce5ace337b 98 }
andrewboyson 44:83ce5ace337b 99
andrewboyson 10:f0854784e960 100 static uint32_t readOption32(char** pp)
andrewboyson 10:f0854784e960 101 {
andrewboyson 10:f0854784e960 102 uint32_t value = 0;
andrewboyson 10:f0854784e960 103 char* p = *pp;
andrewboyson 10:f0854784e960 104 int len = *++p;
andrewboyson 10:f0854784e960 105 if (len >= 4)
andrewboyson 10:f0854784e960 106 {
andrewboyson 10:f0854784e960 107 value = *++p << 24;
andrewboyson 10:f0854784e960 108 value |= *++p << 16;
andrewboyson 10:f0854784e960 109 value |= *++p << 8;
andrewboyson 10:f0854784e960 110 value |= *++p << 0;
andrewboyson 10:f0854784e960 111 }
andrewboyson 10:f0854784e960 112 *pp += len + 1;
andrewboyson 10:f0854784e960 113 return value;
andrewboyson 10:f0854784e960 114 }
andrewboyson 10:f0854784e960 115 static uint32_t readIp(char** pp)
andrewboyson 10:f0854784e960 116 {
andrewboyson 10:f0854784e960 117 uint32_t value = 0;
andrewboyson 10:f0854784e960 118 char* p = *pp;
andrewboyson 10:f0854784e960 119 int len = *++p;
andrewboyson 10:f0854784e960 120 if (len >= 4)
andrewboyson 10:f0854784e960 121 {
andrewboyson 10:f0854784e960 122 value = *++p << 0;
andrewboyson 10:f0854784e960 123 value |= *++p << 8;
andrewboyson 10:f0854784e960 124 value |= *++p << 16;
andrewboyson 10:f0854784e960 125 value |= *++p << 24;
andrewboyson 10:f0854784e960 126 }
andrewboyson 10:f0854784e960 127 *pp += len + 1;
andrewboyson 10:f0854784e960 128 return value;
andrewboyson 10:f0854784e960 129 }
andrewboyson 10:f0854784e960 130 static void readString(char** pp, char* pText)
andrewboyson 10:f0854784e960 131 {
andrewboyson 10:f0854784e960 132 char* p = *pp;
andrewboyson 10:f0854784e960 133 int len = *++p;
andrewboyson 10:f0854784e960 134 for (int i = 0; i < len; i++) pText[i] = *++p;
andrewboyson 10:f0854784e960 135 *pp += len + 1;
andrewboyson 10:f0854784e960 136 }
andrewboyson 10:f0854784e960 137 static void readOptions(int size, char * pOptions)
andrewboyson 10:f0854784e960 138 {
andrewboyson 10:f0854784e960 139 int len = 0;
andrewboyson 10:f0854784e960 140 char* p = pOptions;
andrewboyson 10:f0854784e960 141 char* pE = pOptions + size;
andrewboyson 10:f0854784e960 142 while( p < pE)
andrewboyson 10:f0854784e960 143 {
andrewboyson 10:f0854784e960 144 switch (*p)
andrewboyson 10:f0854784e960 145 {
andrewboyson 183:ee809769bf89 146 case 0: break; //NOP
andrewboyson 183:ee809769bf89 147 case 255: return; //End of options
andrewboyson 183:ee809769bf89 148 case 1: DhcpSubnetMask = readIp(&p); break; //Subnet Mask
andrewboyson 183:ee809769bf89 149 case 3: DhcpRouterIp = readIp(&p); break; //Router
andrewboyson 183:ee809769bf89 150 case 6: DhcpDnsServerIp = readIp(&p); break; //DNS server
andrewboyson 183:ee809769bf89 151 case 12: readString(&p, DhcpHostName); break; //Host name
andrewboyson 183:ee809769bf89 152 case 15: readString(&p, DhcpDomainName); break; //Domain name
andrewboyson 183:ee809769bf89 153 case 19: len = *++p; p+= len; break; //IP forwarding yes/no
andrewboyson 183:ee809769bf89 154 case 28: DhcpBroadcastIp = readIp(&p); break; //Broadcast IP
andrewboyson 183:ee809769bf89 155 case 42: DhcpNtpIp = readIp(&p); break; //NTP
andrewboyson 183:ee809769bf89 156 case 44: len = *++p; p+= len; break; //NetBIOS name server
andrewboyson 183:ee809769bf89 157 case 45: len = *++p; p+= len; break; //NetBIOS datagram server
andrewboyson 183:ee809769bf89 158 case 46: len = *++p; p+= len; break; //NetBIOS node type
andrewboyson 183:ee809769bf89 159 case 47: len = *++p; p+= len; break; //NetBIOS scope
andrewboyson 183:ee809769bf89 160 case 53: len = *++p; _dhcpMessageType = *++p; break; //DHCP message type
andrewboyson 183:ee809769bf89 161 case 51: DhcpLeaseTime = readOption32(&p); break; //Address lease time
andrewboyson 183:ee809769bf89 162 case 54: _serverId = readIp(&p); break; //DHCP server
andrewboyson 183:ee809769bf89 163 case 58: DhcpRenewalT1 = readOption32(&p); break; //T1
andrewboyson 183:ee809769bf89 164 case 59: DhcpRenewalT2 = readOption32(&p); break; //T2
andrewboyson 10:f0854784e960 165 default:
andrewboyson 37:793b39683406 166 if (DhcpTrace) LogTimeF("Ignoring option %d\r\n", *p);
andrewboyson 10:f0854784e960 167 len = *++p;
andrewboyson 10:f0854784e960 168 p += len;
andrewboyson 10:f0854784e960 169 return;
andrewboyson 10:f0854784e960 170 }
andrewboyson 10:f0854784e960 171 p++;
andrewboyson 10:f0854784e960 172 }
andrewboyson 10:f0854784e960 173 }
andrewboyson 183:ee809769bf89 174 static void readOptionMessageType(int size, char * pOptions)
andrewboyson 183:ee809769bf89 175 {
andrewboyson 183:ee809769bf89 176 int len = 0;
andrewboyson 183:ee809769bf89 177 char* p = pOptions;
andrewboyson 183:ee809769bf89 178 char* pE = pOptions + size;
andrewboyson 183:ee809769bf89 179 while( p < pE)
andrewboyson 183:ee809769bf89 180 {
andrewboyson 183:ee809769bf89 181 switch (*p)
andrewboyson 183:ee809769bf89 182 {
andrewboyson 183:ee809769bf89 183 case 0: break; //NOP
andrewboyson 183:ee809769bf89 184 case 255: return; //End of options
andrewboyson 183:ee809769bf89 185 case 53: len = *++p; _dhcpMessageType = *++p; break; //DHCP message type
andrewboyson 183:ee809769bf89 186 default: len = *++p; p += len; break;
andrewboyson 183:ee809769bf89 187 }
andrewboyson 183:ee809769bf89 188 p++;
andrewboyson 183:ee809769bf89 189 }
andrewboyson 183:ee809769bf89 190 }
andrewboyson 183:ee809769bf89 191 static void readOptionServerId(int size, char * pOptions)
andrewboyson 183:ee809769bf89 192 {
andrewboyson 183:ee809769bf89 193 int len = 0;
andrewboyson 183:ee809769bf89 194 char* p = pOptions;
andrewboyson 183:ee809769bf89 195 char* pE = pOptions + size;
andrewboyson 183:ee809769bf89 196 while( p < pE)
andrewboyson 183:ee809769bf89 197 {
andrewboyson 183:ee809769bf89 198 switch (*p)
andrewboyson 183:ee809769bf89 199 {
andrewboyson 183:ee809769bf89 200 case 0: break; //NOP
andrewboyson 183:ee809769bf89 201 case 255: return; //End of options
andrewboyson 183:ee809769bf89 202 case 54: _serverId = readIp(&p); break; //DHCP server
andrewboyson 183:ee809769bf89 203 default: len = *++p; p += len; break;
andrewboyson 183:ee809769bf89 204 }
andrewboyson 183:ee809769bf89 205 p++;
andrewboyson 183:ee809769bf89 206 }
andrewboyson 183:ee809769bf89 207 }
andrewboyson 10:f0854784e960 208 static void writeIp(uint8_t code, uint32_t value, char** pp)
andrewboyson 10:f0854784e960 209 {
andrewboyson 10:f0854784e960 210 if (!value) return;
andrewboyson 136:8a65abb0dc63 211
andrewboyson 10:f0854784e960 212 char* p = *pp;
andrewboyson 136:8a65abb0dc63 213
andrewboyson 10:f0854784e960 214 *p++ = code;
andrewboyson 10:f0854784e960 215 *p++ = 4;
andrewboyson 10:f0854784e960 216 *p++ = (value & 0x000000FF) >> 0;
andrewboyson 10:f0854784e960 217 *p++ = (value & 0x0000FF00) >> 8;
andrewboyson 10:f0854784e960 218 *p++ = (value & 0x00FF0000) >> 16;
andrewboyson 10:f0854784e960 219 *p++ = (value & 0xFF000000) >> 24;
andrewboyson 136:8a65abb0dc63 220
andrewboyson 10:f0854784e960 221 *pp += 6;
andrewboyson 10:f0854784e960 222 }
andrewboyson 178:52714fef5ca1 223 static void writeText(uint8_t code, const char* pText, char** pp)
andrewboyson 178:52714fef5ca1 224 {
andrewboyson 178:52714fef5ca1 225 if (!pText) return;
andrewboyson 178:52714fef5ca1 226 if (!*pText) return;
andrewboyson 178:52714fef5ca1 227
andrewboyson 178:52714fef5ca1 228 char* p = *pp;
andrewboyson 178:52714fef5ca1 229
andrewboyson 178:52714fef5ca1 230 *p++ = code;
andrewboyson 178:52714fef5ca1 231 char* pLength = p++;
andrewboyson 178:52714fef5ca1 232 while (true) //Copy pText without the end zero
andrewboyson 178:52714fef5ca1 233 {
andrewboyson 178:52714fef5ca1 234 *p = *pText;
andrewboyson 178:52714fef5ca1 235 pText++;
andrewboyson 178:52714fef5ca1 236 if (!*pText) break;
andrewboyson 178:52714fef5ca1 237 p++;
andrewboyson 178:52714fef5ca1 238 }
andrewboyson 178:52714fef5ca1 239
andrewboyson 178:52714fef5ca1 240 *pLength = p - pLength;
andrewboyson 178:52714fef5ca1 241
andrewboyson 178:52714fef5ca1 242 *pp += *pLength + 2;
andrewboyson 178:52714fef5ca1 243 }
andrewboyson 184:ad80a63e3002 244 int makeRequest(void* pPacket, uint8_t type, uint32_t ciaddr, uint32_t requestedIp, uint32_t serverId)
andrewboyson 10:f0854784e960 245 {
andrewboyson 184:ad80a63e3002 246 bool broadcast = ciaddr == 0;
andrewboyson 10:f0854784e960 247 uint16_t flags = 0;
andrewboyson 136:8a65abb0dc63 248 if (broadcast) flags |= 0x8000;
andrewboyson 136:8a65abb0dc63 249 DhcpHdrSetOp (pPacket, REQUEST );
andrewboyson 136:8a65abb0dc63 250 DhcpHdrSetHtype (pPacket, ETHERNET );
andrewboyson 136:8a65abb0dc63 251 DhcpHdrSetHlen (pPacket, 6 );
andrewboyson 136:8a65abb0dc63 252 DhcpHdrSetHops (pPacket, 0 );
andrewboyson 183:ee809769bf89 253 DhcpHdrSetXid (pPacket, _xid ); //Randomly chosed transaction id used to associate messages to responses
andrewboyson 136:8a65abb0dc63 254 DhcpHdrSetSecs (pPacket, 0 ); //Seconds since started to boot
andrewboyson 136:8a65abb0dc63 255 DhcpHdrSetFlags (pPacket, flags ); //Broadcast (1) Unicast (0)
andrewboyson 184:ad80a63e3002 256 DhcpHdrSetCiaddr(pPacket, ciaddr ); //'Client' address set by client or 0 if don't know address
andrewboyson 136:8a65abb0dc63 257 DhcpHdrSetYiaddr(pPacket, 0 ); //'Your' address returned by server
andrewboyson 181:169881ecd52f 258 DhcpHdrSetSiaddr(pPacket, 0 ); //'Server' address to use if required
andrewboyson 136:8a65abb0dc63 259 DhcpHdrSetGiaddr(pPacket, 0 ); //'Gateway' address
andrewboyson 136:8a65abb0dc63 260 memcpy(DhcpHdrPtrChaddr(pPacket), MacLocal, 6); //'Client hardware' address. 6 bytes for ethernet
andrewboyson 136:8a65abb0dc63 261 memset(DhcpHdrPtrLegacy(pPacket), 0, 192 ); //BootP legacy fill with zeros
andrewboyson 136:8a65abb0dc63 262 DhcpHdrSetCookie(pPacket, COOKIE ); //Magic cookie
andrewboyson 136:8a65abb0dc63 263
andrewboyson 136:8a65abb0dc63 264 char* pOptions = (char*)pPacket + DHCP_HEADER_LENGTH;
andrewboyson 10:f0854784e960 265 char* p = pOptions;
andrewboyson 183:ee809769bf89 266 *p++ = 53; *p++ = 1; *p++ = type; //DHCP message type
andrewboyson 183:ee809769bf89 267 if (requestedIp) writeIp(50, requestedIp, &p); //Requested IP
andrewboyson 184:ad80a63e3002 268 if ( serverId) writeIp(54, serverId, &p); //Server ip
andrewboyson 183:ee809769bf89 269 writeText(12, NET_NAME, &p); //Host name
andrewboyson 183:ee809769bf89 270 *p++ = 255; //End of options
andrewboyson 178:52714fef5ca1 271
andrewboyson 136:8a65abb0dc63 272 return DHCP_HEADER_LENGTH + p - pOptions;
andrewboyson 136:8a65abb0dc63 273 }
andrewboyson 136:8a65abb0dc63 274 int DhcpHandleResponse(void (*traceback)(void), int sizeRx, char* pPacketRx, int* pSizeTx, char* pPacketTx)
andrewboyson 136:8a65abb0dc63 275 {
andrewboyson 136:8a65abb0dc63 276 uint8_t op = DhcpHdrGetOp (pPacketRx);
andrewboyson 136:8a65abb0dc63 277 uint8_t htype = DhcpHdrGetHtype (pPacketRx);
andrewboyson 136:8a65abb0dc63 278 uint8_t hlen = DhcpHdrGetHlen (pPacketRx);
andrewboyson 136:8a65abb0dc63 279 uint32_t xid = DhcpHdrGetXid (pPacketRx); //Randomly chosen transaction id used to associate messages to responses
andrewboyson 136:8a65abb0dc63 280 uint32_t yiaddr = DhcpHdrGetYiaddr(pPacketRx);
andrewboyson 136:8a65abb0dc63 281 uint32_t siaddr = DhcpHdrGetSiaddr(pPacketRx);
andrewboyson 136:8a65abb0dc63 282 uint32_t cookie = DhcpHdrGetCookie(pPacketRx);
andrewboyson 136:8a65abb0dc63 283
andrewboyson 136:8a65abb0dc63 284 if (op != REPLY) return DO_NOTHING;
andrewboyson 136:8a65abb0dc63 285 if (htype != ETHERNET) return DO_NOTHING;
andrewboyson 136:8a65abb0dc63 286 if (hlen != 6) return DO_NOTHING;
andrewboyson 136:8a65abb0dc63 287 if (memcmp(DhcpHdrPtrChaddr(pPacketRx), MacLocal, 6)) return DO_NOTHING;
andrewboyson 183:ee809769bf89 288 if (!_xid) return DO_NOTHING;
andrewboyson 183:ee809769bf89 289 if (xid != _xid) return DO_NOTHING;
andrewboyson 136:8a65abb0dc63 290 if (cookie != COOKIE) return DO_NOTHING;
andrewboyson 136:8a65abb0dc63 291
andrewboyson 136:8a65abb0dc63 292 char* pOptions = (char*)pPacketRx + DHCP_HEADER_LENGTH;
andrewboyson 183:ee809769bf89 293 readOptionMessageType(sizeRx - DHCP_HEADER_LENGTH, pOptions);
andrewboyson 183:ee809769bf89 294
andrewboyson 183:ee809769bf89 295 switch (_dhcpMessageType)
andrewboyson 10:f0854784e960 296 {
andrewboyson 10:f0854784e960 297 case DHCPOFFER:
andrewboyson 183:ee809769bf89 298 if (_state == STATE_DISCOVER)
andrewboyson 183:ee809769bf89 299 {
andrewboyson 183:ee809769bf89 300 _offeredIp = yiaddr;
andrewboyson 183:ee809769bf89 301 readOptionServerId(sizeRx - DHCP_HEADER_LENGTH, pOptions);
andrewboyson 183:ee809769bf89 302 if (DhcpTrace) { LogTime("DHCP <- offer "); Ip4AddressLog(_offeredIp); Log(" from server "); Ip4AddressLog(_serverId); Log("\r\n"); }
andrewboyson 184:ad80a63e3002 303 _awaitingResponse = false;
andrewboyson 183:ee809769bf89 304 }
andrewboyson 183:ee809769bf89 305 else
andrewboyson 183:ee809769bf89 306 {
andrewboyson 183:ee809769bf89 307 if (DhcpTrace) { LogTime("DHCP <- offer "); Ip4AddressLog(_offeredIp); Log(" from server "); Ip4AddressLog(_serverId); Log(" ignored\r\n"); }
andrewboyson 183:ee809769bf89 308 }
andrewboyson 183:ee809769bf89 309 break;
andrewboyson 10:f0854784e960 310 case DHCPACK:
andrewboyson 183:ee809769bf89 311 if (_state == STATE_SELECT || _state == STATE_RENEW || _state == STATE_REBIND)
andrewboyson 183:ee809769bf89 312 {
andrewboyson 183:ee809769bf89 313 DhcpLocalIp = yiaddr;
andrewboyson 183:ee809769bf89 314 readOptions(sizeRx - DHCP_HEADER_LENGTH, pOptions);
andrewboyson 183:ee809769bf89 315 DhcpServerIp = _serverId;
andrewboyson 183:ee809769bf89 316 if (DhcpTrace) { LogTime("DHCP <- ack "); Ip4AddressLog(DhcpLocalIp); Log(" from server "); Ip4AddressLog(_serverId); Log("\r\n"); }
andrewboyson 183:ee809769bf89 317 _elapsedLifeMsTimer = MsTimerCount; //Start the life timer
andrewboyson 184:ad80a63e3002 318 _awaitingResponse = false;
andrewboyson 183:ee809769bf89 319 }
andrewboyson 183:ee809769bf89 320 else
andrewboyson 183:ee809769bf89 321 {
andrewboyson 183:ee809769bf89 322 if (DhcpTrace) { LogTime("DHCP <- ack "); Ip4AddressLog(DhcpLocalIp); Log(" from server "); Ip4AddressLog(_serverId); Log(" ignored\r\n"); }
andrewboyson 183:ee809769bf89 323 }
andrewboyson 10:f0854784e960 324 break;
andrewboyson 10:f0854784e960 325 case DHCPNAK:
andrewboyson 183:ee809769bf89 326 if (_state == STATE_SELECT || _state == STATE_RENEW || _state == STATE_REBIND)
andrewboyson 183:ee809769bf89 327 {
andrewboyson 183:ee809769bf89 328 readOptionServerId(sizeRx - DHCP_HEADER_LENGTH, pOptions);
andrewboyson 183:ee809769bf89 329 if (DhcpTrace) { LogTime("DHCP <- nack "); Ip4AddressLog(yiaddr); Log(" from server "); Ip4AddressLog(_serverId); Log("\r\n"); }
andrewboyson 183:ee809769bf89 330 clearAll();
andrewboyson 184:ad80a63e3002 331 _awaitingResponse = false;
andrewboyson 183:ee809769bf89 332 }
andrewboyson 183:ee809769bf89 333 else
andrewboyson 183:ee809769bf89 334 {
andrewboyson 183:ee809769bf89 335 if (DhcpTrace) { LogTime("DHCP <- nack "); Ip4AddressLog(yiaddr); Log(" from server "); Ip4AddressLog(_serverId); Log(" ignored\r\n"); }
andrewboyson 183:ee809769bf89 336 }
andrewboyson 10:f0854784e960 337 break;
andrewboyson 10:f0854784e960 338 default:
andrewboyson 183:ee809769bf89 339 LogTimeF("DHCP <- unknown message %d\r\n", _dhcpMessageType);
andrewboyson 10:f0854784e960 340 break;
andrewboyson 10:f0854784e960 341 }
andrewboyson 10:f0854784e960 342 return DO_NOTHING;
andrewboyson 10:f0854784e960 343 }
andrewboyson 10:f0854784e960 344
andrewboyson 10:f0854784e960 345 int DhcpPollForRequestToSend(void* pPacket, int* pSize)
andrewboyson 116:60521b29e4c9 346 {
andrewboyson 183:ee809769bf89 347
andrewboyson 183:ee809769bf89 348 if (!_xid)
andrewboyson 183:ee809769bf89 349 {
andrewboyson 183:ee809769bf89 350 _xid = (uint32_t)MacLocal[2] << 24;
andrewboyson 183:ee809769bf89 351 _xid += (uint32_t)MacLocal[3] << 16;
andrewboyson 183:ee809769bf89 352 _xid += (uint32_t)MacLocal[4] << 8;
andrewboyson 183:ee809769bf89 353 _xid += (uint32_t)MacLocal[5] << 0;
andrewboyson 183:ee809769bf89 354 }
andrewboyson 183:ee809769bf89 355
andrewboyson 119:8e1a7805b801 356 //Check if time to update
andrewboyson 183:ee809769bf89 357 uint32_t elapsedTimeMs = MsTimerCount - _elapsedLifeMsTimer;
andrewboyson 93:580fc113d9e9 358 uint32_t leaseTimeMs = DhcpLeaseTime * 1000;
andrewboyson 183:ee809769bf89 359
andrewboyson 183:ee809769bf89 360 uint32_t T1 = leaseTimeMs >> 1; //0.5
andrewboyson 183:ee809769bf89 361 uint32_t T2 = (leaseTimeMs >> 1) + (leaseTimeMs >> 2) + (leaseTimeMs >> 3); //0.875 = 0.5 + 0.25 + 0.125
andrewboyson 183:ee809769bf89 362
andrewboyson 183:ee809769bf89 363 if (!DhcpLocalIp)
andrewboyson 183:ee809769bf89 364 {
andrewboyson 183:ee809769bf89 365 if (!_offeredIp) _state = STATE_DISCOVER;
andrewboyson 183:ee809769bf89 366 else _state = STATE_SELECT;
andrewboyson 183:ee809769bf89 367 }
andrewboyson 183:ee809769bf89 368 else
andrewboyson 183:ee809769bf89 369 {
andrewboyson 183:ee809769bf89 370 if (elapsedTimeMs < T1)
andrewboyson 183:ee809769bf89 371 {
andrewboyson 183:ee809769bf89 372 _state = STATE_BOUND;
andrewboyson 183:ee809769bf89 373 }
andrewboyson 183:ee809769bf89 374 else if (elapsedTimeMs < T2)
andrewboyson 183:ee809769bf89 375 {
andrewboyson 183:ee809769bf89 376 _state = STATE_RENEW;
andrewboyson 183:ee809769bf89 377 }
andrewboyson 183:ee809769bf89 378 else if (elapsedTimeMs < leaseTimeMs)
andrewboyson 183:ee809769bf89 379 {
andrewboyson 183:ee809769bf89 380 _state = STATE_REBIND;
andrewboyson 183:ee809769bf89 381 }
andrewboyson 183:ee809769bf89 382 else
andrewboyson 183:ee809769bf89 383 {
andrewboyson 183:ee809769bf89 384 _state = STATE_EXPIRED;
andrewboyson 183:ee809769bf89 385 }
andrewboyson 183:ee809769bf89 386 }
andrewboyson 183:ee809769bf89 387 static int stateLastScan = STATE_NONE;
andrewboyson 183:ee809769bf89 388 bool stateHasChanged = _state != stateLastScan;
andrewboyson 183:ee809769bf89 389 stateLastScan = _state;
andrewboyson 183:ee809769bf89 390
andrewboyson 184:ad80a63e3002 391 static uint32_t delayMs;
andrewboyson 184:ad80a63e3002 392 static uint32_t repeatDelayMsTimer;
andrewboyson 184:ad80a63e3002 393
andrewboyson 184:ad80a63e3002 394 bool responseTimeout = _awaitingResponse && MsTimerRelative(repeatDelayMsTimer, delayMs);
andrewboyson 136:8a65abb0dc63 395
andrewboyson 184:ad80a63e3002 396 bool send = stateHasChanged || responseTimeout;
andrewboyson 183:ee809769bf89 397
andrewboyson 184:ad80a63e3002 398 if (!send) return DO_NOTHING;
andrewboyson 184:ad80a63e3002 399
andrewboyson 184:ad80a63e3002 400 int dest = DO_NOTHING;
andrewboyson 184:ad80a63e3002 401 uint8_t type = 0; //DISCOVER or REQUEST
andrewboyson 184:ad80a63e3002 402 uint32_t ciaddr = 0; //goes in ciaddr only for BOUND/RENEW/REBIND
andrewboyson 184:ad80a63e3002 403 uint32_t requestedIp = 0; //goes in option 54 only for SELECTING
andrewboyson 184:ad80a63e3002 404 uint32_t serverId = 0; //goes in option 50 and is the server id for the accepted offer
andrewboyson 136:8a65abb0dc63 405
andrewboyson 119:8e1a7805b801 406 //Send the renewal request
andrewboyson 10:f0854784e960 407 *pSize = 0;
andrewboyson 184:ad80a63e3002 408
andrewboyson 184:ad80a63e3002 409
andrewboyson 183:ee809769bf89 410 switch (_state)
andrewboyson 10:f0854784e960 411 {
andrewboyson 184:ad80a63e3002 412 case STATE_NONE:
andrewboyson 184:ad80a63e3002 413 if (DhcpTrace) { LogTimeF("DHCP -- none\r\n"); }
andrewboyson 183:ee809769bf89 414 clearAll();
andrewboyson 183:ee809769bf89 415 return DO_NOTHING;
andrewboyson 184:ad80a63e3002 416
andrewboyson 184:ad80a63e3002 417 case STATE_DISCOVER:
andrewboyson 184:ad80a63e3002 418 if (DhcpTrace) { LogTimeF("DHCP -> discover\r\n"); }
andrewboyson 184:ad80a63e3002 419 type = DHCPDISCOVER;
andrewboyson 184:ad80a63e3002 420 ciaddr = 0;
andrewboyson 184:ad80a63e3002 421 requestedIp = 0;
andrewboyson 184:ad80a63e3002 422 serverId = 0;
andrewboyson 184:ad80a63e3002 423 dest = BROADCAST;
andrewboyson 184:ad80a63e3002 424 break;
andrewboyson 184:ad80a63e3002 425
andrewboyson 184:ad80a63e3002 426 case STATE_SELECT:
andrewboyson 184:ad80a63e3002 427 if (DhcpTrace) { LogTimeF("DHCP -> select "); Ip4AddressLog(_offeredIp); Log(" from server "); Ip4AddressLog(_serverId); Log("\r\n"); }
andrewboyson 184:ad80a63e3002 428 type = DHCPREQUEST;
andrewboyson 184:ad80a63e3002 429 ciaddr = 0;
andrewboyson 184:ad80a63e3002 430 requestedIp = _offeredIp;
andrewboyson 184:ad80a63e3002 431 serverId = _serverId;
andrewboyson 184:ad80a63e3002 432 dest = BROADCAST;
andrewboyson 184:ad80a63e3002 433 break;
andrewboyson 184:ad80a63e3002 434
andrewboyson 184:ad80a63e3002 435 case STATE_BOUND:
andrewboyson 184:ad80a63e3002 436 if (DhcpTrace) { LogTimeF("DHCP -- bound "); Ip4AddressLog(DhcpLocalIp); Log("\r\n"); }
andrewboyson 184:ad80a63e3002 437 return DO_NOTHING;
andrewboyson 184:ad80a63e3002 438
andrewboyson 184:ad80a63e3002 439 case STATE_RENEW:
andrewboyson 184:ad80a63e3002 440 if (DhcpTrace) { LogTimeF("DHCP -> renew (T1) "); Ip4AddressLog(DhcpLocalIp); Log("\r\n"); }
andrewboyson 184:ad80a63e3002 441 type = DHCPREQUEST;
andrewboyson 184:ad80a63e3002 442 ciaddr = DhcpLocalIp;
andrewboyson 184:ad80a63e3002 443 requestedIp = 0;
andrewboyson 184:ad80a63e3002 444 serverId = 0;
andrewboyson 184:ad80a63e3002 445 dest = UNICAST_DHCP;
andrewboyson 184:ad80a63e3002 446 break;
andrewboyson 184:ad80a63e3002 447
andrewboyson 184:ad80a63e3002 448 case STATE_REBIND:
andrewboyson 184:ad80a63e3002 449 if (DhcpTrace) { LogTimeF("DHCP -> rebind (T2) "); Ip4AddressLog(DhcpLocalIp); Log("\r\n"); }
andrewboyson 184:ad80a63e3002 450 type = DHCPREQUEST;
andrewboyson 184:ad80a63e3002 451 ciaddr = DhcpLocalIp;
andrewboyson 184:ad80a63e3002 452 requestedIp = 0;
andrewboyson 184:ad80a63e3002 453 serverId = 0;
andrewboyson 184:ad80a63e3002 454 dest = BROADCAST;
andrewboyson 184:ad80a63e3002 455 break;
andrewboyson 184:ad80a63e3002 456
andrewboyson 184:ad80a63e3002 457 case STATE_EXPIRED:
andrewboyson 184:ad80a63e3002 458 if (DhcpTrace) { LogTimeF("DHCP -- expired "); Ip4AddressLog(DhcpLocalIp); Log("\r\n"); }
andrewboyson 184:ad80a63e3002 459 clearAll();
andrewboyson 184:ad80a63e3002 460 return DO_NOTHING;
andrewboyson 184:ad80a63e3002 461
andrewboyson 183:ee809769bf89 462 default:
andrewboyson 184:ad80a63e3002 463 LogTimeF("DHCP -- unknown state %d\r\n", _state);
andrewboyson 184:ad80a63e3002 464 return 0;
andrewboyson 10:f0854784e960 465 }
andrewboyson 183:ee809769bf89 466
andrewboyson 184:ad80a63e3002 467 if (!_awaitingResponse)
andrewboyson 184:ad80a63e3002 468 {
andrewboyson 184:ad80a63e3002 469 delayMs = MIN_REPEAT_DELAY_TIME_MS;
andrewboyson 184:ad80a63e3002 470 }
andrewboyson 184:ad80a63e3002 471 else
andrewboyson 184:ad80a63e3002 472 {
andrewboyson 184:ad80a63e3002 473 delayMs <<= 1; //Backoff (double) the delay time after each attempt
andrewboyson 184:ad80a63e3002 474 if (delayMs > MAX_REPEAT_DELAY_TIME_MS) delayMs = MAX_REPEAT_DELAY_TIME_MS; //Don't go beyond a maximum
andrewboyson 184:ad80a63e3002 475 }
andrewboyson 184:ad80a63e3002 476 _awaitingResponse = true;
andrewboyson 184:ad80a63e3002 477 repeatDelayMsTimer = MsTimerCount; //Start the repeat delay timer
andrewboyson 184:ad80a63e3002 478 *pSize = makeRequest(pPacket, type, ciaddr, requestedIp, serverId);
andrewboyson 183:ee809769bf89 479
andrewboyson 181:169881ecd52f 480 return ActionMakeFromDestAndTrace(dest, DhcpTrace && NetTraceStack);
andrewboyson 136:8a65abb0dc63 481 }