Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of WIZnetInterface by
Socket/DHCPClient.cpp
- Committer:
- Helmut Tschemernjak
- Date:
- 2017-10-10
- Revision:
- 35:fe3028eda085
- Parent:
- 15:24a9f2df2145
- Child:
- 36:0ba2e8d5274a
File content as of revision 35:fe3028eda085:
// 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 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);
fill_buf(20, 0x00);
add_buf(chaddr, 6);
fill_buf(10+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,
OPT_END};
add_buf((uint8_t*)options, sizeof(options));
return m_pos;
}
int DHCPClient::request()
{
m_pos = 0;
const uint8_t header[] = {0x01,0x01,0x06,0x00};
add_buf((uint8_t*)header, sizeof(header));
add_buf(xid, 4);
fill_buf(12, 0x00);
add_buf(siaddr, 4);
fill_buf(4, 0x00); // giaddr
add_buf(chaddr, 6);
fill_buf(10+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);
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(int timeout_ms)
{
eth = WIZnet_Chip::getInstance();
if (eth == NULL) {
return -1;
}
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);
}
