This is WIZnet Ethernet Interface using Hardware TCP/IP chip, W5500, W5200 and W5100. One of them can be selected by enabling it in wiznet.h.

Dependents:   Embedded_web EmailButton EmailButton HTTPClient_Weather ... more

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     Endpoint host;
00114     int recv_len = m_udp->receiveFrom(host, (char*)m_buf, sizeof(m_buf));
00115     if (recv_len < 0) {
00116         return;
00117     }
00118     if (!verify(m_buf, recv_len)) {
00119         return;
00120     }
00121     int r = offer(m_buf, recv_len);
00122     if (r == DHCPOFFER) {
00123         int send_size = request();
00124         m_udp->sendTo(m_server, (char*)m_buf, send_size);
00125     } else if (r == DHCPACK) {
00126         exit_flag = true;
00127     }
00128 }
00129 
00130 void  DHCPClient::add_buf(uint8_t c)
00131 {
00132     m_buf[m_pos++] = c;
00133 }
00134 
00135 void  DHCPClient::add_buf(uint8_t* buf, int len)
00136 {
00137     for(int i = 0; i < len; i++) {
00138         add_buf(buf[i]);
00139     }
00140 }
00141 
00142 void DHCPClient::fill_buf(int len, uint8_t data)
00143 {
00144     while(len-- > 0) {
00145         add_buf(data);
00146     }
00147 }
00148 
00149 void  DHCPClient::add_option(uint8_t code, uint8_t* buf, int len)
00150 {
00151     add_buf(code);
00152     if (len > 0) {
00153         add_buf((uint8_t)len);
00154         add_buf(buf, len);
00155     }
00156 }
00157 
00158 int DHCPClient::setup(int timeout_ms)
00159 {
00160     eth = WIZnet_Chip::getInstance();
00161     if (eth == NULL) {
00162         return -1;
00163     }    
00164     eth->reg_rd_mac(SHAR, chaddr);
00165     int interval_ms = 5*1000; // 5000msec
00166     if (timeout_ms < interval_ms) {
00167         interval_ms = timeout_ms;
00168     }
00169     m_udp = new UDPSocket;
00170     m_udp->init();
00171     m_udp->set_blocking(false);
00172     eth->reg_wr<uint32_t>(SIPR, 0x00000000); // local ip "0.0.0.0"
00173     m_udp->bind(68); // local port
00174     m_server.set_address("255.255.255.255", 67); // DHCP broadcast
00175     exit_flag = false;
00176     int err = 0;
00177     int seq = 0;
00178     int send_size;
00179     while(!exit_flag) {
00180         switch(seq) {
00181             case 0:
00182                 m_retry = 0;
00183                 seq++;
00184                 break;
00185             case 1:
00186                 send_size = discover();
00187                 m_udp->sendTo(m_server, (char*)m_buf, send_size);
00188                 m_interval.reset();
00189                 m_interval.start();
00190                 seq++;
00191                 break;
00192             case 2:
00193                 callback();
00194                 if (m_interval.read_ms() > interval_ms) {
00195                     DBG("m_retry: %d\n", m_retry);
00196                     if (++m_retry >= (timeout_ms/interval_ms)) {
00197                         err = -1;
00198                         exit_flag = true;
00199                     }
00200                     seq--;
00201                 }
00202                 break;
00203         }
00204     }
00205     DBG("m_retry: %d, m_interval: %d\n", m_retry, m_interval.read_ms());
00206     delete m_udp;
00207     return err;
00208 }
00209 
00210 DHCPClient::DHCPClient() {
00211 }
00212