W5200(WIZ820io) network interface

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers DHCPClient.cpp Source File

DHCPClient.cpp

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