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
udp/dhcp/dhcp.c@178:52714fef5ca1, 2020-12-29 (annotated)
- Committer:
- andrewboyson
- Date:
- Tue Dec 29 19:14:35 2020 +0000
- Revision:
- 178:52714fef5ca1
- Parent:
- 174:60e5ab296671
- Child:
- 179:55342264fca1
Included host name in DHCP request option 12 to allow my Sky router to display the host name instead of 'UNKNOWN'. Also removed different host names for IPv4 and IPv6.
Who changed what in which revision?
User | Revision | Line number | New 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 ID 75648 |
andrewboyson | 10:f0854784e960 | 32 | #define COOKIE 0x63825363 |
andrewboyson | 10:f0854784e960 | 33 | |
andrewboyson | 116:60521b29e4c9 | 34 | #define MAX_REPEAT_DELAY_TIME_MS 60000 |
andrewboyson | 119:8e1a7805b801 | 35 | #define MIN_REPEAT_DELAY_TIME_MS 900 |
andrewboyson | 119:8e1a7805b801 | 36 | static uint32_t repeatDelayMsTimer = (uint32_t)-MIN_REPEAT_DELAY_TIME_MS; //Initial value ensures no delay at startup |
andrewboyson | 119:8e1a7805b801 | 37 | 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 | 116:60521b29e4c9 | 38 | |
andrewboyson | 136:8a65abb0dc63 | 39 | static uint32_t elapsedLifeMsTimer = 0; //Started whenever an IP address request has been acknowledged |
andrewboyson | 93:580fc113d9e9 | 40 | |
andrewboyson | 93:580fc113d9e9 | 41 | uint32_t DhcpGetElapsedLife() |
andrewboyson | 10:f0854784e960 | 42 | { |
andrewboyson | 119:8e1a7805b801 | 43 | if (!elapsedLifeMsTimer) return 0; |
andrewboyson | 119:8e1a7805b801 | 44 | return (MsTimerCount - elapsedLifeMsTimer) / 1000; |
andrewboyson | 10:f0854784e960 | 45 | } |
andrewboyson | 10:f0854784e960 | 46 | |
andrewboyson | 10:f0854784e960 | 47 | static uint8_t dhcpMessageType = 0; |
andrewboyson | 10:f0854784e960 | 48 | uint32_t DhcpLeaseTime = 0; |
andrewboyson | 116:60521b29e4c9 | 49 | uint32_t DhcpServerIp = 0; |
andrewboyson | 116:60521b29e4c9 | 50 | uint32_t DhcpRouterIp = 0; |
andrewboyson | 10:f0854784e960 | 51 | uint32_t DhcpSubnetMask = 0; |
andrewboyson | 116:60521b29e4c9 | 52 | uint32_t DhcpNtpIp = 0; |
andrewboyson | 10:f0854784e960 | 53 | uint32_t DhcpRenewalT1 = 0; |
andrewboyson | 10:f0854784e960 | 54 | uint32_t DhcpRenewalT2 = 0; |
andrewboyson | 10:f0854784e960 | 55 | uint32_t DhcpBroadcastIp = 0; |
andrewboyson | 10:f0854784e960 | 56 | uint32_t DhcpLocalIp = 0; |
andrewboyson | 116:60521b29e4c9 | 57 | uint32_t DhcpDnsServerIp = 0; |
andrewboyson | 128:79052cb4a41c | 58 | char DhcpDomainName[DNS_MAX_LABEL_LENGTH+1]; |
andrewboyson | 128:79052cb4a41c | 59 | char DhcpHostName [DNS_MAX_LABEL_LENGTH+1]; |
andrewboyson | 44:83ce5ace337b | 60 | |
andrewboyson | 44:83ce5ace337b | 61 | bool DhcpIpNeedsToBeRouted(uint32_t ip) |
andrewboyson | 174:60e5ab296671 | 62 | { |
andrewboyson | 174:60e5ab296671 | 63 | if ((ip & 0x000000FF) == 0xFF) return false; //Broadcast 255.xxx.xxx.xxx |
andrewboyson | 174:60e5ab296671 | 64 | if ((ip & 0x000000FF) == 0xE0) return false; //Multicast 224.xxx.xxx.xxx |
andrewboyson | 174:60e5ab296671 | 65 | if (ip == (DhcpLocalIp | 0xFF000000)) return false; //Local broadcast ip == 192.168.0.255 |
andrewboyson | 174:60e5ab296671 | 66 | |
andrewboyson | 174:60e5ab296671 | 67 | return (ip & DhcpSubnetMask) != (DhcpLocalIp & DhcpSubnetMask); //ip != 192.168.0.xxx |
andrewboyson | 44:83ce5ace337b | 68 | } |
andrewboyson | 44:83ce5ace337b | 69 | |
andrewboyson | 10:f0854784e960 | 70 | static uint32_t readOption32(char** pp) |
andrewboyson | 10:f0854784e960 | 71 | { |
andrewboyson | 10:f0854784e960 | 72 | uint32_t value = 0; |
andrewboyson | 10:f0854784e960 | 73 | char* p = *pp; |
andrewboyson | 10:f0854784e960 | 74 | int len = *++p; |
andrewboyson | 10:f0854784e960 | 75 | if (len >= 4) |
andrewboyson | 10:f0854784e960 | 76 | { |
andrewboyson | 10:f0854784e960 | 77 | value = *++p << 24; |
andrewboyson | 10:f0854784e960 | 78 | value |= *++p << 16; |
andrewboyson | 10:f0854784e960 | 79 | value |= *++p << 8; |
andrewboyson | 10:f0854784e960 | 80 | value |= *++p << 0; |
andrewboyson | 10:f0854784e960 | 81 | } |
andrewboyson | 10:f0854784e960 | 82 | *pp += len + 1; |
andrewboyson | 10:f0854784e960 | 83 | return value; |
andrewboyson | 10:f0854784e960 | 84 | } |
andrewboyson | 10:f0854784e960 | 85 | static uint32_t readIp(char** pp) |
andrewboyson | 10:f0854784e960 | 86 | { |
andrewboyson | 10:f0854784e960 | 87 | uint32_t value = 0; |
andrewboyson | 10:f0854784e960 | 88 | char* p = *pp; |
andrewboyson | 10:f0854784e960 | 89 | int len = *++p; |
andrewboyson | 10:f0854784e960 | 90 | if (len >= 4) |
andrewboyson | 10:f0854784e960 | 91 | { |
andrewboyson | 10:f0854784e960 | 92 | value = *++p << 0; |
andrewboyson | 10:f0854784e960 | 93 | value |= *++p << 8; |
andrewboyson | 10:f0854784e960 | 94 | value |= *++p << 16; |
andrewboyson | 10:f0854784e960 | 95 | value |= *++p << 24; |
andrewboyson | 10:f0854784e960 | 96 | } |
andrewboyson | 10:f0854784e960 | 97 | *pp += len + 1; |
andrewboyson | 10:f0854784e960 | 98 | return value; |
andrewboyson | 10:f0854784e960 | 99 | } |
andrewboyson | 10:f0854784e960 | 100 | static void readString(char** pp, char* pText) |
andrewboyson | 10:f0854784e960 | 101 | { |
andrewboyson | 10:f0854784e960 | 102 | char* p = *pp; |
andrewboyson | 10:f0854784e960 | 103 | int len = *++p; |
andrewboyson | 10:f0854784e960 | 104 | for (int i = 0; i < len; i++) pText[i] = *++p; |
andrewboyson | 10:f0854784e960 | 105 | *pp += len + 1; |
andrewboyson | 10:f0854784e960 | 106 | } |
andrewboyson | 10:f0854784e960 | 107 | static void readOptions(int size, char * pOptions) |
andrewboyson | 10:f0854784e960 | 108 | { |
andrewboyson | 10:f0854784e960 | 109 | int len = 0; |
andrewboyson | 10:f0854784e960 | 110 | char* p = pOptions; |
andrewboyson | 10:f0854784e960 | 111 | char* pE = pOptions + size; |
andrewboyson | 10:f0854784e960 | 112 | while( p < pE) |
andrewboyson | 10:f0854784e960 | 113 | { |
andrewboyson | 10:f0854784e960 | 114 | switch (*p) |
andrewboyson | 10:f0854784e960 | 115 | { |
andrewboyson | 10:f0854784e960 | 116 | case 0: break; //NOP |
andrewboyson | 10:f0854784e960 | 117 | case 255: return; //End of options |
andrewboyson | 136:8a65abb0dc63 | 118 | case 1: DhcpSubnetMask = readIp(&p); break; //Subnet Mask |
andrewboyson | 136:8a65abb0dc63 | 119 | case 3: DhcpRouterIp = readIp(&p); break; //Router |
andrewboyson | 136:8a65abb0dc63 | 120 | case 6: DhcpDnsServerIp = readIp(&p); break; //DNS server |
andrewboyson | 10:f0854784e960 | 121 | case 12: readString(&p, DhcpHostName); break; //Host name |
andrewboyson | 10:f0854784e960 | 122 | case 15: readString(&p, DhcpDomainName); break; //Domain name |
andrewboyson | 10:f0854784e960 | 123 | case 19: len = *++p; p+= len; break; //IP forwarding yes/no |
andrewboyson | 136:8a65abb0dc63 | 124 | case 28: DhcpBroadcastIp = readIp(&p); break; //Broadcast IP |
andrewboyson | 136:8a65abb0dc63 | 125 | case 42: DhcpNtpIp = readIp(&p); break; //NTP |
andrewboyson | 10:f0854784e960 | 126 | case 44: len = *++p; p+= len; break; //NetBIOS name server |
andrewboyson | 10:f0854784e960 | 127 | case 45: len = *++p; p+= len; break; //NetBIOS datagram server |
andrewboyson | 10:f0854784e960 | 128 | case 46: len = *++p; p+= len; break; //NetBIOS node type |
andrewboyson | 10:f0854784e960 | 129 | case 47: len = *++p; p+= len; break; //NetBIOS scope |
andrewboyson | 10:f0854784e960 | 130 | case 53: len = *++p; dhcpMessageType = *++p; break; //DHCP message type |
andrewboyson | 10:f0854784e960 | 131 | case 51: DhcpLeaseTime = readOption32(&p); break; //Address lease time |
andrewboyson | 116:60521b29e4c9 | 132 | case 54: DhcpServerIp = readIp(&p); break; //DHCP server |
andrewboyson | 10:f0854784e960 | 133 | case 58: DhcpRenewalT1 = readOption32(&p); break; //T1 |
andrewboyson | 10:f0854784e960 | 134 | case 59: DhcpRenewalT2 = readOption32(&p); break; //T2 |
andrewboyson | 10:f0854784e960 | 135 | default: |
andrewboyson | 37:793b39683406 | 136 | if (DhcpTrace) LogTimeF("Ignoring option %d\r\n", *p); |
andrewboyson | 10:f0854784e960 | 137 | len = *++p; |
andrewboyson | 10:f0854784e960 | 138 | p += len; |
andrewboyson | 10:f0854784e960 | 139 | return; |
andrewboyson | 10:f0854784e960 | 140 | } |
andrewboyson | 10:f0854784e960 | 141 | p++; |
andrewboyson | 10:f0854784e960 | 142 | } |
andrewboyson | 10:f0854784e960 | 143 | } |
andrewboyson | 10:f0854784e960 | 144 | static void writeIp(uint8_t code, uint32_t value, char** pp) |
andrewboyson | 10:f0854784e960 | 145 | { |
andrewboyson | 10:f0854784e960 | 146 | if (!value) return; |
andrewboyson | 136:8a65abb0dc63 | 147 | |
andrewboyson | 10:f0854784e960 | 148 | char* p = *pp; |
andrewboyson | 136:8a65abb0dc63 | 149 | |
andrewboyson | 10:f0854784e960 | 150 | *p++ = code; |
andrewboyson | 10:f0854784e960 | 151 | *p++ = 4; |
andrewboyson | 10:f0854784e960 | 152 | *p++ = (value & 0x000000FF) >> 0; |
andrewboyson | 10:f0854784e960 | 153 | *p++ = (value & 0x0000FF00) >> 8; |
andrewboyson | 10:f0854784e960 | 154 | *p++ = (value & 0x00FF0000) >> 16; |
andrewboyson | 10:f0854784e960 | 155 | *p++ = (value & 0xFF000000) >> 24; |
andrewboyson | 136:8a65abb0dc63 | 156 | |
andrewboyson | 10:f0854784e960 | 157 | *pp += 6; |
andrewboyson | 10:f0854784e960 | 158 | } |
andrewboyson | 178:52714fef5ca1 | 159 | static void writeText(uint8_t code, const char* pText, char** pp) |
andrewboyson | 178:52714fef5ca1 | 160 | { |
andrewboyson | 178:52714fef5ca1 | 161 | if (!pText) return; |
andrewboyson | 178:52714fef5ca1 | 162 | if (!*pText) return; |
andrewboyson | 178:52714fef5ca1 | 163 | |
andrewboyson | 178:52714fef5ca1 | 164 | char* p = *pp; |
andrewboyson | 178:52714fef5ca1 | 165 | |
andrewboyson | 178:52714fef5ca1 | 166 | *p++ = code; |
andrewboyson | 178:52714fef5ca1 | 167 | char* pLength = p++; |
andrewboyson | 178:52714fef5ca1 | 168 | while (true) //Copy pText without the end zero |
andrewboyson | 178:52714fef5ca1 | 169 | { |
andrewboyson | 178:52714fef5ca1 | 170 | *p = *pText; |
andrewboyson | 178:52714fef5ca1 | 171 | pText++; |
andrewboyson | 178:52714fef5ca1 | 172 | if (!*pText) break; |
andrewboyson | 178:52714fef5ca1 | 173 | p++; |
andrewboyson | 178:52714fef5ca1 | 174 | } |
andrewboyson | 178:52714fef5ca1 | 175 | |
andrewboyson | 178:52714fef5ca1 | 176 | *pLength = p - pLength; |
andrewboyson | 178:52714fef5ca1 | 177 | |
andrewboyson | 178:52714fef5ca1 | 178 | *pp += *pLength + 2; |
andrewboyson | 178:52714fef5ca1 | 179 | } |
andrewboyson | 10:f0854784e960 | 180 | int sendRequest(void* pPacket, uint8_t code, uint32_t srvIp, uint32_t reqIp) |
andrewboyson | 10:f0854784e960 | 181 | { |
andrewboyson | 136:8a65abb0dc63 | 182 | |
andrewboyson | 10:f0854784e960 | 183 | switch (code) |
andrewboyson | 10:f0854784e960 | 184 | { |
andrewboyson | 10:f0854784e960 | 185 | case DHCPDISCOVER: |
andrewboyson | 37:793b39683406 | 186 | if (DhcpTrace) LogTimeF("DHCP -> discover"); |
andrewboyson | 10:f0854784e960 | 187 | break; |
andrewboyson | 10:f0854784e960 | 188 | case DHCPREQUEST: |
andrewboyson | 37:793b39683406 | 189 | if (DhcpTrace) LogTimeF("DHCP -> request"); |
andrewboyson | 10:f0854784e960 | 190 | break; |
andrewboyson | 10:f0854784e960 | 191 | default: |
andrewboyson | 10:f0854784e960 | 192 | LogTimeF("DHCP -> unknown message %d", code); |
andrewboyson | 10:f0854784e960 | 193 | break; |
andrewboyson | 10:f0854784e960 | 194 | } |
andrewboyson | 37:793b39683406 | 195 | if (DhcpTrace) |
andrewboyson | 10:f0854784e960 | 196 | { |
andrewboyson | 47:73af5c0b0dc2 | 197 | Log(" server=" ); Ip4AddressLog(srvIp); |
andrewboyson | 47:73af5c0b0dc2 | 198 | Log(" request="); Ip4AddressLog(reqIp); |
andrewboyson | 47:73af5c0b0dc2 | 199 | Log(" local=" ); Ip4AddressLog(DhcpLocalIp); |
andrewboyson | 47:73af5c0b0dc2 | 200 | Log("\r\n"); |
andrewboyson | 10:f0854784e960 | 201 | } |
andrewboyson | 136:8a65abb0dc63 | 202 | |
andrewboyson | 10:f0854784e960 | 203 | bool broadcast = DhcpLocalIp == 0; |
andrewboyson | 10:f0854784e960 | 204 | uint16_t flags = 0; |
andrewboyson | 136:8a65abb0dc63 | 205 | if (broadcast) flags |= 0x8000; |
andrewboyson | 136:8a65abb0dc63 | 206 | DhcpHdrSetOp (pPacket, REQUEST ); |
andrewboyson | 136:8a65abb0dc63 | 207 | DhcpHdrSetHtype (pPacket, ETHERNET ); |
andrewboyson | 136:8a65abb0dc63 | 208 | DhcpHdrSetHlen (pPacket, 6 ); |
andrewboyson | 136:8a65abb0dc63 | 209 | DhcpHdrSetHops (pPacket, 0 ); |
andrewboyson | 136:8a65abb0dc63 | 210 | DhcpHdrSetXid (pPacket, ID ); //Randomly chosed transaction id used to associate messages to responses |
andrewboyson | 136:8a65abb0dc63 | 211 | DhcpHdrSetSecs (pPacket, 0 ); //Seconds since started to boot |
andrewboyson | 136:8a65abb0dc63 | 212 | DhcpHdrSetFlags (pPacket, flags ); //Broadcast (1) Unicast (0) |
andrewboyson | 136:8a65abb0dc63 | 213 | DhcpHdrSetCiaddr(pPacket, DhcpLocalIp ); //'Client' address set by client or 0 if don't know address |
andrewboyson | 136:8a65abb0dc63 | 214 | DhcpHdrSetYiaddr(pPacket, 0 ); //'Your' address returned by server |
andrewboyson | 136:8a65abb0dc63 | 215 | DhcpHdrSetSiaddr(pPacket, srvIp ); //'Server' address to use if required |
andrewboyson | 136:8a65abb0dc63 | 216 | DhcpHdrSetGiaddr(pPacket, 0 ); //'Gateway' address |
andrewboyson | 136:8a65abb0dc63 | 217 | memcpy(DhcpHdrPtrChaddr(pPacket), MacLocal, 6); //'Client hardware' address. 6 bytes for ethernet |
andrewboyson | 136:8a65abb0dc63 | 218 | memset(DhcpHdrPtrLegacy(pPacket), 0, 192 ); //BootP legacy fill with zeros |
andrewboyson | 136:8a65abb0dc63 | 219 | DhcpHdrSetCookie(pPacket, COOKIE ); //Magic cookie |
andrewboyson | 136:8a65abb0dc63 | 220 | |
andrewboyson | 136:8a65abb0dc63 | 221 | char* pOptions = (char*)pPacket + DHCP_HEADER_LENGTH; |
andrewboyson | 10:f0854784e960 | 222 | char* p = pOptions; |
andrewboyson | 10:f0854784e960 | 223 | *p++ = 53; //Message code |
andrewboyson | 10:f0854784e960 | 224 | *p++ = 1; |
andrewboyson | 10:f0854784e960 | 225 | *p++ = code; |
andrewboyson | 136:8a65abb0dc63 | 226 | |
andrewboyson | 10:f0854784e960 | 227 | writeIp(50, reqIp, &p); //Requested IP |
andrewboyson | 10:f0854784e960 | 228 | writeIp(54, srvIp, &p); //Server ip |
andrewboyson | 178:52714fef5ca1 | 229 | |
andrewboyson | 178:52714fef5ca1 | 230 | writeText(12, NET_NAME, &p); |
andrewboyson | 136:8a65abb0dc63 | 231 | |
andrewboyson | 10:f0854784e960 | 232 | *p++ = 255; //End of options |
andrewboyson | 10:f0854784e960 | 233 | |
andrewboyson | 136:8a65abb0dc63 | 234 | return DHCP_HEADER_LENGTH + p - pOptions; |
andrewboyson | 136:8a65abb0dc63 | 235 | } |
andrewboyson | 136:8a65abb0dc63 | 236 | int DhcpHandleResponse(void (*traceback)(void), int sizeRx, char* pPacketRx, int* pSizeTx, char* pPacketTx) |
andrewboyson | 136:8a65abb0dc63 | 237 | { |
andrewboyson | 136:8a65abb0dc63 | 238 | uint8_t op = DhcpHdrGetOp (pPacketRx); |
andrewboyson | 136:8a65abb0dc63 | 239 | uint8_t htype = DhcpHdrGetHtype (pPacketRx); |
andrewboyson | 136:8a65abb0dc63 | 240 | uint8_t hlen = DhcpHdrGetHlen (pPacketRx); |
andrewboyson | 136:8a65abb0dc63 | 241 | uint32_t xid = DhcpHdrGetXid (pPacketRx); //Randomly chosen transaction id used to associate messages to responses |
andrewboyson | 136:8a65abb0dc63 | 242 | uint32_t yiaddr = DhcpHdrGetYiaddr(pPacketRx); |
andrewboyson | 136:8a65abb0dc63 | 243 | uint32_t siaddr = DhcpHdrGetSiaddr(pPacketRx); |
andrewboyson | 136:8a65abb0dc63 | 244 | uint32_t cookie = DhcpHdrGetCookie(pPacketRx); |
andrewboyson | 136:8a65abb0dc63 | 245 | |
andrewboyson | 136:8a65abb0dc63 | 246 | if (op != REPLY) return DO_NOTHING; |
andrewboyson | 136:8a65abb0dc63 | 247 | if (htype != ETHERNET) return DO_NOTHING; |
andrewboyson | 136:8a65abb0dc63 | 248 | if (hlen != 6) return DO_NOTHING; |
andrewboyson | 136:8a65abb0dc63 | 249 | if (memcmp(DhcpHdrPtrChaddr(pPacketRx), MacLocal, 6)) return DO_NOTHING; |
andrewboyson | 136:8a65abb0dc63 | 250 | if (xid != ID) return DO_NOTHING; |
andrewboyson | 136:8a65abb0dc63 | 251 | if (cookie != COOKIE) return DO_NOTHING; |
andrewboyson | 136:8a65abb0dc63 | 252 | |
andrewboyson | 136:8a65abb0dc63 | 253 | char* pOptions = (char*)pPacketRx + DHCP_HEADER_LENGTH; |
andrewboyson | 136:8a65abb0dc63 | 254 | readOptions(sizeRx - DHCP_HEADER_LENGTH, pOptions); |
andrewboyson | 136:8a65abb0dc63 | 255 | |
andrewboyson | 10:f0854784e960 | 256 | switch (dhcpMessageType) |
andrewboyson | 10:f0854784e960 | 257 | { |
andrewboyson | 10:f0854784e960 | 258 | case DHCPOFFER: |
andrewboyson | 47:73af5c0b0dc2 | 259 | if (DhcpTrace) { LogTime("DHCP <- offer ip "); Ip4AddressLog(yiaddr); Log("\r\n"); } |
andrewboyson | 59:e0e556c8bd46 | 260 | *pSizeTx = sendRequest(pPacketTx, DHCPREQUEST, siaddr, yiaddr); |
andrewboyson | 10:f0854784e960 | 261 | return BROADCAST; |
andrewboyson | 10:f0854784e960 | 262 | case DHCPACK: |
andrewboyson | 47:73af5c0b0dc2 | 263 | if (DhcpTrace) { LogTime("DHCP <- ack ip "); Ip4AddressLog(yiaddr); Log("\r\n"); } |
andrewboyson | 10:f0854784e960 | 264 | DhcpLocalIp = yiaddr; |
andrewboyson | 119:8e1a7805b801 | 265 | elapsedLifeMsTimer = MsTimerCount; //Start the life timer |
andrewboyson | 116:60521b29e4c9 | 266 | delayMs = MIN_REPEAT_DELAY_TIME_MS; //Set the delay time back to minimum |
andrewboyson | 10:f0854784e960 | 267 | break; |
andrewboyson | 10:f0854784e960 | 268 | case DHCPNAK: |
andrewboyson | 47:73af5c0b0dc2 | 269 | if (DhcpTrace) { LogTime("DHCP <- nack ip "); Ip4AddressLog(yiaddr); Log("\r\n"); } |
andrewboyson | 10:f0854784e960 | 270 | break; |
andrewboyson | 10:f0854784e960 | 271 | default: |
andrewboyson | 10:f0854784e960 | 272 | LogTimeF("DHCP <- unknown message %d\r\n", dhcpMessageType); |
andrewboyson | 10:f0854784e960 | 273 | break; |
andrewboyson | 10:f0854784e960 | 274 | } |
andrewboyson | 10:f0854784e960 | 275 | return DO_NOTHING; |
andrewboyson | 10:f0854784e960 | 276 | } |
andrewboyson | 10:f0854784e960 | 277 | |
andrewboyson | 10:f0854784e960 | 278 | int DhcpPollForRequestToSend(void* pPacket, int* pSize) |
andrewboyson | 116:60521b29e4c9 | 279 | { |
andrewboyson | 119:8e1a7805b801 | 280 | //Check if time to update |
andrewboyson | 119:8e1a7805b801 | 281 | uint32_t elapsedTimeMs = MsTimerCount - elapsedLifeMsTimer; |
andrewboyson | 93:580fc113d9e9 | 282 | uint32_t leaseTimeMs = DhcpLeaseTime * 1000; |
andrewboyson | 93:580fc113d9e9 | 283 | |
andrewboyson | 119:8e1a7805b801 | 284 | if (DhcpLocalIp && elapsedTimeMs < (leaseTimeMs >> 1)) return DO_NOTHING; //Do nothing if have address and within T1 |
andrewboyson | 136:8a65abb0dc63 | 285 | |
andrewboyson | 119:8e1a7805b801 | 286 | //Limit retries with a backoff delay |
andrewboyson | 133:a37eb35a03f1 | 287 | if (!MsTimerRelative(repeatDelayMsTimer, delayMs)) return DO_NOTHING; //Don't retry within the delay time |
andrewboyson | 119:8e1a7805b801 | 288 | delayMs <<= 1; //Backoff (double) the delay time after each attempt |
andrewboyson | 119:8e1a7805b801 | 289 | if (delayMs > MAX_REPEAT_DELAY_TIME_MS) delayMs = MAX_REPEAT_DELAY_TIME_MS; //Don't go beyond a maximum |
andrewboyson | 119:8e1a7805b801 | 290 | repeatDelayMsTimer = MsTimerCount; //Start the delay timer |
andrewboyson | 136:8a65abb0dc63 | 291 | |
andrewboyson | 119:8e1a7805b801 | 292 | //Send the renewal request |
andrewboyson | 10:f0854784e960 | 293 | *pSize = 0; |
andrewboyson | 37:793b39683406 | 294 | int dest = DO_NOTHING; |
andrewboyson | 93:580fc113d9e9 | 295 | if (DhcpLocalIp && elapsedTimeMs < leaseTimeMs) |
andrewboyson | 10:f0854784e960 | 296 | { |
andrewboyson | 116:60521b29e4c9 | 297 | *pSize = sendRequest(pPacket, DHCPREQUEST, DhcpServerIp, DhcpLocalIp); //if within T2 then send request to the server - not broadcast |
andrewboyson | 37:793b39683406 | 298 | dest = UNICAST_DHCP; |
andrewboyson | 10:f0854784e960 | 299 | } |
andrewboyson | 10:f0854784e960 | 300 | else |
andrewboyson | 10:f0854784e960 | 301 | { |
andrewboyson | 37:793b39683406 | 302 | if (DhcpTrace) LogTimeF("DHCP lease has expired\r\n"); |
andrewboyson | 10:f0854784e960 | 303 | DhcpLocalIp = 0; |
andrewboyson | 116:60521b29e4c9 | 304 | DhcpServerIp = 0; |
andrewboyson | 10:f0854784e960 | 305 | *pSize = sendRequest(pPacket, DHCPDISCOVER, 0, 0); //If outside T2 then start from scratch to do a full DHCP |
andrewboyson | 37:793b39683406 | 306 | dest = BROADCAST; |
andrewboyson | 10:f0854784e960 | 307 | } |
andrewboyson | 37:793b39683406 | 308 | return ActionMakeFromDestAndTrace(dest, DhcpTrace); |
andrewboyson | 136:8a65abb0dc63 | 309 | } |