WIZNet W5500 with additional enhancements
Fork of WIZnetInterface by
Socket/DHCPClient.cpp@35:fe3028eda085, 2017-10-10 (annotated)
- Committer:
- Helmut Tschemernjak
- Date:
- Tue Oct 10 20:56:13 2017 +0200
- Revision:
- 35:fe3028eda085
- Parent:
- 15:24a9f2df2145
- Child:
- 36:0ba2e8d5274a
Added support for DHCP lease time and domain name
Enhance DHCP code to use opcode defines to make it easier to
understand and maintain.
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| Soohwan Kim |
0:6f28332c466f | 1 | // DHCPClient.cpp 2013/4/10 |
| Soohwan Kim |
0:6f28332c466f | 2 | #include "mbed.h" |
| Soohwan Kim |
0:6f28332c466f | 3 | #include "mbed_debug.h" |
| Soohwan Kim |
0:6f28332c466f | 4 | #include "UDPSocket.h" |
| Soohwan Kim |
0:6f28332c466f | 5 | #include "DHCPClient.h" |
| Soohwan Kim |
0:6f28332c466f | 6 | |
| Soohwan Kim |
0:6f28332c466f | 7 | #define DBG_DHCP 0 |
| Soohwan Kim |
0:6f28332c466f | 8 | |
| Soohwan Kim |
0:6f28332c466f | 9 | #if DBG_DHCP |
| Soohwan Kim |
0:6f28332c466f | 10 | #define DBG(...) do{debug("[%s:%d]", __PRETTY_FUNCTION__,__LINE__);debug(__VA_ARGS__);} while(0); |
| Soohwan Kim |
0:6f28332c466f | 11 | #define DBG_HEX(A,B) do{debug("[%s:%d]\r\n", __PRETTY_FUNCTION__,__LINE__);debug_hex(A,B);} while(0); |
| Soohwan Kim |
0:6f28332c466f | 12 | #else |
| Soohwan Kim |
0:6f28332c466f | 13 | #define DBG(...) while(0); |
| Soohwan Kim |
0:6f28332c466f | 14 | #define DBG_HEX(A,B) while(0); |
| Soohwan Kim |
0:6f28332c466f | 15 | #endif |
| Soohwan Kim |
0:6f28332c466f | 16 | |
| Soohwan Kim |
0:6f28332c466f | 17 | int DHCPClient::discover() |
| Soohwan Kim |
0:6f28332c466f | 18 | { |
| Soohwan Kim |
0:6f28332c466f | 19 | m_pos = 0; |
| Soohwan Kim |
0:6f28332c466f | 20 | const uint8_t header[] = {0x01,0x01,0x06,0x00}; |
| Soohwan Kim |
0:6f28332c466f | 21 | add_buf((uint8_t*)header, sizeof(header)); |
| Soohwan Kim |
0:6f28332c466f | 22 | uint32_t x = time(NULL) + rand(); |
| Soohwan Kim |
0:6f28332c466f | 23 | xid[0] = x>>24; xid[1] = x>>16; xid[2] = x>>8; xid[3] = x; |
| Soohwan Kim |
0:6f28332c466f | 24 | add_buf(xid, 4); |
| Soohwan Kim |
0:6f28332c466f | 25 | fill_buf(20, 0x00); |
| Soohwan Kim |
0:6f28332c466f | 26 | add_buf(chaddr, 6); |
| Soohwan Kim |
0:6f28332c466f | 27 | fill_buf(10+192, 0x00); |
| Helmut Tschemernjak | 35:fe3028eda085 | 28 | const uint8_t options[] = {0x63,0x82,0x53,0x63, // DHCP_MAGIC_COOKIE |
| Helmut Tschemernjak | 35:fe3028eda085 | 29 | OPT_DHCP_MESSAGE, 1, DHCPDISCOVER, // // DHCP message, len, discover |
| Helmut Tschemernjak | 35:fe3028eda085 | 30 | OPT_PARAMETER_REQ, 5, OPT_SUBNET_MASK, OPT_ROUTER, OPT_TIME_SERVER, OPT_DOMAIN_NAME, OPT_DNS, |
| Helmut Tschemernjak | 35:fe3028eda085 | 31 | OPT_END}; |
| Soohwan Kim |
0:6f28332c466f | 32 | add_buf((uint8_t*)options, sizeof(options)); |
| Soohwan Kim |
0:6f28332c466f | 33 | return m_pos; |
| Soohwan Kim |
0:6f28332c466f | 34 | } |
| Soohwan Kim |
0:6f28332c466f | 35 | |
| Soohwan Kim |
0:6f28332c466f | 36 | int DHCPClient::request() |
| Soohwan Kim |
0:6f28332c466f | 37 | { |
| Soohwan Kim |
0:6f28332c466f | 38 | m_pos = 0; |
| Soohwan Kim |
0:6f28332c466f | 39 | const uint8_t header[] = {0x01,0x01,0x06,0x00}; |
| Soohwan Kim |
0:6f28332c466f | 40 | add_buf((uint8_t*)header, sizeof(header)); |
| Soohwan Kim |
0:6f28332c466f | 41 | add_buf(xid, 4); |
| Soohwan Kim |
0:6f28332c466f | 42 | fill_buf(12, 0x00); |
| Soohwan Kim |
0:6f28332c466f | 43 | add_buf(siaddr, 4); |
| Soohwan Kim |
0:6f28332c466f | 44 | fill_buf(4, 0x00); // giaddr |
| Soohwan Kim |
0:6f28332c466f | 45 | add_buf(chaddr, 6); |
| Soohwan Kim |
0:6f28332c466f | 46 | fill_buf(10+192, 0x00); |
| Helmut Tschemernjak | 35:fe3028eda085 | 47 | const uint8_t options[] = {0x63,0x82,0x53,0x63, // DHCP_MAGIC_COOKIE |
| Helmut Tschemernjak | 35:fe3028eda085 | 48 | OPT_DHCP_MESSAGE,1, DHCPREQUEST, // DHCP message, len, request |
| Helmut Tschemernjak | 35:fe3028eda085 | 49 | OPT_PARAMETER_REQ, 5, OPT_SUBNET_MASK, OPT_ROUTER, OPT_TIME_SERVER, OPT_DOMAIN_NAME, OPT_DNS }; |
| Soohwan Kim |
0:6f28332c466f | 50 | add_buf((uint8_t*)options, sizeof(options)); |
| Helmut Tschemernjak | 35:fe3028eda085 | 51 | add_option(OPT_IP_ADDR_REQ, yiaddr, 4); |
| Helmut Tschemernjak | 35:fe3028eda085 | 52 | add_option(OPT_SERVER_IDENT, siaddr, 4); |
| Helmut Tschemernjak | 35:fe3028eda085 | 53 | add_option(OPT_END); |
| Soohwan Kim |
0:6f28332c466f | 54 | return m_pos; |
| Soohwan Kim |
0:6f28332c466f | 55 | } |
| Soohwan Kim |
0:6f28332c466f | 56 | |
| Soohwan Kim |
0:6f28332c466f | 57 | int DHCPClient::offer(uint8_t buf[], int size) { |
| Soohwan Kim |
0:6f28332c466f | 58 | memcpy(yiaddr, buf+DHCP_OFFSET_YIADDR, 4); |
| Helmut Tschemernjak | 35:fe3028eda085 | 59 | memcpy(siaddr, buf+DHCP_OFFSET_SIADDR, 4); |
| Helmut Tschemernjak | 35:fe3028eda085 | 60 | |
| Helmut Tschemernjak | 35:fe3028eda085 | 61 | memset(dnsaddr, 0, sizeof(dnsaddr)); |
| Helmut Tschemernjak | 35:fe3028eda085 | 62 | memset(gateway, 0, sizeof(gateway)); |
| Helmut Tschemernjak | 35:fe3028eda085 | 63 | memset(netmask, 0, sizeof(netmask)); |
| Helmut Tschemernjak | 35:fe3028eda085 | 64 | memset(timesrv, 0, sizeof(timesrv)); |
| Helmut Tschemernjak | 35:fe3028eda085 | 65 | memset(leaseTime, 0, sizeof(leaseTime)); |
| Helmut Tschemernjak | 35:fe3028eda085 | 66 | |
| Soohwan Kim |
0:6f28332c466f | 67 | uint8_t *p; |
| Soohwan Kim |
0:6f28332c466f | 68 | int msg_type = -1; |
| Soohwan Kim |
0:6f28332c466f | 69 | p = buf + DHCP_OFFSET_OPTIONS; |
| Helmut Tschemernjak | 35:fe3028eda085 | 70 | while(*p != OPT_END && p < (buf+size)) { |
| Soohwan Kim |
0:6f28332c466f | 71 | uint8_t code = *p++; |
| Soohwan Kim |
0:6f28332c466f | 72 | if (code == 0) { // Pad Option |
| Soohwan Kim |
0:6f28332c466f | 73 | continue; |
| Soohwan Kim |
0:6f28332c466f | 74 | } |
| Soohwan Kim |
0:6f28332c466f | 75 | int len = *p++; |
| Soohwan Kim |
0:6f28332c466f | 76 | |
| Soohwan Kim |
0:6f28332c466f | 77 | DBG("DHCP option: %d\r\n", code); |
| Soohwan Kim |
0:6f28332c466f | 78 | DBG_HEX(p, len); |
| Soohwan Kim |
0:6f28332c466f | 79 | |
| Soohwan Kim |
0:6f28332c466f | 80 | switch(code) { |
| Helmut Tschemernjak | 35:fe3028eda085 | 81 | case OPT_DHCP_MESSAGE: |
| Soohwan Kim |
0:6f28332c466f | 82 | msg_type = *p; |
| Soohwan Kim |
0:6f28332c466f | 83 | break; |
| Helmut Tschemernjak | 35:fe3028eda085 | 84 | case OPT_SUBNET_MASK: |
| Helmut Tschemernjak | 35:fe3028eda085 | 85 | memcpy(netmask, p, 4); |
| Soohwan Kim |
0:6f28332c466f | 86 | break; |
| Helmut Tschemernjak | 35:fe3028eda085 | 87 | case OPT_ROUTER: |
| Helmut Tschemernjak | 35:fe3028eda085 | 88 | memcpy(gateway, p, 4); |
| Soohwan Kim |
0:6f28332c466f | 89 | break; |
| Helmut Tschemernjak | 35:fe3028eda085 | 90 | case OPT_DNS: |
| Soohwan Kim |
0:6f28332c466f | 91 | memcpy(dnsaddr, p, 4); |
| Soohwan Kim |
0:6f28332c466f | 92 | break; |
| Helmut Tschemernjak | 35:fe3028eda085 | 93 | case OPT_TIME_SERVER: |
| Helmut Tschemernjak | 35:fe3028eda085 | 94 | memcpy(timesrv, p, 4); |
| Helmut Tschemernjak | 35:fe3028eda085 | 95 | break; |
| Helmut Tschemernjak | 35:fe3028eda085 | 96 | case OPT_ADDR_LEASE_TIME: |
| Helmut Tschemernjak | 35:fe3028eda085 | 97 | memcpy(leaseTime, p, 4); |
| Soohwan Kim |
0:6f28332c466f | 98 | break; |
| Helmut Tschemernjak | 35:fe3028eda085 | 99 | case OPT_DOMAIN_NAME: |
| Helmut Tschemernjak | 35:fe3028eda085 | 100 | { |
| Helmut Tschemernjak | 35:fe3028eda085 | 101 | int cplen = len; |
| Helmut Tschemernjak | 35:fe3028eda085 | 102 | if (cplen > 63) |
| Helmut Tschemernjak | 35:fe3028eda085 | 103 | cplen = 63; // max domain name |
| Helmut Tschemernjak | 35:fe3028eda085 | 104 | if (domainName) { |
| Helmut Tschemernjak | 35:fe3028eda085 | 105 | free(domainName); |
| Helmut Tschemernjak | 35:fe3028eda085 | 106 | domainName = NULL; |
| Helmut Tschemernjak | 35:fe3028eda085 | 107 | } |
| Helmut Tschemernjak | 35:fe3028eda085 | 108 | if (cplen) { |
| Helmut Tschemernjak | 35:fe3028eda085 | 109 | domainName = (char *)calloc(1, cplen+1); |
| Helmut Tschemernjak | 35:fe3028eda085 | 110 | memcpy(domainName, p, cplen); // zero term is already here via calloc |
| Helmut Tschemernjak | 35:fe3028eda085 | 111 | } |
| Helmut Tschemernjak | 35:fe3028eda085 | 112 | } |
| Helmut Tschemernjak | 35:fe3028eda085 | 113 | break; |
| Helmut Tschemernjak | 35:fe3028eda085 | 114 | case OPT_SERVER_IDENT: |
| Soohwan Kim |
0:6f28332c466f | 115 | memcpy(siaddr, p, 4); |
| Soohwan Kim |
0:6f28332c466f | 116 | break; |
| Soohwan Kim |
0:6f28332c466f | 117 | } |
| Soohwan Kim |
0:6f28332c466f | 118 | p += len; |
| Soohwan Kim |
0:6f28332c466f | 119 | } |
| Soohwan Kim |
0:6f28332c466f | 120 | return msg_type; |
| Soohwan Kim |
0:6f28332c466f | 121 | } |
| Soohwan Kim |
0:6f28332c466f | 122 | |
| Soohwan Kim |
0:6f28332c466f | 123 | bool DHCPClient::verify(uint8_t buf[], int len) { |
| Soohwan Kim |
0:6f28332c466f | 124 | if (len < DHCP_OFFSET_OPTIONS) { |
| Soohwan Kim |
0:6f28332c466f | 125 | return false; |
| Soohwan Kim |
0:6f28332c466f | 126 | } |
| Soohwan Kim |
0:6f28332c466f | 127 | if (buf[DHCP_OFFSET_OP] != 0x02) { |
| Soohwan Kim |
0:6f28332c466f | 128 | return false; |
| Soohwan Kim |
0:6f28332c466f | 129 | } |
| Soohwan Kim |
0:6f28332c466f | 130 | if (memcmp(buf+DHCP_OFFSET_XID, xid, 4) != 0) { |
| Soohwan Kim |
0:6f28332c466f | 131 | return false; |
| Soohwan Kim |
0:6f28332c466f | 132 | } |
| Soohwan Kim |
0:6f28332c466f | 133 | return true; |
| Soohwan Kim |
0:6f28332c466f | 134 | } |
| Soohwan Kim |
0:6f28332c466f | 135 | |
| Soohwan Kim |
0:6f28332c466f | 136 | void DHCPClient::callback() |
| Soohwan Kim |
0:6f28332c466f | 137 | { |
| embeddist | 15:24a9f2df2145 | 138 | Endpoint host; |
| embeddist | 15:24a9f2df2145 | 139 | int recv_len = m_udp->receiveFrom(host, (char*)m_buf, sizeof(m_buf)); |
| Soohwan Kim |
0:6f28332c466f | 140 | if (recv_len < 0) { |
| Soohwan Kim |
0:6f28332c466f | 141 | return; |
| Soohwan Kim |
0:6f28332c466f | 142 | } |
| Soohwan Kim |
0:6f28332c466f | 143 | if (!verify(m_buf, recv_len)) { |
| Soohwan Kim |
0:6f28332c466f | 144 | return; |
| Soohwan Kim |
0:6f28332c466f | 145 | } |
| Soohwan Kim |
0:6f28332c466f | 146 | int r = offer(m_buf, recv_len); |
| Soohwan Kim |
0:6f28332c466f | 147 | if (r == DHCPOFFER) { |
| Soohwan Kim |
0:6f28332c466f | 148 | int send_size = request(); |
| Soohwan Kim |
0:6f28332c466f | 149 | m_udp->sendTo(m_server, (char*)m_buf, send_size); |
| Soohwan Kim |
0:6f28332c466f | 150 | } else if (r == DHCPACK) { |
| Soohwan Kim |
0:6f28332c466f | 151 | exit_flag = true; |
| Soohwan Kim |
0:6f28332c466f | 152 | } |
| Soohwan Kim |
0:6f28332c466f | 153 | } |
| Soohwan Kim |
0:6f28332c466f | 154 | |
| Soohwan Kim |
0:6f28332c466f | 155 | void DHCPClient::add_buf(uint8_t c) |
| Soohwan Kim |
0:6f28332c466f | 156 | { |
| Soohwan Kim |
0:6f28332c466f | 157 | m_buf[m_pos++] = c; |
| Soohwan Kim |
0:6f28332c466f | 158 | } |
| Soohwan Kim |
0:6f28332c466f | 159 | |
| Soohwan Kim |
0:6f28332c466f | 160 | void DHCPClient::add_buf(uint8_t* buf, int len) |
| Soohwan Kim |
0:6f28332c466f | 161 | { |
| Soohwan Kim |
0:6f28332c466f | 162 | for(int i = 0; i < len; i++) { |
| Soohwan Kim |
0:6f28332c466f | 163 | add_buf(buf[i]); |
| Soohwan Kim |
0:6f28332c466f | 164 | } |
| Soohwan Kim |
0:6f28332c466f | 165 | } |
| Soohwan Kim |
0:6f28332c466f | 166 | |
| Soohwan Kim |
0:6f28332c466f | 167 | void DHCPClient::fill_buf(int len, uint8_t data) |
| Soohwan Kim |
0:6f28332c466f | 168 | { |
| Soohwan Kim |
0:6f28332c466f | 169 | while(len-- > 0) { |
| Soohwan Kim |
0:6f28332c466f | 170 | add_buf(data); |
| Soohwan Kim |
0:6f28332c466f | 171 | } |
| Soohwan Kim |
0:6f28332c466f | 172 | } |
| Soohwan Kim |
0:6f28332c466f | 173 | |
| Soohwan Kim |
0:6f28332c466f | 174 | void DHCPClient::add_option(uint8_t code, uint8_t* buf, int len) |
| Soohwan Kim |
0:6f28332c466f | 175 | { |
| Soohwan Kim |
0:6f28332c466f | 176 | add_buf(code); |
| Soohwan Kim |
0:6f28332c466f | 177 | if (len > 0) { |
| Soohwan Kim |
0:6f28332c466f | 178 | add_buf((uint8_t)len); |
| Soohwan Kim |
0:6f28332c466f | 179 | add_buf(buf, len); |
| Soohwan Kim |
0:6f28332c466f | 180 | } |
| Soohwan Kim |
0:6f28332c466f | 181 | } |
| Soohwan Kim |
0:6f28332c466f | 182 | |
| Soohwan Kim |
0:6f28332c466f | 183 | int DHCPClient::setup(int timeout_ms) |
| Soohwan Kim |
0:6f28332c466f | 184 | { |
| Soohwan Kim |
0:6f28332c466f | 185 | eth = WIZnet_Chip::getInstance(); |
| Soohwan Kim |
0:6f28332c466f | 186 | if (eth == NULL) { |
| Soohwan Kim |
0:6f28332c466f | 187 | return -1; |
| Soohwan Kim |
0:6f28332c466f | 188 | } |
| Soohwan Kim |
0:6f28332c466f | 189 | eth->reg_rd_mac(SHAR, chaddr); |
| Soohwan Kim |
0:6f28332c466f | 190 | int interval_ms = 5*1000; // 5000msec |
| Soohwan Kim |
0:6f28332c466f | 191 | if (timeout_ms < interval_ms) { |
| Soohwan Kim |
0:6f28332c466f | 192 | interval_ms = timeout_ms; |
| Soohwan Kim |
0:6f28332c466f | 193 | } |
| Soohwan Kim |
0:6f28332c466f | 194 | m_udp = new UDPSocket; |
| Soohwan Kim |
0:6f28332c466f | 195 | m_udp->init(); |
| Soohwan Kim |
0:6f28332c466f | 196 | m_udp->set_blocking(false); |
| Soohwan Kim |
0:6f28332c466f | 197 | eth->reg_wr<uint32_t>(SIPR, 0x00000000); // local ip "0.0.0.0" |
| Helmut Tschemernjak | 35:fe3028eda085 | 198 | m_udp->bind(DHCP_CLIENT_PORT); // local port |
| Helmut Tschemernjak | 35:fe3028eda085 | 199 | m_server.set_address("255.255.255.255", DHCP_SERVER_PORT); // DHCP broadcast |
| Soohwan Kim |
0:6f28332c466f | 200 | exit_flag = false; |
| Soohwan Kim |
0:6f28332c466f | 201 | int err = 0; |
| Soohwan Kim |
0:6f28332c466f | 202 | int seq = 0; |
| Soohwan Kim |
0:6f28332c466f | 203 | int send_size; |
| Soohwan Kim |
0:6f28332c466f | 204 | while(!exit_flag) { |
| Soohwan Kim |
0:6f28332c466f | 205 | switch(seq) { |
| Soohwan Kim |
0:6f28332c466f | 206 | case 0: |
| Soohwan Kim |
0:6f28332c466f | 207 | m_retry = 0; |
| Soohwan Kim |
0:6f28332c466f | 208 | seq++; |
| Soohwan Kim |
0:6f28332c466f | 209 | break; |
| Soohwan Kim |
0:6f28332c466f | 210 | case 1: |
| Soohwan Kim |
0:6f28332c466f | 211 | send_size = discover(); |
| Soohwan Kim |
0:6f28332c466f | 212 | m_udp->sendTo(m_server, (char*)m_buf, send_size); |
| Soohwan Kim |
0:6f28332c466f | 213 | m_interval.reset(); |
| Soohwan Kim |
0:6f28332c466f | 214 | m_interval.start(); |
| Soohwan Kim |
0:6f28332c466f | 215 | seq++; |
| Soohwan Kim |
0:6f28332c466f | 216 | break; |
| Soohwan Kim |
0:6f28332c466f | 217 | case 2: |
| Soohwan Kim |
0:6f28332c466f | 218 | callback(); |
| Soohwan Kim |
0:6f28332c466f | 219 | if (m_interval.read_ms() > interval_ms) { |
| Soohwan Kim |
0:6f28332c466f | 220 | DBG("m_retry: %d\n", m_retry); |
| Soohwan Kim |
0:6f28332c466f | 221 | if (++m_retry >= (timeout_ms/interval_ms)) { |
| Soohwan Kim |
0:6f28332c466f | 222 | err = -1; |
| Soohwan Kim |
0:6f28332c466f | 223 | exit_flag = true; |
| Soohwan Kim |
0:6f28332c466f | 224 | } |
| Soohwan Kim |
0:6f28332c466f | 225 | seq--; |
| Soohwan Kim |
0:6f28332c466f | 226 | } |
| Soohwan Kim |
0:6f28332c466f | 227 | break; |
| Soohwan Kim |
0:6f28332c466f | 228 | } |
| Soohwan Kim |
0:6f28332c466f | 229 | } |
| Soohwan Kim |
0:6f28332c466f | 230 | DBG("m_retry: %d, m_interval: %d\n", m_retry, m_interval.read_ms()); |
| Soohwan Kim |
0:6f28332c466f | 231 | delete m_udp; |
| Soohwan Kim |
0:6f28332c466f | 232 | return err; |
| Soohwan Kim |
0:6f28332c466f | 233 | } |
| Soohwan Kim |
0:6f28332c466f | 234 | |
| Soohwan Kim |
0:6f28332c466f | 235 | DHCPClient::DHCPClient() { |
| Helmut Tschemernjak | 35:fe3028eda085 | 236 | domainName = NULL; |
| Soohwan Kim |
0:6f28332c466f | 237 | } |
| Soohwan Kim |
0:6f28332c466f | 238 | |
| Helmut Tschemernjak | 35:fe3028eda085 | 239 | DHCPClient::~DHCPClient() { |
| Helmut Tschemernjak | 35:fe3028eda085 | 240 | if (domainName) |
| Helmut Tschemernjak | 35:fe3028eda085 | 241 | free(domainName); |
| Helmut Tschemernjak | 35:fe3028eda085 | 242 | } |
Helmut Tschemernjak
