DHCP Client

Committer:
dgriffin65
Date:
Thu Jun 15 20:17:57 2017 +0000
Revision:
0:9697009514d0
Updated to mbed-os

Who changed what in which revision?

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