Helmut Tschemernjak / WIZnetInterface

Fork of WIZnetInterface by WIZnet

Committer:
Helmut Tschemernjak
Date:
Tue Oct 10 20:56:13 2017 +0200
Revision:
35:fe3028eda085
Parent:
15:24a9f2df2145
Child:
36:0ba2e8d5274a
Added support for DHCP lease time and domain name
Enhance DHCP code to use opcode defines to make it easier to
understand and maintain.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Soohwan Kim 0:6f28332c466f 1 // DHCPClient.cpp 2013/4/10
Soohwan Kim 0:6f28332c466f 2 #include "mbed.h"
Soohwan Kim 0:6f28332c466f 3 #include "mbed_debug.h"
Soohwan Kim 0:6f28332c466f 4 #include "UDPSocket.h"
Soohwan Kim 0:6f28332c466f 5 #include "DHCPClient.h"
Soohwan Kim 0:6f28332c466f 6
Soohwan Kim 0:6f28332c466f 7 #define DBG_DHCP 0
Soohwan Kim 0:6f28332c466f 8
Soohwan Kim 0:6f28332c466f 9 #if DBG_DHCP
Soohwan Kim 0:6f28332c466f 10 #define DBG(...) do{debug("[%s:%d]", __PRETTY_FUNCTION__,__LINE__);debug(__VA_ARGS__);} while(0);
Soohwan Kim 0:6f28332c466f 11 #define DBG_HEX(A,B) do{debug("[%s:%d]\r\n", __PRETTY_FUNCTION__,__LINE__);debug_hex(A,B);} while(0);
Soohwan Kim 0:6f28332c466f 12 #else
Soohwan Kim 0:6f28332c466f 13 #define DBG(...) while(0);
Soohwan Kim 0:6f28332c466f 14 #define DBG_HEX(A,B) while(0);
Soohwan Kim 0:6f28332c466f 15 #endif
Soohwan Kim 0:6f28332c466f 16
Soohwan Kim 0:6f28332c466f 17 int DHCPClient::discover()
Soohwan Kim 0:6f28332c466f 18 {
Soohwan Kim 0:6f28332c466f 19 m_pos = 0;
Soohwan Kim 0:6f28332c466f 20 const uint8_t header[] = {0x01,0x01,0x06,0x00};
Soohwan Kim 0:6f28332c466f 21 add_buf((uint8_t*)header, sizeof(header));
Soohwan Kim 0:6f28332c466f 22 uint32_t x = time(NULL) + rand();
Soohwan Kim 0:6f28332c466f 23 xid[0] = x>>24; xid[1] = x>>16; xid[2] = x>>8; xid[3] = x;
Soohwan Kim 0:6f28332c466f 24 add_buf(xid, 4);
Soohwan Kim 0:6f28332c466f 25 fill_buf(20, 0x00);
Soohwan Kim 0:6f28332c466f 26 add_buf(chaddr, 6);
Soohwan Kim 0:6f28332c466f 27 fill_buf(10+192, 0x00);
Helmut Tschemernjak 35:fe3028eda085 28 const uint8_t options[] = {0x63,0x82,0x53,0x63, // DHCP_MAGIC_COOKIE
Helmut Tschemernjak 35:fe3028eda085 29 OPT_DHCP_MESSAGE, 1, DHCPDISCOVER, // // DHCP message, len, discover
Helmut Tschemernjak 35:fe3028eda085 30 OPT_PARAMETER_REQ, 5, OPT_SUBNET_MASK, OPT_ROUTER, OPT_TIME_SERVER, OPT_DOMAIN_NAME, OPT_DNS,
Helmut Tschemernjak 35:fe3028eda085 31 OPT_END};
Soohwan Kim 0:6f28332c466f 32 add_buf((uint8_t*)options, sizeof(options));
Soohwan Kim 0:6f28332c466f 33 return m_pos;
Soohwan Kim 0:6f28332c466f 34 }
Soohwan Kim 0:6f28332c466f 35
Soohwan Kim 0:6f28332c466f 36 int DHCPClient::request()
Soohwan Kim 0:6f28332c466f 37 {
Soohwan Kim 0:6f28332c466f 38 m_pos = 0;
Soohwan Kim 0:6f28332c466f 39 const uint8_t header[] = {0x01,0x01,0x06,0x00};
Soohwan Kim 0:6f28332c466f 40 add_buf((uint8_t*)header, sizeof(header));
Soohwan Kim 0:6f28332c466f 41 add_buf(xid, 4);
Soohwan Kim 0:6f28332c466f 42 fill_buf(12, 0x00);
Soohwan Kim 0:6f28332c466f 43 add_buf(siaddr, 4);
Soohwan Kim 0:6f28332c466f 44 fill_buf(4, 0x00); // giaddr
Soohwan Kim 0:6f28332c466f 45 add_buf(chaddr, 6);
Soohwan Kim 0:6f28332c466f 46 fill_buf(10+192, 0x00);
Helmut Tschemernjak 35:fe3028eda085 47 const uint8_t options[] = {0x63,0x82,0x53,0x63, // DHCP_MAGIC_COOKIE
Helmut Tschemernjak 35:fe3028eda085 48 OPT_DHCP_MESSAGE,1, DHCPREQUEST, // DHCP message, len, request
Helmut Tschemernjak 35:fe3028eda085 49 OPT_PARAMETER_REQ, 5, OPT_SUBNET_MASK, OPT_ROUTER, OPT_TIME_SERVER, OPT_DOMAIN_NAME, OPT_DNS };
Soohwan Kim 0:6f28332c466f 50 add_buf((uint8_t*)options, sizeof(options));
Helmut Tschemernjak 35:fe3028eda085 51 add_option(OPT_IP_ADDR_REQ, yiaddr, 4);
Helmut Tschemernjak 35:fe3028eda085 52 add_option(OPT_SERVER_IDENT, siaddr, 4);
Helmut Tschemernjak 35:fe3028eda085 53 add_option(OPT_END);
Soohwan Kim 0:6f28332c466f 54 return m_pos;
Soohwan Kim 0:6f28332c466f 55 }
Soohwan Kim 0:6f28332c466f 56
Soohwan Kim 0:6f28332c466f 57 int DHCPClient::offer(uint8_t buf[], int size) {
Soohwan Kim 0:6f28332c466f 58 memcpy(yiaddr, buf+DHCP_OFFSET_YIADDR, 4);
Helmut Tschemernjak 35:fe3028eda085 59 memcpy(siaddr, buf+DHCP_OFFSET_SIADDR, 4);
Helmut Tschemernjak 35:fe3028eda085 60
Helmut Tschemernjak 35:fe3028eda085 61 memset(dnsaddr, 0, sizeof(dnsaddr));
Helmut Tschemernjak 35:fe3028eda085 62 memset(gateway, 0, sizeof(gateway));
Helmut Tschemernjak 35:fe3028eda085 63 memset(netmask, 0, sizeof(netmask));
Helmut Tschemernjak 35:fe3028eda085 64 memset(timesrv, 0, sizeof(timesrv));
Helmut Tschemernjak 35:fe3028eda085 65 memset(leaseTime, 0, sizeof(leaseTime));
Helmut Tschemernjak 35:fe3028eda085 66
Soohwan Kim 0:6f28332c466f 67 uint8_t *p;
Soohwan Kim 0:6f28332c466f 68 int msg_type = -1;
Soohwan Kim 0:6f28332c466f 69 p = buf + DHCP_OFFSET_OPTIONS;
Helmut Tschemernjak 35:fe3028eda085 70 while(*p != OPT_END && p < (buf+size)) {
Soohwan Kim 0:6f28332c466f 71 uint8_t code = *p++;
Soohwan Kim 0:6f28332c466f 72 if (code == 0) { // Pad Option
Soohwan Kim 0:6f28332c466f 73 continue;
Soohwan Kim 0:6f28332c466f 74 }
Soohwan Kim 0:6f28332c466f 75 int len = *p++;
Soohwan Kim 0:6f28332c466f 76
Soohwan Kim 0:6f28332c466f 77 DBG("DHCP option: %d\r\n", code);
Soohwan Kim 0:6f28332c466f 78 DBG_HEX(p, len);
Soohwan Kim 0:6f28332c466f 79
Soohwan Kim 0:6f28332c466f 80 switch(code) {
Helmut Tschemernjak 35:fe3028eda085 81 case OPT_DHCP_MESSAGE:
Soohwan Kim 0:6f28332c466f 82 msg_type = *p;
Soohwan Kim 0:6f28332c466f 83 break;
Helmut Tschemernjak 35:fe3028eda085 84 case OPT_SUBNET_MASK:
Helmut Tschemernjak 35:fe3028eda085 85 memcpy(netmask, p, 4);
Soohwan Kim 0:6f28332c466f 86 break;
Helmut Tschemernjak 35:fe3028eda085 87 case OPT_ROUTER:
Helmut Tschemernjak 35:fe3028eda085 88 memcpy(gateway, p, 4);
Soohwan Kim 0:6f28332c466f 89 break;
Helmut Tschemernjak 35:fe3028eda085 90 case OPT_DNS:
Soohwan Kim 0:6f28332c466f 91 memcpy(dnsaddr, p, 4);
Soohwan Kim 0:6f28332c466f 92 break;
Helmut Tschemernjak 35:fe3028eda085 93 case OPT_TIME_SERVER:
Helmut Tschemernjak 35:fe3028eda085 94 memcpy(timesrv, p, 4);
Helmut Tschemernjak 35:fe3028eda085 95 break;
Helmut Tschemernjak 35:fe3028eda085 96 case OPT_ADDR_LEASE_TIME:
Helmut Tschemernjak 35:fe3028eda085 97 memcpy(leaseTime, p, 4);
Soohwan Kim 0:6f28332c466f 98 break;
Helmut Tschemernjak 35:fe3028eda085 99 case OPT_DOMAIN_NAME:
Helmut Tschemernjak 35:fe3028eda085 100 {
Helmut Tschemernjak 35:fe3028eda085 101 int cplen = len;
Helmut Tschemernjak 35:fe3028eda085 102 if (cplen > 63)
Helmut Tschemernjak 35:fe3028eda085 103 cplen = 63; // max domain name
Helmut Tschemernjak 35:fe3028eda085 104 if (domainName) {
Helmut Tschemernjak 35:fe3028eda085 105 free(domainName);
Helmut Tschemernjak 35:fe3028eda085 106 domainName = NULL;
Helmut Tschemernjak 35:fe3028eda085 107 }
Helmut Tschemernjak 35:fe3028eda085 108 if (cplen) {
Helmut Tschemernjak 35:fe3028eda085 109 domainName = (char *)calloc(1, cplen+1);
Helmut Tschemernjak 35:fe3028eda085 110 memcpy(domainName, p, cplen); // zero term is already here via calloc
Helmut Tschemernjak 35:fe3028eda085 111 }
Helmut Tschemernjak 35:fe3028eda085 112 }
Helmut Tschemernjak 35:fe3028eda085 113 break;
Helmut Tschemernjak 35:fe3028eda085 114 case OPT_SERVER_IDENT:
Soohwan Kim 0:6f28332c466f 115 memcpy(siaddr, p, 4);
Soohwan Kim 0:6f28332c466f 116 break;
Soohwan Kim 0:6f28332c466f 117 }
Soohwan Kim 0:6f28332c466f 118 p += len;
Soohwan Kim 0:6f28332c466f 119 }
Soohwan Kim 0:6f28332c466f 120 return msg_type;
Soohwan Kim 0:6f28332c466f 121 }
Soohwan Kim 0:6f28332c466f 122
Soohwan Kim 0:6f28332c466f 123 bool DHCPClient::verify(uint8_t buf[], int len) {
Soohwan Kim 0:6f28332c466f 124 if (len < DHCP_OFFSET_OPTIONS) {
Soohwan Kim 0:6f28332c466f 125 return false;
Soohwan Kim 0:6f28332c466f 126 }
Soohwan Kim 0:6f28332c466f 127 if (buf[DHCP_OFFSET_OP] != 0x02) {
Soohwan Kim 0:6f28332c466f 128 return false;
Soohwan Kim 0:6f28332c466f 129 }
Soohwan Kim 0:6f28332c466f 130 if (memcmp(buf+DHCP_OFFSET_XID, xid, 4) != 0) {
Soohwan Kim 0:6f28332c466f 131 return false;
Soohwan Kim 0:6f28332c466f 132 }
Soohwan Kim 0:6f28332c466f 133 return true;
Soohwan Kim 0:6f28332c466f 134 }
Soohwan Kim 0:6f28332c466f 135
Soohwan Kim 0:6f28332c466f 136 void DHCPClient::callback()
Soohwan Kim 0:6f28332c466f 137 {
embeddist 15:24a9f2df2145 138 Endpoint host;
embeddist 15:24a9f2df2145 139 int recv_len = m_udp->receiveFrom(host, (char*)m_buf, sizeof(m_buf));
Soohwan Kim 0:6f28332c466f 140 if (recv_len < 0) {
Soohwan Kim 0:6f28332c466f 141 return;
Soohwan Kim 0:6f28332c466f 142 }
Soohwan Kim 0:6f28332c466f 143 if (!verify(m_buf, recv_len)) {
Soohwan Kim 0:6f28332c466f 144 return;
Soohwan Kim 0:6f28332c466f 145 }
Soohwan Kim 0:6f28332c466f 146 int r = offer(m_buf, recv_len);
Soohwan Kim 0:6f28332c466f 147 if (r == DHCPOFFER) {
Soohwan Kim 0:6f28332c466f 148 int send_size = request();
Soohwan Kim 0:6f28332c466f 149 m_udp->sendTo(m_server, (char*)m_buf, send_size);
Soohwan Kim 0:6f28332c466f 150 } else if (r == DHCPACK) {
Soohwan Kim 0:6f28332c466f 151 exit_flag = true;
Soohwan Kim 0:6f28332c466f 152 }
Soohwan Kim 0:6f28332c466f 153 }
Soohwan Kim 0:6f28332c466f 154
Soohwan Kim 0:6f28332c466f 155 void DHCPClient::add_buf(uint8_t c)
Soohwan Kim 0:6f28332c466f 156 {
Soohwan Kim 0:6f28332c466f 157 m_buf[m_pos++] = c;
Soohwan Kim 0:6f28332c466f 158 }
Soohwan Kim 0:6f28332c466f 159
Soohwan Kim 0:6f28332c466f 160 void DHCPClient::add_buf(uint8_t* buf, int len)
Soohwan Kim 0:6f28332c466f 161 {
Soohwan Kim 0:6f28332c466f 162 for(int i = 0; i < len; i++) {
Soohwan Kim 0:6f28332c466f 163 add_buf(buf[i]);
Soohwan Kim 0:6f28332c466f 164 }
Soohwan Kim 0:6f28332c466f 165 }
Soohwan Kim 0:6f28332c466f 166
Soohwan Kim 0:6f28332c466f 167 void DHCPClient::fill_buf(int len, uint8_t data)
Soohwan Kim 0:6f28332c466f 168 {
Soohwan Kim 0:6f28332c466f 169 while(len-- > 0) {
Soohwan Kim 0:6f28332c466f 170 add_buf(data);
Soohwan Kim 0:6f28332c466f 171 }
Soohwan Kim 0:6f28332c466f 172 }
Soohwan Kim 0:6f28332c466f 173
Soohwan Kim 0:6f28332c466f 174 void DHCPClient::add_option(uint8_t code, uint8_t* buf, int len)
Soohwan Kim 0:6f28332c466f 175 {
Soohwan Kim 0:6f28332c466f 176 add_buf(code);
Soohwan Kim 0:6f28332c466f 177 if (len > 0) {
Soohwan Kim 0:6f28332c466f 178 add_buf((uint8_t)len);
Soohwan Kim 0:6f28332c466f 179 add_buf(buf, len);
Soohwan Kim 0:6f28332c466f 180 }
Soohwan Kim 0:6f28332c466f 181 }
Soohwan Kim 0:6f28332c466f 182
Soohwan Kim 0:6f28332c466f 183 int DHCPClient::setup(int timeout_ms)
Soohwan Kim 0:6f28332c466f 184 {
Soohwan Kim 0:6f28332c466f 185 eth = WIZnet_Chip::getInstance();
Soohwan Kim 0:6f28332c466f 186 if (eth == NULL) {
Soohwan Kim 0:6f28332c466f 187 return -1;
Soohwan Kim 0:6f28332c466f 188 }
Soohwan Kim 0:6f28332c466f 189 eth->reg_rd_mac(SHAR, chaddr);
Soohwan Kim 0:6f28332c466f 190 int interval_ms = 5*1000; // 5000msec
Soohwan Kim 0:6f28332c466f 191 if (timeout_ms < interval_ms) {
Soohwan Kim 0:6f28332c466f 192 interval_ms = timeout_ms;
Soohwan Kim 0:6f28332c466f 193 }
Soohwan Kim 0:6f28332c466f 194 m_udp = new UDPSocket;
Soohwan Kim 0:6f28332c466f 195 m_udp->init();
Soohwan Kim 0:6f28332c466f 196 m_udp->set_blocking(false);
Soohwan Kim 0:6f28332c466f 197 eth->reg_wr<uint32_t>(SIPR, 0x00000000); // local ip "0.0.0.0"
Helmut Tschemernjak 35:fe3028eda085 198 m_udp->bind(DHCP_CLIENT_PORT); // local port
Helmut Tschemernjak 35:fe3028eda085 199 m_server.set_address("255.255.255.255", DHCP_SERVER_PORT); // DHCP broadcast
Soohwan Kim 0:6f28332c466f 200 exit_flag = false;
Soohwan Kim 0:6f28332c466f 201 int err = 0;
Soohwan Kim 0:6f28332c466f 202 int seq = 0;
Soohwan Kim 0:6f28332c466f 203 int send_size;
Soohwan Kim 0:6f28332c466f 204 while(!exit_flag) {
Soohwan Kim 0:6f28332c466f 205 switch(seq) {
Soohwan Kim 0:6f28332c466f 206 case 0:
Soohwan Kim 0:6f28332c466f 207 m_retry = 0;
Soohwan Kim 0:6f28332c466f 208 seq++;
Soohwan Kim 0:6f28332c466f 209 break;
Soohwan Kim 0:6f28332c466f 210 case 1:
Soohwan Kim 0:6f28332c466f 211 send_size = discover();
Soohwan Kim 0:6f28332c466f 212 m_udp->sendTo(m_server, (char*)m_buf, send_size);
Soohwan Kim 0:6f28332c466f 213 m_interval.reset();
Soohwan Kim 0:6f28332c466f 214 m_interval.start();
Soohwan Kim 0:6f28332c466f 215 seq++;
Soohwan Kim 0:6f28332c466f 216 break;
Soohwan Kim 0:6f28332c466f 217 case 2:
Soohwan Kim 0:6f28332c466f 218 callback();
Soohwan Kim 0:6f28332c466f 219 if (m_interval.read_ms() > interval_ms) {
Soohwan Kim 0:6f28332c466f 220 DBG("m_retry: %d\n", m_retry);
Soohwan Kim 0:6f28332c466f 221 if (++m_retry >= (timeout_ms/interval_ms)) {
Soohwan Kim 0:6f28332c466f 222 err = -1;
Soohwan Kim 0:6f28332c466f 223 exit_flag = true;
Soohwan Kim 0:6f28332c466f 224 }
Soohwan Kim 0:6f28332c466f 225 seq--;
Soohwan Kim 0:6f28332c466f 226 }
Soohwan Kim 0:6f28332c466f 227 break;
Soohwan Kim 0:6f28332c466f 228 }
Soohwan Kim 0:6f28332c466f 229 }
Soohwan Kim 0:6f28332c466f 230 DBG("m_retry: %d, m_interval: %d\n", m_retry, m_interval.read_ms());
Soohwan Kim 0:6f28332c466f 231 delete m_udp;
Soohwan Kim 0:6f28332c466f 232 return err;
Soohwan Kim 0:6f28332c466f 233 }
Soohwan Kim 0:6f28332c466f 234
Soohwan Kim 0:6f28332c466f 235 DHCPClient::DHCPClient() {
Helmut Tschemernjak 35:fe3028eda085 236 domainName = NULL;
Soohwan Kim 0:6f28332c466f 237 }
Soohwan Kim 0:6f28332c466f 238
Helmut Tschemernjak 35:fe3028eda085 239 DHCPClient::~DHCPClient() {
Helmut Tschemernjak 35:fe3028eda085 240 if (domainName)
Helmut Tschemernjak 35:fe3028eda085 241 free(domainName);
Helmut Tschemernjak 35:fe3028eda085 242 }