Stefan Schuermans commited on 2012-04-04 22:27:47
Showing 5 changed files, with 544 additions and 4 deletions.
... | ... |
@@ -2,15 +2,26 @@ |
2 | 2 |
#include "macros.h" |
3 | 3 |
#include "nethelp.h" |
4 | 4 |
|
5 |
-// MAC address |
|
5 |
+/// MAC address |
|
6 | 6 |
/* extern */ struct config_mac config_mac = { |
7 | 7 |
.mac = { 0x02, 0x4D, 0x49, 0x50, 0x53, 0x01 } |
8 | 8 |
}; |
9 | 9 |
|
10 |
-// IP configuration |
|
10 |
+/** |
|
11 |
+ * @brief IP configuration |
|
12 |
+ * |
|
13 |
+ * fill with meaningful data for static configuration |
|
14 |
+ * or fill with zeros for DHCP |
|
15 |
+ */ |
|
11 | 16 |
/* extern */ struct config_ip config_ip = { |
17 |
+#if 0 |
|
12 | 18 |
.ip = { 192, 168, 0, 89 }, |
13 | 19 |
.mask = { 255, 255, 255, 0 }, |
14 | 20 |
.gw = { 192, 168, 0, 1 } |
21 |
+#else |
|
22 |
+ .ip = { 0, 0, 0, 0 }, |
|
23 |
+ .mask = { 0, 0, 0, 0 }, |
|
24 |
+ .gw = { 0, 0, 0, 0 } |
|
25 |
+#endif |
|
15 | 26 |
}; |
16 | 27 |
|
... | ... |
@@ -0,0 +1,476 @@ |
1 |
+#include "config.h" |
|
2 |
+#include "checksum.h" |
|
3 |
+#include "dhcp.h" |
|
4 |
+#include "ethernet.h" |
|
5 |
+#include "ip.h" |
|
6 |
+#include "macros.h" |
|
7 |
+#include "memcpy.h" |
|
8 |
+#include "nethelp.h" |
|
9 |
+#include "random.h" |
|
10 |
+#include "udp.h" |
|
11 |
+ |
|
12 |
+/// configuration |
|
13 |
+//@{ |
|
14 |
+/// avarage timeout after which to retry DHCP action |
|
15 |
+static const unsigned char dhcp_retry_secs_max = 10; |
|
16 |
+/// maximum number of retries before aborting DHCP action |
|
17 |
+static const unsigned char dhcp_retries_max = 5; |
|
18 |
+/// when to ask to extend lease |
|
19 |
+static const unsigned long dhcp_lease_rest_min = 300; |
|
20 |
+/// to renw lease when only this fraction of lease is left |
|
21 |
+static const unsigned char dhcp_lease_renew_fraction = 8; |
|
22 |
+//@} |
|
23 |
+ |
|
24 |
+/// DHCP tick counter to get full seconds |
|
25 |
+static unsigned char dhcp_ticks = 0; |
|
26 |
+ |
|
27 |
+/// time of current DHCP action |
|
28 |
+//@{ |
|
29 |
+static unsigned char dhcp_in_progress = 0; ///< if DHCP action is in progress |
|
30 |
+static unsigned char dhcp_retries = 0; ///< number of retries left |
|
31 |
+static unsigned char dhcp_retry_secs = 0; ///< rest of time for current retry |
|
32 |
+//@} |
|
33 |
+ |
|
34 |
+/// current x_id |
|
35 |
+//@{ |
|
36 |
+static unsigned char dhcp_have_x_id = 0; ///< if an x_id exists at the moment |
|
37 |
+static unsigned long dhcp_x_id = 0; ///< the current x_id data |
|
38 |
+static unsigned short dhcp_x_id_secs = 0; ///< time of x_id |
|
39 |
+//@} |
|
40 |
+ |
|
41 |
+/// DHCP server and lease time |
|
42 |
+//@{ |
|
43 |
+static unsigned char dhcp_active = 0; ///< if own IP is leased from DHCP |
|
44 |
+static unsigned char dhcp_server[4]; /**< IP address of DHCP server |
|
45 |
+ own IP is leased from */ |
|
46 |
+static unsigned long dhcp_lease_time = 0; ///< total lease time |
|
47 |
+static unsigned long dhcp_lease_rest = 0; ///< rest of lease time |
|
48 |
+//@} |
|
49 |
+ |
|
50 |
+/** |
|
51 |
+ * @brief send a DHCP packet |
|
52 |
+ * @param[in] ptr pointer to data of packet |
|
53 |
+ * @param[in] sz size of packet |
|
54 |
+ * |
|
55 |
+ * ptr must point to a dhcp_packet |
|
56 |
+ * with ip_hdr.dest, dhcp_hdr.x_id, dhcp_hdr.secs, dhcp_hdr.flags |
|
57 |
+ * and dhcp_hdr.yi_addr already initialized |
|
58 |
+ */ |
|
59 |
+static void dhcp_send(void *ptr, unsigned int sz) |
|
60 |
+{ |
|
61 |
+ struct dhcp_packet *p_dhcp_pack; |
|
62 |
+ |
|
63 |
+ // packet too short |
|
64 |
+ if (sz < sizeof(struct dhcp_packet)) |
|
65 |
+ return; |
|
66 |
+ |
|
67 |
+ p_dhcp_pack = ptr; |
|
68 |
+ |
|
69 |
+ // we are DHCP client |
|
70 |
+ // - source port must be 68 |
|
71 |
+ // - destination port must be 67 |
|
72 |
+ p_dhcp_pack->udp_hdr.src_port = htons(68); |
|
73 |
+ p_dhcp_pack->udp_hdr.dest_port = htons(67); |
|
74 |
+ // set up DHCP header fields as client |
|
75 |
+ p_dhcp_pack->dhcp_hdr.op = 1; |
|
76 |
+ p_dhcp_pack->dhcp_hdr.h_type = 1; |
|
77 |
+ p_dhcp_pack->dhcp_hdr.h_len = 6; |
|
78 |
+ p_dhcp_pack->dhcp_hdr.h_ops = 0; |
|
79 |
+ memset(p_dhcp_pack->dhcp_hdr.ci_addr, 0, 4); |
|
80 |
+ memset(p_dhcp_pack->dhcp_hdr.si_addr, 0, 4); |
|
81 |
+ memset(p_dhcp_pack->dhcp_hdr.gi_addr, 0, 4); |
|
82 |
+ mac_cpy(p_dhcp_pack->dhcp_hdr.ch_addr, config_mac.mac); |
|
83 |
+ memset(p_dhcp_pack->dhcp_hdr.ch_addr + 6, 0, 10); |
|
84 |
+ memset(p_dhcp_pack->dhcp_hdr.s_name, 0, 64); |
|
85 |
+ memset(p_dhcp_pack->dhcp_hdr.file, 0, 128); |
|
86 |
+ p_dhcp_pack->dhcp_hdr.m_cookie = htonl(0x63825363); |
|
87 |
+ |
|
88 |
+ // send DHCP packet |
|
89 |
+ udp_send(ptr, sz); |
|
90 |
+} |
|
91 |
+ |
|
92 |
+/// send a DHCP discover packet |
|
93 |
+static void dhcp_discover(void) |
|
94 |
+{ |
|
95 |
+ struct { |
|
96 |
+ struct dhcp_packet dhcp_pack; |
|
97 |
+ unsigned char opt_type[3]; |
|
98 |
+ unsigned char opt_end[2]; |
|
99 |
+ } __attribute__((packed)) dhcp_discover; |
|
100 |
+ |
|
101 |
+ ip_cpy(dhcp_discover.dhcp_pack.ip_hdr.dest, "\xFF\xFF\xFF\xFF"); // broadcast |
|
102 |
+ dhcp_discover.dhcp_pack.dhcp_hdr.x_id = htonl(dhcp_x_id); |
|
103 |
+ dhcp_discover.dhcp_pack.dhcp_hdr.secs = htons(dhcp_x_id_secs); // x_id time |
|
104 |
+ dhcp_discover.dhcp_pack.dhcp_hdr.flags = htons(0x8000); // broadcast |
|
105 |
+ memset(dhcp_discover.dhcp_pack.dhcp_hdr.yi_addr, 0, 4); |
|
106 |
+ dhcp_discover.opt_type[0] = 0x35; // DHCP discover |
|
107 |
+ dhcp_discover.opt_type[1] = 0x01; |
|
108 |
+ dhcp_discover.opt_type[2] = 0x01; |
|
109 |
+ dhcp_discover.opt_end[0] = 0xFF; // end of options |
|
110 |
+ dhcp_discover.opt_end[1] = 0x00; |
|
111 |
+ |
|
112 |
+ dhcp_send(&dhcp_discover, sizeof(dhcp_discover)); |
|
113 |
+} |
|
114 |
+ |
|
115 |
+/// send a DHCP request packet |
|
116 |
+static void dhcp_request(void) |
|
117 |
+{ |
|
118 |
+ struct { |
|
119 |
+ struct dhcp_packet dhcp_pack; |
|
120 |
+ unsigned char opt_type[3]; |
|
121 |
+ unsigned char opt_req[6]; |
|
122 |
+ unsigned char opt_server[6]; |
|
123 |
+ unsigned char opt_end[2]; |
|
124 |
+ } __attribute__((packed)) dhcp_request; |
|
125 |
+ |
|
126 |
+ ip_cpy(dhcp_request.dhcp_pack.ip_hdr.dest, dhcp_server); // to DHCP server |
|
127 |
+ dhcp_request.dhcp_pack.dhcp_hdr.x_id = htonl(dhcp_x_id); |
|
128 |
+ dhcp_request.dhcp_pack.dhcp_hdr.secs = htons(dhcp_x_id_secs); // x_id time |
|
129 |
+ dhcp_request.dhcp_pack.dhcp_hdr.flags = htons(0x0000); |
|
130 |
+ ip_cpy(dhcp_request.dhcp_pack.dhcp_hdr.yi_addr, config_ip.ip); |
|
131 |
+ dhcp_request.opt_type[0] = 0x35; // DHCP request |
|
132 |
+ dhcp_request.opt_type[1] = 0x01; |
|
133 |
+ dhcp_request.opt_type[2] = 0x03; |
|
134 |
+ dhcp_request.opt_req[0] = 0x32; // requested IP |
|
135 |
+ dhcp_request.opt_req[1] = 0x04; |
|
136 |
+ ip_cpy(&dhcp_request.opt_req[2], config_ip.ip); |
|
137 |
+ dhcp_request.opt_server[0] = 0x36; // DHCP server |
|
138 |
+ dhcp_request.opt_server[1] = 0x04; |
|
139 |
+ ip_cpy(&dhcp_request.opt_server[2], dhcp_server); |
|
140 |
+ dhcp_request.opt_end[0] = 0xFF; // end of options |
|
141 |
+ dhcp_request.opt_end[1] = 0x00; |
|
142 |
+ |
|
143 |
+ dhcp_send(&dhcp_request, sizeof(dhcp_request)); |
|
144 |
+} |
|
145 |
+ |
|
146 |
+/// abort DHCP action |
|
147 |
+static void dhcp_abort(void) |
|
148 |
+{ |
|
149 |
+ // reset DHCP action status |
|
150 |
+ dhcp_in_progress = 0; |
|
151 |
+ dhcp_retries = 0; |
|
152 |
+ dhcp_retry_secs = 0; |
|
153 |
+ |
|
154 |
+ // forget x_id |
|
155 |
+ dhcp_have_x_id = 0; |
|
156 |
+ dhcp_x_id = 0; |
|
157 |
+ dhcp_x_id_secs = 0; |
|
158 |
+ |
|
159 |
+ // give up IP address if it was leased |
|
160 |
+ if (dhcp_active) { |
|
161 |
+ ip_cpy(config_ip.ip, "\0\0\0\0"); |
|
162 |
+ ip_cpy(config_ip.mask, "\0\0\0\0"); |
|
163 |
+ ip_cpy(config_ip.gw, "\0\0\0\0"); |
|
164 |
+ dhcp_active = 0; |
|
165 |
+ dhcp_lease_time = 0; |
|
166 |
+ dhcp_lease_rest = 0; |
|
167 |
+ } |
|
168 |
+} |
|
169 |
+ |
|
170 |
+/// retry DHCP action |
|
171 |
+static void dhcp_retry(void) |
|
172 |
+{ |
|
173 |
+ // DHCP lease not active ---> re-send DHCP discover |
|
174 |
+ if (! dhcp_active) { |
|
175 |
+ // get time for next try |
|
176 |
+ random_get_data(&dhcp_retry_secs, sizeof(dhcp_retry_secs)); |
|
177 |
+ dhcp_retry_secs = dhcp_retry_secs % dhcp_retry_secs_max + |
|
178 |
+ dhcp_retry_secs_max / 2; |
|
179 |
+ // re-send DHCP discover |
|
180 |
+ dhcp_discover(); |
|
181 |
+ } |
|
182 |
+ |
|
183 |
+ // DHCP lease active and lease time almost over ---> re-send DHCP request |
|
184 |
+ if (dhcp_active && (dhcp_lease_rest < dhcp_lease_rest_min || |
|
185 |
+ dhcp_lease_rest < dhcp_lease_time / |
|
186 |
+ dhcp_lease_renew_fraction)) { |
|
187 |
+ // get time for next try |
|
188 |
+ random_get_data(&dhcp_retry_secs, sizeof(dhcp_retry_secs)); |
|
189 |
+ dhcp_retry_secs = dhcp_retry_secs % dhcp_retry_secs_max + |
|
190 |
+ dhcp_retry_secs_max / 2; |
|
191 |
+ // re-send DHCP request |
|
192 |
+ dhcp_request(); |
|
193 |
+ } |
|
194 |
+} |
|
195 |
+ |
|
196 |
+/// start new DHCP action |
|
197 |
+static void dhcp_start(void) |
|
198 |
+{ |
|
199 |
+ // DHCP lease not active ---> DHCP discover |
|
200 |
+ if (! dhcp_active) { |
|
201 |
+ // DHCP operation starts |
|
202 |
+ dhcp_in_progress = 1; |
|
203 |
+ dhcp_retries = dhcp_retries_max; |
|
204 |
+ random_get_data(&dhcp_retry_secs, sizeof(dhcp_retry_secs)); |
|
205 |
+ dhcp_retry_secs = dhcp_retry_secs % dhcp_retry_secs_max + |
|
206 |
+ dhcp_retry_secs_max / 2; |
|
207 |
+ // get new x_id |
|
208 |
+ random_get_data(&dhcp_x_id, sizeof(dhcp_x_id)); |
|
209 |
+ dhcp_x_id_secs++; |
|
210 |
+ dhcp_have_x_id = 1; |
|
211 |
+ // send DHCP discover |
|
212 |
+ dhcp_discover(); |
|
213 |
+ } |
|
214 |
+ |
|
215 |
+ // DHCP lease active and lease time almost over ---> DHCP request |
|
216 |
+ if (dhcp_active && (dhcp_lease_rest < dhcp_lease_rest_min || |
|
217 |
+ dhcp_lease_rest < dhcp_lease_time / |
|
218 |
+ dhcp_lease_renew_fraction)) { |
|
219 |
+ // DHCP operation starts |
|
220 |
+ dhcp_in_progress = 1; |
|
221 |
+ dhcp_retries = dhcp_retries_max; |
|
222 |
+ random_get_data(&dhcp_retry_secs, sizeof(dhcp_retry_secs)); |
|
223 |
+ dhcp_retry_secs = dhcp_retry_secs % dhcp_retry_secs_max + |
|
224 |
+ dhcp_retry_secs_max / 2; |
|
225 |
+ // get new x_id if none available |
|
226 |
+ if (! dhcp_have_x_id) { |
|
227 |
+ random_get_data(&dhcp_x_id, sizeof(dhcp_x_id)); |
|
228 |
+ dhcp_x_id_secs++; |
|
229 |
+ dhcp_have_x_id = 1; |
|
230 |
+ } |
|
231 |
+ // send DHCP request |
|
232 |
+ dhcp_request(); |
|
233 |
+ } |
|
234 |
+} |
|
235 |
+ |
|
236 |
+/// tick procedure - every 1000ms |
|
237 |
+static void dhcp_tick1000(void) |
|
238 |
+{ |
|
239 |
+ // DHCP operation in progress |
|
240 |
+ if (dhcp_in_progress) { |
|
241 |
+ |
|
242 |
+ // count down time of current try of current action |
|
243 |
+ dhcp_retry_secs--; |
|
244 |
+ if (dhcp_retry_secs <= 0) { |
|
245 |
+ |
|
246 |
+ // count down retries |
|
247 |
+ dhcp_retries--; |
|
248 |
+ |
|
249 |
+ // no more retries left ---> abort, retry otherwise |
|
250 |
+ if (dhcp_retries <= 0) |
|
251 |
+ dhcp_abort(); |
|
252 |
+ else |
|
253 |
+ dhcp_retry(); |
|
254 |
+ |
|
255 |
+ } |
|
256 |
+ |
|
257 |
+ } |
|
258 |
+ |
|
259 |
+ // increase time of x_id |
|
260 |
+ dhcp_x_id_secs++; |
|
261 |
+ |
|
262 |
+ // dcrease remaining lease time |
|
263 |
+ dhcp_lease_rest--; |
|
264 |
+ // lease timed out ---> abort DHCP (will also invalidate IP) |
|
265 |
+ if (dhcp_lease_rest <= 0) |
|
266 |
+ dhcp_abort(); |
|
267 |
+} |
|
268 |
+ |
|
269 |
+/// tick procedure - call every 200ms |
|
270 |
+void dhcp_tick200(void) |
|
271 |
+{ |
|
272 |
+ // get 1 second interval |
|
273 |
+ dhcp_ticks++; |
|
274 |
+ if (dhcp_ticks >= 5) { |
|
275 |
+ dhcp_ticks = 0; |
|
276 |
+ dhcp_tick1000(); |
|
277 |
+ } |
|
278 |
+ |
|
279 |
+ // no DHCP operation in progress |
|
280 |
+ if (! dhcp_in_progress) { |
|
281 |
+ // DHCP lease active or no IP address ---> DHCP allowed (i.e. no static IP) |
|
282 |
+ if (dhcp_active || ip_eq(config_ip.ip, "\0\0\0\0")) { |
|
283 |
+ // start new DHCP action |
|
284 |
+ dhcp_start(); |
|
285 |
+ } |
|
286 |
+ } |
|
287 |
+} |
|
288 |
+ |
|
289 |
+/** |
|
290 |
+ * @brief process a received DHCP offer |
|
291 |
+ * @param[in] addr assigned IP address |
|
292 |
+ * @param[in] mask assigned subnet mask |
|
293 |
+ * @param[in] gateway assigned gateway IP address |
|
294 |
+ * @param[in] time lease time in seconds |
|
295 |
+ * @param[in] DHCP server IP address |
|
296 |
+ */ |
|
297 |
+static void dhcp_offer(unsigned char addr[4], unsigned char mask[4], |
|
298 |
+ unsigned char gateway[4], unsigned long time, |
|
299 |
+ unsigned char server[4]) |
|
300 |
+{ |
|
301 |
+ // use this IP address, mask and gateway |
|
302 |
+ ip_cpy(config_ip.ip, addr); |
|
303 |
+ ip_cpy(config_ip.mask, mask); |
|
304 |
+ ip_cpy(config_ip.gw, gateway); |
|
305 |
+ |
|
306 |
+ // store DHCP server and lease time |
|
307 |
+ dhcp_active = 1; |
|
308 |
+ ip_cpy(dhcp_server, server); |
|
309 |
+ dhcp_lease_time = time; |
|
310 |
+ dhcp_lease_rest = dhcp_lease_rest_min; // schedule DHCP request |
|
311 |
+ |
|
312 |
+ // DHCP action finished |
|
313 |
+ dhcp_in_progress = 0; |
|
314 |
+ dhcp_retries = 0; |
|
315 |
+ dhcp_retry_secs = 0; |
|
316 |
+} |
|
317 |
+ |
|
318 |
+/** |
|
319 |
+ * @brief process a received DHCP ack |
|
320 |
+ * @param[in] addr assigned IP address |
|
321 |
+ * @param[in] mask assigned subnet mask |
|
322 |
+ * @param[in] gateway assigned gateway IP address |
|
323 |
+ * @param[in] time lease time in seconds |
|
324 |
+ * @param[in] DHCP server IP address |
|
325 |
+ */ |
|
326 |
+static void dhcp_ack(unsigned char addr[4], unsigned char mask[4], |
|
327 |
+ unsigned char gateway[4], unsigned long time, |
|
328 |
+ unsigned char server[4]) |
|
329 |
+{ |
|
330 |
+ // check if IP address, mask and gateway match |
|
331 |
+ if (! ip_eq(config_ip.ip, addr) || |
|
332 |
+ ! ip_eq(config_ip.mask, mask) || |
|
333 |
+ ! ip_eq(config_ip.gw, gateway)) |
|
334 |
+ { |
|
335 |
+ // mismatch ---> something is wrong, abort |
|
336 |
+ dhcp_abort(); |
|
337 |
+ return; |
|
338 |
+ } |
|
339 |
+ |
|
340 |
+ // store DHCP server and lease time |
|
341 |
+ dhcp_active = 1; |
|
342 |
+ ip_cpy(dhcp_server, server); |
|
343 |
+ dhcp_lease_time = time; |
|
344 |
+ dhcp_lease_rest = time; |
|
345 |
+ |
|
346 |
+ // DHCP action finished |
|
347 |
+ dhcp_in_progress = 0; |
|
348 |
+ dhcp_retries = 0; |
|
349 |
+ dhcp_retry_secs = 0; |
|
350 |
+ |
|
351 |
+ // forget x_id |
|
352 |
+ dhcp_have_x_id = 0; |
|
353 |
+ dhcp_x_id = 0; |
|
354 |
+ dhcp_x_id_secs = 0; |
|
355 |
+} |
|
356 |
+ |
|
357 |
+/** |
|
358 |
+ * @brief process a received DHCP packet |
|
359 |
+ * @param[in] ptr pointer to data of packet |
|
360 |
+ * @param[in] sz size of packet |
|
361 |
+ */ |
|
362 |
+void dhcp_recv(void *ptr, unsigned int sz) |
|
363 |
+{ |
|
364 |
+ struct dhcp_packet *p_dhcp_pack; |
|
365 |
+ unsigned char *opt_ptr, tag, len; |
|
366 |
+ unsigned short opt_len; |
|
367 |
+ unsigned char type; |
|
368 |
+ unsigned char have_mask, mask[4], have_gateway, gateway[4]; |
|
369 |
+ unsigned char have_time, have_server, server[4]; |
|
370 |
+ unsigned long time; |
|
371 |
+ |
|
372 |
+ // packet too short |
|
373 |
+ if (sz < sizeof(struct dhcp_packet)) |
|
374 |
+ return; |
|
375 |
+ |
|
376 |
+ p_dhcp_pack = ptr; |
|
377 |
+ |
|
378 |
+ // we are DHCP client |
|
379 |
+ // - source port must be 67 |
|
380 |
+ // - destination port must be 68 |
|
381 |
+ if (p_dhcp_pack->udp_hdr.src_port != htons(67) || |
|
382 |
+ p_dhcp_pack->udp_hdr.dest_port != htons(68)) |
|
383 |
+ return; |
|
384 |
+ // check DHCP fields |
|
385 |
+ if (p_dhcp_pack->dhcp_hdr.op != 2 || |
|
386 |
+ p_dhcp_pack->dhcp_hdr.h_type != 1 || |
|
387 |
+ p_dhcp_pack->dhcp_hdr.h_len != 6 || |
|
388 |
+ p_dhcp_pack->dhcp_hdr.h_ops != 0 || |
|
389 |
+ p_dhcp_pack->dhcp_hdr.m_cookie != htonl(0x63825363)) |
|
390 |
+ return; |
|
391 |
+ |
|
392 |
+ // check x_id |
|
393 |
+ if (! dhcp_have_x_id || ntohl(p_dhcp_pack->dhcp_hdr.x_id) != dhcp_x_id) |
|
394 |
+ return; |
|
395 |
+ |
|
396 |
+ // get options |
|
397 |
+ opt_ptr = ptr + sizeof(struct dhcp_packet); |
|
398 |
+ opt_len = sz - sizeof(struct dhcp_packet); |
|
399 |
+ |
|
400 |
+ // parse options |
|
401 |
+ type = 0; |
|
402 |
+ have_mask = 0; |
|
403 |
+ have_gateway = 0; |
|
404 |
+ time = 0; |
|
405 |
+ have_time = 0; |
|
406 |
+ have_server = 0; |
|
407 |
+ while (opt_len > 2) { |
|
408 |
+ |
|
409 |
+ // get tag and length |
|
410 |
+ tag = *opt_ptr++; |
|
411 |
+ len = *opt_ptr++; |
|
412 |
+ if (opt_len < 2 + len) |
|
413 |
+ break; |
|
414 |
+ |
|
415 |
+ // get option |
|
416 |
+ switch (tag) { |
|
417 |
+ // type |
|
418 |
+ case 0x35: |
|
419 |
+ if (len >= 1) |
|
420 |
+ type = opt_ptr[0]; |
|
421 |
+ break; |
|
422 |
+ // subnet mask |
|
423 |
+ case 0x01: |
|
424 |
+ if (len >= 4) |
|
425 |
+ memcpy(mask, opt_ptr, 4); |
|
426 |
+ have_mask = 1; |
|
427 |
+ break; |
|
428 |
+ // gateway |
|
429 |
+ case 0x03: |
|
430 |
+ if (len >= 4) { |
|
431 |
+ memcpy(gateway, opt_ptr, 4); |
|
432 |
+ have_gateway = 1; |
|
433 |
+ } |
|
434 |
+ break; |
|
435 |
+ // lease time |
|
436 |
+ case 0x33: |
|
437 |
+ if (len >= 4) { |
|
438 |
+ time = ntohl(*(unsigned long *)opt_ptr); |
|
439 |
+ have_time = 1; |
|
440 |
+ } |
|
441 |
+ break; |
|
442 |
+ // DHCP server |
|
443 |
+ case 0x36: |
|
444 |
+ if (len >= 4) { |
|
445 |
+ memcpy(server, opt_ptr, 4); |
|
446 |
+ have_server = 1; |
|
447 |
+ } |
|
448 |
+ break; |
|
449 |
+ } |
|
450 |
+ |
|
451 |
+ // skip option |
|
452 |
+ opt_ptr += len; |
|
453 |
+ opt_len -= len; |
|
454 |
+ } |
|
455 |
+ |
|
456 |
+ // fill in server from source address if not present |
|
457 |
+ if (! have_server) { |
|
458 |
+ ip_cpy(server, p_dhcp_pack->ip_hdr.src); |
|
459 |
+ have_server = 1; |
|
460 |
+ } |
|
461 |
+ |
|
462 |
+ // process DHCP response |
|
463 |
+ switch (type) { |
|
464 |
+ // DHCP offer |
|
465 |
+ case 2: |
|
466 |
+ if (have_mask && have_gateway && have_time && have_server) |
|
467 |
+ dhcp_offer(p_dhcp_pack->dhcp_hdr.yi_addr, mask, gateway, time, server); |
|
468 |
+ break; |
|
469 |
+ // DHCP ack |
|
470 |
+ case 5: |
|
471 |
+ if (have_mask && have_gateway && have_time && have_server) |
|
472 |
+ dhcp_ack(p_dhcp_pack->dhcp_hdr.yi_addr, mask, gateway, time, server); |
|
473 |
+ break; |
|
474 |
+ } |
|
475 |
+} |
|
476 |
+ |
... | ... |
@@ -0,0 +1,48 @@ |
1 |
+#ifndef DHCP_H |
|
2 |
+#define DHCP_H |
|
3 |
+ |
|
4 |
+#include "ethernet.h" |
|
5 |
+#include "ip.h" |
|
6 |
+#include "udp.h" |
|
7 |
+ |
|
8 |
+/// header of DHCP packet |
|
9 |
+struct dhcp_header |
|
10 |
+{ |
|
11 |
+ unsigned char op; |
|
12 |
+ unsigned char h_type; |
|
13 |
+ unsigned char h_len; |
|
14 |
+ unsigned char h_ops; |
|
15 |
+ unsigned long x_id; |
|
16 |
+ unsigned short secs; |
|
17 |
+ unsigned short flags; |
|
18 |
+ unsigned char ci_addr[4]; |
|
19 |
+ unsigned char yi_addr[4]; |
|
20 |
+ unsigned char si_addr[4]; |
|
21 |
+ unsigned char gi_addr[4]; |
|
22 |
+ unsigned char ch_addr[16]; |
|
23 |
+ unsigned char s_name[64]; |
|
24 |
+ unsigned char file[128]; |
|
25 |
+ unsigned long m_cookie; |
|
26 |
+} __attribute__((packed)); |
|
27 |
+ |
|
28 |
+/// DHCP packet |
|
29 |
+struct dhcp_packet |
|
30 |
+{ |
|
31 |
+ struct ethernet_header eth_hdr; |
|
32 |
+ struct ip_header ip_hdr; |
|
33 |
+ struct udp_header udp_hdr; |
|
34 |
+ struct dhcp_header dhcp_hdr; |
|
35 |
+} __attribute__((packed)); |
|
36 |
+ |
|
37 |
+/// tick procedure - call every 200ms |
|
38 |
+void dhcp_tick200(void); |
|
39 |
+ |
|
40 |
+/** |
|
41 |
+ * @brief process a received DHCP packet |
|
42 |
+ * @param[in] ptr pointer to data of packet |
|
43 |
+ * @param[in] sz size of packet |
|
44 |
+ */ |
|
45 |
+void dhcp_recv(void *ptr, unsigned int sz); |
|
46 |
+ |
|
47 |
+#endif // #ifdef DHCP_H |
|
48 |
+ |
... | ... |
@@ -1,6 +1,7 @@ |
1 | 1 |
#include "config.h" |
2 | 2 |
#include "checksum.h" |
3 | 3 |
#include "ethernet.h" |
4 |
+#include "dhcp.h" |
|
4 | 5 |
#include "ip.h" |
5 | 6 |
#include "macros.h" |
6 | 7 |
#include "nethelp.h" |
... | ... |
@@ -102,6 +103,10 @@ void udp_recv(void *ptr, unsigned int sz) |
102 | 103 |
case 7: |
103 | 104 |
udp_echo_recv(ptr, sz); |
104 | 105 |
break; |
106 |
+ // DHCP |
|
107 |
+ case 68: |
|
108 |
+ dhcp_recv(ptr, sz); |
|
109 |
+ break; |
|
105 | 110 |
} |
106 | 111 |
} |
107 | 112 |
|
... | ... |
@@ -111,7 +116,7 @@ void udp_recv(void *ptr, unsigned int sz) |
111 | 116 |
* @param[in] sz size of packet |
112 | 117 |
* |
113 | 118 |
* ptr must point to a udp_packet |
114 |
- * with ip_hdr.proto and udp_hdr.src_port, udp_hdr.dest_port, ip_hdr.dest |
|
119 |
+ * with ip_hdr.proto ip_hdr.dest, udp_hdr.src_port and udp_hdr.dest_port |
|
115 | 120 |
* already initialized |
116 | 121 |
*/ |
117 | 122 |
void udp_send(void *ptr, unsigned int sz) |
... | ... |
@@ -37,7 +37,7 @@ void udp_recv(void *ptr, unsigned int sz); |
37 | 37 |
* @param[in] sz size of packet |
38 | 38 |
* |
39 | 39 |
* ptr must point to a udp_packet |
40 |
- * with ip_hdr.proto and udp_hdr.src_port, udp_hdr.dest_port, ip_hdr.dest |
|
40 |
+ * with ip_hdr.proto ip_hdr.dest, udp_hdr.src_port and udp_hdr.dest_port |
|
41 | 41 |
* already initialized |
42 | 42 |
*/ |
43 | 43 |
void udp_send(void *ptr, unsigned int sz); |
44 | 44 |