WIZNet W5500 with additional enhancements
Fork of WIZnetInterface by
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 zero[] = { 0, 0, 0, 0 }; 00021 const uint8_t header[] = {0x01,0x01,0x06,0x00}; 00022 add_buf((uint8_t*)header, sizeof(header)); 00023 uint32_t x = time(NULL) + rand(); 00024 xid[0] = x>>24; xid[1] = x>>16; xid[2] = x>>8; xid[3] = x; 00025 add_buf(xid, 4); // transaction id 00026 add_buf((uint8_t*)zero, 2); // seconds elapsed 00027 add_buf((uint8_t*)zero, 2); // bootp flags 00028 add_buf((uint8_t*)zero, 4); // requester ip address 00029 add_buf((uint8_t*)zero, 4); // client ip address 00030 add_buf((uint8_t*)zero, 4); // next server ip address 00031 add_buf((uint8_t*)zero, 4); // relay agent ip address 00032 add_buf(chaddr, 6); // MAC address 00033 fill_buf(10, 0x00); // padding 00034 fill_buf(192, 0x00); 00035 const uint8_t options[] = {0x63,0x82,0x53,0x63, // DHCP_MAGIC_COOKIE 00036 OPT_DHCP_MESSAGE, 1, DHCPDISCOVER, // // DHCP message, len, discover 00037 OPT_PARAMETER_REQ, 5, OPT_SUBNET_MASK, OPT_ROUTER, OPT_TIME_SERVER, OPT_DOMAIN_NAME, OPT_DNS }; 00038 add_buf((uint8_t*)options, sizeof(options)); 00039 if (_hostname) { 00040 int hlen = strlen(_hostname); 00041 add_buf(OPT_HOSTNAME); 00042 add_buf(hlen); 00043 add_buf((uint8_t *)_hostname, hlen); 00044 } 00045 add_option(OPT_END); 00046 00047 return m_pos; 00048 } 00049 00050 int DHCPClient::request() 00051 { 00052 m_pos = 0; 00053 const uint8_t zero[] = { 0, 0, 0, 0 }; 00054 const uint8_t header[] = {0x01,0x01,0x06,0x00}; 00055 add_buf((uint8_t*)header, sizeof(header)); 00056 add_buf(xid, 4); // transaction id 00057 add_buf((uint8_t*)zero, 2); // seconds elapsed 00058 add_buf((uint8_t*)zero, 2); // bootp flags 00059 add_buf((uint8_t*)zero, 4); // requester ip address 00060 add_buf((uint8_t*)zero, 4); // client ip address 00061 add_buf(siaddr, 4); // next server ip address 00062 add_buf((uint8_t*)zero, 4); // relay agent ip address (giaddr) 00063 add_buf(chaddr, 6); // MAC address 00064 fill_buf(10, 0x00); // padding 00065 fill_buf(192, 0x00); 00066 const uint8_t options[] = {0x63,0x82,0x53,0x63, // DHCP_MAGIC_COOKIE 00067 OPT_DHCP_MESSAGE,1, DHCPREQUEST, // DHCP message, len, request 00068 OPT_PARAMETER_REQ, 5, OPT_SUBNET_MASK, OPT_ROUTER, OPT_TIME_SERVER, OPT_DOMAIN_NAME, OPT_DNS }; 00069 add_buf((uint8_t*)options, sizeof(options)); 00070 add_option(OPT_IP_ADDR_REQ, yiaddr, 4); 00071 add_option(OPT_SERVER_IDENT, siaddr, 4); 00072 if (_hostname) { 00073 int hlen = strlen(_hostname); 00074 add_buf(OPT_HOSTNAME); 00075 add_buf(hlen); 00076 add_buf((uint8_t *)_hostname, hlen); 00077 } 00078 add_option(OPT_END); 00079 return m_pos; 00080 } 00081 00082 int DHCPClient::offer(uint8_t buf[], int size) { 00083 memcpy(yiaddr, buf+DHCP_OFFSET_YIADDR, 4); 00084 memcpy(siaddr, buf+DHCP_OFFSET_SIADDR, 4); 00085 00086 memset(dnsaddr, 0, sizeof(dnsaddr)); 00087 memset(gateway, 0, sizeof(gateway)); 00088 memset(netmask, 0, sizeof(netmask)); 00089 memset(timesrv, 0, sizeof(timesrv)); 00090 memset(leaseTime, 0, sizeof(leaseTime)); 00091 00092 uint8_t *p; 00093 int msg_type = -1; 00094 p = buf + DHCP_OFFSET_OPTIONS; 00095 while(*p != OPT_END && p < (buf+size)) { 00096 uint8_t code = *p++; 00097 if (code == 0) { // Pad Option 00098 continue; 00099 } 00100 int len = *p++; 00101 00102 DBG("DHCP option: %d\r\n", code); 00103 DBG_HEX(p, len); 00104 00105 switch(code) { 00106 case OPT_DHCP_MESSAGE: 00107 msg_type = *p; 00108 break; 00109 case OPT_SUBNET_MASK: 00110 memcpy(netmask, p, 4); 00111 break; 00112 case OPT_ROUTER: 00113 memcpy(gateway, p, 4); 00114 break; 00115 case OPT_DNS: 00116 memcpy(dnsaddr, p, 4); 00117 break; 00118 case OPT_TIME_SERVER: 00119 memcpy(timesrv, p, 4); 00120 break; 00121 case OPT_ADDR_LEASE_TIME: 00122 memcpy(leaseTime, p, 4); 00123 break; 00124 case OPT_DOMAIN_NAME: 00125 { 00126 int cplen = len; 00127 if (cplen > 63) 00128 cplen = 63; // max domain name 00129 if (domainName) { 00130 free(domainName); 00131 domainName = NULL; 00132 } 00133 if (cplen) { 00134 domainName = (char *)calloc(1, cplen+1); 00135 memcpy(domainName, p, cplen); // zero term is already here via calloc 00136 } 00137 } 00138 break; 00139 case OPT_SERVER_IDENT: 00140 memcpy(siaddr, p, 4); 00141 break; 00142 } 00143 p += len; 00144 } 00145 return msg_type; 00146 } 00147 00148 bool DHCPClient::verify(uint8_t buf[], int len) { 00149 if (len < DHCP_OFFSET_OPTIONS) { 00150 return false; 00151 } 00152 if (buf[DHCP_OFFSET_OP] != 0x02) { 00153 return false; 00154 } 00155 if (memcmp(buf+DHCP_OFFSET_XID, xid, 4) != 0) { 00156 return false; 00157 } 00158 return true; 00159 } 00160 00161 void DHCPClient::callback() 00162 { 00163 Endpoint host; 00164 int recv_len = m_udp->receiveFrom(host, (char*)m_buf, sizeof(m_buf)); 00165 if (recv_len < 0) { 00166 return; 00167 } 00168 if (!verify(m_buf, recv_len)) { 00169 return; 00170 } 00171 int r = offer(m_buf, recv_len); 00172 if (r == DHCPOFFER) { 00173 int send_size = request(); 00174 m_udp->sendTo(m_server, (char*)m_buf, send_size); 00175 } else if (r == DHCPACK) { 00176 exit_flag = true; 00177 } 00178 } 00179 00180 void DHCPClient::add_buf(uint8_t c) 00181 { 00182 m_buf[m_pos++] = c; 00183 } 00184 00185 void DHCPClient::add_buf(uint8_t* buf, int len) 00186 { 00187 for(int i = 0; i < len; i++) { 00188 add_buf(buf[i]); 00189 } 00190 } 00191 00192 void DHCPClient::fill_buf(int len, uint8_t data) 00193 { 00194 while(len-- > 0) { 00195 add_buf(data); 00196 } 00197 } 00198 00199 void DHCPClient::add_option(uint8_t code, uint8_t* buf, int len) 00200 { 00201 add_buf(code); 00202 if (len > 0) { 00203 add_buf((uint8_t)len); 00204 add_buf(buf, len); 00205 } 00206 } 00207 00208 int DHCPClient::setup(const char *hostnane, int timeout_ms) 00209 { 00210 eth = WIZnet_Chip::getInstance(); 00211 if (eth == NULL) { 00212 return -1; 00213 } 00214 _hostname = hostnane; 00215 eth->reg_rd_mac(SHAR, chaddr); 00216 int interval_ms = 5*1000; // 5000msec 00217 if (timeout_ms < interval_ms) { 00218 interval_ms = timeout_ms; 00219 } 00220 m_udp = new UDPSocket; 00221 m_udp->init(); 00222 m_udp->set_blocking(false); 00223 eth->reg_wr<uint32_t>(SIPR, 0x00000000); // local ip "0.0.0.0" 00224 m_udp->bind(DHCP_CLIENT_PORT); // local port 00225 m_server.set_address("255.255.255.255", DHCP_SERVER_PORT); // DHCP broadcast 00226 exit_flag = false; 00227 int err = 0; 00228 int seq = 0; 00229 int send_size; 00230 while(!exit_flag) { 00231 switch(seq) { 00232 case 0: 00233 m_retry = 0; 00234 seq++; 00235 break; 00236 case 1: 00237 send_size = discover(); 00238 m_udp->sendTo(m_server, (char*)m_buf, send_size); 00239 m_interval.reset(); 00240 m_interval.start(); 00241 seq++; 00242 break; 00243 case 2: 00244 callback(); 00245 if (m_interval.read_ms() > interval_ms) { 00246 DBG("m_retry: %d\n", m_retry); 00247 if (++m_retry >= (timeout_ms/interval_ms)) { 00248 err = -1; 00249 exit_flag = true; 00250 } 00251 seq--; 00252 } 00253 break; 00254 } 00255 } 00256 DBG("m_retry: %d, m_interval: %d\n", m_retry, m_interval.read_ms()); 00257 delete m_udp; 00258 return err; 00259 } 00260 00261 DHCPClient::DHCPClient() { 00262 domainName = NULL; 00263 } 00264 00265 DHCPClient::~DHCPClient() { 00266 if (domainName) 00267 free(domainName); 00268 }
Generated on Tue Jul 12 2022 17:13:34 by 1.7.2