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 108 2015-06-11 09:15:46Z coas-nagasima $
|
---|
32 | */
|
---|
33 |
|
---|
34 | #include <stdio.h>
|
---|
35 | #include <string.h>
|
---|
36 |
|
---|
37 | #include "uip.h"
|
---|
38 | #include "dhcpc.h"
|
---|
39 | #include "timer.h"
|
---|
40 | #include "pt.h"
|
---|
41 |
|
---|
42 | #define STATE_INITIAL 0
|
---|
43 | #define STATE_SENDING 1
|
---|
44 | #define STATE_OFFER_RECEIVED 2
|
---|
45 | #define STATE_CONFIG_RECEIVED 3
|
---|
46 |
|
---|
47 | #ifdef __RX
|
---|
48 | #pragma pack
|
---|
49 | #elif _MSC_VER
|
---|
50 | #pragma pack(push, 1)
|
---|
51 | #endif
|
---|
52 |
|
---|
53 | struct dhcp_msg {
|
---|
54 | u8_t op, htype, hlen, hops;
|
---|
55 | u8_t xid[4];
|
---|
56 | u16_t secs, flags;
|
---|
57 | u8_t ciaddr[4];
|
---|
58 | u8_t yiaddr[4];
|
---|
59 | u8_t siaddr[4];
|
---|
60 | u8_t giaddr[4];
|
---|
61 | u8_t chaddr[16];
|
---|
62 | #ifndef UIP_CONF_DHCP_LIGHT
|
---|
63 | u8_t sname[64];
|
---|
64 | u8_t file[128];
|
---|
65 | #endif
|
---|
66 | u8_t options[312];
|
---|
67 | };
|
---|
68 |
|
---|
69 | #ifdef __RX
|
---|
70 | #pragma unpack
|
---|
71 | #elif _MSC_VER
|
---|
72 | #pragma pack(pop)
|
---|
73 | #endif
|
---|
74 |
|
---|
75 | #define BOOTP_BROADCAST 0x8000
|
---|
76 |
|
---|
77 | #define DHCP_REQUEST 1
|
---|
78 | #define DHCP_REPLY 2
|
---|
79 | #define DHCP_HTYPE_ETHERNET 1
|
---|
80 | #define DHCP_HLEN_ETHERNET 6
|
---|
81 | #define DHCP_MSG_LEN 236
|
---|
82 |
|
---|
83 | #define DHCPC_SERVER_PORT 67
|
---|
84 | #define DHCPC_CLIENT_PORT 68
|
---|
85 |
|
---|
86 | #define DHCPDISCOVER 1
|
---|
87 | #define DHCPOFFER 2
|
---|
88 | #define DHCPREQUEST 3
|
---|
89 | #define DHCPDECLINE 4
|
---|
90 | #define DHCPACK 5
|
---|
91 | #define DHCPNAK 6
|
---|
92 | #define DHCPRELEASE 7
|
---|
93 |
|
---|
94 | #define DHCP_OPTION_SUBNET_MASK 1
|
---|
95 | #define DHCP_OPTION_ROUTER 3
|
---|
96 | #define DHCP_OPTION_DNS_SERVER 6
|
---|
97 | #define DHCP_OPTION_REQ_IPADDR 50
|
---|
98 | #define DHCP_OPTION_LEASE_TIME 51
|
---|
99 | #define DHCP_OPTION_MSG_TYPE 53
|
---|
100 | #define DHCP_OPTION_SERVER_ID 54
|
---|
101 | #define DHCP_OPTION_REQ_LIST 55
|
---|
102 | #define DHCP_OPTION_END 255
|
---|
103 |
|
---|
104 | static const u8_t xid[4] = {0xad, 0xde, 0x12, 0x23};
|
---|
105 | static const u8_t magic_cookie[4] = {99, 130, 83, 99};
|
---|
106 | /*---------------------------------------------------------------------------*/
|
---|
107 | static u8_t *
|
---|
108 | add_msg_type(u8_t *optptr, u8_t type)
|
---|
109 | {
|
---|
110 | *optptr++ = DHCP_OPTION_MSG_TYPE;
|
---|
111 | *optptr++ = 1;
|
---|
112 | *optptr++ = type;
|
---|
113 | return optptr;
|
---|
114 | }
|
---|
115 | /*---------------------------------------------------------------------------*/
|
---|
116 | static u8_t *
|
---|
117 | add_server_id(struct dhcpc_state *s, u8_t *optptr)
|
---|
118 | {
|
---|
119 | *optptr++ = DHCP_OPTION_SERVER_ID;
|
---|
120 | *optptr++ = 4;
|
---|
121 | memcpy(optptr, s->serverid, 4);
|
---|
122 | return optptr + 4;
|
---|
123 | }
|
---|
124 | /*---------------------------------------------------------------------------*/
|
---|
125 | static u8_t *
|
---|
126 | add_req_ipaddr(struct dhcpc_state *s, u8_t *optptr)
|
---|
127 | {
|
---|
128 | *optptr++ = DHCP_OPTION_REQ_IPADDR;
|
---|
129 | *optptr++ = 4;
|
---|
130 | memcpy(optptr, s->ipaddr, 4);
|
---|
131 | return optptr + 4;
|
---|
132 | }
|
---|
133 | /*---------------------------------------------------------------------------*/
|
---|
134 | static u8_t *
|
---|
135 | add_req_options(u8_t *optptr)
|
---|
136 | {
|
---|
137 | *optptr++ = DHCP_OPTION_REQ_LIST;
|
---|
138 | *optptr++ = 3;
|
---|
139 | *optptr++ = DHCP_OPTION_SUBNET_MASK;
|
---|
140 | *optptr++ = DHCP_OPTION_ROUTER;
|
---|
141 | *optptr++ = DHCP_OPTION_DNS_SERVER;
|
---|
142 | return optptr;
|
---|
143 | }
|
---|
144 | /*---------------------------------------------------------------------------*/
|
---|
145 | static u8_t *
|
---|
146 | add_end(u8_t *optptr)
|
---|
147 | {
|
---|
148 | *optptr++ = DHCP_OPTION_END;
|
---|
149 | return optptr;
|
---|
150 | }
|
---|
151 | /*---------------------------------------------------------------------------*/
|
---|
152 | static void
|
---|
153 | create_msg(struct dhcpc_state *s, struct dhcp_msg *m)
|
---|
154 | {
|
---|
155 | m->op = DHCP_REQUEST;
|
---|
156 | m->htype = DHCP_HTYPE_ETHERNET;
|
---|
157 | m->hlen = s->mac_len;
|
---|
158 | m->hops = 0;
|
---|
159 | memcpy(m->xid, xid, sizeof(m->xid));
|
---|
160 | m->secs = 0;
|
---|
161 | m->flags = HTONS(BOOTP_BROADCAST); /* Broadcast bit. */
|
---|
162 | /* uip_ipaddr_copy(m->ciaddr, uip_hostaddr);*/
|
---|
163 | memcpy(m->ciaddr, uip_hostaddr, sizeof(m->ciaddr));
|
---|
164 | memset(m->yiaddr, 0, sizeof(m->yiaddr));
|
---|
165 | memset(m->siaddr, 0, sizeof(m->siaddr));
|
---|
166 | memset(m->giaddr, 0, sizeof(m->giaddr));
|
---|
167 | memcpy(m->chaddr, s->mac_addr, s->mac_len);
|
---|
168 | memset(&m->chaddr[s->mac_len], 0, sizeof(m->chaddr) - s->mac_len);
|
---|
169 | #ifndef UIP_CONF_DHCP_LIGHT
|
---|
170 | memset(m->sname, 0, sizeof(m->sname));
|
---|
171 | memset(m->file, 0, sizeof(m->file));
|
---|
172 | #endif
|
---|
173 |
|
---|
174 | memcpy(m->options, magic_cookie, sizeof(magic_cookie));
|
---|
175 | }
|
---|
176 | /*---------------------------------------------------------------------------*/
|
---|
177 | static void
|
---|
178 | send_discover(struct dhcpc_state *s)
|
---|
179 | {
|
---|
180 | u8_t *end;
|
---|
181 | struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
|
---|
182 |
|
---|
183 | create_msg(s, m);
|
---|
184 |
|
---|
185 | end = add_msg_type(&m->options[4], DHCPDISCOVER);
|
---|
186 | end = add_req_options(end);
|
---|
187 | end = add_end(end);
|
---|
188 |
|
---|
189 | uip_send(uip_appdata, end - (u8_t *)uip_appdata);
|
---|
190 | }
|
---|
191 | /*---------------------------------------------------------------------------*/
|
---|
192 | static void
|
---|
193 | send_request(struct dhcpc_state *s)
|
---|
194 | {
|
---|
195 | u8_t *end;
|
---|
196 | struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
|
---|
197 |
|
---|
198 | create_msg(s, m);
|
---|
199 |
|
---|
200 | end = add_msg_type(&m->options[4], DHCPREQUEST);
|
---|
201 | end = add_server_id(s, end);
|
---|
202 | end = add_req_ipaddr(s, end);
|
---|
203 | end = add_end(end);
|
---|
204 |
|
---|
205 | uip_send(uip_appdata, end - (u8_t *)uip_appdata);
|
---|
206 | }
|
---|
207 | /*---------------------------------------------------------------------------*/
|
---|
208 | static u8_t
|
---|
209 | parse_options(struct dhcpc_state *s, u8_t *optptr, int len)
|
---|
210 | {
|
---|
211 | u8_t *end = optptr + len;
|
---|
212 | u8_t type = 0;
|
---|
213 |
|
---|
214 | while(optptr < end) {
|
---|
215 | switch(*optptr) {
|
---|
216 | case DHCP_OPTION_SUBNET_MASK:
|
---|
217 | memcpy(s->netmask, optptr + 2, 4);
|
---|
218 | break;
|
---|
219 | case DHCP_OPTION_ROUTER:
|
---|
220 | memcpy(s->default_router, optptr + 2, 4);
|
---|
221 | break;
|
---|
222 | case DHCP_OPTION_DNS_SERVER:
|
---|
223 | memcpy(s->dnsaddr, optptr + 2, 4);
|
---|
224 | break;
|
---|
225 | case DHCP_OPTION_MSG_TYPE:
|
---|
226 | type = *(optptr + 2);
|
---|
227 | break;
|
---|
228 | case DHCP_OPTION_SERVER_ID:
|
---|
229 | memcpy(s->serverid, optptr + 2, 4);
|
---|
230 | break;
|
---|
231 | case DHCP_OPTION_LEASE_TIME:
|
---|
232 | memcpy(s->lease_time, optptr + 2, 4);
|
---|
233 | break;
|
---|
234 | case DHCP_OPTION_END:
|
---|
235 | return type;
|
---|
236 | }
|
---|
237 |
|
---|
238 | optptr += optptr[1] + 2;
|
---|
239 | }
|
---|
240 | return type;
|
---|
241 | }
|
---|
242 | /*---------------------------------------------------------------------------*/
|
---|
243 | static u8_t
|
---|
244 | parse_msg(struct dhcpc_state *s)
|
---|
245 | {
|
---|
246 | struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
|
---|
247 |
|
---|
248 | if(m->op == DHCP_REPLY &&
|
---|
249 | memcmp(m->xid, xid, sizeof(xid)) == 0 &&
|
---|
250 | memcmp(m->chaddr, s->mac_addr, s->mac_len) == 0) {
|
---|
251 | memcpy(s->ipaddr, m->yiaddr, 4);
|
---|
252 | return parse_options(s, &m->options[4], uip_datalen());
|
---|
253 | }
|
---|
254 | return 0;
|
---|
255 | }
|
---|
256 | /*---------------------------------------------------------------------------*/
|
---|
257 | static
|
---|
258 | PT_THREAD(handle_dhcp(struct dhcpc_state *s))
|
---|
259 | {
|
---|
260 | int ret;
|
---|
261 | PT_BEGIN(&s->pt);
|
---|
262 |
|
---|
263 | /* try_again:*/
|
---|
264 | s->state = STATE_SENDING;
|
---|
265 | s->ticks = 5 * CLOCK_SECOND;
|
---|
266 |
|
---|
267 | send_discover(s);
|
---|
268 | timer_set(&s->timer, s->ticks);
|
---|
269 |
|
---|
270 | do {
|
---|
271 | PT_WAIT_UNTIL(&s->pt, (ret = uip_newdata() ? 1 : (timer_expired(&s->timer) ? 2 : 0)) != 0);
|
---|
272 |
|
---|
273 | if((ret == 1) && parse_msg(s) == DHCPOFFER) {
|
---|
274 | s->state = STATE_OFFER_RECEIVED;
|
---|
275 | break;
|
---|
276 | }
|
---|
277 | if(ret != 2)
|
---|
278 | continue;
|
---|
279 |
|
---|
280 | if(s->ticks < CLOCK_SECOND * 60) {
|
---|
281 | s->ticks += CLOCK_SECOND;
|
---|
282 | }
|
---|
283 | timer_set(&s->timer, s->ticks);
|
---|
284 | } while(s->state != STATE_OFFER_RECEIVED);
|
---|
285 |
|
---|
286 | s->ticks = CLOCK_SECOND;
|
---|
287 |
|
---|
288 | PT_YIELD(&s->pt);
|
---|
289 |
|
---|
290 | send_request(s);
|
---|
291 | timer_set(&s->timer, s->ticks);
|
---|
292 |
|
---|
293 | do {
|
---|
294 | PT_WAIT_UNTIL(&s->pt, (ret = uip_newdata() ? 1 : (timer_expired(&s->timer) ? 2 : 0)) != 0);
|
---|
295 |
|
---|
296 | if((ret == 1) && parse_msg(s) == DHCPACK) {
|
---|
297 | s->state = STATE_CONFIG_RECEIVED;
|
---|
298 | break;
|
---|
299 | }
|
---|
300 | if(ret != 2)
|
---|
301 | continue;
|
---|
302 |
|
---|
303 | if(s->ticks <= CLOCK_SECOND * 60) {
|
---|
304 | s->ticks += CLOCK_SECOND;
|
---|
305 | timer_set(&s->timer, s->ticks);
|
---|
306 | } else {
|
---|
307 | PT_RESTART(&s->pt);
|
---|
308 | }
|
---|
309 | } while(s->state != STATE_CONFIG_RECEIVED);
|
---|
310 |
|
---|
311 | #if 0
|
---|
312 | printf("Got IP address %d.%d.%d.%d\n",
|
---|
313 | uip_ipaddr1(s->ipaddr), uip_ipaddr2(s->ipaddr),
|
---|
314 | uip_ipaddr3(s->ipaddr), uip_ipaddr4(s->ipaddr));
|
---|
315 | printf("Got netmask %d.%d.%d.%d\n",
|
---|
316 | uip_ipaddr1(s->netmask), uip_ipaddr2(s->netmask),
|
---|
317 | uip_ipaddr3(s->netmask), uip_ipaddr4(s->netmask));
|
---|
318 | printf("Got DNS server %d.%d.%d.%d\n",
|
---|
319 | uip_ipaddr1(s->dnsaddr), uip_ipaddr2(s->dnsaddr),
|
---|
320 | uip_ipaddr3(s->dnsaddr), uip_ipaddr4(s->dnsaddr));
|
---|
321 | printf("Got default router %d.%d.%d.%d\n",
|
---|
322 | uip_ipaddr1(s->default_router), uip_ipaddr2(s->default_router),
|
---|
323 | uip_ipaddr3(s->default_router), uip_ipaddr4(s->default_router));
|
---|
324 | printf("Lease expires in %ld seconds\n",
|
---|
325 | ntohs(s->lease_time[0])*65536ul + ntohs(s->lease_time[1]));
|
---|
326 | #endif
|
---|
327 |
|
---|
328 | dhcpc_configured(s);
|
---|
329 |
|
---|
330 | /* timer_stop(&s->timer);*/
|
---|
331 |
|
---|
332 | /*
|
---|
333 | * PT_END restarts the thread so we do this instead. Eventually we
|
---|
334 | * should reacquire expired leases here.
|
---|
335 | */
|
---|
336 | while(1) {
|
---|
337 | PT_YIELD(&s->pt);
|
---|
338 | if(s->state == STATE_INITIAL)
|
---|
339 | PT_RESTART(&s->pt);
|
---|
340 | }
|
---|
341 |
|
---|
342 | PT_END(&s->pt);
|
---|
343 | }
|
---|
344 | /*---------------------------------------------------------------------------*/
|
---|
345 | struct dhcpc_state *
|
---|
346 | dhcpc_init(const void *mac_addr, int mac_len)
|
---|
347 | {
|
---|
348 | struct uip_udp_conn *conn;
|
---|
349 | struct dhcpc_state *s;
|
---|
350 | uip_ipaddr_t addr;
|
---|
351 |
|
---|
352 | uip_ipaddr(addr, 255,255,255,255);
|
---|
353 | conn = uip_udp_new(&addr, HTONS(DHCPC_SERVER_PORT));
|
---|
354 | if(conn != NULL) {
|
---|
355 | s = &conn->appstate.parblk.dhcpc;
|
---|
356 | s->conn = conn;
|
---|
357 | s->mac_addr = mac_addr;
|
---|
358 | s->mac_len = mac_len;
|
---|
359 |
|
---|
360 | s->state = STATE_INITIAL;
|
---|
361 | s->conn->appstate.udp_callback = dhcpc_appcall;
|
---|
362 |
|
---|
363 | uip_udp_bind(conn, HTONS(DHCPC_CLIENT_PORT));
|
---|
364 |
|
---|
365 | PT_INIT(&s->pt);
|
---|
366 |
|
---|
367 | return s;
|
---|
368 | }
|
---|
369 |
|
---|
370 | return NULL;
|
---|
371 | }
|
---|
372 | /*---------------------------------------------------------------------------*/
|
---|
373 | void
|
---|
374 | dhcpc_appcall(struct uip_udp_conn *uip_udp_conn, int fncd, void *p_parblk)
|
---|
375 | {
|
---|
376 | handle_dhcp((struct dhcpc_state *)p_parblk);
|
---|
377 | }
|
---|
378 | /*---------------------------------------------------------------------------*/
|
---|
379 | void
|
---|
380 | dhcpc_request(struct dhcpc_state *s)
|
---|
381 | {
|
---|
382 | u16_t ipaddr[2];
|
---|
383 |
|
---|
384 | s->state = STATE_INITIAL;
|
---|
385 | uip_ipaddr(ipaddr, 0,0,0,0);
|
---|
386 | uip_sethostaddr(ipaddr);
|
---|
387 | uip_udp_conn = s->conn;
|
---|
388 | uip_process(UIP_UDP_TIMER);
|
---|
389 | }
|
---|
390 | /*---------------------------------------------------------------------------*/
|
---|