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 May 20 14:32:52 2021 +0000
Revision:
200:5acbc41bf469
Parent:
187:122fc1996c86
Increased number of arp entries from 20 to 30 to accommodate the number of WIZ devices plus a few incoming port 80 calls from the internet.

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 185:e8f516e142c4 261 memset(DhcpHdrPtrChaddr(pPacket) + 6, 0, 10 ); //Pad the remainder of the hardware address field with zeros
andrewboyson 136:8a65abb0dc63 262 memset(DhcpHdrPtrLegacy(pPacket), 0, 192 ); //BootP legacy fill with zeros
andrewboyson 136:8a65abb0dc63 263 DhcpHdrSetCookie(pPacket, COOKIE ); //Magic cookie
andrewboyson 136:8a65abb0dc63 264
andrewboyson 136:8a65abb0dc63 265 char* pOptions = (char*)pPacket + DHCP_HEADER_LENGTH;
andrewboyson 10:f0854784e960 266 char* p = pOptions;
andrewboyson 183:ee809769bf89 267 *p++ = 53; *p++ = 1; *p++ = type; //DHCP message type
andrewboyson 183:ee809769bf89 268 if (requestedIp) writeIp(50, requestedIp, &p); //Requested IP
andrewboyson 184:ad80a63e3002 269 if ( serverId) writeIp(54, serverId, &p); //Server ip
andrewboyson 183:ee809769bf89 270 writeText(12, NET_NAME, &p); //Host name
andrewboyson 183:ee809769bf89 271 *p++ = 255; //End of options
andrewboyson 178:52714fef5ca1 272
andrewboyson 136:8a65abb0dc63 273 return DHCP_HEADER_LENGTH + p - pOptions;
andrewboyson 136:8a65abb0dc63 274 }
andrewboyson 136:8a65abb0dc63 275 int DhcpHandleResponse(void (*traceback)(void), int sizeRx, char* pPacketRx, int* pSizeTx, char* pPacketTx)
andrewboyson 136:8a65abb0dc63 276 {
andrewboyson 136:8a65abb0dc63 277 uint8_t op = DhcpHdrGetOp (pPacketRx);
andrewboyson 136:8a65abb0dc63 278 uint8_t htype = DhcpHdrGetHtype (pPacketRx);
andrewboyson 136:8a65abb0dc63 279 uint8_t hlen = DhcpHdrGetHlen (pPacketRx);
andrewboyson 136:8a65abb0dc63 280 uint32_t xid = DhcpHdrGetXid (pPacketRx); //Randomly chosen transaction id used to associate messages to responses
andrewboyson 136:8a65abb0dc63 281 uint32_t yiaddr = DhcpHdrGetYiaddr(pPacketRx);
andrewboyson 136:8a65abb0dc63 282 uint32_t siaddr = DhcpHdrGetSiaddr(pPacketRx);
andrewboyson 136:8a65abb0dc63 283 uint32_t cookie = DhcpHdrGetCookie(pPacketRx);
andrewboyson 136:8a65abb0dc63 284
andrewboyson 136:8a65abb0dc63 285 if (op != REPLY) return DO_NOTHING;
andrewboyson 136:8a65abb0dc63 286 if (htype != ETHERNET) return DO_NOTHING;
andrewboyson 136:8a65abb0dc63 287 if (hlen != 6) return DO_NOTHING;
andrewboyson 136:8a65abb0dc63 288 if (memcmp(DhcpHdrPtrChaddr(pPacketRx), MacLocal, 6)) return DO_NOTHING;
andrewboyson 183:ee809769bf89 289 if (!_xid) return DO_NOTHING;
andrewboyson 183:ee809769bf89 290 if (xid != _xid) return DO_NOTHING;
andrewboyson 136:8a65abb0dc63 291 if (cookie != COOKIE) return DO_NOTHING;
andrewboyson 136:8a65abb0dc63 292
andrewboyson 136:8a65abb0dc63 293 char* pOptions = (char*)pPacketRx + DHCP_HEADER_LENGTH;
andrewboyson 183:ee809769bf89 294 readOptionMessageType(sizeRx - DHCP_HEADER_LENGTH, pOptions);
andrewboyson 183:ee809769bf89 295
andrewboyson 183:ee809769bf89 296 switch (_dhcpMessageType)
andrewboyson 10:f0854784e960 297 {
andrewboyson 10:f0854784e960 298 case DHCPOFFER:
andrewboyson 183:ee809769bf89 299 if (_state == STATE_DISCOVER)
andrewboyson 183:ee809769bf89 300 {
andrewboyson 183:ee809769bf89 301 _offeredIp = yiaddr;
andrewboyson 183:ee809769bf89 302 readOptionServerId(sizeRx - DHCP_HEADER_LENGTH, pOptions);
andrewboyson 187:122fc1996c86 303 if (DhcpTrace) { LogTime("DHCP <- offer "); Ip4AddrLog(_offeredIp); Log(" from server "); Ip4AddrLog(_serverId); Log("\r\n"); }
andrewboyson 184:ad80a63e3002 304 _awaitingResponse = false;
andrewboyson 183:ee809769bf89 305 }
andrewboyson 183:ee809769bf89 306 else
andrewboyson 183:ee809769bf89 307 {
andrewboyson 187:122fc1996c86 308 if (DhcpTrace) { LogTime("DHCP <- offer "); Ip4AddrLog(_offeredIp); Log(" from server "); Ip4AddrLog(_serverId); Log(" ignored\r\n"); }
andrewboyson 183:ee809769bf89 309 }
andrewboyson 183:ee809769bf89 310 break;
andrewboyson 10:f0854784e960 311 case DHCPACK:
andrewboyson 183:ee809769bf89 312 if (_state == STATE_SELECT || _state == STATE_RENEW || _state == STATE_REBIND)
andrewboyson 183:ee809769bf89 313 {
andrewboyson 183:ee809769bf89 314 DhcpLocalIp = yiaddr;
andrewboyson 183:ee809769bf89 315 readOptions(sizeRx - DHCP_HEADER_LENGTH, pOptions);
andrewboyson 183:ee809769bf89 316 DhcpServerIp = _serverId;
andrewboyson 187:122fc1996c86 317 if (DhcpTrace) { LogTime("DHCP <- ack "); Ip4AddrLog(DhcpLocalIp); Log(" from server "); Ip4AddrLog(_serverId); Log("\r\n"); }
andrewboyson 183:ee809769bf89 318 _elapsedLifeMsTimer = MsTimerCount; //Start the life timer
andrewboyson 184:ad80a63e3002 319 _awaitingResponse = false;
andrewboyson 183:ee809769bf89 320 }
andrewboyson 183:ee809769bf89 321 else
andrewboyson 183:ee809769bf89 322 {
andrewboyson 187:122fc1996c86 323 if (DhcpTrace) { LogTime("DHCP <- ack "); Ip4AddrLog(DhcpLocalIp); Log(" from server "); Ip4AddrLog(_serverId); Log(" ignored\r\n"); }
andrewboyson 183:ee809769bf89 324 }
andrewboyson 10:f0854784e960 325 break;
andrewboyson 10:f0854784e960 326 case DHCPNAK:
andrewboyson 183:ee809769bf89 327 if (_state == STATE_SELECT || _state == STATE_RENEW || _state == STATE_REBIND)
andrewboyson 183:ee809769bf89 328 {
andrewboyson 183:ee809769bf89 329 readOptionServerId(sizeRx - DHCP_HEADER_LENGTH, pOptions);
andrewboyson 187:122fc1996c86 330 if (DhcpTrace) { LogTime("DHCP <- nack "); Ip4AddrLog(yiaddr); Log(" from server "); Ip4AddrLog(_serverId); Log("\r\n"); }
andrewboyson 183:ee809769bf89 331 clearAll();
andrewboyson 184:ad80a63e3002 332 _awaitingResponse = false;
andrewboyson 183:ee809769bf89 333 }
andrewboyson 183:ee809769bf89 334 else
andrewboyson 183:ee809769bf89 335 {
andrewboyson 187:122fc1996c86 336 if (DhcpTrace) { LogTime("DHCP <- nack "); Ip4AddrLog(yiaddr); Log(" from server "); Ip4AddrLog(_serverId); Log(" ignored\r\n"); }
andrewboyson 183:ee809769bf89 337 }
andrewboyson 10:f0854784e960 338 break;
andrewboyson 10:f0854784e960 339 default:
andrewboyson 183:ee809769bf89 340 LogTimeF("DHCP <- unknown message %d\r\n", _dhcpMessageType);
andrewboyson 10:f0854784e960 341 break;
andrewboyson 10:f0854784e960 342 }
andrewboyson 10:f0854784e960 343 return DO_NOTHING;
andrewboyson 10:f0854784e960 344 }
andrewboyson 10:f0854784e960 345
andrewboyson 10:f0854784e960 346 int DhcpPollForRequestToSend(void* pPacket, int* pSize)
andrewboyson 116:60521b29e4c9 347 {
andrewboyson 183:ee809769bf89 348
andrewboyson 183:ee809769bf89 349 if (!_xid)
andrewboyson 183:ee809769bf89 350 {
andrewboyson 183:ee809769bf89 351 _xid = (uint32_t)MacLocal[2] << 24;
andrewboyson 183:ee809769bf89 352 _xid += (uint32_t)MacLocal[3] << 16;
andrewboyson 183:ee809769bf89 353 _xid += (uint32_t)MacLocal[4] << 8;
andrewboyson 183:ee809769bf89 354 _xid += (uint32_t)MacLocal[5] << 0;
andrewboyson 183:ee809769bf89 355 }
andrewboyson 183:ee809769bf89 356
andrewboyson 119:8e1a7805b801 357 //Check if time to update
andrewboyson 183:ee809769bf89 358 uint32_t elapsedTimeMs = MsTimerCount - _elapsedLifeMsTimer;
andrewboyson 93:580fc113d9e9 359 uint32_t leaseTimeMs = DhcpLeaseTime * 1000;
andrewboyson 183:ee809769bf89 360
andrewboyson 183:ee809769bf89 361 uint32_t T1 = leaseTimeMs >> 1; //0.5
andrewboyson 183:ee809769bf89 362 uint32_t T2 = (leaseTimeMs >> 1) + (leaseTimeMs >> 2) + (leaseTimeMs >> 3); //0.875 = 0.5 + 0.25 + 0.125
andrewboyson 183:ee809769bf89 363
andrewboyson 183:ee809769bf89 364 if (!DhcpLocalIp)
andrewboyson 183:ee809769bf89 365 {
andrewboyson 183:ee809769bf89 366 if (!_offeredIp) _state = STATE_DISCOVER;
andrewboyson 183:ee809769bf89 367 else _state = STATE_SELECT;
andrewboyson 183:ee809769bf89 368 }
andrewboyson 183:ee809769bf89 369 else
andrewboyson 183:ee809769bf89 370 {
andrewboyson 183:ee809769bf89 371 if (elapsedTimeMs < T1)
andrewboyson 183:ee809769bf89 372 {
andrewboyson 183:ee809769bf89 373 _state = STATE_BOUND;
andrewboyson 183:ee809769bf89 374 }
andrewboyson 183:ee809769bf89 375 else if (elapsedTimeMs < T2)
andrewboyson 183:ee809769bf89 376 {
andrewboyson 183:ee809769bf89 377 _state = STATE_RENEW;
andrewboyson 183:ee809769bf89 378 }
andrewboyson 183:ee809769bf89 379 else if (elapsedTimeMs < leaseTimeMs)
andrewboyson 183:ee809769bf89 380 {
andrewboyson 183:ee809769bf89 381 _state = STATE_REBIND;
andrewboyson 183:ee809769bf89 382 }
andrewboyson 183:ee809769bf89 383 else
andrewboyson 183:ee809769bf89 384 {
andrewboyson 183:ee809769bf89 385 _state = STATE_EXPIRED;
andrewboyson 183:ee809769bf89 386 }
andrewboyson 183:ee809769bf89 387 }
andrewboyson 183:ee809769bf89 388 static int stateLastScan = STATE_NONE;
andrewboyson 183:ee809769bf89 389 bool stateHasChanged = _state != stateLastScan;
andrewboyson 183:ee809769bf89 390 stateLastScan = _state;
andrewboyson 183:ee809769bf89 391
andrewboyson 184:ad80a63e3002 392 static uint32_t delayMs;
andrewboyson 184:ad80a63e3002 393 static uint32_t repeatDelayMsTimer;
andrewboyson 184:ad80a63e3002 394
andrewboyson 184:ad80a63e3002 395 bool responseTimeout = _awaitingResponse && MsTimerRelative(repeatDelayMsTimer, delayMs);
andrewboyson 136:8a65abb0dc63 396
andrewboyson 184:ad80a63e3002 397 bool send = stateHasChanged || responseTimeout;
andrewboyson 183:ee809769bf89 398
andrewboyson 184:ad80a63e3002 399 if (!send) return DO_NOTHING;
andrewboyson 184:ad80a63e3002 400
andrewboyson 184:ad80a63e3002 401 int dest = DO_NOTHING;
andrewboyson 184:ad80a63e3002 402 uint8_t type = 0; //DISCOVER or REQUEST
andrewboyson 184:ad80a63e3002 403 uint32_t ciaddr = 0; //goes in ciaddr only for BOUND/RENEW/REBIND
andrewboyson 184:ad80a63e3002 404 uint32_t requestedIp = 0; //goes in option 54 only for SELECTING
andrewboyson 184:ad80a63e3002 405 uint32_t serverId = 0; //goes in option 50 and is the server id for the accepted offer
andrewboyson 136:8a65abb0dc63 406
andrewboyson 119:8e1a7805b801 407 //Send the renewal request
andrewboyson 10:f0854784e960 408 *pSize = 0;
andrewboyson 184:ad80a63e3002 409
andrewboyson 184:ad80a63e3002 410
andrewboyson 183:ee809769bf89 411 switch (_state)
andrewboyson 10:f0854784e960 412 {
andrewboyson 184:ad80a63e3002 413 case STATE_NONE:
andrewboyson 184:ad80a63e3002 414 if (DhcpTrace) { LogTimeF("DHCP -- none\r\n"); }
andrewboyson 183:ee809769bf89 415 clearAll();
andrewboyson 183:ee809769bf89 416 return DO_NOTHING;
andrewboyson 184:ad80a63e3002 417
andrewboyson 184:ad80a63e3002 418 case STATE_DISCOVER:
andrewboyson 184:ad80a63e3002 419 if (DhcpTrace) { LogTimeF("DHCP -> discover\r\n"); }
andrewboyson 184:ad80a63e3002 420 type = DHCPDISCOVER;
andrewboyson 184:ad80a63e3002 421 ciaddr = 0;
andrewboyson 184:ad80a63e3002 422 requestedIp = 0;
andrewboyson 184:ad80a63e3002 423 serverId = 0;
andrewboyson 184:ad80a63e3002 424 dest = BROADCAST;
andrewboyson 184:ad80a63e3002 425 break;
andrewboyson 184:ad80a63e3002 426
andrewboyson 184:ad80a63e3002 427 case STATE_SELECT:
andrewboyson 187:122fc1996c86 428 if (DhcpTrace) { LogTimeF("DHCP -> select "); Ip4AddrLog(_offeredIp); Log(" from server "); Ip4AddrLog(_serverId); Log("\r\n"); }
andrewboyson 184:ad80a63e3002 429 type = DHCPREQUEST;
andrewboyson 184:ad80a63e3002 430 ciaddr = 0;
andrewboyson 184:ad80a63e3002 431 requestedIp = _offeredIp;
andrewboyson 184:ad80a63e3002 432 serverId = _serverId;
andrewboyson 184:ad80a63e3002 433 dest = BROADCAST;
andrewboyson 184:ad80a63e3002 434 break;
andrewboyson 184:ad80a63e3002 435
andrewboyson 184:ad80a63e3002 436 case STATE_BOUND:
andrewboyson 187:122fc1996c86 437 if (DhcpTrace) { LogTimeF("DHCP -- bound "); Ip4AddrLog(DhcpLocalIp); Log("\r\n"); }
andrewboyson 184:ad80a63e3002 438 return DO_NOTHING;
andrewboyson 184:ad80a63e3002 439
andrewboyson 184:ad80a63e3002 440 case STATE_RENEW:
andrewboyson 187:122fc1996c86 441 if (DhcpTrace) { LogTimeF("DHCP -> renew (T1) "); Ip4AddrLog(DhcpLocalIp); Log("\r\n"); }
andrewboyson 184:ad80a63e3002 442 type = DHCPREQUEST;
andrewboyson 184:ad80a63e3002 443 ciaddr = DhcpLocalIp;
andrewboyson 184:ad80a63e3002 444 requestedIp = 0;
andrewboyson 184:ad80a63e3002 445 serverId = 0;
andrewboyson 184:ad80a63e3002 446 dest = UNICAST_DHCP;
andrewboyson 184:ad80a63e3002 447 break;
andrewboyson 184:ad80a63e3002 448
andrewboyson 184:ad80a63e3002 449 case STATE_REBIND:
andrewboyson 187:122fc1996c86 450 if (DhcpTrace) { LogTimeF("DHCP -> rebind (T2) "); Ip4AddrLog(DhcpLocalIp); Log("\r\n"); }
andrewboyson 184:ad80a63e3002 451 type = DHCPREQUEST;
andrewboyson 184:ad80a63e3002 452 ciaddr = DhcpLocalIp;
andrewboyson 184:ad80a63e3002 453 requestedIp = 0;
andrewboyson 184:ad80a63e3002 454 serverId = 0;
andrewboyson 184:ad80a63e3002 455 dest = BROADCAST;
andrewboyson 184:ad80a63e3002 456 break;
andrewboyson 184:ad80a63e3002 457
andrewboyson 184:ad80a63e3002 458 case STATE_EXPIRED:
andrewboyson 187:122fc1996c86 459 if (DhcpTrace) { LogTimeF("DHCP -- expired "); Ip4AddrLog(DhcpLocalIp); Log("\r\n"); }
andrewboyson 184:ad80a63e3002 460 clearAll();
andrewboyson 184:ad80a63e3002 461 return DO_NOTHING;
andrewboyson 184:ad80a63e3002 462
andrewboyson 183:ee809769bf89 463 default:
andrewboyson 184:ad80a63e3002 464 LogTimeF("DHCP -- unknown state %d\r\n", _state);
andrewboyson 184:ad80a63e3002 465 return 0;
andrewboyson 10:f0854784e960 466 }
andrewboyson 183:ee809769bf89 467
andrewboyson 184:ad80a63e3002 468 if (!_awaitingResponse)
andrewboyson 184:ad80a63e3002 469 {
andrewboyson 184:ad80a63e3002 470 delayMs = MIN_REPEAT_DELAY_TIME_MS;
andrewboyson 184:ad80a63e3002 471 }
andrewboyson 184:ad80a63e3002 472 else
andrewboyson 184:ad80a63e3002 473 {
andrewboyson 184:ad80a63e3002 474 delayMs <<= 1; //Backoff (double) the delay time after each attempt
andrewboyson 184:ad80a63e3002 475 if (delayMs > MAX_REPEAT_DELAY_TIME_MS) delayMs = MAX_REPEAT_DELAY_TIME_MS; //Don't go beyond a maximum
andrewboyson 184:ad80a63e3002 476 }
andrewboyson 184:ad80a63e3002 477 _awaitingResponse = true;
andrewboyson 184:ad80a63e3002 478 repeatDelayMsTimer = MsTimerCount; //Start the repeat delay timer
andrewboyson 184:ad80a63e3002 479 *pSize = makeRequest(pPacket, type, ciaddr, requestedIp, serverId);
andrewboyson 183:ee809769bf89 480
andrewboyson 181:169881ecd52f 481 return ActionMakeFromDestAndTrace(dest, DhcpTrace && NetTraceStack);
andrewboyson 136:8a65abb0dc63 482 }