W5500 driver for mbed OS 5

Dependents:   http-webserver-example mbed-os-example-sockets

Fork of W5500Interface by Sergei G

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers DHCPClient.cpp Source File

DHCPClient.cpp

00001 /*
00002 * DHCPClient.cpp
00003 * Mbed OS5 support added by Sergei G <https://os.mbed.com/users/sgnezdov/>
00004 * Ported here on Aug/09/2018
00005 *
00006 */
00007 
00008 // DHCPClient.cpp 2013/4/10
00009 #include "mbed.h"
00010 #include "mbed_debug.h"
00011 #include "UDPSocket.h"
00012 #include "DHCPClient.h"
00013 
00014 #define DBG_DHCP 0
00015 
00016 #if DBG_DHCP
00017 #define DBG(...) do{debug("[%s:%d]", __PRETTY_FUNCTION__,__LINE__);debug(__VA_ARGS__);} while(0);
00018 #define DBG_HEX(A,B) do{debug("[%s:%d]\r\n", __PRETTY_FUNCTION__,__LINE__);debug_hex(A,B);} while(0);
00019 #else
00020 #define DBG(...) while(0);
00021 #define DBG_HEX(A,B) while(0);
00022 #endif
00023 
00024 int DHCPClient::discover()
00025 {
00026     m_pos = 0;
00027     const uint8_t header[] = {0x01,0x01,0x06,0x00};
00028     add_buf((uint8_t*)header, sizeof(header));
00029     uint32_t x = time(NULL) + rand();
00030     xid[0] = x>>24; xid[1] = x>>16; xid[2] = x>>8; xid[3] = x;
00031     add_buf(xid, 4);
00032     fill_buf(20, 0x00);
00033     add_buf(chaddr, 6);
00034     fill_buf(10+192, 0x00);
00035     const uint8_t options[] = {0x63,0x82,0x53,0x63, // magic cookie
00036                                53,1,DHCPDISCOVER,   // DHCP option 53: DHCP Discover
00037                                55,4,1,3,15,6,
00038                                255}; 
00039     add_buf((uint8_t*)options, sizeof(options));
00040     return m_pos;
00041 }
00042 
00043 int DHCPClient::request()
00044 {
00045     m_pos = 0;
00046     const uint8_t header[] = {0x01,0x01,0x06,0x00};
00047     add_buf((uint8_t*)header, sizeof(header));
00048     add_buf(xid, 4);
00049     fill_buf(12, 0x00);
00050     add_buf(siaddr, 4);
00051     fill_buf(4, 0x00); // giaddr
00052     add_buf(chaddr, 6);
00053     fill_buf(10+192, 0x00);
00054     const uint8_t options[] = {0x63,0x82,0x53,0x63, // magic cookie
00055                                53,1,DHCPREQUEST,    // DHCP option 53: DHCP Request
00056                                55,4,1,3,15,6,       // DHCP option 55:
00057                                };
00058     add_buf((uint8_t*)options, sizeof(options));
00059     add_option(50, yiaddr, 4);
00060     add_option(54, siaddr, 4);
00061     add_option(255);
00062     return m_pos;
00063 }
00064 
00065 int DHCPClient::offer(uint8_t buf[], int size) {
00066     memcpy(yiaddr, buf+DHCP_OFFSET_YIADDR, 4);   
00067     memcpy(siaddr, buf+DHCP_OFFSET_SIADDR, 4);   
00068     uint8_t *p;
00069     int msg_type = -1;
00070     p = buf + DHCP_OFFSET_OPTIONS;
00071     while(*p != 255 && p < (buf+size)) {
00072         uint8_t code = *p++;
00073         if (code == 0) { // Pad Option
00074             continue;
00075         }
00076         int len = *p++;
00077  
00078         DBG("DHCP option: %d\r\n", code);
00079         DBG_HEX(p, len);
00080 
00081         switch(code) {
00082             case 53:
00083                 msg_type = *p;
00084                 break;
00085             case 1:
00086                 memcpy(netmask, p, 4); // Subnet mask address
00087                 break;
00088             case 3:
00089                 memcpy(gateway, p, 4); // Gateway IP address
00090                 break; 
00091             case 6:  // DNS server
00092                 memcpy(dnsaddr, p, 4);
00093                 break;
00094             case 51: // IP lease time 
00095                 break;
00096             case 54: // DHCP server
00097                 memcpy(siaddr, p, 4);
00098                 break;
00099         }
00100         p += len;
00101     }
00102     return msg_type;
00103 }
00104 
00105 bool DHCPClient::verify(uint8_t buf[], int len) {
00106     if (len < DHCP_OFFSET_OPTIONS) {
00107         return false;
00108     }
00109     if (buf[DHCP_OFFSET_OP] != 0x02) {
00110         return false;
00111     }
00112     if (memcmp(buf+DHCP_OFFSET_XID, xid, 4) != 0) {
00113         return false;
00114     }
00115     return true;
00116 }
00117 
00118 void DHCPClient::callback()
00119 {
00120     DBG("DHCPClient callback\n");
00121     SocketAddress host;
00122     int recv_len = m_udp->recvfrom(&host, (char*)m_buf, sizeof(m_buf));
00123     if (recv_len < 0) {
00124         return;
00125     }
00126     if (!verify(m_buf, recv_len)) {
00127         return;
00128     }
00129     int r = offer(m_buf, recv_len);
00130     if (r == DHCPOFFER) {
00131         int send_size = request();
00132         m_udp->sendto(m_server, (char*)m_buf, send_size);
00133     } else if (r == DHCPACK) {
00134         exit_flag = true;
00135     }
00136 }
00137 
00138 void  DHCPClient::add_buf(uint8_t c)
00139 {
00140     m_buf[m_pos++] = c;
00141 }
00142 
00143 void  DHCPClient::add_buf(uint8_t* buf, int len)
00144 {
00145     for(int i = 0; i < len; i++) {
00146         add_buf(buf[i]);
00147     }
00148 }
00149 
00150 void DHCPClient::fill_buf(int len, uint8_t data)
00151 {
00152     while(len-- > 0) {
00153         add_buf(data);
00154     }
00155 }
00156 
00157 void  DHCPClient::add_option(uint8_t code, uint8_t* buf, int len)
00158 {
00159     add_buf(code);
00160     if (len > 0) {
00161         add_buf((uint8_t)len);
00162         add_buf(buf, len);
00163     }
00164 }
00165 
00166 int DHCPClient::setup(NetworkStack *ns, uint8_t mac_addr[6], int timeout_ms)
00167 {
00168     memcpy(chaddr, mac_addr, 6);
00169     
00170     int interval_ms = 5*1000; // 5000msec
00171     if (timeout_ms < interval_ms) {
00172         interval_ms = timeout_ms;
00173     }
00174     
00175     UDPSocket udp_sock;
00176     m_udp = &udp_sock;
00177     {
00178         nsapi_error_t err = udp_sock.open(ns);
00179         if (err) {
00180             DBG("setup failed to open UDP socket.");
00181             return err;
00182         }
00183         udp_sock.set_blocking(false);
00184         err = udp_sock.bind(68); // local port
00185         if (err) {
00186             DBG("setup failed in bind: %d", err);
00187             return err;
00188         }
00189     }
00190     
00191     m_server.set_ip_address("255.255.255.255"); // DHCP broadcast
00192     m_server.set_port(67);                      // DHCP broadcast
00193     exit_flag = false;
00194     int err = 0;
00195     int seq = 0;
00196     int send_size;
00197     while(!exit_flag) {
00198         switch(seq) {
00199             case 0:
00200                 m_retry = 0;
00201                 seq++;
00202                 break;
00203             case 1:
00204                 send_size = discover();
00205                 nsapi_size_or_error_t err2 = udp_sock.sendto(m_server, (char*)m_buf, send_size);
00206                 if (err2 < 0) {
00207                     DBG("setup sendto error: %d\n", err2);
00208                     return err2;
00209                 }
00210                 m_interval.reset();
00211                 m_interval.start();
00212                 seq++;
00213                 break;
00214             case 2:
00215                 callback();
00216                 if (m_interval.read_ms() > interval_ms) {
00217                     DBG("m_retry: %d\n", m_retry);
00218                     if (++m_retry >= (timeout_ms/interval_ms)) {
00219                         err = -1;
00220                         exit_flag = true;
00221                     }
00222                     seq--;
00223                 }
00224                 break;
00225         }
00226     }
00227     DBG("m_retry: %d, m_interval: %d\n", m_retry, m_interval.read_ms());
00228     return err;
00229 }
00230 
00231 DHCPClient::DHCPClient() {
00232 }