This is the Interface library for WIZnet W5500 chip which forked of EthernetInterfaceW5500, WIZnetInterface and WIZ550ioInterface. This library has simple name as "W5500Interface". and can be used for Wiz550io users also.

Dependents:   EvrythngApi Websocket_Ethernet_HelloWorld_W5500 Websocket_Ethernet_W5500 CurrentWeatherData_W5500 ... 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 }