Revised to prevent DHCPClient::discover from hanging.

Fork of WIZ820ioInterface by ban4jp -

Committer:
rraab
Date:
Fri Aug 15 19:53:25 2014 +0000
Revision:
9:c1722862c13b
Parent:
5:fb15c35d1e28
Fixed DHCPClient::discover calling rand, which hangs in an infinite loop.

Who changed what in which revision?

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