1 | /*
|
---|
2 | * Copyright (c) 2005, Swedish Institute of Computer Science
|
---|
3 | * All rights reserved.
|
---|
4 | *
|
---|
5 | * Redistribution and use in source and binary forms, with or without
|
---|
6 | * modification, are permitted provided that the following conditions
|
---|
7 | * are met:
|
---|
8 | * 1. Redistributions of source code must retain the above copyright
|
---|
9 | * notice, this list of conditions and the following disclaimer.
|
---|
10 | * 2. Redistributions in binary form must reproduce the above copyright
|
---|
11 | * notice, this list of conditions and the following disclaimer in the
|
---|
12 | * documentation and/or other materials provided with the distribution.
|
---|
13 | * 3. Neither the name of the Institute nor the names of its contributors
|
---|
14 | * may be used to endorse or promote products derived from this software
|
---|
15 | * without specific prior written permission.
|
---|
16 | *
|
---|
17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
---|
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
---|
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
---|
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
---|
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
---|
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
---|
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
---|
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
---|
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
---|
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
---|
27 | * SUCH DAMAGE.
|
---|
28 | *
|
---|
29 | * This file is part of the uIP TCP/IP stack
|
---|
30 | *
|
---|
31 | * @(#)$Id: dhcpc.c 262 2016-11-18 05:58:30Z coas-nagasima $
|
---|
32 | */
|
---|
33 |
|
---|
34 | #include <stdio.h>
|
---|
35 | #include <string.h>
|
---|
36 |
|
---|
37 | #include "net/ip/uip.h"
|
---|
38 | #include "dhcpc/dhcpc.h"
|
---|
39 | #include "sys/timer.h"
|
---|
40 | #include "sys/pt.h"
|
---|
41 |
|
---|
42 | #define STATE_INITIAL 0
|
---|
43 | #define STATE_REQUEST 1
|
---|
44 | #define STATE_SENDING 2
|
---|
45 | #define STATE_OFFER_RECEIVED 3
|
---|
46 | #define STATE_CONFIG_RECEIVED 4
|
---|
47 |
|
---|
48 | #ifdef __RX
|
---|
49 | #pragma pack
|
---|
50 | #elif _MSC_VER
|
---|
51 | #pragma pack(push, 1)
|
---|
52 | #endif
|
---|
53 |
|
---|
54 | struct dhcp_msg {
|
---|
55 | uint8_t op, htype, hlen, hops;
|
---|
56 | uint8_t xid[4];
|
---|
57 | uint16_t secs, flags;
|
---|
58 | uint8_t ciaddr[4];
|
---|
59 | uint8_t yiaddr[4];
|
---|
60 | uint8_t siaddr[4];
|
---|
61 | uint8_t giaddr[4];
|
---|
62 | uint8_t chaddr[16];
|
---|
63 | #ifndef UIP_CONF_DHCP_LIGHT
|
---|
64 | uint8_t sname[64];
|
---|
65 | uint8_t file[128];
|
---|
66 | #endif
|
---|
67 | uint8_t options[312];
|
---|
68 | };
|
---|
69 |
|
---|
70 | #ifdef __RX
|
---|
71 | #pragma unpack
|
---|
72 | #elif _MSC_VER
|
---|
73 | #pragma pack(pop)
|
---|
74 | #endif
|
---|
75 |
|
---|
76 | #define BOOTP_BROADCAST 0x8000
|
---|
77 |
|
---|
78 | #define DHCP_REQUEST 1
|
---|
79 | #define DHCP_REPLY 2
|
---|
80 | #define DHCP_HTYPE_ETHERNET 1
|
---|
81 | #define DHCP_HLEN_ETHERNET 6
|
---|
82 | #define DHCP_MSG_LEN 236
|
---|
83 |
|
---|
84 | #define DHCPC_SERVER_PORT 67
|
---|
85 | #define DHCPC_CLIENT_PORT 68
|
---|
86 |
|
---|
87 | #define DHCPDISCOVER 1
|
---|
88 | #define DHCPOFFER 2
|
---|
89 | #define DHCPREQUEST 3
|
---|
90 | #define DHCPDECLINE 4
|
---|
91 | #define DHCPACK 5
|
---|
92 | #define DHCPNAK 6
|
---|
93 | #define DHCPRELEASE 7
|
---|
94 |
|
---|
95 | #define DHCP_OPTION_SUBNET_MASK 1
|
---|
96 | #define DHCP_OPTION_ROUTER 3
|
---|
97 | #define DHCP_OPTION_DNS_SERVER 6
|
---|
98 | #define DHCP_OPTION_REQ_IPADDR 50
|
---|
99 | #define DHCP_OPTION_LEASE_TIME 51
|
---|
100 | #define DHCP_OPTION_MSG_TYPE 53
|
---|
101 | #define DHCP_OPTION_SERVER_ID 54
|
---|
102 | #define DHCP_OPTION_REQ_LIST 55
|
---|
103 | #define DHCP_OPTION_END 255
|
---|
104 |
|
---|
105 | static const uint8_t xid[4] = {0xad, 0xde, 0x12, 0x23};
|
---|
106 | static const uint8_t magic_cookie[4] = {99, 130, 83, 99};
|
---|
107 | /*---------------------------------------------------------------------------*/
|
---|
108 | static uint8_t *
|
---|
109 | add_msg_type(uint8_t *optptr, uint8_t type)
|
---|
110 | {
|
---|
111 | *optptr++ = DHCP_OPTION_MSG_TYPE;
|
---|
112 | *optptr++ = 1;
|
---|
113 | *optptr++ = type;
|
---|
114 | return optptr;
|
---|
115 | }
|
---|
116 | /*---------------------------------------------------------------------------*/
|
---|
117 | static uint8_t *
|
---|
118 | add_server_id(struct dhcpc_state *s, uint8_t *optptr)
|
---|
119 | {
|
---|
120 | *optptr++ = DHCP_OPTION_SERVER_ID;
|
---|
121 | *optptr++ = 4;
|
---|
122 | memcpy(optptr, s->serverid, 4);
|
---|
123 | return optptr + 4;
|
---|
124 | }
|
---|
125 | /*---------------------------------------------------------------------------*/
|
---|
126 | static uint8_t *
|
---|
127 | add_req_ipaddr(struct dhcpc_state *s, uint8_t *optptr)
|
---|
128 | {
|
---|
129 | *optptr++ = DHCP_OPTION_REQ_IPADDR;
|
---|
130 | *optptr++ = 4;
|
---|
131 | memcpy(optptr, s->ipaddr, 4);
|
---|
132 | return optptr + 4;
|
---|
133 | }
|
---|
134 | /*---------------------------------------------------------------------------*/
|
---|
135 | static uint8_t *
|
---|
136 | add_req_options(uint8_t *optptr)
|
---|
137 | {
|
---|
138 | *optptr++ = DHCP_OPTION_REQ_LIST;
|
---|
139 | *optptr++ = 3;
|
---|
140 | *optptr++ = DHCP_OPTION_SUBNET_MASK;
|
---|
141 | *optptr++ = DHCP_OPTION_ROUTER;
|
---|
142 | *optptr++ = DHCP_OPTION_DNS_SERVER;
|
---|
143 | return optptr;
|
---|
144 | }
|
---|
145 | /*---------------------------------------------------------------------------*/
|
---|
146 | static uint8_t *
|
---|
147 | add_end(uint8_t *optptr)
|
---|
148 | {
|
---|
149 | *optptr++ = DHCP_OPTION_END;
|
---|
150 | return optptr;
|
---|
151 | }
|
---|
152 | /*---------------------------------------------------------------------------*/
|
---|
153 | static void
|
---|
154 | create_msg(struct dhcpc_state *s, struct dhcp_msg *m)
|
---|
155 | {
|
---|
156 | m->op = DHCP_REQUEST;
|
---|
157 | m->htype = DHCP_HTYPE_ETHERNET;
|
---|
158 | m->hlen = s->mac_len;
|
---|
159 | m->hops = 0;
|
---|
160 | memcpy(m->xid, xid, sizeof(m->xid));
|
---|
161 | m->secs = 0;
|
---|
162 | m->flags = UIP_HTONS(BOOTP_BROADCAST); /* Broadcast bit. */
|
---|
163 | /* uip_ipaddr_copy(&m->ciaddr, &uip_hostaddr);*/
|
---|
164 | memcpy(m->ciaddr, &uip_hostaddr, sizeof(m->ciaddr));
|
---|
165 | memset(m->yiaddr, 0, sizeof(m->yiaddr));
|
---|
166 | memset(m->siaddr, 0, sizeof(m->siaddr));
|
---|
167 | memset(m->giaddr, 0, sizeof(m->giaddr));
|
---|
168 | memcpy(m->chaddr, s->mac_addr, s->mac_len);
|
---|
169 | memset(&m->chaddr[s->mac_len], 0, sizeof(m->chaddr) - s->mac_len);
|
---|
170 | #ifndef UIP_CONF_DHCP_LIGHT
|
---|
171 | memset(m->sname, 0, sizeof(m->sname));
|
---|
172 | memset(m->file, 0, sizeof(m->file));
|
---|
173 | #endif
|
---|
174 |
|
---|
175 | memcpy(m->options, magic_cookie, sizeof(magic_cookie));
|
---|
176 | }
|
---|
177 | /*---------------------------------------------------------------------------*/
|
---|
178 | static void
|
---|
179 | send_discover(struct dhcpc_state *s)
|
---|
180 | {
|
---|
181 | uint8_t *end;
|
---|
182 | struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
|
---|
183 |
|
---|
184 | create_msg(s, m);
|
---|
185 |
|
---|
186 | end = add_msg_type(&m->options[4], DHCPDISCOVER);
|
---|
187 | end = add_req_options(end);
|
---|
188 | end = add_end(end);
|
---|
189 |
|
---|
190 | uip_send(uip_appdata, end - (uint8_t *)uip_appdata);
|
---|
191 | }
|
---|
192 | /*---------------------------------------------------------------------------*/
|
---|
193 | static void
|
---|
194 | send_request(struct dhcpc_state *s)
|
---|
195 | {
|
---|
196 | uint8_t *end;
|
---|
197 | struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
|
---|
198 |
|
---|
199 | create_msg(s, m);
|
---|
200 |
|
---|
201 | end = add_msg_type(&m->options[4], DHCPREQUEST);
|
---|
202 | end = add_server_id(s, end);
|
---|
203 | end = add_req_ipaddr(s, end);
|
---|
204 | end = add_end(end);
|
---|
205 |
|
---|
206 | uip_send(uip_appdata, end - (uint8_t *)uip_appdata);
|
---|
207 | }
|
---|
208 | /*---------------------------------------------------------------------------*/
|
---|
209 | static uint8_t
|
---|
210 | parse_options(struct dhcpc_state *s, uint8_t *optptr, int len)
|
---|
211 | {
|
---|
212 | uint8_t *end = optptr + len;
|
---|
213 | uint8_t type = 0;
|
---|
214 |
|
---|
215 | while(optptr < end) {
|
---|
216 | switch(*optptr) {
|
---|
217 | case DHCP_OPTION_SUBNET_MASK:
|
---|
218 | memcpy(s->netmask, optptr + 2, 4);
|
---|
219 | break;
|
---|
220 | case DHCP_OPTION_ROUTER:
|
---|
221 | memcpy(s->default_router, optptr + 2, 4);
|
---|
222 | break;
|
---|
223 | case DHCP_OPTION_DNS_SERVER:
|
---|
224 | memcpy(s->dnsaddr, optptr + 2, 4);
|
---|
225 | break;
|
---|
226 | case DHCP_OPTION_MSG_TYPE:
|
---|
227 | type = *(optptr + 2);
|
---|
228 | break;
|
---|
229 | case DHCP_OPTION_SERVER_ID:
|
---|
230 | memcpy(s->serverid, optptr + 2, 4);
|
---|
231 | break;
|
---|
232 | case DHCP_OPTION_LEASE_TIME:
|
---|
233 | memcpy(s->lease_time, optptr + 2, 4);
|
---|
234 | break;
|
---|
235 | case DHCP_OPTION_END:
|
---|
236 | return type;
|
---|
237 | }
|
---|
238 |
|
---|
239 | optptr += optptr[1] + 2;
|
---|
240 | }
|
---|
241 | return type;
|
---|
242 | }
|
---|
243 | /*---------------------------------------------------------------------------*/
|
---|
244 | static uint8_t
|
---|
245 | parse_msg(struct dhcpc_state *s)
|
---|
246 | {
|
---|
247 | struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
|
---|
248 |
|
---|
249 | if(m->op == DHCP_REPLY &&
|
---|
250 | memcmp(m->xid, xid, sizeof(xid)) == 0 &&
|
---|
251 | memcmp(m->chaddr, s->mac_addr, s->mac_len) == 0) {
|
---|
252 | memcpy(s->ipaddr, m->yiaddr, 4);
|
---|
253 | return parse_options(s, &m->options[4], uip_datalen());
|
---|
254 | }
|
---|
255 | return 0;
|
---|
256 | }
|
---|
257 | /*---------------------------------------------------------------------------*/
|
---|
258 | static
|
---|
259 | PT_THREAD(handle_dhcp(struct dhcpc_state *s))
|
---|
260 | {
|
---|
261 | int ret;
|
---|
262 | PT_BEGIN(&s->pt);
|
---|
263 |
|
---|
264 | if(s->state != STATE_REQUEST)
|
---|
265 | PT_YIELD(&s->pt);
|
---|
266 |
|
---|
267 | /* try_again:*/
|
---|
268 | s->state = STATE_SENDING;
|
---|
269 | s->ticks = 5 * CLOCK_SECOND;
|
---|
270 |
|
---|
271 | do {
|
---|
272 | printf("send_discover(%d)\n", s->timer);
|
---|
273 | send_discover(s);
|
---|
274 | timer_set(&s->timer, s->ticks);
|
---|
275 |
|
---|
276 | PT_WAIT_UNTIL(&s->pt, (ret = uip_newdata() ? 1 : (timer_expired(&s->timer) ? 2 : 0)) != 0);
|
---|
277 |
|
---|
278 | if((ret == 1) && parse_msg(s) == DHCPOFFER) {
|
---|
279 | s->state = STATE_OFFER_RECEIVED;
|
---|
280 | break;
|
---|
281 | }
|
---|
282 | if(ret != 2)
|
---|
283 | continue;
|
---|
284 |
|
---|
285 | if(s->ticks < CLOCK_SECOND * 60) {
|
---|
286 | s->ticks += CLOCK_SECOND;
|
---|
287 | }
|
---|
288 | timer_set(&s->timer, s->ticks);
|
---|
289 | } while(s->state != STATE_OFFER_RECEIVED);
|
---|
290 |
|
---|
291 | s->ticks = CLOCK_SECOND;
|
---|
292 |
|
---|
293 | PT_YIELD(&s->pt);
|
---|
294 |
|
---|
295 | do {
|
---|
296 | printf("send_request(%d)\n", s->timer);
|
---|
297 | send_request(s);
|
---|
298 | timer_set(&s->timer, s->ticks);
|
---|
299 |
|
---|
300 | PT_WAIT_UNTIL(&s->pt, (ret = uip_newdata() ? 1 : (timer_expired(&s->timer) ? 2 : 0)) != 0);
|
---|
301 |
|
---|
302 | if((ret == 1) && parse_msg(s) == DHCPACK) {
|
---|
303 | s->state = STATE_CONFIG_RECEIVED;
|
---|
304 | break;
|
---|
305 | }
|
---|
306 | if(ret != 2)
|
---|
307 | continue;
|
---|
308 |
|
---|
309 | if(s->ticks <= CLOCK_SECOND * 60) {
|
---|
310 | s->ticks += CLOCK_SECOND;
|
---|
311 | timer_set(&s->timer, s->ticks);
|
---|
312 | } else {
|
---|
313 | PT_RESTART(&s->pt);
|
---|
314 | }
|
---|
315 | } while(s->state != STATE_CONFIG_RECEIVED);
|
---|
316 |
|
---|
317 | #if 0
|
---|
318 | printf("Got IP address %d.%d.%d.%d\n",
|
---|
319 | uip_ipaddr1(s->ipaddr), uip_ipaddr2(s->ipaddr),
|
---|
320 | uip_ipaddr3(s->ipaddr), uip_ipaddr4(s->ipaddr));
|
---|
321 | printf("Got netmask %d.%d.%d.%d\n",
|
---|
322 | uip_ipaddr1(s->netmask), uip_ipaddr2(s->netmask),
|
---|
323 | uip_ipaddr3(s->netmask), uip_ipaddr4(s->netmask));
|
---|
324 | printf("Got DNS server %d.%d.%d.%d\n",
|
---|
325 | uip_ipaddr1(s->dnsaddr), uip_ipaddr2(s->dnsaddr),
|
---|
326 | uip_ipaddr3(s->dnsaddr), uip_ipaddr4(s->dnsaddr));
|
---|
327 | printf("Got default router %d.%d.%d.%d\n",
|
---|
328 | uip_ipaddr1(s->default_router), uip_ipaddr2(s->default_router),
|
---|
329 | uip_ipaddr3(s->default_router), uip_ipaddr4(s->default_router));
|
---|
330 | printf("Lease expires in %ld seconds\n",
|
---|
331 | uip_ntohs(s->lease_time[0])*65536ul + uip_ntohs(s->lease_time[1]));
|
---|
332 | #endif
|
---|
333 |
|
---|
334 | dhcpc_configured(s);
|
---|
335 |
|
---|
336 | /* timer_stop(&s->timer);*/
|
---|
337 |
|
---|
338 | /*
|
---|
339 | * PT_END restarts the thread so we do this instead. Eventually we
|
---|
340 | * should reacquire expired leases here.
|
---|
341 | */
|
---|
342 | while(1) {
|
---|
343 | PT_YIELD(&s->pt);
|
---|
344 | if(s->state == STATE_INITIAL)
|
---|
345 | PT_RESTART(&s->pt);
|
---|
346 | }
|
---|
347 |
|
---|
348 | PT_END(&s->pt);
|
---|
349 | }
|
---|
350 | /*---------------------------------------------------------------------------*/
|
---|
351 | struct dhcpc_state *
|
---|
352 | dhcpc_init(const void *mac_addr, int mac_len)
|
---|
353 | {
|
---|
354 | struct uip_udp_conn *conn;
|
---|
355 | struct dhcpc_state *s;
|
---|
356 | uip_ipaddr_t addr;
|
---|
357 |
|
---|
358 | uip_ipaddr(&addr, 255,255,255,255);
|
---|
359 | conn = uip_udp_new(&addr, UIP_HTONS(DHCPC_SERVER_PORT));
|
---|
360 | if(conn != NULL) {
|
---|
361 | s = &conn->appstate.parblk.dhcpc;
|
---|
362 | s->conn = conn;
|
---|
363 | s->mac_addr = mac_addr;
|
---|
364 | s->mac_len = mac_len;
|
---|
365 |
|
---|
366 | s->state = STATE_INITIAL;
|
---|
367 | s->conn->appstate.udp_callback = dhcpc_appcall;
|
---|
368 |
|
---|
369 | uip_udp_bind(conn, UIP_HTONS(DHCPC_CLIENT_PORT));
|
---|
370 |
|
---|
371 | PT_INIT(&s->pt);
|
---|
372 |
|
---|
373 | return s;
|
---|
374 | }
|
---|
375 |
|
---|
376 | return NULL;
|
---|
377 | }
|
---|
378 | /*---------------------------------------------------------------------------*/
|
---|
379 | void
|
---|
380 | dhcpc_appcall(struct uip_udp_conn *uip_udp_conn, int fncd, void *p_parblk)
|
---|
381 | {
|
---|
382 | handle_dhcp((struct dhcpc_state *)p_parblk);
|
---|
383 | }
|
---|
384 | /*---------------------------------------------------------------------------*/
|
---|
385 | void
|
---|
386 | dhcpc_request(struct dhcpc_state *s)
|
---|
387 | {
|
---|
388 | uip_ipaddr_t ipaddr;
|
---|
389 |
|
---|
390 | s->state = STATE_REQUEST;
|
---|
391 | uip_ipaddr(&ipaddr, 0,0,0,0);
|
---|
392 | uip_sethostaddr(&ipaddr);
|
---|
393 | uip_udp_conn = s->conn;
|
---|
394 | uip_process(UIP_UDP_TIMER);
|
---|
395 | }
|
---|
396 | /*---------------------------------------------------------------------------*/
|
---|