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