WIZnetInterface using namespace

Dependents:   DualNetworkInterface-Basic

Fork of WIZnetInterface by WIZnet

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