Network Services

Dependents:   PwrCond_mbed5

Fork of W5500Interface_K22F by Andrew McCartney

Committer:
Bongjun
Date:
Wed Aug 20 00:28:37 2014 +0000
Revision:
0:e11e8793c3ce
first release.

Who changed what in which revision?

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