Helmut Tschemernjak / WIZnetInterface

Fork of WIZnetInterface by WIZnet

Committer:
Helmut Tschemernjak
Date:
Wed Oct 11 11:18:41 2017 +0200
Revision:
36:0ba2e8d5274a
Parent:
35:fe3028eda085
More DHCP cleanup, added precise DHCP packet construction
DHCP hostname support (added to the DHCP request) which
allows dynamic DNS updates and routers will show the client name.

Who changed what in which revision?

UserRevisionLine numberNew 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;
Helmut Tschemernjak 36:0ba2e8d5274a 20 const uint8_t zero[] = { 0, 0, 0, 0 };
Soohwan Kim 0:6f28332c466f 21 const uint8_t header[] = {0x01,0x01,0x06,0x00};
Soohwan Kim 0:6f28332c466f 22 add_buf((uint8_t*)header, sizeof(header));
Soohwan Kim 0:6f28332c466f 23 uint32_t x = time(NULL) + rand();
Soohwan Kim 0:6f28332c466f 24 xid[0] = x>>24; xid[1] = x>>16; xid[2] = x>>8; xid[3] = x;
Helmut Tschemernjak 36:0ba2e8d5274a 25 add_buf(xid, 4); // transaction id
Helmut Tschemernjak 36:0ba2e8d5274a 26 add_buf((uint8_t*)zero, 2); // seconds elapsed
Helmut Tschemernjak 36:0ba2e8d5274a 27 add_buf((uint8_t*)zero, 2); // bootp flags
Helmut Tschemernjak 36:0ba2e8d5274a 28 add_buf((uint8_t*)zero, 4); // requester ip address
Helmut Tschemernjak 36:0ba2e8d5274a 29 add_buf((uint8_t*)zero, 4); // client ip address
Helmut Tschemernjak 36:0ba2e8d5274a 30 add_buf((uint8_t*)zero, 4); // next server ip address
Helmut Tschemernjak 36:0ba2e8d5274a 31 add_buf((uint8_t*)zero, 4); // relay agent ip address
Helmut Tschemernjak 36:0ba2e8d5274a 32 add_buf(chaddr, 6); // MAC address
Helmut Tschemernjak 36:0ba2e8d5274a 33 fill_buf(10, 0x00); // padding
Helmut Tschemernjak 36:0ba2e8d5274a 34 fill_buf(192, 0x00);
Helmut Tschemernjak 35:fe3028eda085 35 const uint8_t options[] = {0x63,0x82,0x53,0x63, // DHCP_MAGIC_COOKIE
Helmut Tschemernjak 35:fe3028eda085 36 OPT_DHCP_MESSAGE, 1, DHCPDISCOVER, // // DHCP message, len, discover
Helmut Tschemernjak 36:0ba2e8d5274a 37 OPT_PARAMETER_REQ, 5, OPT_SUBNET_MASK, OPT_ROUTER, OPT_TIME_SERVER, OPT_DOMAIN_NAME, OPT_DNS };
Soohwan Kim 0:6f28332c466f 38 add_buf((uint8_t*)options, sizeof(options));
Helmut Tschemernjak 36:0ba2e8d5274a 39 if (_hostname) {
Helmut Tschemernjak 36:0ba2e8d5274a 40 int hlen = strlen(_hostname);
Helmut Tschemernjak 36:0ba2e8d5274a 41 add_buf(OPT_HOSTNAME);
Helmut Tschemernjak 36:0ba2e8d5274a 42 add_buf(hlen);
Helmut Tschemernjak 36:0ba2e8d5274a 43 add_buf((uint8_t *)_hostname, hlen);
Helmut Tschemernjak 36:0ba2e8d5274a 44 }
Helmut Tschemernjak 36:0ba2e8d5274a 45 add_option(OPT_END);
Helmut Tschemernjak 36:0ba2e8d5274a 46
Soohwan Kim 0:6f28332c466f 47 return m_pos;
Soohwan Kim 0:6f28332c466f 48 }
Soohwan Kim 0:6f28332c466f 49
Soohwan Kim 0:6f28332c466f 50 int DHCPClient::request()
Soohwan Kim 0:6f28332c466f 51 {
Soohwan Kim 0:6f28332c466f 52 m_pos = 0;
Helmut Tschemernjak 36:0ba2e8d5274a 53 const uint8_t zero[] = { 0, 0, 0, 0 };
Soohwan Kim 0:6f28332c466f 54 const uint8_t header[] = {0x01,0x01,0x06,0x00};
Soohwan Kim 0:6f28332c466f 55 add_buf((uint8_t*)header, sizeof(header));
Helmut Tschemernjak 36:0ba2e8d5274a 56 add_buf(xid, 4); // transaction id
Helmut Tschemernjak 36:0ba2e8d5274a 57 add_buf((uint8_t*)zero, 2); // seconds elapsed
Helmut Tschemernjak 36:0ba2e8d5274a 58 add_buf((uint8_t*)zero, 2); // bootp flags
Helmut Tschemernjak 36:0ba2e8d5274a 59 add_buf((uint8_t*)zero, 4); // requester ip address
Helmut Tschemernjak 36:0ba2e8d5274a 60 add_buf((uint8_t*)zero, 4); // client ip address
Helmut Tschemernjak 36:0ba2e8d5274a 61 add_buf(siaddr, 4); // next server ip address
Helmut Tschemernjak 36:0ba2e8d5274a 62 add_buf((uint8_t*)zero, 4); // relay agent ip address (giaddr)
Helmut Tschemernjak 36:0ba2e8d5274a 63 add_buf(chaddr, 6); // MAC address
Helmut Tschemernjak 36:0ba2e8d5274a 64 fill_buf(10, 0x00); // padding
Helmut Tschemernjak 36:0ba2e8d5274a 65 fill_buf(192, 0x00);
Helmut Tschemernjak 35:fe3028eda085 66 const uint8_t options[] = {0x63,0x82,0x53,0x63, // DHCP_MAGIC_COOKIE
Helmut Tschemernjak 35:fe3028eda085 67 OPT_DHCP_MESSAGE,1, DHCPREQUEST, // DHCP message, len, request
Helmut Tschemernjak 35:fe3028eda085 68 OPT_PARAMETER_REQ, 5, OPT_SUBNET_MASK, OPT_ROUTER, OPT_TIME_SERVER, OPT_DOMAIN_NAME, OPT_DNS };
Soohwan Kim 0:6f28332c466f 69 add_buf((uint8_t*)options, sizeof(options));
Helmut Tschemernjak 35:fe3028eda085 70 add_option(OPT_IP_ADDR_REQ, yiaddr, 4);
Helmut Tschemernjak 35:fe3028eda085 71 add_option(OPT_SERVER_IDENT, siaddr, 4);
Helmut Tschemernjak 36:0ba2e8d5274a 72 if (_hostname) {
Helmut Tschemernjak 36:0ba2e8d5274a 73 int hlen = strlen(_hostname);
Helmut Tschemernjak 36:0ba2e8d5274a 74 add_buf(OPT_HOSTNAME);
Helmut Tschemernjak 36:0ba2e8d5274a 75 add_buf(hlen);
Helmut Tschemernjak 36:0ba2e8d5274a 76 add_buf((uint8_t *)_hostname, hlen);
Helmut Tschemernjak 36:0ba2e8d5274a 77 }
Helmut Tschemernjak 35:fe3028eda085 78 add_option(OPT_END);
Soohwan Kim 0:6f28332c466f 79 return m_pos;
Soohwan Kim 0:6f28332c466f 80 }
Soohwan Kim 0:6f28332c466f 81
Soohwan Kim 0:6f28332c466f 82 int DHCPClient::offer(uint8_t buf[], int size) {
Soohwan Kim 0:6f28332c466f 83 memcpy(yiaddr, buf+DHCP_OFFSET_YIADDR, 4);
Helmut Tschemernjak 35:fe3028eda085 84 memcpy(siaddr, buf+DHCP_OFFSET_SIADDR, 4);
Helmut Tschemernjak 35:fe3028eda085 85
Helmut Tschemernjak 35:fe3028eda085 86 memset(dnsaddr, 0, sizeof(dnsaddr));
Helmut Tschemernjak 35:fe3028eda085 87 memset(gateway, 0, sizeof(gateway));
Helmut Tschemernjak 35:fe3028eda085 88 memset(netmask, 0, sizeof(netmask));
Helmut Tschemernjak 35:fe3028eda085 89 memset(timesrv, 0, sizeof(timesrv));
Helmut Tschemernjak 35:fe3028eda085 90 memset(leaseTime, 0, sizeof(leaseTime));
Helmut Tschemernjak 35:fe3028eda085 91
Soohwan Kim 0:6f28332c466f 92 uint8_t *p;
Soohwan Kim 0:6f28332c466f 93 int msg_type = -1;
Soohwan Kim 0:6f28332c466f 94 p = buf + DHCP_OFFSET_OPTIONS;
Helmut Tschemernjak 35:fe3028eda085 95 while(*p != OPT_END && p < (buf+size)) {
Soohwan Kim 0:6f28332c466f 96 uint8_t code = *p++;
Soohwan Kim 0:6f28332c466f 97 if (code == 0) { // Pad Option
Soohwan Kim 0:6f28332c466f 98 continue;
Soohwan Kim 0:6f28332c466f 99 }
Soohwan Kim 0:6f28332c466f 100 int len = *p++;
Soohwan Kim 0:6f28332c466f 101
Soohwan Kim 0:6f28332c466f 102 DBG("DHCP option: %d\r\n", code);
Soohwan Kim 0:6f28332c466f 103 DBG_HEX(p, len);
Soohwan Kim 0:6f28332c466f 104
Soohwan Kim 0:6f28332c466f 105 switch(code) {
Helmut Tschemernjak 35:fe3028eda085 106 case OPT_DHCP_MESSAGE:
Soohwan Kim 0:6f28332c466f 107 msg_type = *p;
Soohwan Kim 0:6f28332c466f 108 break;
Helmut Tschemernjak 35:fe3028eda085 109 case OPT_SUBNET_MASK:
Helmut Tschemernjak 35:fe3028eda085 110 memcpy(netmask, p, 4);
Soohwan Kim 0:6f28332c466f 111 break;
Helmut Tschemernjak 35:fe3028eda085 112 case OPT_ROUTER:
Helmut Tschemernjak 35:fe3028eda085 113 memcpy(gateway, p, 4);
Soohwan Kim 0:6f28332c466f 114 break;
Helmut Tschemernjak 35:fe3028eda085 115 case OPT_DNS:
Soohwan Kim 0:6f28332c466f 116 memcpy(dnsaddr, p, 4);
Soohwan Kim 0:6f28332c466f 117 break;
Helmut Tschemernjak 35:fe3028eda085 118 case OPT_TIME_SERVER:
Helmut Tschemernjak 35:fe3028eda085 119 memcpy(timesrv, p, 4);
Helmut Tschemernjak 35:fe3028eda085 120 break;
Helmut Tschemernjak 35:fe3028eda085 121 case OPT_ADDR_LEASE_TIME:
Helmut Tschemernjak 35:fe3028eda085 122 memcpy(leaseTime, p, 4);
Soohwan Kim 0:6f28332c466f 123 break;
Helmut Tschemernjak 35:fe3028eda085 124 case OPT_DOMAIN_NAME:
Helmut Tschemernjak 35:fe3028eda085 125 {
Helmut Tschemernjak 35:fe3028eda085 126 int cplen = len;
Helmut Tschemernjak 35:fe3028eda085 127 if (cplen > 63)
Helmut Tschemernjak 35:fe3028eda085 128 cplen = 63; // max domain name
Helmut Tschemernjak 35:fe3028eda085 129 if (domainName) {
Helmut Tschemernjak 35:fe3028eda085 130 free(domainName);
Helmut Tschemernjak 35:fe3028eda085 131 domainName = NULL;
Helmut Tschemernjak 35:fe3028eda085 132 }
Helmut Tschemernjak 35:fe3028eda085 133 if (cplen) {
Helmut Tschemernjak 35:fe3028eda085 134 domainName = (char *)calloc(1, cplen+1);
Helmut Tschemernjak 35:fe3028eda085 135 memcpy(domainName, p, cplen); // zero term is already here via calloc
Helmut Tschemernjak 35:fe3028eda085 136 }
Helmut Tschemernjak 35:fe3028eda085 137 }
Helmut Tschemernjak 35:fe3028eda085 138 break;
Helmut Tschemernjak 35:fe3028eda085 139 case OPT_SERVER_IDENT:
Soohwan Kim 0:6f28332c466f 140 memcpy(siaddr, p, 4);
Soohwan Kim 0:6f28332c466f 141 break;
Soohwan Kim 0:6f28332c466f 142 }
Soohwan Kim 0:6f28332c466f 143 p += len;
Soohwan Kim 0:6f28332c466f 144 }
Soohwan Kim 0:6f28332c466f 145 return msg_type;
Soohwan Kim 0:6f28332c466f 146 }
Soohwan Kim 0:6f28332c466f 147
Soohwan Kim 0:6f28332c466f 148 bool DHCPClient::verify(uint8_t buf[], int len) {
Soohwan Kim 0:6f28332c466f 149 if (len < DHCP_OFFSET_OPTIONS) {
Soohwan Kim 0:6f28332c466f 150 return false;
Soohwan Kim 0:6f28332c466f 151 }
Soohwan Kim 0:6f28332c466f 152 if (buf[DHCP_OFFSET_OP] != 0x02) {
Soohwan Kim 0:6f28332c466f 153 return false;
Soohwan Kim 0:6f28332c466f 154 }
Soohwan Kim 0:6f28332c466f 155 if (memcmp(buf+DHCP_OFFSET_XID, xid, 4) != 0) {
Soohwan Kim 0:6f28332c466f 156 return false;
Soohwan Kim 0:6f28332c466f 157 }
Soohwan Kim 0:6f28332c466f 158 return true;
Soohwan Kim 0:6f28332c466f 159 }
Soohwan Kim 0:6f28332c466f 160
Soohwan Kim 0:6f28332c466f 161 void DHCPClient::callback()
Soohwan Kim 0:6f28332c466f 162 {
embeddist 15:24a9f2df2145 163 Endpoint host;
embeddist 15:24a9f2df2145 164 int recv_len = m_udp->receiveFrom(host, (char*)m_buf, sizeof(m_buf));
Soohwan Kim 0:6f28332c466f 165 if (recv_len < 0) {
Soohwan Kim 0:6f28332c466f 166 return;
Soohwan Kim 0:6f28332c466f 167 }
Soohwan Kim 0:6f28332c466f 168 if (!verify(m_buf, recv_len)) {
Soohwan Kim 0:6f28332c466f 169 return;
Soohwan Kim 0:6f28332c466f 170 }
Soohwan Kim 0:6f28332c466f 171 int r = offer(m_buf, recv_len);
Soohwan Kim 0:6f28332c466f 172 if (r == DHCPOFFER) {
Soohwan Kim 0:6f28332c466f 173 int send_size = request();
Soohwan Kim 0:6f28332c466f 174 m_udp->sendTo(m_server, (char*)m_buf, send_size);
Soohwan Kim 0:6f28332c466f 175 } else if (r == DHCPACK) {
Soohwan Kim 0:6f28332c466f 176 exit_flag = true;
Soohwan Kim 0:6f28332c466f 177 }
Soohwan Kim 0:6f28332c466f 178 }
Soohwan Kim 0:6f28332c466f 179
Soohwan Kim 0:6f28332c466f 180 void DHCPClient::add_buf(uint8_t c)
Soohwan Kim 0:6f28332c466f 181 {
Soohwan Kim 0:6f28332c466f 182 m_buf[m_pos++] = c;
Soohwan Kim 0:6f28332c466f 183 }
Soohwan Kim 0:6f28332c466f 184
Soohwan Kim 0:6f28332c466f 185 void DHCPClient::add_buf(uint8_t* buf, int len)
Soohwan Kim 0:6f28332c466f 186 {
Soohwan Kim 0:6f28332c466f 187 for(int i = 0; i < len; i++) {
Soohwan Kim 0:6f28332c466f 188 add_buf(buf[i]);
Soohwan Kim 0:6f28332c466f 189 }
Soohwan Kim 0:6f28332c466f 190 }
Soohwan Kim 0:6f28332c466f 191
Soohwan Kim 0:6f28332c466f 192 void DHCPClient::fill_buf(int len, uint8_t data)
Soohwan Kim 0:6f28332c466f 193 {
Soohwan Kim 0:6f28332c466f 194 while(len-- > 0) {
Soohwan Kim 0:6f28332c466f 195 add_buf(data);
Soohwan Kim 0:6f28332c466f 196 }
Soohwan Kim 0:6f28332c466f 197 }
Soohwan Kim 0:6f28332c466f 198
Soohwan Kim 0:6f28332c466f 199 void DHCPClient::add_option(uint8_t code, uint8_t* buf, int len)
Soohwan Kim 0:6f28332c466f 200 {
Soohwan Kim 0:6f28332c466f 201 add_buf(code);
Soohwan Kim 0:6f28332c466f 202 if (len > 0) {
Soohwan Kim 0:6f28332c466f 203 add_buf((uint8_t)len);
Soohwan Kim 0:6f28332c466f 204 add_buf(buf, len);
Soohwan Kim 0:6f28332c466f 205 }
Soohwan Kim 0:6f28332c466f 206 }
Soohwan Kim 0:6f28332c466f 207
Helmut Tschemernjak 36:0ba2e8d5274a 208 int DHCPClient::setup(const char *hostnane, int timeout_ms)
Soohwan Kim 0:6f28332c466f 209 {
Soohwan Kim 0:6f28332c466f 210 eth = WIZnet_Chip::getInstance();
Soohwan Kim 0:6f28332c466f 211 if (eth == NULL) {
Soohwan Kim 0:6f28332c466f 212 return -1;
Helmut Tschemernjak 36:0ba2e8d5274a 213 }
Helmut Tschemernjak 36:0ba2e8d5274a 214 _hostname = hostnane;
Soohwan Kim 0:6f28332c466f 215 eth->reg_rd_mac(SHAR, chaddr);
Soohwan Kim 0:6f28332c466f 216 int interval_ms = 5*1000; // 5000msec
Soohwan Kim 0:6f28332c466f 217 if (timeout_ms < interval_ms) {
Soohwan Kim 0:6f28332c466f 218 interval_ms = timeout_ms;
Soohwan Kim 0:6f28332c466f 219 }
Soohwan Kim 0:6f28332c466f 220 m_udp = new UDPSocket;
Soohwan Kim 0:6f28332c466f 221 m_udp->init();
Soohwan Kim 0:6f28332c466f 222 m_udp->set_blocking(false);
Soohwan Kim 0:6f28332c466f 223 eth->reg_wr<uint32_t>(SIPR, 0x00000000); // local ip "0.0.0.0"
Helmut Tschemernjak 35:fe3028eda085 224 m_udp->bind(DHCP_CLIENT_PORT); // local port
Helmut Tschemernjak 35:fe3028eda085 225 m_server.set_address("255.255.255.255", DHCP_SERVER_PORT); // DHCP broadcast
Soohwan Kim 0:6f28332c466f 226 exit_flag = false;
Soohwan Kim 0:6f28332c466f 227 int err = 0;
Soohwan Kim 0:6f28332c466f 228 int seq = 0;
Soohwan Kim 0:6f28332c466f 229 int send_size;
Soohwan Kim 0:6f28332c466f 230 while(!exit_flag) {
Soohwan Kim 0:6f28332c466f 231 switch(seq) {
Soohwan Kim 0:6f28332c466f 232 case 0:
Soohwan Kim 0:6f28332c466f 233 m_retry = 0;
Soohwan Kim 0:6f28332c466f 234 seq++;
Soohwan Kim 0:6f28332c466f 235 break;
Soohwan Kim 0:6f28332c466f 236 case 1:
Soohwan Kim 0:6f28332c466f 237 send_size = discover();
Soohwan Kim 0:6f28332c466f 238 m_udp->sendTo(m_server, (char*)m_buf, send_size);
Soohwan Kim 0:6f28332c466f 239 m_interval.reset();
Soohwan Kim 0:6f28332c466f 240 m_interval.start();
Soohwan Kim 0:6f28332c466f 241 seq++;
Soohwan Kim 0:6f28332c466f 242 break;
Soohwan Kim 0:6f28332c466f 243 case 2:
Soohwan Kim 0:6f28332c466f 244 callback();
Soohwan Kim 0:6f28332c466f 245 if (m_interval.read_ms() > interval_ms) {
Soohwan Kim 0:6f28332c466f 246 DBG("m_retry: %d\n", m_retry);
Soohwan Kim 0:6f28332c466f 247 if (++m_retry >= (timeout_ms/interval_ms)) {
Soohwan Kim 0:6f28332c466f 248 err = -1;
Soohwan Kim 0:6f28332c466f 249 exit_flag = true;
Soohwan Kim 0:6f28332c466f 250 }
Soohwan Kim 0:6f28332c466f 251 seq--;
Soohwan Kim 0:6f28332c466f 252 }
Soohwan Kim 0:6f28332c466f 253 break;
Soohwan Kim 0:6f28332c466f 254 }
Soohwan Kim 0:6f28332c466f 255 }
Soohwan Kim 0:6f28332c466f 256 DBG("m_retry: %d, m_interval: %d\n", m_retry, m_interval.read_ms());
Soohwan Kim 0:6f28332c466f 257 delete m_udp;
Soohwan Kim 0:6f28332c466f 258 return err;
Soohwan Kim 0:6f28332c466f 259 }
Soohwan Kim 0:6f28332c466f 260
Soohwan Kim 0:6f28332c466f 261 DHCPClient::DHCPClient() {
Helmut Tschemernjak 35:fe3028eda085 262 domainName = NULL;
Soohwan Kim 0:6f28332c466f 263 }
Soohwan Kim 0:6f28332c466f 264
Helmut Tschemernjak 35:fe3028eda085 265 DHCPClient::~DHCPClient() {
Helmut Tschemernjak 35:fe3028eda085 266 if (domainName)
Helmut Tschemernjak 35:fe3028eda085 267 free(domainName);
Helmut Tschemernjak 35:fe3028eda085 268 }