2 * Copyright (c) 2005, Swedish Institute of Computer Science
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
29 * This file is part of the uIP TCP/IP stack
31 * @(#)$Id: dhcpc.c,v 1.2 2006/06/11 21:46:37 adam Exp $
44 #define STATE_INITIAL 0
45 #define STATE_SENDING 1
46 #define STATE_OFFER_RECEIVED 2
47 #define STATE_CONFIG_RECEIVED 3
49 #define ntohl(a) ((((a) >> 24) & 0x000000FF) | (((a) >> 8) & 0x0000FF00) | (((a) << 8) & 0x00FF0000) | (((a) << 24) & 0xFF000000))
50 static struct dhcpc_state s
__attribute__ ((section ("AHBSRAM1")));
51 //#define UIP_CONF_DHCP_LIGHT
54 u8_t op
, htype
, hlen
, hops
;
62 #ifndef UIP_CONF_DHCP_LIGHT
69 #define BOOTP_BROADCAST 0x8000
71 #define DHCP_REQUEST 1
73 #define DHCP_HTYPE_ETHERNET 1
74 #define DHCP_HLEN_ETHERNET 6
75 #define DHCP_MSG_LEN 236
77 #define DHCPC_SERVER_PORT 67
78 #define DHCPC_CLIENT_PORT 68
80 #define DHCPDISCOVER 1
88 #define DHCP_OPTION_SUBNET_MASK 1
89 #define DHCP_OPTION_ROUTER 3
90 #define DHCP_OPTION_DNS_SERVER 6
91 #define DHCP_OPTION_HOSTNAME 12
92 #define DHCP_OPTION_REQ_IPADDR 50
93 #define DHCP_OPTION_LEASE_TIME 51
94 #define DHCP_OPTION_MSG_TYPE 53
95 #define DHCP_OPTION_SERVER_ID 54
96 #define DHCP_OPTION_REQ_LIST 55
97 #define DHCP_OPTION_END 255
99 static uint32_t xid
= 0x00112233;
101 static const u8_t magic_cookie
[4] = {99, 130, 83, 99};
102 /*---------------------------------------------------------------------------*/
104 add_msg_type(u8_t
*optptr
, u8_t type
)
106 *optptr
++ = DHCP_OPTION_MSG_TYPE
;
111 /*---------------------------------------------------------------------------*/
113 add_server_id(u8_t
*optptr
)
115 *optptr
++ = DHCP_OPTION_SERVER_ID
;
117 memcpy(optptr
, &s
.serverid
, 4);
120 /*---------------------------------------------------------------------------*/
122 add_req_ipaddr(u8_t
*optptr
)
124 *optptr
++ = DHCP_OPTION_REQ_IPADDR
;
126 memcpy(optptr
, &s
.ipaddr
, 4);
129 /*---------------------------------------------------------------------------*/
131 add_hostname(u8_t
*optptr
)
133 if (s
.hostname
== NULL
) {
136 const u8_t l
= strlen(s
.hostname
);
137 *optptr
++ = DHCP_OPTION_HOSTNAME
;
139 memcpy(optptr
, s
.hostname
, l
);
142 /*---------------------------------------------------------------------------*/
144 add_req_options(u8_t
*optptr
)
146 *optptr
++ = DHCP_OPTION_REQ_LIST
;
147 *optptr
++ = s
.hostname
== NULL
? 3 : 4;
148 *optptr
++ = DHCP_OPTION_SUBNET_MASK
;
149 *optptr
++ = DHCP_OPTION_ROUTER
;
150 *optptr
++ = DHCP_OPTION_DNS_SERVER
;
151 if (s
.hostname
!= NULL
) {
152 *optptr
++ = DHCP_OPTION_HOSTNAME
;
156 /*---------------------------------------------------------------------------*/
158 add_end(u8_t
*optptr
)
160 *optptr
++ = DHCP_OPTION_END
;
163 /*---------------------------------------------------------------------------*/
165 create_msg(register struct dhcp_msg
*m
, int rea
)
167 m
->op
= DHCP_REQUEST
;
168 m
->htype
= DHCP_HTYPE_ETHERNET
;
171 memcpy(m
->xid
, &xid
, sizeof(m
->xid
));
173 m
->flags
= HTONS(BOOTP_BROADCAST
); /* Broadcast bit. */
174 /* uip_ipaddr_copy(m->ciaddr, uip_hostaddr);*/
175 if(rea
== 0 ) memcpy(m
->ciaddr
, uip_hostaddr
, sizeof(m
->ciaddr
));
176 else memset(m
->ciaddr
, 0, sizeof(m
->ciaddr
));
177 memset(m
->yiaddr
, 0, sizeof(m
->yiaddr
));
178 memset(m
->siaddr
, 0, sizeof(m
->siaddr
));
179 memset(m
->giaddr
, 0, sizeof(m
->giaddr
));
180 memcpy(m
->chaddr
, s
.mac_addr
, s
.mac_len
);
181 memset(&m
->chaddr
[s
.mac_len
], 0, sizeof(m
->chaddr
) - s
.mac_len
);
182 #ifndef UIP_CONF_DHCP_LIGHT
183 memset(m
->sname
, 0, sizeof(m
->sname
));
184 memset(m
->file
, 0, sizeof(m
->file
));
187 memcpy(m
->options
, magic_cookie
, sizeof(magic_cookie
));
189 /*---------------------------------------------------------------------------*/
194 struct dhcp_msg
*m
= (struct dhcp_msg
*)uip_appdata
;
198 end
= add_msg_type(&m
->options
[4], DHCPDISCOVER
);
199 end
= add_req_options(end
);
202 uip_send(uip_appdata
, end
- (u8_t
*)uip_appdata
);
204 /*---------------------------------------------------------------------------*/
206 send_request(int rea
)
209 struct dhcp_msg
*m
= (struct dhcp_msg
*)uip_appdata
;
213 end
= add_msg_type(&m
->options
[4], DHCPREQUEST
);
214 end
= add_server_id(end
);
215 end
= add_req_ipaddr(end
);
216 end
= add_hostname(end
);
219 uip_send(uip_appdata
, end
- (u8_t
*)uip_appdata
);
221 /*---------------------------------------------------------------------------*/
223 parse_options(u8_t
*optptr
, int len
)
225 u8_t
*end
= optptr
+ len
;
228 while (optptr
< end
) {
230 case DHCP_OPTION_SUBNET_MASK
:
231 memcpy(&s
.netmask
, optptr
+ 2, 4);
233 case DHCP_OPTION_ROUTER
:
234 memcpy(&s
.default_router
, optptr
+ 2, 4);
236 case DHCP_OPTION_DNS_SERVER
:
237 memcpy(&s
.dnsaddr
, optptr
+ 2, 4);
239 case DHCP_OPTION_MSG_TYPE
:
240 type
= *(optptr
+ 2);
242 case DHCP_OPTION_SERVER_ID
:
243 memcpy(s
.serverid
, optptr
+ 2, 4);
245 case DHCP_OPTION_LEASE_TIME
:
246 memcpy(&s
.lease_time
, optptr
+ 2, 4);
248 case DHCP_OPTION_END
:
252 optptr
+= optptr
[1] + 2;
256 /*---------------------------------------------------------------------------*/
260 struct dhcp_msg
*m
= (struct dhcp_msg
*)uip_appdata
;
262 if (m
->op
== DHCP_REPLY
&&
263 memcmp(m
->xid
, &xid
, sizeof(xid
)) == 0 &&
264 memcmp(m
->chaddr
, s
.mac_addr
, s
.mac_len
) == 0) {
265 memcpy(&s
.ipaddr
, m
->yiaddr
, 4);
266 return parse_options(&m
->options
[4], uip_datalen());
270 /*---------------------------------------------------------------------------*/
272 PT_THREAD(handle_dhcp(void))
277 s
.state
= STATE_SENDING
;
278 s
.ticks
= CLOCK_SECOND
;
283 timer_set(&s
.timer
, s
.ticks
);
284 PT_WAIT_UNTIL(&s
.pt
, uip_newdata() || timer_expired(&s
.timer
));
285 // if we timed out then increase time out and send discover again
286 if (timer_expired(&s
.timer
)) {
287 if (s
.ticks
< CLOCK_SECOND
* 60) {
292 // we may have gotten some other UDP packet in which case just wait some more for the right packet
293 if (uip_newdata() && parse_msg() == DHCPOFFER
) {
294 s
.state
= STATE_OFFER_RECEIVED
;
300 } while (s
.state
!= STATE_OFFER_RECEIVED
);
302 s
.ticks
= CLOCK_SECOND
;
307 timer_set(&s
.timer
, s
.ticks
);
308 PT_WAIT_UNTIL(&s
.pt
, uip_newdata() || timer_expired(&s
.timer
));
310 if (timer_expired(&s
.timer
)) {
311 if (s
.ticks
<= CLOCK_SECOND
* 10) {
312 s
.ticks
+= CLOCK_SECOND
;
313 send_request(0); // resend only on timeout
318 if (uip_newdata() && parse_msg() == DHCPACK
) {
319 s
.state
= STATE_CONFIG_RECEIVED
;
325 } while (s
.state
!= STATE_CONFIG_RECEIVED
);
327 dhcpc_configured(&s
);
329 // now we wait for close to expiration and renew the lease
331 // we should reacquire expired leases here.
332 timer_set(&s
.timer
, (ntohl(s
.lease_time
) * 0.5)*CLOCK_SECOND
); // half of lease expire time
333 PT_WAIT_UNTIL(&s
.pt
, timer_expired(&s
.timer
));
335 uip_log("reaquire dhcp lease");
337 // spec says send request direct to server that gave it to us, but seems to be unecessary
338 //uip_ipaddr_copy(&s.conn->ripaddr, s.serverid);
340 s
.ticks
= CLOCK_SECOND
;
344 timer_set(&s
.timer
, s
.ticks
);
345 PT_WAIT_UNTIL(&s
.pt
, uip_newdata() || timer_expired(&s
.timer
));
347 if (timer_expired(&s
.timer
)) {
348 if (s
.ticks
<= CLOCK_SECOND
* 10) {
349 s
.ticks
+= CLOCK_SECOND
;
350 send_request(0); // resend only on timeout
353 // TODO probably need to deal with upstream apps and stop them then reinit them
357 if (parse_msg() == DHCPACK
) {
358 uip_log("dhcp lease renewed");
369 /*---------------------------------------------------------------------------*/
371 dhcpc_init(const void *mac_addr
, int mac_len
, char *hostname
)
375 s
.mac_addr
= mac_addr
;
377 s
.hostname
= hostname
;
379 s
.state
= STATE_INITIAL
;
380 uip_ipaddr(addr
, 255, 255, 255, 255);
381 s
.conn
= uip_udp_new(&addr
, HTONS(DHCPC_SERVER_PORT
));
382 if (s
.conn
!= NULL
) {
383 uip_udp_bind(s
.conn
, HTONS(DHCPC_CLIENT_PORT
));
387 /*---------------------------------------------------------------------------*/
393 /*---------------------------------------------------------------------------*/
399 if (s
.state
== STATE_INITIAL
) {
400 uip_ipaddr(ipaddr
, 0, 0, 0, 0);
401 uip_sethostaddr(ipaddr
);
402 /* handle_dhcp(PROCESS_EVENT_NONE, NULL);*/
405 /*---------------------------------------------------------------------------*/