blob: 932f1f7e1f0c247944354313dc7554c1fe6c0cad [file] [log] [blame]
adamdunkelse33d4372004-09-17 20:41:30 +00001
2#include "contiki.h"
3#include "dhcpc.h"
4#include "uip_arp.h"
5#include "pt.h"
6
7#include <string.h>
8
9#define STATE_INITIAL 0
10#define STATE_SENDING 1
11#define STATE_OFFER_RECEIVED 2
12#define STATE_CONFIG_RECEIVED 3
13
14static struct {
15 struct pt pt;
16 char state;
17 struct uip_udp_conn *conn;
18 struct timer timer;
19 u16_t secs;
20
21 u8_t serverid[4];
22
23 u16_t ipaddr[2];
24 u16_t netmask[2];
25 u16_t dnsaddr[2];
26 u16_t default_router[2];
27} s;
28
29struct dhcp_msg {
30 u8_t op, htype, hlen, hops;
31 u8_t xid[4];
32 u16_t secs, flags;
33 u8_t ciaddr[4];
34 u8_t yiaddr[4];
35 u8_t siaddr[4];
36 u8_t giaddr[4];
37 u8_t chaddr[16];
38 u8_t sname[64];
39 u8_t file[128];
40 u8_t options[312];
41};
42#define DHCP_REQUEST 1
43#define DHCP_REPLY 2
44#define DHCP_HTYPE_ETHERNET 1
45#define DHCP_HLEN_ETHERNET 6
46#define DHCP_MSG_LEN 236
47
48#define DHCPC_SERVER_PORT 67
49#define DHCPC_CLIENT_PORT 68
50
51#define DHCPDISCOVER 1
52#define DHCPOFFER 2
53#define DHCPREQUEST 3
54#define DHCPDECLINE 4
55#define DHCPACK 5
56#define DHCPNAK 6
57#define DHCPRELEASE 7
58
59#define DHCP_OPTION_SUBNET_MASK 1
60#define DHCP_OPTION_ROUTER 3
61#define DHCP_OPTION_DNS_SERVER 6
62#define DHCP_OPTION_REQ_IPADDR 50
63#define DHCP_OPTION_MSG_TYPE 53
64#define DHCP_OPTION_SERVER_ID 54
adamdunkelsced5f972004-09-18 20:15:45 +000065#define DHCP_OPTION_REQ_LIST 55
adamdunkelse33d4372004-09-17 20:41:30 +000066#define DHCP_OPTION_END 255
67
adamdunkelsced5f972004-09-18 20:15:45 +000068static const u8_t xid[4] = {0xad, 0xde, 0x12, 0x23};
adamdunkelse33d4372004-09-17 20:41:30 +000069static const u8_t magic_cookie[4] = {99, 130, 83, 99};
70/*---------------------------------------------------------------------------*/
71static u8_t *
72add_msg_type(u8_t *optptr, u8_t type)
73{
74 *optptr++ = DHCP_OPTION_MSG_TYPE;
75 *optptr++ = 1;
76 *optptr++ = type;
77 return optptr;
78}
79/*---------------------------------------------------------------------------*/
80static u8_t *
81add_server_id(u8_t *optptr)
82{
83 *optptr++ = DHCP_OPTION_SERVER_ID;
84 *optptr++ = 4;
85 memcpy(optptr, s.serverid, 4);
86 return optptr + 4;
87}
88/*---------------------------------------------------------------------------*/
89static u8_t *
90add_req_ipaddr(u8_t *optptr)
91{
92 *optptr++ = DHCP_OPTION_REQ_IPADDR;
93 *optptr++ = 4;
94 memcpy(optptr, s.ipaddr, 4);
95 return optptr + 4;
96}
97/*---------------------------------------------------------------------------*/
98static u8_t *
adamdunkelsced5f972004-09-18 20:15:45 +000099add_req_options(u8_t *optptr)
100{
101 *optptr++ = DHCP_OPTION_REQ_LIST;
102 *optptr++ = 3;
103 *optptr++ = DHCP_OPTION_SUBNET_MASK;
104 *optptr++ = DHCP_OPTION_ROUTER;
105 *optptr++ = DHCP_OPTION_DNS_SERVER;
106 return optptr;
107}
108/*---------------------------------------------------------------------------*/
109static u8_t *
adamdunkelse33d4372004-09-17 20:41:30 +0000110add_end(u8_t *optptr)
111{
112 *optptr++ = DHCP_OPTION_END;
113 return optptr;
114}
115/*---------------------------------------------------------------------------*/
116static void
adamdunkelsced5f972004-09-18 20:15:45 +0000117create_msg(register struct dhcp_msg *m)
adamdunkelse33d4372004-09-17 20:41:30 +0000118{
119 m->op = DHCP_REQUEST;
120 m->htype = DHCP_HTYPE_ETHERNET;
121 m->hlen = DHCP_HLEN_ETHERNET;
122 m->hops = 0;
123 memcpy(m->xid, xid, sizeof(m->xid));
124 m->secs = 0;
125 m->flags = 0;
adamdunkelsced5f972004-09-18 20:15:45 +0000126 /* uip_ipaddr_copy(m->ciaddr, uip_hostaddr);*/
127 memcpy(m->ciaddr, uip_hostaddr, sizeof(m->ciaddr));
adamdunkelse33d4372004-09-17 20:41:30 +0000128 memset(m->yiaddr, 0, sizeof(m->yiaddr));
129 memset(m->siaddr, 0, sizeof(m->siaddr));
130 memset(m->giaddr, 0, sizeof(m->giaddr));
131 memcpy(m->chaddr, &uip_ethaddr, 6);
132 memset(&m->chaddr[6], 0, 10);
133 memset(m->sname, 0, sizeof(m->sname));
134 memset(m->file, 0, sizeof(m->file));
135
136 memcpy(m->options, magic_cookie, sizeof(magic_cookie));
137}
138/*---------------------------------------------------------------------------*/
139static void
140send_discover(void)
141{
142 struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
143
144 create_msg(m);
145
adamdunkelsced5f972004-09-18 20:15:45 +0000146 add_end(add_req_options(add_msg_type(&m->options[4], DHCPDISCOVER)));
147
148
adamdunkelse33d4372004-09-17 20:41:30 +0000149 uip_udp_send(300);
150}
151/*---------------------------------------------------------------------------*/
152static void
153send_request(void)
154{
155 struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
156
157 create_msg(m);
158
159 add_end(add_req_ipaddr(add_server_id(add_msg_type(&m->options[4],
160 DHCPREQUEST))));
161
162 uip_udp_send(300);
163}
164/*---------------------------------------------------------------------------*/
165static u8_t
166parse_options(u8_t *optptr, int len)
167{
168 u8_t *optptr2;
169 u8_t type;
170
171 type = 0;
172 optptr2 = NULL;
173
174 while(*optptr != DHCP_OPTION_END) {
175 switch(*optptr) {
176 case DHCP_OPTION_SUBNET_MASK:
177 memcpy(s.netmask, optptr + 2, 4);
178 break;
179 case DHCP_OPTION_ROUTER:
180 memcpy(s.default_router, optptr + 2, 4);
181 break;
182 case DHCP_OPTION_DNS_SERVER:
183 memcpy(s.dnsaddr, optptr + 2, 4);
184 break;
185 case DHCP_OPTION_MSG_TYPE:
186 type = *(optptr + 2);
187 break;
188 case DHCP_OPTION_SERVER_ID:
189 memcpy(s.serverid, optptr + 2, 4);
190 break;
191 }
192
193 /* printf("option type %d len %d\n", *optptr, *(optptr + 1));*/
194 len -= *(optptr + 1) + 2;
195 optptr += *(optptr + 1) + 2;
196 if(len <= 0) {
197 return 0;
198 }
199
200 if(optptr == optptr2) {
201 /* Abort if we don't make progress. */
202 return 0;
203 }
204 }
205 return type;
206}
207/*---------------------------------------------------------------------------*/
208static void
209parse_msg(void)
210{
211 struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
212
adamdunkelsced5f972004-09-18 20:15:45 +0000213 if(m->op == DHCP_REPLY &&
214 memcmp(m->xid, xid, sizeof(xid)) == 0/* &&
215 memcmp(m->chaddr, &uip_ethaddr, sizeof(uip_ethaddr))*/) {
adamdunkelse33d4372004-09-17 20:41:30 +0000216 memcpy(s.ipaddr, m->yiaddr, 4);
217 parse_options(&m->options[4], uip_datalen());
218 }
219}
220/*---------------------------------------------------------------------------*/
221static
222PT_THREAD(handle_dhcp(void))
223{
224 PT_BEGIN(&s.pt);
225
226 PT_WAIT_UNTIL(&s.pt, s.state == STATE_SENDING);
227
228 s.secs = 0;
229 timer_set(&s.timer, CLOCK_SECOND * 2);
230
231 while(s.state != STATE_OFFER_RECEIVED) {
232 send_discover();
233 PT_WAIT_UNTIL(&s.pt, uip_newdata() || timer_expired(&s.timer));
234
235 timer_reset(&s.timer);
236
237 if(uip_newdata()) {
238 parse_msg();
239 s.state = STATE_OFFER_RECEIVED;
240 }
241 ++s.secs;
242 }
243
244 while(s.state != STATE_CONFIG_RECEIVED) {
245
246 send_request();
247
248 PT_WAIT_UNTIL(&s.pt, uip_newdata() || timer_expired(&s.timer));
249
250 timer_reset(&s.timer);
251
252 if(uip_newdata()) {
253 s.state = STATE_CONFIG_RECEIVED;
254 }
255 ++s.secs;
256 }
257
258 /* printf("Got IP address %d.%d.%d.%d\n",
259 uip_ipaddr1(s.ipaddr), uip_ipaddr2(s.ipaddr),
260 uip_ipaddr3(s.ipaddr), uip_ipaddr4(s.ipaddr));
261 printf("Got netmask %d.%d.%d.%d\n",
262 uip_ipaddr1(s.netmask), uip_ipaddr2(s.netmask),
263 uip_ipaddr3(s.netmask), uip_ipaddr4(s.netmask));
264 printf("Got DNS server %d.%d.%d.%d\n",
265 uip_ipaddr1(s.dnsaddr), uip_ipaddr2(s.dnsaddr),
266 uip_ipaddr3(s.dnsaddr), uip_ipaddr4(s.dnsaddr));
267 printf("Got default router %d.%d.%d.%d\n",
268 uip_ipaddr1(s.default_router), uip_ipaddr2(s.default_router),
269 uip_ipaddr3(s.default_router), uip_ipaddr4(s.default_router));*/
270
271 uip_sethostaddr(s.ipaddr);
272 uip_setnetmask(s.netmask);
273 uip_setdraddr(s.default_router);
274 resolv_conf(s.dnsaddr);
275 dhcpc_configured();
276
277 PT_END(&s.pt);
278}
279/*---------------------------------------------------------------------------*/
280void
281dhcpc_init(void)
282{
283 u16_t addr[2];
284
285 s.state = STATE_INITIAL;
286 uip_ipaddr(addr, 255,255,255,255);
287 s.conn = udp_new(addr, HTONS(DHCPC_SERVER_PORT), NULL);
288 if(s.conn != NULL) {
289 udp_bind(s.conn, HTONS(DHCPC_CLIENT_PORT));
290 }
291 PT_INIT(&s.pt);
292}
293/*---------------------------------------------------------------------------*/
294void
295dhcpc_appcall(void *state)
296{
297 handle_dhcp();
298}
299/*---------------------------------------------------------------------------*/
300void
301dhcpc_request(void)
302{
303 u16_t ipaddr[2];
304
305 if(s.state == STATE_INITIAL) {
306 uip_ipaddr(ipaddr, 0,0,0,0);
307 uip_sethostaddr(ipaddr);
308 s.state = STATE_SENDING;
309 tcpip_poll_udp(s.conn);
310 }
311}
312/*---------------------------------------------------------------------------*/