Norimasa Okamoto / WIZ820ioNetIf
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers DHCPClient.cpp Source File

DHCPClient.cpp

00001 // DHCPClient.cpp 2012/4/21
00002 // DHCP Client for WIZ820io(W5200)
00003 #include "mbed.h"
00004 #include "w5200.h"
00005 //#include "UDPSocket.h"
00006 #include "DHCPClient.h"
00007 //#define __DEBUG
00008 #include "dbg/dbg.h"
00009 
00010 #ifdef __DEBUG
00011 #define DBG2(...) do{ DebugStream::debug("%p %d %s ", this,__LINE__,__PRETTY_FUNCTION__); DebugStream::debug(__VA_ARGS__); } while(0);
00012 #else
00013 #define DBG2(...) while(0);
00014 #endif //__DEBUG
00015 
00016 //#define DEBUG
00017 
00018 #ifdef DEBUG
00019 #include "Utils.h"
00020 #define PRINT_FUNC() printf("%p %d:%s\n", this,__LINE__,__PRETTY_FUNCTION__)
00021 #else //DEBUG
00022 #define PRINT_FUNC()
00023 #endif //DEBUG
00024 
00025 int DHCPClient::discover(uint8_t buf[], int size) {
00026     memset(buf, 0x00, size);
00027     const uint8_t headers[] = {0x01,0x01,0x06,0x00,
00028                                0x12,0x34,0x56,0x78}; // xid
00029     memcpy(buf, headers, sizeof(headers));
00030     int t = clock();
00031     xid[0] = t<<24;
00032     xid[1] = t<<16;
00033     xid[2] = t<<8;
00034     xid[3] = t;
00035     memcpy(buf+DHCP_OFFSET_XID, xid, 4);
00036     W5200.getMACAddress(buf+DHCP_OFFSET_CHADDR);
00037     const uint8_t options[] = {0x63,0x82,0x53,0x63, // magic cookie
00038                                0x35,0x01,0x01, // DHCP DISCOVER
00039                                0xff};
00040     memcpy(buf+DHCP_OFFSET_MAGIC_COOKIE, options, sizeof(options));
00041     uint8_t ip[4] = {0,0,0,0};
00042     W5200.setIPAddress(ip);
00043     return DHCP_OFFSET_MAGIC_COOKIE + sizeof(options);
00044 }
00045 
00046 int DHCPClient::request(uint8_t buf[], int size) {
00047     memset(buf, 0x00, size);
00048     const uint8_t headers[] = {0x01,0x01,0x06,0x00,
00049                                0x12,0x34,0x56,0x78}; // xid
00050     memcpy(buf, headers, sizeof(headers));
00051     memcpy(buf+DHCP_OFFSET_XID, xid, 4);
00052     memcpy(buf+DHCP_OFFSET_YIADDR, yiaddr, 4);
00053     W5200.getMACAddress(buf+DHCP_OFFSET_CHADDR);
00054     const uint8_t options[] = {0x63,0x82,0x53,0x63, // magic cookie
00055                                0x35,0x01,0x03, // DHCP REQUEST
00056                                0x32,0x04,0x00,0x00,0x00,0x00, // request IP
00057                                0xff};
00058     memcpy(buf+DHCP_OFFSET_MAGIC_COOKIE, options, sizeof(options));
00059     memcpy(buf+DHCP_OFFSET_MAGIC_COOKIE+9, yiaddr, 4);
00060     return DHCP_OFFSET_MAGIC_COOKIE + sizeof(options);
00061 }
00062 
00063 int DHCPClient::offer_ack(uint8_t buf[], int size) {
00064     memcpy(yiaddr, &buf[DHCP_OFFSET_YIADDR], 4);   
00065     uint8_t *p;
00066     int msg_type = -1;
00067     p = buf + DHCP_OFFSET_OPTIONS;
00068     while(*p != 0xff && p < (uint8_t*)&buf[DHCP_MAX_PACKET_SIZE]) {
00069         int code = *p++;
00070         if (code == 0x00) {
00071             continue;
00072         }
00073         int len = *p++;
00074 #ifdef DEBUG           
00075         char codeStr[24];
00076         snprintf(codeStr, sizeof(codeStr), "DHCP option: %d", code);
00077         printfBytes(codeStr, p, len);
00078 #endif //DEBUG
00079         if (code == 53) {
00080            msg_type = *p;
00081         } else if (code == 1) {
00082             memcpy(netmask, p, 4); // Subnet mask address
00083         } else if (code == 3) {
00084             memcpy(gateway, p, 4); // Gateway IP address 
00085         } else if (code == 6) {// DNS
00086             memcpy(dnsaddr, p, 4);
00087         }
00088         p += len;
00089     }
00090     return msg_type;
00091 }
00092 
00093 bool DHCPClient::verify(uint8_t buf[], int len) {
00094     if (len < DHCP_OFFSET_OPTIONS) {
00095         return false;
00096     }
00097     if (buf[DHCP_OFFSET_OP] != 0x02) {
00098         return false;
00099     }
00100     if (memcmp(buf+DHCP_OFFSET_XID, xid, 4) != 0) {
00101         return false;
00102     }
00103     return true;
00104 }
00105 
00106 void DHCPClient::callback(UDPSocketEvent e)
00107 {
00108     PRINT_FUNC();
00109     uint8_t buf[DHCP_MAX_PACKET_SIZE];
00110     Host host;
00111     int len = m_udp->recvfrom((char*)buf, sizeof(buf), &host);
00112     if (!verify(buf, len)) {
00113         return;
00114     }
00115     int r = offer_ack(buf, len);
00116     if (r == 2) { // OFFER
00117         request(buf, 300);
00118         Host server(IpAddr(255,255,255,255), 67); // DHCP broadcast
00119         m_udp->sendto((char*)buf, 300, &server);
00120     } else if (r == 5) { // ACK
00121         exit_flag = true;
00122     }
00123 }
00124 
00125 int DHCPClient::setup(int timeout_ms)
00126 {
00127     PRINT_FUNC();   
00128     int interval_ms = 2000; // 2000msec
00129     if (timeout_ms < interval_ms) {
00130         interval_ms = timeout_ms;
00131     }
00132     m_retry = 0;
00133     m_interval.start();
00134     m_udp = new UDPSocket;
00135     m_udp->setOnEvent(this, &DHCPClient::callback);
00136     Host local(IpAddr(0,0,0,0), 68);
00137     Host server(IpAddr(255,255,255,255), 67); // DHCP broadcast
00138     m_udp->bind(local);
00139     uint8_t buf[300];
00140     discover(buf, sizeof(buf));
00141     m_udp->sendto((char*)buf, sizeof(buf), &server);
00142     m_interval.reset();
00143     exit_flag = false;
00144     int err = 0;
00145     while(1) {
00146         Net::poll();
00147         if (exit_flag) {
00148             DBG2("m_retry: %d, m_interval: %d\n", m_retry, m_interval.read_ms());
00149             break;
00150         }
00151         if (m_interval.read_ms() > interval_ms) {
00152             DBG2("m_retry: %d\n", m_retry);
00153             if (++m_retry >= (timeout_ms/interval_ms)) {
00154                 err = -1;
00155                 break;
00156             }
00157             m_udp->sendto((char*)buf, sizeof(buf), &server);
00158             m_interval.reset();
00159         }
00160 #ifdef DEBUG            
00161         wait_ms(500);
00162 #endif //DEBUG
00163     }
00164     delete m_udp;
00165     return err;
00166 }
00167 
00168 DHCPClient::DHCPClient() {
00169     m_udp = NULL;
00170 }