WIZNet W5500 with additional enhancements
Fork of WIZnetInterface by
Socket/DHCPClient.cpp
- Committer:
- Helmut Tschemernjak
- Date:
- 2017-10-12
- Revision:
- 38:67e763cdde02
- Parent:
- 36:0ba2e8d5274a
File content as of revision 38:67e763cdde02:
// DHCPClient.cpp 2013/4/10 #include "mbed.h" #include "mbed_debug.h" #include "UDPSocket.h" #include "DHCPClient.h" #define DBG_DHCP 0 #if DBG_DHCP #define DBG(...) do{debug("[%s:%d]", __PRETTY_FUNCTION__,__LINE__);debug(__VA_ARGS__);} while(0); #define DBG_HEX(A,B) do{debug("[%s:%d]\r\n", __PRETTY_FUNCTION__,__LINE__);debug_hex(A,B);} while(0); #else #define DBG(...) while(0); #define DBG_HEX(A,B) while(0); #endif int DHCPClient::discover() { m_pos = 0; const uint8_t zero[] = { 0, 0, 0, 0 }; const uint8_t header[] = {0x01,0x01,0x06,0x00}; add_buf((uint8_t*)header, sizeof(header)); uint32_t x = time(NULL) + rand(); xid[0] = x>>24; xid[1] = x>>16; xid[2] = x>>8; xid[3] = x; add_buf(xid, 4); // transaction id add_buf((uint8_t*)zero, 2); // seconds elapsed add_buf((uint8_t*)zero, 2); // bootp flags add_buf((uint8_t*)zero, 4); // requester ip address add_buf((uint8_t*)zero, 4); // client ip address add_buf((uint8_t*)zero, 4); // next server ip address add_buf((uint8_t*)zero, 4); // relay agent ip address add_buf(chaddr, 6); // MAC address fill_buf(10, 0x00); // padding fill_buf(192, 0x00); const uint8_t options[] = {0x63,0x82,0x53,0x63, // DHCP_MAGIC_COOKIE OPT_DHCP_MESSAGE, 1, DHCPDISCOVER, // // DHCP message, len, discover OPT_PARAMETER_REQ, 5, OPT_SUBNET_MASK, OPT_ROUTER, OPT_TIME_SERVER, OPT_DOMAIN_NAME, OPT_DNS }; add_buf((uint8_t*)options, sizeof(options)); if (_hostname) { int hlen = strlen(_hostname); add_buf(OPT_HOSTNAME); add_buf(hlen); add_buf((uint8_t *)_hostname, hlen); } add_option(OPT_END); return m_pos; } int DHCPClient::request() { m_pos = 0; const uint8_t zero[] = { 0, 0, 0, 0 }; const uint8_t header[] = {0x01,0x01,0x06,0x00}; add_buf((uint8_t*)header, sizeof(header)); add_buf(xid, 4); // transaction id add_buf((uint8_t*)zero, 2); // seconds elapsed add_buf((uint8_t*)zero, 2); // bootp flags add_buf((uint8_t*)zero, 4); // requester ip address add_buf((uint8_t*)zero, 4); // client ip address add_buf(siaddr, 4); // next server ip address add_buf((uint8_t*)zero, 4); // relay agent ip address (giaddr) add_buf(chaddr, 6); // MAC address fill_buf(10, 0x00); // padding fill_buf(192, 0x00); const uint8_t options[] = {0x63,0x82,0x53,0x63, // DHCP_MAGIC_COOKIE OPT_DHCP_MESSAGE,1, DHCPREQUEST, // DHCP message, len, request OPT_PARAMETER_REQ, 5, OPT_SUBNET_MASK, OPT_ROUTER, OPT_TIME_SERVER, OPT_DOMAIN_NAME, OPT_DNS }; add_buf((uint8_t*)options, sizeof(options)); add_option(OPT_IP_ADDR_REQ, yiaddr, 4); add_option(OPT_SERVER_IDENT, siaddr, 4); if (_hostname) { int hlen = strlen(_hostname); add_buf(OPT_HOSTNAME); add_buf(hlen); add_buf((uint8_t *)_hostname, hlen); } add_option(OPT_END); return m_pos; } int DHCPClient::offer(uint8_t buf[], int size) { memcpy(yiaddr, buf+DHCP_OFFSET_YIADDR, 4); memcpy(siaddr, buf+DHCP_OFFSET_SIADDR, 4); memset(dnsaddr, 0, sizeof(dnsaddr)); memset(gateway, 0, sizeof(gateway)); memset(netmask, 0, sizeof(netmask)); memset(timesrv, 0, sizeof(timesrv)); memset(leaseTime, 0, sizeof(leaseTime)); uint8_t *p; int msg_type = -1; p = buf + DHCP_OFFSET_OPTIONS; while(*p != OPT_END && p < (buf+size)) { uint8_t code = *p++; if (code == 0) { // Pad Option continue; } int len = *p++; DBG("DHCP option: %d\r\n", code); DBG_HEX(p, len); switch(code) { case OPT_DHCP_MESSAGE: msg_type = *p; break; case OPT_SUBNET_MASK: memcpy(netmask, p, 4); break; case OPT_ROUTER: memcpy(gateway, p, 4); break; case OPT_DNS: memcpy(dnsaddr, p, 4); break; case OPT_TIME_SERVER: memcpy(timesrv, p, 4); break; case OPT_ADDR_LEASE_TIME: memcpy(leaseTime, p, 4); break; case OPT_DOMAIN_NAME: { int cplen = len; if (cplen > 63) cplen = 63; // max domain name if (domainName) { free(domainName); domainName = NULL; } if (cplen) { domainName = (char *)calloc(1, cplen+1); memcpy(domainName, p, cplen); // zero term is already here via calloc } } break; case OPT_SERVER_IDENT: memcpy(siaddr, p, 4); break; } p += len; } return msg_type; } bool DHCPClient::verify(uint8_t buf[], int len) { if (len < DHCP_OFFSET_OPTIONS) { return false; } if (buf[DHCP_OFFSET_OP] != 0x02) { return false; } if (memcmp(buf+DHCP_OFFSET_XID, xid, 4) != 0) { return false; } return true; } void DHCPClient::callback() { Endpoint host; int recv_len = m_udp->receiveFrom(host, (char*)m_buf, sizeof(m_buf)); if (recv_len < 0) { return; } if (!verify(m_buf, recv_len)) { return; } int r = offer(m_buf, recv_len); if (r == DHCPOFFER) { int send_size = request(); m_udp->sendTo(m_server, (char*)m_buf, send_size); } else if (r == DHCPACK) { exit_flag = true; } } void DHCPClient::add_buf(uint8_t c) { m_buf[m_pos++] = c; } void DHCPClient::add_buf(uint8_t* buf, int len) { for(int i = 0; i < len; i++) { add_buf(buf[i]); } } void DHCPClient::fill_buf(int len, uint8_t data) { while(len-- > 0) { add_buf(data); } } void DHCPClient::add_option(uint8_t code, uint8_t* buf, int len) { add_buf(code); if (len > 0) { add_buf((uint8_t)len); add_buf(buf, len); } } int DHCPClient::setup(const char *hostnane, int timeout_ms) { eth = WIZnet_Chip::getInstance(); if (eth == NULL) { return -1; } _hostname = hostnane; eth->reg_rd_mac(SHAR, chaddr); int interval_ms = 5*1000; // 5000msec if (timeout_ms < interval_ms) { interval_ms = timeout_ms; } m_udp = new UDPSocket; m_udp->init(); m_udp->set_blocking(false); eth->reg_wr<uint32_t>(SIPR, 0x00000000); // local ip "0.0.0.0" m_udp->bind(DHCP_CLIENT_PORT); // local port m_server.set_address("255.255.255.255", DHCP_SERVER_PORT); // DHCP broadcast exit_flag = false; int err = 0; int seq = 0; int send_size; while(!exit_flag) { switch(seq) { case 0: m_retry = 0; seq++; break; case 1: send_size = discover(); m_udp->sendTo(m_server, (char*)m_buf, send_size); m_interval.reset(); m_interval.start(); seq++; break; case 2: callback(); if (m_interval.read_ms() > interval_ms) { DBG("m_retry: %d\n", m_retry); if (++m_retry >= (timeout_ms/interval_ms)) { err = -1; exit_flag = true; } seq--; } break; } } DBG("m_retry: %d, m_interval: %d\n", m_retry, m_interval.read_ms()); delete m_udp; return err; } DHCPClient::DHCPClient() { domainName = NULL; } DHCPClient::~DHCPClient() { if (domainName) free(domainName); }