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