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:
Tue Jan 12 19:10:22 2021 +0000
Revision:
183:ee809769bf89
Parent:
181:169881ecd52f
Child:
184:ad80a63e3002
Added acheck as to whether DNS could be used for internal lookups and prevented external lookups being passed to LLMNR or MDNS.; Modified DHCP to try to solve the sky router sometimes sending spurious NAKs.

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