Sergei G / NetworkServices

Dependents:   coap-example Borsch coap-example

Fork of NetworkServices by AMETEK Powervar

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers DHCPClient.cpp Source File

DHCPClient.cpp

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