|
|
1.1 root 1: /******************************************************************************
2: * Copyright (c) 2004, 2008 IBM Corporation
3: * All rights reserved.
4: * This program and the accompanying materials
5: * are made available under the terms of the BSD License
6: * which accompanies this distribution, and is available at
7: * http://www.opensource.org/licenses/bsd-license.php
8: *
9: * Contributors:
10: * IBM Corporation - initial implementation
11: *****************************************************************************/
12:
13:
14: /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ALGORITHMS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
15:
16: /** \file dhcp.c <pre>
17: * **************** State-transition diagram for DHCP client *************
18: *
19: * +---------+ Note: DHCP-server msg / DHCP-client msg
20: * | INIT |
21: * +---------+
22: * |
23: * | - / Discover
24: * V
25: * +---------+
26: * | SELECT | Timeout
27: * +---------+ |
28: * | |
29: * | Offer / Request |
30: * | |
31: * V V
32: * +---------+ NACK / - ***********
33: * | REQUEST | ----------------> * FAULT *
34: * +---------+ ***********
35: * |
36: * | ACK / - ***********
37: * +----------------------> * SUCCESS *
38: * ***********
39: *
40: * ************************************************************************
41: * </pre> */
42:
43:
44: /*>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<<<*/
45:
46: #include <dhcp.h>
47: #include <ethernet.h>
48: #include <ipv4.h>
49: #include <udp.h>
50: #include <dns.h>
51:
52: #include <stdio.h>
53: #include <string.h>
54: #include <time.h>
55: #include <sys/socket.h>
56: #include <ctype.h>
57: #include <stdlib.h>
58:
59: /* DHCP Message Types */
60: #define DHCPDISCOVER 1
61: #define DHCPOFFER 2
62: #define DHCPREQUEST 3
63: #define DHCPDECLINE 4
64: #define DHCPACK 5
65: #define DHCPNACK 6
66: #define DHCPRELEASE 7
67: #define DHCPINFORM 8
68:
69: /* DHCP Option Codes */
70: #define DHCP_MASK 1
71: #define DHCP_ROUTER 3
72: #define DHCP_DNS 6
73: #define DHCP_REQUESTED_IP 50
74: #define DHCP_OVERLOAD 52
75: #define DHCP_MSG_TYPE 53
76: #define DHCP_SERVER_ID 54
77: #define DHCP_REQUEST_LIST 55
78: #define DHCP_TFTP_SERVER 66
79: #define DHCP_BOOTFILE 67
80: #define DHCP_ENDOPT 0xFF
81: #define DHCP_PADOPT 0x00
82:
83: /* "file/sname" overload option values */
84: #define DHCP_OVERLOAD_FILE 1
85: #define DHCP_OVERLOAD_SNAME 2
86: #define DHCP_OVERLOAD_BOTH 3
87:
88: /* DHCP states codes */
89: #define DHCP_STATE_SELECT 1
90: #define DHCP_STATE_REQUEST 2
91: #define DHCP_STATE_SUCCESS 3
92: #define DHCP_STATE_FAULT 4
93:
94: static uint8_t dhcp_magic[] = {0x63, 0x82, 0x53, 0x63};
95: /**< DHCP_magic is a cookie, that identifies DHCP options (see RFC 2132) */
96:
97: /** \struct dhcp_options_t
98: * This structure is used to fill options in DHCP-msg during transmitting
99: * or to retrieve options from DHCP-msg during receiving.
100: * <p>
101: * If flag[i] == TRUE then field for i-th option retains valid value and
102: * information from this field may retrived (in case of receiving) or will
103: * be transmitted (in case of transmitting).
104: *
105: */
106: typedef struct {
107: uint8_t flag[256]; /**< Show if corresponding opt. is valid */
108: uint8_t request_list[256]; /**< o.55 If i-th member is TRUE, then i-th
109: option will be requested from server */
110: uint32_t server_ID; /**< o.54 Identifies DHCP-server */
111: uint32_t requested_IP; /**< o.50 Must be filled in DHCP-Request */
112: uint32_t dns_IP; /**< o. 6 DNS IP */
113: uint32_t router_IP; /**< o. 3 Router IP */
114: uint32_t subnet_mask; /**< o. 1 Subnet mask */
115: uint8_t msg_type; /**< o.53 DHCP-message type */
116: uint8_t overload; /**< o.52 Overload sname/file fields */
117: int8_t tftp_server[256]; /**< o.66 TFTP server name */
118: int8_t bootfile[256]; /**< o.67 Boot file name */
119: } dhcp_options_t;
120:
121: /** Stores state of DHCP-client (refer to State-transition diagram) */
122: static uint8_t dhcp_state;
123:
124:
125: /*>>>>>>>>>>>>>>>>>>>>>>>>>>>> PROTOTYPES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
126:
127: static int32_t
128: dhcp_attempt(void);
129:
130: static int32_t
131: dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct);
132:
133: static int32_t
134: dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len,
135: dhcp_options_t * opt_struct);
136:
137: static int8_t
138: dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len,
139: uint8_t src_options[], uint32_t src_len);
140:
141: static int8_t
142: dhcp_find_option(uint8_t options[], uint32_t len,
143: uint8_t op_code, uint32_t * op_offset);
144:
145: static void
146: dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len,
147: uint8_t * new_option);
148:
149: static void
150: dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len,
151: uint32_t dst_offset, uint8_t * new_option);
152:
153: static void
154: dhcp_send_discover(void);
155:
156: static void
157: dhcp_send_request(void);
158:
159: static uint8_t
160: strtoip(int8_t * str, uint32_t * ip);
161:
162:
163: /*>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<<*/
164:
165: static uint8_t ether_packet[ETH_MTU_SIZE];
166: static uint32_t dhcp_own_ip = 0;
167: static uint32_t dhcp_server_ip = 0;
168: static uint32_t dhcp_siaddr_ip = 0;
169: static int8_t dhcp_filename[256];
170: static int8_t dhcp_tftp_name[256];
171:
172: static char * response_buffer;
173:
174: /*>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<*/
175:
176: /**
177: * DHCP: Obtains IP and configuration info from DHCP server
178: * (makes several attempts).
179: *
180: * @param boot_device a socket number used to send and recieve packets
181: * @param fn_ip contains the following configuration information:
182: * client MAC, client IP, TFTP-server MAC,
183: * TFTP-server IP, Boot file name
184: * @return ZERO - IP and configuration info obtained;
185: * NON ZERO - error condition occurs.
186: */
187: int32_t
188: dhcp(char *ret_buffer, filename_ip_t * fn_ip, unsigned int retries) {
189: int i = (int) retries+1;
190:
191: uint32_t dhcp_tftp_ip = 0;
192: strcpy((char *) dhcp_filename, "");
193: strcpy((char *) dhcp_tftp_name, "");
194:
195: response_buffer = ret_buffer;
196:
197: printf(" ");
198:
199: do {
200: printf("\b\b\b%03d", i-1);
201: if (getchar() == 27) {
202: printf("\nAborted\n");
203: return -1;
204: }
205: if (!--i) {
206: printf("\nGiving up after %d DHCP requests\n", retries);
207: return -1;
208: }
209: } while (!dhcp_attempt());
210: printf("\b\b\b\b");
211:
212: if (fn_ip->own_ip) {
213: dhcp_own_ip = fn_ip->own_ip;
214: }
215: if (fn_ip->server_ip) {
216: dhcp_siaddr_ip = fn_ip->server_ip;
217: }
218: if(fn_ip->filename[0] != 0) {
219: strcpy((char *) dhcp_filename, (char *) fn_ip->filename);
220: }
221:
222: // TFTP SERVER
223: if (!strlen((char *) dhcp_tftp_name)) {
224: if (!dhcp_siaddr_ip) {
225: // ERROR: TFTP name is not presented
226: return -3;
227: }
228:
229: // take TFTP-ip from siaddr field
230: dhcp_tftp_ip = dhcp_siaddr_ip;
231: }
232: else {
233: // TFTP server defined by its name
234: if (!strtoip(dhcp_tftp_name, &(dhcp_tftp_ip))) {
235: if (!dns_get_ip(dhcp_tftp_name, &(dhcp_tftp_ip))) {
236: // DNS error - can't obtain TFTP-server name
237: // Use TFTP-ip from siaddr field, if presented
238: if (dhcp_siaddr_ip) {
239: dhcp_tftp_ip = dhcp_siaddr_ip;
240: }
241: else {
242: // ERROR: Can't obtain TFTP server IP
243: return -4;
244: }
245: }
246: }
247: }
248:
249: // Store configuration info into filename_ip strucutre
250: fn_ip -> own_ip = dhcp_own_ip;
251: fn_ip -> server_ip = dhcp_tftp_ip;
252: strcpy((char *) fn_ip -> filename, (char *) dhcp_filename);
253:
254: return 0;
255: }
256:
257: /**
258: * DHCP: Tries o obtain DHCP parameters, refer to state-transition diagram
259: */
260: static int32_t
261: dhcp_attempt(void) {
262: int sec;
263:
264: // Send DISCOVER message and switch DHCP-client to SELECT state
265: dhcp_send_discover();
266:
267: dhcp_state = DHCP_STATE_SELECT;
268:
269: // setting up a timer with a timeout of two seconds
270: for (sec = 0; sec < 2; sec++) {
271: set_timer(TICKS_SEC);
272: do {
273: receive_ether();
274:
275: // Wait until client will switch to Final state or Timeout occurs
276: switch (dhcp_state) {
277: case DHCP_STATE_SUCCESS :
278: return 1;
279: case DHCP_STATE_FAULT :
280: return 0;
281: }
282: } while (get_timer() > 0);
283: }
284:
285: // timeout
286: return 0;
287: }
288:
289: /**
290: * DHCP: Supplements DHCP-message with options stored in structure.
291: * For more information about option coding see dhcp_options_t.
292: *
293: * @param opt_field Points to the "vend" field of DHCP-message
294: * (destination)
295: * @param opt_struct this structure stores info about the options wich
296: * will be added to DHCP-message (source)
297: * @return TRUE - options packed;
298: * FALSE - error condition occurs.
299: * @see dhcp_options_t
300: */
301: static int32_t
302: dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct) {
303: uint8_t * options = opt_field;
304: uint16_t i, sum; // used to define is any options set
305:
306: // magic
307: memcpy(options, dhcp_magic, 4);
308: options += 4;
309:
310: // fill message type
311: switch (opt_struct -> msg_type) {
312: case DHCPDISCOVER :
313: case DHCPREQUEST :
314: case DHCPDECLINE :
315: case DHCPINFORM :
316: case DHCPRELEASE :
317: options[0] = DHCP_MSG_TYPE;
318: options[1] = 1;
319: options[2] = opt_struct -> msg_type;
320: options += 3;
321: break;
322: default :
323: return 0; // Unsupported DHCP-message
324: }
325:
326: if (opt_struct -> overload) {
327: options[0] = DHCP_OVERLOAD;
328: options[1] = 0x01;
329: options[2] = opt_struct -> overload;
330: options +=3;
331: }
332:
333: if (opt_struct -> flag[DHCP_REQUESTED_IP]) {
334: options[0] = DHCP_REQUESTED_IP;
335: options[1] = 0x04;
336: * (uint32_t *) (options + 2) = htonl (opt_struct -> requested_IP);
337: options +=6;
338: }
339:
340: if (opt_struct -> flag[DHCP_SERVER_ID]) {
341: options[0] = DHCP_SERVER_ID;
342: options[1] = 0x04;
343: * (uint32_t *) (options + 2) = htonl (opt_struct -> server_ID);
344: options +=6;
345: }
346:
347: sum = 0;
348: for (i = 0; i < 256; i++)
349: sum += opt_struct -> request_list[i];
350:
351: if (sum) {
352: options[0] = DHCP_REQUEST_LIST;
353: options[1] = sum;
354: options += 2;
355: for (i = 0; i < 256; i++) {
356: if (opt_struct -> request_list[i]) {
357: options[0] = i; options++;
358: }
359: }
360: }
361:
362: if (opt_struct -> flag[DHCP_TFTP_SERVER]) {
363: options[0] = DHCP_TFTP_SERVER;
364: options[1] = strlen((char *) opt_struct -> tftp_server) + 1;
365: memcpy(options + 2, opt_struct -> tftp_server, options[1]);
366: options += options[1] + 2;
367: }
368:
369: if (opt_struct -> flag[DHCP_BOOTFILE]) {
370: options[0] = DHCP_BOOTFILE;
371: options[1] = strlen((char *) opt_struct -> bootfile) + 1;
372: memcpy(options + 2, opt_struct -> bootfile, options[1]);
373: options += options[1] + 2;
374: }
375:
376: // end options
377: options[0] = 0xFF;
378: options++;
379:
380: return 1;
381: }
382:
383: /**
384: * DHCP: Extracts encoded options from DHCP-message into the structure.
385: * For more information about option coding see dhcp_options_t.
386: *
387: * @param opt_field Points to the "options" field of DHCP-message
388: * (source).
389: * @param opt_len Length of "options" field.
390: * @param opt_struct this structure stores info about the options wich
391: * was extracted from DHCP-message (destination).
392: * @return TRUE - options extracted;
393: * FALSE - error condition occurs.
394: * @see dhcp_options_t
395: */
396: static int32_t
397: dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len,
398: dhcp_options_t * opt_struct) {
399: int32_t offset = 0;
400:
401: memset(opt_struct, 0, sizeof(dhcp_options_t));
402:
403: // magic
404: if (memcmp(opt_field, dhcp_magic, 4)) {
405: return 0;
406: }
407:
408: offset += 4;
409: while (offset < opt_len) {
410: opt_struct -> flag[opt_field[offset]] = 1;
411: switch(opt_field[offset]) {
412: case DHCP_OVERLOAD :
413: opt_struct -> overload = opt_field[offset + 2];
414: offset += 2 + opt_field[offset + 1];
415: break;
416:
417: case DHCP_REQUESTED_IP :
418: opt_struct -> requested_IP = htonl(* (uint32_t *) (opt_field + offset + 2));
419: offset += 2 + opt_field[offset + 1];
420: break;
421:
422: case DHCP_MASK :
423: opt_struct -> flag[DHCP_MASK] = 1;
424: opt_struct -> subnet_mask = htonl(* (uint32_t *) (opt_field + offset + 2));
425: offset += 2 + opt_field[offset + 1];
426: break;
427:
428: case DHCP_DNS :
429: opt_struct -> flag[DHCP_DNS] = 1;
430: opt_struct -> dns_IP = htonl(* (uint32_t *) (opt_field + offset + 2));
431: offset += 2 + opt_field[offset + 1];
432: break;
433:
434: case DHCP_ROUTER :
435: opt_struct -> flag[DHCP_ROUTER] = 1;
436: opt_struct -> router_IP = htonl(* (uint32_t *) (opt_field + offset + 2));
437: offset += 2 + opt_field[offset + 1];
438: break;
439:
440: case DHCP_MSG_TYPE :
441: if ((opt_field[offset + 2] > 0) && (opt_field[offset + 2] < 9))
442: opt_struct -> msg_type = opt_field[offset + 2];
443: else
444: return 0;
445: offset += 2 + opt_field[offset + 1];
446: break;
447:
448: case DHCP_SERVER_ID :
449: opt_struct -> server_ID = htonl(* (uint32_t *) (opt_field + offset + 2));
450: offset += 2 + opt_field[offset + 1];
451: break;
452:
453: case DHCP_TFTP_SERVER :
454: memcpy(opt_struct -> tftp_server, opt_field + offset + 2, opt_field[offset + 1]);
455: (opt_struct -> tftp_server)[opt_field[offset + 1]] = 0;
456: offset += 2 + opt_field[offset + 1];
457: break;
458:
459: case DHCP_BOOTFILE :
460: memcpy(opt_struct -> bootfile, opt_field + offset + 2, opt_field[offset + 1]);
461: (opt_struct -> bootfile)[opt_field[offset + 1]] = 0;
462: offset += 2 + opt_field[offset + 1];
463: break;
464:
465: case DHCP_PADOPT :
466: offset++;
467: break;
468:
469: case DHCP_ENDOPT : // End of options
470: return 1;
471:
472: default :
473: offset += 2 + opt_field[offset + 1]; // Unsupported opt. - do nothing
474: }
475: }
476: if (offset == opt_len)
477: return 1; // options finished without 0xFF
478:
479: return 0;
480: }
481:
482: /**
483: * DHCP: Appends information from source "options" into dest "options".
484: * This function is used to support "file/sname" overloading.
485: *
486: * @param dst_options destanation "options" field
487: * @param dst_len size of dst_options (modified by this function)
488: * @param src_options source "options" field
489: * @param src_len size of src_options
490: * @return TRUE - options merged;
491: * FALSE - error condition occurs.
492: */
493: static int8_t dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len,
494: uint8_t src_options[], uint32_t src_len) {
495: int32_t dst_offset, src_offset = 0;
496:
497: // remove ENDOPT if presented
498: if (dhcp_find_option(dst_options, * dst_len, DHCP_ENDOPT, (uint32_t *) &dst_offset))
499: * dst_len = dst_offset;
500:
501: while (src_offset < src_len) {
502: switch(src_options[src_offset]) {
503: case DHCP_PADOPT:
504: src_offset++;
505: break;
506: case DHCP_ENDOPT:
507: return 1;
508: default:
509: if (dhcp_find_option(dst_options, * dst_len,
510: src_options[src_offset],
511: (uint32_t *) &dst_offset)) {
512: dhcp_combine_option(dst_options, dst_len,
513: dst_offset,
514: (uint8_t *) src_options +
515: src_offset);
516: }
517: else {
518: dhcp_append_option(dst_options, dst_len, src_options + src_offset);
519: }
520: src_offset += 2 + src_options[src_offset + 1];
521: }
522: }
523:
524: if (src_offset == src_len)
525: return 1;
526: return 0;
527: }
528:
529: /**
530: * DHCP: Finds given occurence of the option with the given code (op_code)
531: * in "options" field of DHCP-message.
532: *
533: * @param options "options" field of DHCP-message
534: * @param len length of the "options" field
535: * @param op_code code of the option to find
536: * @param op_offset SUCCESS - offset to an option occurence;
537: * FAULT - offset is set to zero.
538: * @return TRUE - option was find;
539: * FALSE - option wasn't find.
540: */
541: static int8_t dhcp_find_option(uint8_t options[], uint32_t len,
542: uint8_t op_code, uint32_t * op_offset) {
543: uint32_t srch_offset = 0;
544: * op_offset = 0;
545:
546: while (srch_offset < len) {
547: if (options[srch_offset] == op_code) {
548: * op_offset = srch_offset;
549: return 1;
550: }
551: if (options[srch_offset] == DHCP_ENDOPT)
552: return 0;
553:
554: if (options[srch_offset] == DHCP_PADOPT)
555: srch_offset++;
556: else
557: srch_offset += 2 + options[srch_offset + 1];
558: }
559: return 0;
560: }
561:
562: /**
563: * DHCP: Appends new option from one list (src) into the tail
564: * of another option list (dst)
565: *
566: * @param dst_options "options" field of DHCP-message
567: * @param dst_len length of the "options" field (modified)
568: * @param new_option points to an option in another list (src)
569: */
570: static void
571: dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len,
572: uint8_t * new_option) {
573: memcpy(dst_options + ( * dst_len), new_option, 2 + (* (new_option + 1)));
574: * dst_len += 2 + *(new_option + 1);
575: }
576:
577: /**
578: * DHCP: This function is used when options with the same code are
579: * presented in both merged lists. In this case information
580: * about the option from one list (src) is combined (complemented)
581: * with information about the option in another list (dst).
582: *
583: * @param dst_options "options" field of DHCP-message
584: * @param dst_len length of the "options" field (modified)
585: * @param dst_offset offset of the option from beggining of the list
586: * @param new_option points to an option in another list (src)
587: */
588: static void
589: dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len,
590: uint32_t dst_offset, uint8_t * new_option) {
591:
592: uint8_t tmp_buffer[1024]; // use to provide safe memcpy
593: uint32_t tail_len;
594:
595: // move all subsequent options (allocate size for additional info)
596: tail_len = (* dst_len) - dst_offset - 2 - dst_options[dst_offset + 1];
597:
598: memcpy(tmp_buffer, dst_options + (* dst_len) - tail_len, tail_len);
599: memcpy(dst_options + (* dst_len) - tail_len + (* (new_option + 1)),
600: tmp_buffer, tail_len);
601:
602: // add new_content to option
603: memcpy(dst_options + (* dst_len) - tail_len, new_option + 2,
604: * (new_option + 1));
605: dst_options[dst_offset + 1] += * (new_option + 1);
606:
607: // correct dst_len
608: * dst_len += * (new_option + 1);
609: }
610:
611: /**
612: * DHCP: Sends DHCP-Discover message. Looks for DHCP servers.
613: */
614: static void
615: dhcp_send_discover(void) {
616: uint32_t packetsize = sizeof(struct iphdr) +
617: sizeof(struct udphdr) + sizeof(struct btphdr);
618: struct btphdr *btph;
619: dhcp_options_t opt;
620:
621: memset(ether_packet, 0, packetsize);
622:
623: btph = (struct btphdr *) (ðer_packet[
624: sizeof(struct iphdr) + sizeof(struct udphdr)]);
625:
626: btph -> op = 1;
627: btph -> htype = 1;
628: btph -> hlen = 6;
629: memcpy(btph -> chaddr, get_mac_address(), 6);
630:
631: memset(&opt, 0, sizeof(dhcp_options_t));
632:
633: opt.msg_type = DHCPDISCOVER;
634:
635: opt.request_list[DHCP_MASK] = 1;
636: opt.request_list[DHCP_DNS] = 1;
637: opt.request_list[DHCP_ROUTER] = 1;
638: opt.request_list[DHCP_TFTP_SERVER] = 1;
639: opt.request_list[DHCP_BOOTFILE] = 1;
640:
641: dhcp_encode_options(btph -> vend, &opt);
642:
643: fill_udphdr(ðer_packet[sizeof(struct iphdr)],
644: sizeof(struct btphdr) + sizeof(struct udphdr),
645: UDPPORT_BOOTPC, UDPPORT_BOOTPS);
646: fill_iphdr(ether_packet, sizeof(struct btphdr) +
647: sizeof(struct udphdr) + sizeof(struct iphdr),
648: IPTYPE_UDP, dhcp_own_ip, 0xFFFFFFFF);
649:
650: send_ipv4(ether_packet, packetsize);
651: }
652:
653: /**
654: * DHCP: Sends DHCP-Request message. Asks for acknowledgment to occupy IP.
655: */
656: static void
657: dhcp_send_request(void) {
658: uint32_t packetsize = sizeof(struct iphdr) +
659: sizeof(struct udphdr) + sizeof(struct btphdr);
660: struct btphdr *btph;
661: dhcp_options_t opt;
662:
663: memset(ether_packet, 0, packetsize);
664:
665: btph = (struct btphdr *) (ðer_packet[
666: sizeof(struct iphdr) + sizeof(struct udphdr)]);
667:
668: btph -> op = 1;
669: btph -> htype = 1;
670: btph -> hlen = 6;
671: memcpy(btph -> chaddr, get_mac_address(), 6);
672:
673: memset(&opt, 0, sizeof(dhcp_options_t));
674:
675: opt.msg_type = DHCPREQUEST;
676: memcpy(&(opt.requested_IP), &dhcp_own_ip, 4);
677: opt.flag[DHCP_REQUESTED_IP] = 1;
678: memcpy(&(opt.server_ID), &dhcp_server_ip, 4);
679: opt.flag[DHCP_SERVER_ID] = 1;
680:
681: opt.request_list[DHCP_MASK] = 1;
682: opt.request_list[DHCP_DNS] = 1;
683: opt.request_list[DHCP_ROUTER] = 1;
684: opt.request_list[DHCP_TFTP_SERVER] = 1;
685: opt.request_list[DHCP_BOOTFILE] = 1;
686:
687: dhcp_encode_options(btph -> vend, &opt);
688:
689: fill_udphdr(ðer_packet[sizeof(struct iphdr)],
690: sizeof(struct btphdr) + sizeof(struct udphdr),
691: UDPPORT_BOOTPC, UDPPORT_BOOTPS);
692: fill_iphdr(ether_packet, sizeof(struct btphdr) +
693: sizeof(struct udphdr) + sizeof(struct iphdr),
694: IPTYPE_UDP, 0, 0xFFFFFFFF);
695:
696: send_ipv4(ether_packet, packetsize);
697: }
698:
699:
700: /**
701: * DHCP: Sends DHCP-Release message. Releases occupied IP.
702: */
703: void dhcp_send_release(void) {
704: uint32_t packetsize = sizeof(struct iphdr) +
705: sizeof(struct udphdr) + sizeof(struct btphdr);
706: struct btphdr *btph;
707: dhcp_options_t opt;
708:
709: btph = (struct btphdr *) (ðer_packet[
710: sizeof(struct iphdr) + sizeof(struct udphdr)]);
711:
712: memset(ether_packet, 0, packetsize);
713:
714: btph -> op = 1;
715: btph -> htype = 1;
716: btph -> hlen = 6;
717: strcpy((char *) btph -> file, "");
718: memcpy(btph -> chaddr, get_mac_address(), 6);
719: btph -> ciaddr = htonl(dhcp_own_ip);
720:
721: memset(&opt, 0, sizeof(dhcp_options_t));
722:
723: opt.msg_type = DHCPRELEASE;
724: opt.server_ID = dhcp_server_ip;
725: opt.flag[DHCP_SERVER_ID] = 1;
726:
727: dhcp_encode_options(btph -> vend, &opt);
728:
729: fill_udphdr(ðer_packet[sizeof(struct iphdr)],
730: sizeof(struct btphdr) + sizeof(struct udphdr),
731: UDPPORT_BOOTPC, UDPPORT_BOOTPS);
732: fill_iphdr(ether_packet, sizeof(struct btphdr) +
733: sizeof(struct udphdr) + sizeof(struct iphdr), IPTYPE_UDP,
734: dhcp_own_ip, dhcp_server_ip);
735:
736: send_ipv4(ether_packet, packetsize);
737: }
738:
739: /**
740: * DHCP: Handles DHCP-messages according to Receive-handle diagram.
741: * Changes the state of DHCP-client.
742: *
743: * @param packet BootP/DHCP-packet to be handled
744: * @param packetsize length of the packet
745: * @return ZERO - packet handled successfully;
746: * NON ZERO - packet was not handled (e.g. bad format)
747: * @see receive_ether
748: * @see btphdr
749: */
750:
751: int8_t
752: handle_dhcp(uint8_t * packet, int32_t packetsize) {
753: struct btphdr * btph;
754: struct iphdr * iph;
755: dhcp_options_t opt;
756:
757: memset(&opt, 0, sizeof(dhcp_options_t));
758: btph = (struct btphdr *) packet;
759: iph = (struct iphdr *) packet - sizeof(struct udphdr) -
760: sizeof(struct iphdr);
761: if (btph -> op != 2)
762: return -1; // it is not Boot Reply
763:
764: if(response_buffer) {
765: if(packetsize <= 1720)
766: memcpy(response_buffer, packet, packetsize);
767: else
768: memcpy(response_buffer, packet, 1720);
769: }
770:
771: if (memcmp(btph -> vend, dhcp_magic, 4)) {
772: // It is BootP - RFC 951
773: dhcp_own_ip = htonl(btph -> yiaddr);
774: dhcp_siaddr_ip = htonl(btph -> siaddr);
775: dhcp_server_ip = htonl(iph -> ip_src);
776:
777: if (strlen((char *) btph -> sname) && !dhcp_siaddr_ip) {
778: strncpy((char *) dhcp_tftp_name, (char *) btph -> sname,
779: sizeof(btph -> sname));
780: dhcp_tftp_name[sizeof(btph -> sname)] = 0;
781: }
782:
783: if (strlen((char *) btph -> file)) {
784: strncpy((char *) dhcp_filename, (char *) btph -> file, sizeof(btph -> file));
785: dhcp_filename[sizeof(btph -> file)] = 0;
786: }
787:
788: dhcp_state = DHCP_STATE_SUCCESS;
789: return 0;
790: }
791:
792:
793: // decode options
794: if (!dhcp_decode_options(btph -> vend, packetsize -
795: sizeof(struct btphdr) + sizeof(btph -> vend),
796: &opt)) {
797: return -1; // can't decode options
798: }
799:
800: if (opt.overload) {
801: int16_t decode_res = 0;
802: uint8_t options[1024]; // buffer for merged options
803: uint32_t opt_len;
804:
805: // move 1-st part of options from vend field into buffer
806: opt_len = packetsize - sizeof(struct btphdr) +
807: sizeof(btph -> vend) - 4;
808: memcpy(options, btph -> vend, opt_len + 4);
809:
810: // add other parts
811: switch (opt.overload) {
812: case DHCP_OVERLOAD_FILE:
813: decode_res = dhcp_merge_options(options + 4, &opt_len,
814: btph -> file,
815: sizeof(btph -> file));
816: break;
817: case DHCP_OVERLOAD_SNAME:
818: decode_res = dhcp_merge_options(options + 4, &opt_len,
819: btph -> sname,
820: sizeof(btph -> sname));
821: break;
822: case DHCP_OVERLOAD_BOTH:
823: decode_res = dhcp_merge_options(options + 4, &opt_len,
824: btph -> file,
825: sizeof(btph -> file));
826: if (!decode_res)
827: break;
828: decode_res = dhcp_merge_options(options + 4, &opt_len,
829: btph -> sname,
830: sizeof(btph -> sname));
831: break;
832: }
833:
834: if (!decode_res)
835: return -1; // bad options in sname/file fields
836:
837: // decode merged options
838: if (!dhcp_decode_options(options, opt_len + 4, &opt)) {
839: return -1; // can't decode options
840: }
841: }
842:
843: if (!opt.msg_type) {
844: // It is BootP with Extensions - RFC 1497
845: // retrieve conf. settings from BootP - reply
846: dhcp_own_ip = htonl(btph -> yiaddr);
847: dhcp_siaddr_ip = htonl(btph -> siaddr);
848: if (strlen((char *) btph -> sname) && !dhcp_siaddr_ip) {
849: strncpy((char *) dhcp_tftp_name, (char *) btph -> sname, sizeof(btph -> sname));
850: dhcp_tftp_name[sizeof(btph -> sname)] = 0;
851: }
852:
853: if (strlen((char *) btph -> file)) {
854: strncpy((char *) dhcp_filename, (char *) btph -> file, sizeof(btph -> file));
855: dhcp_filename[sizeof(btph -> file)] = 0;
856: }
857:
858: // retrieve DHCP-server IP from IP-header
859: dhcp_server_ip = iph -> htonl(ip_src);
860:
861: dhcp_state = DHCP_STATE_SUCCESS;
862: }
863: else {
864: // It is DHCP - RFC 2131 & RFC 2132
865: // opt contains parameters from server
866: switch (dhcp_state) {
867: case DHCP_STATE_SELECT :
868: if (opt.msg_type == DHCPOFFER) {
869: dhcp_own_ip = htonl(btph -> yiaddr);
870: dhcp_server_ip = opt.server_ID;
871: dhcp_send_request();
872: dhcp_state = DHCP_STATE_REQUEST;
873: }
874: return 0;
875: case DHCP_STATE_REQUEST :
876: switch (opt.msg_type) {
877: case DHCPNACK :
878: dhcp_own_ip = 0;
879: dhcp_server_ip = 0;
880: dhcp_state = DHCP_STATE_FAULT;
881: break;
882: case DHCPACK :
883: dhcp_own_ip = htonl(btph -> yiaddr);
884: dhcp_server_ip = opt.server_ID;
885: dhcp_siaddr_ip = htonl(btph -> siaddr);
886: if (opt.flag[DHCP_TFTP_SERVER]) {
887: strcpy((char *) dhcp_tftp_name, (char *) opt.tftp_server);
888: }
889: else {
890: strcpy((char *) dhcp_tftp_name, "");
891: if ((opt.overload != DHCP_OVERLOAD_SNAME &&
892: opt.overload != DHCP_OVERLOAD_BOTH) &&
893: !dhcp_siaddr_ip) {
894: strncpy((char *) dhcp_tftp_name,
895: (char *) btph->sname,
896: sizeof(btph -> sname));
897: dhcp_tftp_name[sizeof(btph->sname)] = 0;
898: }
899: }
900:
901: if (opt.flag[DHCP_BOOTFILE]) {
902: strcpy((char *) dhcp_filename, (char *) opt.bootfile);
903: }
904: else {
905: strcpy((char *) dhcp_filename, "");
906: if (opt.overload != DHCP_OVERLOAD_FILE &&
907: opt.overload != DHCP_OVERLOAD_BOTH &&
908: strlen((char *) btph -> file)) {
909: strncpy((char *) dhcp_filename,
910: (char *) btph->file,
911: sizeof(btph->file));
912: dhcp_filename[sizeof(btph -> file)] = 0;
913: }
914: }
915:
916: dhcp_state = DHCP_STATE_SUCCESS;
917: break;
918: default:
919: break; // Unused DHCP-message - do nothing
920: }
921: break;
922: default :
923: return -1; // Illegal DHCP-client state
924: }
925: }
926:
927: if (dhcp_state == DHCP_STATE_SUCCESS) {
928:
929: // initialize network entity with real own_ip
930: // to be able to answer for foreign requests
931: set_ipv4_address(dhcp_own_ip);
932:
933: /* Subnet mask */
934: if (opt.flag[DHCP_MASK]) {
935: /* Router */
936: if (opt.flag[DHCP_ROUTER]) {
937: set_ipv4_router(opt.router_IP);
938: set_ipv4_netmask(opt.subnet_mask);
939: }
940: }
941:
942: /* DNS-server */
943: if (opt.flag[DHCP_DNS]) {
944: dns_init(opt.dns_IP);
945: }
946: }
947:
948: return 0;
949: }
950:
951: /**
952: * DHCP: Converts "255.255.255.255" -> 32-bit long IP
953: *
954: * @param str string to be converted
955: * @param ip in case of SUCCESS - 32-bit long IP
956: in case of FAULT - zero
957: * @return TRUE - IP converted successfully;
958: * FALSE - error condition occurs (e.g. bad format)
959: */
960: static uint8_t
961: strtoip(int8_t * str, uint32_t * ip) {
962: int8_t ** ptr = &str;
963: int16_t i = 0, res, len;
964: char octet[256];
965:
966: * ip = 0;
967:
968: while (**ptr != 0) {
969: if (i > 3 || !isdigit(**ptr))
970: return 0;
971: if (strstr((char *) * ptr, ".") != NULL) {
972: len = (int16_t) ((int8_t *) strstr((char *) * ptr, ".") -
973: (int8_t *) (* ptr));
974: strncpy(octet, (char *) * ptr, len); octet[len] = 0;
975: * ptr += len;
976: }
977: else {
978: strcpy(octet, (char *) * ptr);
979: * ptr += strlen(octet);
980: }
981: res = strtol(octet, NULL, 10);
982: if ((res > 255) || (res < 0))
983: return 0;
984: * ip = ((* ip) << 8) + res;
985: i++;
986: if (** ptr == '.')
987: (*ptr)++;
988: }
989:
990: if (i != 4)
991: return 0;
992: return 1;
993: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.