Sergei G / NetworkServices

Dependents:   coap-example Borsch coap-example

Fork of NetworkServices by AMETEK Powervar

Committer:
sgnezdov
Date:
Sat Jul 01 07:20:29 2017 +0000
Revision:
16:82e7a0bf58d8
Parent:
15:14382459c8b7
Child:
17:c976088bf39d
fixes to DHCP communication; ; * send IP address properly (was not sent); * additional error handling; * lots of debug statements, because it is a work in progress

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 16:82e7a0bf58d8 7 #define DBG_DHCP 1
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 16:82e7a0bf58d8 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) {
sgnezdov 16:82e7a0bf58d8 117 //DBG("recv_len < 0\n");
dgriffin65 15:14382459c8b7 118 return;
dgriffin65 15:14382459c8b7 119 }
dgriffin65 15:14382459c8b7 120 if (!verify(m_buf, recv_len)) {
sgnezdov 16:82e7a0bf58d8 121 DBG("!verify(m_buf, recv_len)\n");
dgriffin65 15:14382459c8b7 122 return;
dgriffin65 15:14382459c8b7 123 }
dgriffin65 15:14382459c8b7 124 int r = offer(m_buf, recv_len);
dgriffin65 15:14382459c8b7 125 if (r == DHCPOFFER) {
sgnezdov 16:82e7a0bf58d8 126 DBG("r == DHCPOFFER\n");
dgriffin65 15:14382459c8b7 127 int send_size = request();
dgriffin65 15:14382459c8b7 128 m_udp->sendto(m_server, (char*)m_buf, send_size);
dgriffin65 15:14382459c8b7 129 } else if (r == DHCPACK) {
sgnezdov 16:82e7a0bf58d8 130 DBG("r == DHCPACK\n");
dgriffin65 15:14382459c8b7 131 exit_flag = true;
dgriffin65 15:14382459c8b7 132 }
dgriffin65 15:14382459c8b7 133 }
dgriffin65 15:14382459c8b7 134
dgriffin65 15:14382459c8b7 135 void DHCPClient::add_buf(uint8_t c)
dgriffin65 15:14382459c8b7 136 {
dgriffin65 15:14382459c8b7 137 m_buf[m_pos++] = c;
dgriffin65 15:14382459c8b7 138 }
dgriffin65 15:14382459c8b7 139
dgriffin65 15:14382459c8b7 140 void DHCPClient::add_buf(uint8_t* buf, int len)
dgriffin65 15:14382459c8b7 141 {
dgriffin65 15:14382459c8b7 142 for(int i = 0; i < len; i++) {
dgriffin65 15:14382459c8b7 143 add_buf(buf[i]);
dgriffin65 15:14382459c8b7 144 }
dgriffin65 15:14382459c8b7 145 }
dgriffin65 15:14382459c8b7 146
dgriffin65 15:14382459c8b7 147 void DHCPClient::fill_buf(int len, uint8_t data)
dgriffin65 15:14382459c8b7 148 {
dgriffin65 15:14382459c8b7 149 while(len-- > 0) {
dgriffin65 15:14382459c8b7 150 add_buf(data);
dgriffin65 15:14382459c8b7 151 }
dgriffin65 15:14382459c8b7 152 }
dgriffin65 15:14382459c8b7 153
dgriffin65 15:14382459c8b7 154 void DHCPClient::add_option(uint8_t code, uint8_t* buf, int len)
dgriffin65 15:14382459c8b7 155 {
dgriffin65 15:14382459c8b7 156 add_buf(code);
dgriffin65 15:14382459c8b7 157 if (len > 0) {
dgriffin65 15:14382459c8b7 158 add_buf((uint8_t)len);
dgriffin65 15:14382459c8b7 159 add_buf(buf, len);
dgriffin65 15:14382459c8b7 160 }
dgriffin65 15:14382459c8b7 161 }
dgriffin65 15:14382459c8b7 162
sgnezdov 16:82e7a0bf58d8 163 int DHCPClient::setup(NetworkStack *ns, uint8_t mac_addr[6], int timeout_ms)
dgriffin65 15:14382459c8b7 164 {
sgnezdov 16:82e7a0bf58d8 165 memcpy(chaddr, mac_addr, 6);
sgnezdov 16:82e7a0bf58d8 166
dgriffin65 15:14382459c8b7 167 int interval_ms = 5*1000; // 5000msec
dgriffin65 15:14382459c8b7 168 if (timeout_ms < interval_ms) {
dgriffin65 15:14382459c8b7 169 interval_ms = timeout_ms;
dgriffin65 15:14382459c8b7 170 }
sgnezdov 16:82e7a0bf58d8 171
dgriffin65 15:14382459c8b7 172 UDPSocket udp_sock;
dgriffin65 15:14382459c8b7 173 m_udp = &udp_sock;
dgriffin65 15:14382459c8b7 174
sgnezdov 16:82e7a0bf58d8 175 nsapi_error_t err;
sgnezdov 16:82e7a0bf58d8 176 err = udp_sock.open(ns);
sgnezdov 16:82e7a0bf58d8 177 if (err) {
sgnezdov 16:82e7a0bf58d8 178 DBG("setup failed to open UDP socket.");
sgnezdov 16:82e7a0bf58d8 179 return err;
sgnezdov 16:82e7a0bf58d8 180 }
dgriffin65 15:14382459c8b7 181 udp_sock.set_blocking(false);
sgnezdov 16:82e7a0bf58d8 182 err = udp_sock.bind(68); // local port
sgnezdov 16:82e7a0bf58d8 183 if (err) {
sgnezdov 16:82e7a0bf58d8 184 DBG("setup failed in bind: %d", err);
sgnezdov 16:82e7a0bf58d8 185 return err;
sgnezdov 16:82e7a0bf58d8 186 }
dgriffin65 15:14382459c8b7 187 m_server.set_ip_address("255.255.255.255"); // DHCP broadcast
dgriffin65 15:14382459c8b7 188 m_server.set_port(67); // DHCP broadcast
dgriffin65 15:14382459c8b7 189 exit_flag = false;
sgnezdov 16:82e7a0bf58d8 190 err = 0;
dgriffin65 15:14382459c8b7 191 int seq = 0;
dgriffin65 15:14382459c8b7 192 int send_size;
dgriffin65 15:14382459c8b7 193 while(!exit_flag) {
dgriffin65 15:14382459c8b7 194 switch(seq) {
dgriffin65 15:14382459c8b7 195 case 0:
sgnezdov 16:82e7a0bf58d8 196 DBG("case 0\n");
dgriffin65 15:14382459c8b7 197 m_retry = 0;
dgriffin65 15:14382459c8b7 198 seq++;
dgriffin65 15:14382459c8b7 199 break;
dgriffin65 15:14382459c8b7 200 case 1:
sgnezdov 16:82e7a0bf58d8 201 DBG("case 1\n");
dgriffin65 15:14382459c8b7 202 send_size = discover();
sgnezdov 16:82e7a0bf58d8 203 DBG("udp sock sendto begins\n");
sgnezdov 16:82e7a0bf58d8 204 nsapi_size_or_error_t err;
sgnezdov 16:82e7a0bf58d8 205 err = udp_sock.sendto(m_server, (char*)m_buf, send_size);
sgnezdov 16:82e7a0bf58d8 206 DBG("udp sock sendto ends\n");
sgnezdov 16:82e7a0bf58d8 207 if (err < 0) {
sgnezdov 16:82e7a0bf58d8 208 DBG("udp sendto error: %d\n", err);
sgnezdov 16:82e7a0bf58d8 209 return err;
sgnezdov 16:82e7a0bf58d8 210 }
dgriffin65 15:14382459c8b7 211 m_interval.reset();
dgriffin65 15:14382459c8b7 212 m_interval.start();
dgriffin65 15:14382459c8b7 213 seq++;
dgriffin65 15:14382459c8b7 214 break;
dgriffin65 15:14382459c8b7 215 case 2:
dgriffin65 15:14382459c8b7 216 callback();
dgriffin65 15:14382459c8b7 217 if (m_interval.read_ms() > interval_ms) {
dgriffin65 15:14382459c8b7 218 DBG("m_retry: %d\n", m_retry);
dgriffin65 15:14382459c8b7 219 if (++m_retry >= (timeout_ms/interval_ms)) {
dgriffin65 15:14382459c8b7 220 err = -1;
dgriffin65 15:14382459c8b7 221 exit_flag = true;
dgriffin65 15:14382459c8b7 222 }
dgriffin65 15:14382459c8b7 223 seq--;
dgriffin65 15:14382459c8b7 224 }
dgriffin65 15:14382459c8b7 225 break;
dgriffin65 15:14382459c8b7 226 }
dgriffin65 15:14382459c8b7 227 }
dgriffin65 15:14382459c8b7 228 DBG("m_retry: %d, m_interval: %d\n", m_retry, m_interval.read_ms());
dgriffin65 15:14382459c8b7 229 return err;
dgriffin65 15:14382459c8b7 230 }
dgriffin65 15:14382459c8b7 231
dgriffin65 15:14382459c8b7 232 DHCPClient::DHCPClient() {
dgriffin65 15:14382459c8b7 233 }