NetworkServices with NUCLEO-L476RG and W5500 by SeeedStudio stack.

Dependents:   coap-example Borsch coap-example

Fork of NetworkServices by AMETEK Powervar

Committer:
sgnezdov
Date:
Wed Jul 05 18:34:39 2017 +0000
Revision:
17:c976088bf39d
Parent:
16:82e7a0bf58d8
Changed setup interface to take MAC address, because W5500 may use software defined MAC when obtaining IP.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dgriffin65 15:14382459c8b7 1 // DHCPClient.cpp 2013/4/10
dgriffin65 15:14382459c8b7 2 #include "mbed.h"
dgriffin65 15:14382459c8b7 3 #include "mbed_debug.h"
dgriffin65 15:14382459c8b7 4 #include "UDPSocket.h"
dgriffin65 15:14382459c8b7 5 #include "DHCPClient.h"
dgriffin65 15:14382459c8b7 6
sgnezdov 17:c976088bf39d 7 #define DBG_DHCP 0
dgriffin65 15:14382459c8b7 8
dgriffin65 15:14382459c8b7 9 #if DBG_DHCP
dgriffin65 15:14382459c8b7 10 #define DBG(...) do{debug("[%s:%d]", __PRETTY_FUNCTION__,__LINE__);debug(__VA_ARGS__);} while(0);
dgriffin65 15:14382459c8b7 11 #define DBG_HEX(A,B) do{debug("[%s:%d]\r\n", __PRETTY_FUNCTION__,__LINE__);debug_hex(A,B);} while(0);
dgriffin65 15:14382459c8b7 12 #else
dgriffin65 15:14382459c8b7 13 #define DBG(...) while(0);
dgriffin65 15:14382459c8b7 14 #define DBG_HEX(A,B) while(0);
dgriffin65 15:14382459c8b7 15 #endif
dgriffin65 15:14382459c8b7 16
dgriffin65 15:14382459c8b7 17 int DHCPClient::discover()
dgriffin65 15:14382459c8b7 18 {
dgriffin65 15:14382459c8b7 19 m_pos = 0;
dgriffin65 15:14382459c8b7 20 const uint8_t header[] = {0x01,0x01,0x06,0x00};
dgriffin65 15:14382459c8b7 21 add_buf((uint8_t*)header, sizeof(header));
dgriffin65 15:14382459c8b7 22 uint32_t x = time(NULL) + rand();
dgriffin65 15:14382459c8b7 23 xid[0] = x>>24; xid[1] = x>>16; xid[2] = x>>8; xid[3] = x;
dgriffin65 15:14382459c8b7 24 add_buf(xid, 4);
dgriffin65 15:14382459c8b7 25 fill_buf(20, 0x00);
dgriffin65 15:14382459c8b7 26 add_buf(chaddr, 6);
dgriffin65 15:14382459c8b7 27 fill_buf(10+192, 0x00);
dgriffin65 15:14382459c8b7 28 const uint8_t options[] = {0x63,0x82,0x53,0x63, // magic cookie
dgriffin65 15:14382459c8b7 29 53,1,DHCPDISCOVER, // DHCP option 53: DHCP Discover
dgriffin65 15:14382459c8b7 30 55,4,1,3,15,6,
dgriffin65 15:14382459c8b7 31 255};
dgriffin65 15:14382459c8b7 32 add_buf((uint8_t*)options, sizeof(options));
dgriffin65 15:14382459c8b7 33 return m_pos;
dgriffin65 15:14382459c8b7 34 }
dgriffin65 15:14382459c8b7 35
dgriffin65 15:14382459c8b7 36 int DHCPClient::request()
dgriffin65 15:14382459c8b7 37 {
dgriffin65 15:14382459c8b7 38 m_pos = 0;
dgriffin65 15:14382459c8b7 39 const uint8_t header[] = {0x01,0x01,0x06,0x00};
dgriffin65 15:14382459c8b7 40 add_buf((uint8_t*)header, sizeof(header));
dgriffin65 15:14382459c8b7 41 add_buf(xid, 4);
dgriffin65 15:14382459c8b7 42 fill_buf(12, 0x00);
dgriffin65 15:14382459c8b7 43 add_buf(siaddr, 4);
dgriffin65 15:14382459c8b7 44 fill_buf(4, 0x00); // giaddr
dgriffin65 15:14382459c8b7 45 add_buf(chaddr, 6);
dgriffin65 15:14382459c8b7 46 fill_buf(10+192, 0x00);
dgriffin65 15:14382459c8b7 47 const uint8_t options[] = {0x63,0x82,0x53,0x63, // magic cookie
dgriffin65 15:14382459c8b7 48 53,1,DHCPREQUEST, // DHCP option 53: DHCP Request
dgriffin65 15:14382459c8b7 49 55,4,1,3,15,6, // DHCP option 55:
dgriffin65 15:14382459c8b7 50 };
dgriffin65 15:14382459c8b7 51 add_buf((uint8_t*)options, sizeof(options));
dgriffin65 15:14382459c8b7 52 add_option(50, yiaddr, 4);
dgriffin65 15:14382459c8b7 53 add_option(54, siaddr, 4);
dgriffin65 15:14382459c8b7 54 add_option(255);
dgriffin65 15:14382459c8b7 55 return m_pos;
dgriffin65 15:14382459c8b7 56 }
dgriffin65 15:14382459c8b7 57
dgriffin65 15:14382459c8b7 58 int DHCPClient::offer(uint8_t buf[], int size) {
dgriffin65 15:14382459c8b7 59 memcpy(yiaddr, buf+DHCP_OFFSET_YIADDR, 4);
dgriffin65 15:14382459c8b7 60 memcpy(siaddr, buf+DHCP_OFFSET_SIADDR, 4);
dgriffin65 15:14382459c8b7 61 uint8_t *p;
dgriffin65 15:14382459c8b7 62 int msg_type = -1;
dgriffin65 15:14382459c8b7 63 p = buf + DHCP_OFFSET_OPTIONS;
dgriffin65 15:14382459c8b7 64 while(*p != 255 && p < (buf+size)) {
dgriffin65 15:14382459c8b7 65 uint8_t code = *p++;
dgriffin65 15:14382459c8b7 66 if (code == 0) { // Pad Option
dgriffin65 15:14382459c8b7 67 continue;
dgriffin65 15:14382459c8b7 68 }
dgriffin65 15:14382459c8b7 69 int len = *p++;
dgriffin65 15:14382459c8b7 70
dgriffin65 15:14382459c8b7 71 DBG("DHCP option: %d\r\n", code);
dgriffin65 15:14382459c8b7 72 DBG_HEX(p, len);
dgriffin65 15:14382459c8b7 73
dgriffin65 15:14382459c8b7 74 switch(code) {
dgriffin65 15:14382459c8b7 75 case 53:
dgriffin65 15:14382459c8b7 76 msg_type = *p;
dgriffin65 15:14382459c8b7 77 break;
dgriffin65 15:14382459c8b7 78 case 1:
dgriffin65 15:14382459c8b7 79 memcpy(netmask, p, 4); // Subnet mask address
dgriffin65 15:14382459c8b7 80 break;
dgriffin65 15:14382459c8b7 81 case 3:
dgriffin65 15:14382459c8b7 82 memcpy(gateway, p, 4); // Gateway IP address
dgriffin65 15:14382459c8b7 83 break;
dgriffin65 15:14382459c8b7 84 case 6: // DNS server
dgriffin65 15:14382459c8b7 85 memcpy(dnsaddr, p, 4);
dgriffin65 15:14382459c8b7 86 break;
dgriffin65 15:14382459c8b7 87 case 51: // IP lease time
dgriffin65 15:14382459c8b7 88 break;
dgriffin65 15:14382459c8b7 89 case 54: // DHCP server
dgriffin65 15:14382459c8b7 90 memcpy(siaddr, p, 4);
dgriffin65 15:14382459c8b7 91 break;
dgriffin65 15:14382459c8b7 92 }
dgriffin65 15:14382459c8b7 93 p += len;
dgriffin65 15:14382459c8b7 94 }
dgriffin65 15:14382459c8b7 95 return msg_type;
dgriffin65 15:14382459c8b7 96 }
dgriffin65 15:14382459c8b7 97
dgriffin65 15:14382459c8b7 98 bool DHCPClient::verify(uint8_t buf[], int len) {
dgriffin65 15:14382459c8b7 99 if (len < DHCP_OFFSET_OPTIONS) {
dgriffin65 15:14382459c8b7 100 return false;
dgriffin65 15:14382459c8b7 101 }
dgriffin65 15:14382459c8b7 102 if (buf[DHCP_OFFSET_OP] != 0x02) {
dgriffin65 15:14382459c8b7 103 return false;
dgriffin65 15:14382459c8b7 104 }
dgriffin65 15:14382459c8b7 105 if (memcmp(buf+DHCP_OFFSET_XID, xid, 4) != 0) {
dgriffin65 15:14382459c8b7 106 return false;
dgriffin65 15:14382459c8b7 107 }
dgriffin65 15:14382459c8b7 108 return true;
dgriffin65 15:14382459c8b7 109 }
dgriffin65 15:14382459c8b7 110
dgriffin65 15:14382459c8b7 111 void DHCPClient::callback()
dgriffin65 15:14382459c8b7 112 {
sgnezdov 17:c976088bf39d 113 DBG("DHCPClient callback\n");
dgriffin65 15:14382459c8b7 114 SocketAddress host;
dgriffin65 15:14382459c8b7 115 int recv_len = m_udp->recvfrom(&host, (char*)m_buf, sizeof(m_buf));
dgriffin65 15:14382459c8b7 116 if (recv_len < 0) {
dgriffin65 15:14382459c8b7 117 return;
dgriffin65 15:14382459c8b7 118 }
dgriffin65 15:14382459c8b7 119 if (!verify(m_buf, recv_len)) {
dgriffin65 15:14382459c8b7 120 return;
dgriffin65 15:14382459c8b7 121 }
dgriffin65 15:14382459c8b7 122 int r = offer(m_buf, recv_len);
dgriffin65 15:14382459c8b7 123 if (r == DHCPOFFER) {
dgriffin65 15:14382459c8b7 124 int send_size = request();
dgriffin65 15:14382459c8b7 125 m_udp->sendto(m_server, (char*)m_buf, send_size);
dgriffin65 15:14382459c8b7 126 } else if (r == DHCPACK) {
dgriffin65 15:14382459c8b7 127 exit_flag = true;
dgriffin65 15:14382459c8b7 128 }
dgriffin65 15:14382459c8b7 129 }
dgriffin65 15:14382459c8b7 130
dgriffin65 15:14382459c8b7 131 void DHCPClient::add_buf(uint8_t c)
dgriffin65 15:14382459c8b7 132 {
dgriffin65 15:14382459c8b7 133 m_buf[m_pos++] = c;
dgriffin65 15:14382459c8b7 134 }
dgriffin65 15:14382459c8b7 135
dgriffin65 15:14382459c8b7 136 void DHCPClient::add_buf(uint8_t* buf, int len)
dgriffin65 15:14382459c8b7 137 {
dgriffin65 15:14382459c8b7 138 for(int i = 0; i < len; i++) {
dgriffin65 15:14382459c8b7 139 add_buf(buf[i]);
dgriffin65 15:14382459c8b7 140 }
dgriffin65 15:14382459c8b7 141 }
dgriffin65 15:14382459c8b7 142
dgriffin65 15:14382459c8b7 143 void DHCPClient::fill_buf(int len, uint8_t data)
dgriffin65 15:14382459c8b7 144 {
dgriffin65 15:14382459c8b7 145 while(len-- > 0) {
dgriffin65 15:14382459c8b7 146 add_buf(data);
dgriffin65 15:14382459c8b7 147 }
dgriffin65 15:14382459c8b7 148 }
dgriffin65 15:14382459c8b7 149
dgriffin65 15:14382459c8b7 150 void DHCPClient::add_option(uint8_t code, uint8_t* buf, int len)
dgriffin65 15:14382459c8b7 151 {
dgriffin65 15:14382459c8b7 152 add_buf(code);
dgriffin65 15:14382459c8b7 153 if (len > 0) {
dgriffin65 15:14382459c8b7 154 add_buf((uint8_t)len);
dgriffin65 15:14382459c8b7 155 add_buf(buf, len);
dgriffin65 15:14382459c8b7 156 }
dgriffin65 15:14382459c8b7 157 }
dgriffin65 15:14382459c8b7 158
sgnezdov 16:82e7a0bf58d8 159 int DHCPClient::setup(NetworkStack *ns, uint8_t mac_addr[6], int timeout_ms)
dgriffin65 15:14382459c8b7 160 {
sgnezdov 16:82e7a0bf58d8 161 memcpy(chaddr, mac_addr, 6);
sgnezdov 16:82e7a0bf58d8 162
dgriffin65 15:14382459c8b7 163 int interval_ms = 5*1000; // 5000msec
dgriffin65 15:14382459c8b7 164 if (timeout_ms < interval_ms) {
dgriffin65 15:14382459c8b7 165 interval_ms = timeout_ms;
dgriffin65 15:14382459c8b7 166 }
sgnezdov 16:82e7a0bf58d8 167
dgriffin65 15:14382459c8b7 168 UDPSocket udp_sock;
dgriffin65 15:14382459c8b7 169 m_udp = &udp_sock;
sgnezdov 17:c976088bf39d 170 {
sgnezdov 17:c976088bf39d 171 nsapi_error_t err = udp_sock.open(ns);
sgnezdov 17:c976088bf39d 172 if (err) {
sgnezdov 17:c976088bf39d 173 DBG("setup failed to open UDP socket.");
sgnezdov 17:c976088bf39d 174 return err;
sgnezdov 17:c976088bf39d 175 }
sgnezdov 17:c976088bf39d 176 udp_sock.set_blocking(false);
sgnezdov 17:c976088bf39d 177 err = udp_sock.bind(68); // local port
sgnezdov 17:c976088bf39d 178 if (err) {
sgnezdov 17:c976088bf39d 179 DBG("setup failed in bind: %d", err);
sgnezdov 17:c976088bf39d 180 return err;
sgnezdov 17:c976088bf39d 181 }
sgnezdov 16:82e7a0bf58d8 182 }
sgnezdov 17:c976088bf39d 183
dgriffin65 15:14382459c8b7 184 m_server.set_ip_address("255.255.255.255"); // DHCP broadcast
dgriffin65 15:14382459c8b7 185 m_server.set_port(67); // DHCP broadcast
dgriffin65 15:14382459c8b7 186 exit_flag = false;
sgnezdov 17:c976088bf39d 187 int err = 0;
dgriffin65 15:14382459c8b7 188 int seq = 0;
dgriffin65 15:14382459c8b7 189 int send_size;
dgriffin65 15:14382459c8b7 190 while(!exit_flag) {
dgriffin65 15:14382459c8b7 191 switch(seq) {
dgriffin65 15:14382459c8b7 192 case 0:
dgriffin65 15:14382459c8b7 193 m_retry = 0;
dgriffin65 15:14382459c8b7 194 seq++;
dgriffin65 15:14382459c8b7 195 break;
dgriffin65 15:14382459c8b7 196 case 1:
dgriffin65 15:14382459c8b7 197 send_size = discover();
sgnezdov 17:c976088bf39d 198 nsapi_size_or_error_t err2 = udp_sock.sendto(m_server, (char*)m_buf, send_size);
sgnezdov 17:c976088bf39d 199 if (err2 < 0) {
sgnezdov 17:c976088bf39d 200 DBG("setup sendto error: %d\n", err2);
sgnezdov 17:c976088bf39d 201 return err2;
sgnezdov 16:82e7a0bf58d8 202 }
dgriffin65 15:14382459c8b7 203 m_interval.reset();
dgriffin65 15:14382459c8b7 204 m_interval.start();
dgriffin65 15:14382459c8b7 205 seq++;
dgriffin65 15:14382459c8b7 206 break;
dgriffin65 15:14382459c8b7 207 case 2:
dgriffin65 15:14382459c8b7 208 callback();
dgriffin65 15:14382459c8b7 209 if (m_interval.read_ms() > interval_ms) {
dgriffin65 15:14382459c8b7 210 DBG("m_retry: %d\n", m_retry);
dgriffin65 15:14382459c8b7 211 if (++m_retry >= (timeout_ms/interval_ms)) {
dgriffin65 15:14382459c8b7 212 err = -1;
dgriffin65 15:14382459c8b7 213 exit_flag = true;
dgriffin65 15:14382459c8b7 214 }
dgriffin65 15:14382459c8b7 215 seq--;
dgriffin65 15:14382459c8b7 216 }
dgriffin65 15:14382459c8b7 217 break;
dgriffin65 15:14382459c8b7 218 }
dgriffin65 15:14382459c8b7 219 }
dgriffin65 15:14382459c8b7 220 DBG("m_retry: %d, m_interval: %d\n", m_retry, m_interval.read_ms());
dgriffin65 15:14382459c8b7 221 return err;
dgriffin65 15:14382459c8b7 222 }
dgriffin65 15:14382459c8b7 223
dgriffin65 15:14382459c8b7 224 DHCPClient::DHCPClient() {
dgriffin65 15:14382459c8b7 225 }