1 /******************************************************************************
2 * Copyright (c) 2004, 2008 IBM Corporation
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
10 * IBM Corporation - initial implementation
11 *****************************************************************************/
14 /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ALGORITHMS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
16 /** \file dhcp.c <pre>
17 * **************** State-transition diagram for DHCP client *************
19 * +---------+ Note: DHCP-server msg / DHCP-client msg
32 * +---------+ NACK / - ***********
33 * | REQUEST | ----------------> * FAULT *
34 * +---------+ ***********
36 * | ACK / - ***********
37 * +----------------------> * SUCCESS *
40 * ************************************************************************
44 /*>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<<<*/
55 #include <sys/socket.h>
59 /* DHCP Message Types */
60 #define DHCPDISCOVER 1
69 /* DHCP Option Codes */
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_CLIENT_ARCH 93
81 #define DHCP_ENDOPT 0xFF
82 #define DHCP_PADOPT 0x00
84 /* "file/sname" overload option values */
85 #define DHCP_OVERLOAD_FILE 1
86 #define DHCP_OVERLOAD_SNAME 2
87 #define DHCP_OVERLOAD_BOTH 3
89 /* DHCP states codes */
90 #define DHCP_STATE_SELECT 1
91 #define DHCP_STATE_REQUEST 2
92 #define DHCP_STATE_SUCCESS 3
93 #define DHCP_STATE_FAULT 4
95 /* DHCP Client Architecture */
97 #define USE_DHCPARCH 0
100 #define USE_DHCPARCH 1
103 static uint8_t dhcp_magic[] = {0x63, 0x82, 0x53, 0x63};
104 /**< DHCP_magic is a cookie, that identifies DHCP options (see RFC 2132) */
106 /** \struct dhcp_options_t
107 * This structure is used to fill options in DHCP-msg during transmitting
108 * or to retrieve options from DHCP-msg during receiving.
110 * If flag[i] == TRUE then field for i-th option retains valid value and
111 * information from this field may retrived (in case of receiving) or will
112 * be transmitted (in case of transmitting).
116 uint8_t flag[256]; /**< Show if corresponding opt. is valid */
117 uint8_t request_list[256]; /**< o.55 If i-th member is TRUE, then i-th
118 option will be requested from server */
119 uint32_t server_ID; /**< o.54 Identifies DHCP-server */
120 uint32_t requested_IP; /**< o.50 Must be filled in DHCP-Request */
121 uint32_t dns_IP; /**< o. 6 DNS IP */
122 uint32_t router_IP; /**< o. 3 Router IP */
123 uint32_t subnet_mask; /**< o. 1 Subnet mask */
124 uint8_t msg_type; /**< o.53 DHCP-message type */
125 uint8_t overload; /**< o.52 Overload sname/file fields */
126 int8_t tftp_server[256]; /**< o.66 TFTP server name */
127 int8_t bootfile[256]; /**< o.67 Boot file name */
128 uint16_t client_arch; /**< o.93 Client architecture type */
131 /** Stores state of DHCP-client (refer to State-transition diagram) */
132 static uint8_t dhcp_state;
135 /*>>>>>>>>>>>>>>>>>>>>>>>>>>>> PROTOTYPES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
138 dhcp_attempt(int fd);
141 dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct);
144 dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len,
145 dhcp_options_t * opt_struct);
148 dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len,
149 uint8_t src_options[], uint32_t src_len);
152 dhcp_find_option(uint8_t options[], uint32_t len,
153 uint8_t op_code, uint32_t * op_offset);
156 dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len,
157 uint8_t * new_option);
160 dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len,
161 uint32_t dst_offset, uint8_t * new_option);
164 dhcp_send_discover(int fd);
167 dhcp_send_request(int fd);
170 strtoip(int8_t * str, uint32_t * ip);
173 /*>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<<*/
175 static uint8_t ether_packet[ETH_MTU_SIZE];
176 static uint32_t dhcp_own_ip = 0;
177 static uint32_t dhcp_server_ip = 0;
178 static uint32_t dhcp_siaddr_ip = 0;
179 static int8_t dhcp_filename[256];
180 static int8_t dhcp_tftp_name[256];
182 static char * response_buffer;
184 /*>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<*/
187 dhcpv4(char *ret_buffer, filename_ip_t * fn_ip) {
189 uint32_t dhcp_tftp_ip = 0;
192 strcpy((char *) dhcp_filename, "");
193 strcpy((char *) dhcp_tftp_name, "");
195 response_buffer = ret_buffer;
197 if (dhcp_attempt(fd) == 0)
201 dhcp_own_ip = fn_ip->own_ip;
203 if (fn_ip->server_ip) {
204 dhcp_siaddr_ip = fn_ip->server_ip;
206 if(fn_ip->filename[0] != 0) {
207 strcpy((char *) dhcp_filename, (char *) fn_ip->filename);
211 if (!strlen((char *) dhcp_tftp_name)) {
212 if (!dhcp_siaddr_ip) {
213 // ERROR: TFTP name is not presented
217 // take TFTP-ip from siaddr field
218 dhcp_tftp_ip = dhcp_siaddr_ip;
221 // TFTP server defined by its name
222 if (!strtoip(dhcp_tftp_name, &(dhcp_tftp_ip))) {
223 if (!dns_get_ip(fd, dhcp_tftp_name, (uint8_t *)&(dhcp_tftp_ip), 4)) {
224 // DNS error - can't obtain TFTP-server name
225 // Use TFTP-ip from siaddr field, if presented
226 if (dhcp_siaddr_ip) {
227 dhcp_tftp_ip = dhcp_siaddr_ip;
230 // ERROR: Can't obtain TFTP server IP
237 // Store configuration info into filename_ip strucutre
238 fn_ip -> own_ip = dhcp_own_ip;
239 fn_ip -> server_ip = dhcp_tftp_ip;
240 strcpy((char *) fn_ip -> filename, (char *) dhcp_filename);
246 * DHCP: Tries o obtain DHCP parameters, refer to state-transition diagram
249 dhcp_attempt(int fd) {
252 // Send DISCOVER message and switch DHCP-client to SELECT state
253 dhcp_send_discover(fd);
255 dhcp_state = DHCP_STATE_SELECT;
257 // setting up a timer with a timeout of two seconds
258 for (sec = 0; sec < 2; sec++) {
259 set_timer(TICKS_SEC);
263 // Wait until client will switch to Final state or Timeout occurs
264 switch (dhcp_state) {
265 case DHCP_STATE_SUCCESS :
267 case DHCP_STATE_FAULT :
270 } while (get_timer() > 0);
278 * DHCP: Supplements DHCP-message with options stored in structure.
279 * For more information about option coding see dhcp_options_t.
281 * @param opt_field Points to the "vend" field of DHCP-message
283 * @param opt_struct this structure stores info about the options which
284 * will be added to DHCP-message (source)
285 * @return TRUE - options packed;
286 * FALSE - error condition occurs.
287 * @see dhcp_options_t
290 dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct) {
291 uint8_t * options = opt_field;
292 uint16_t i, sum; // used to define is any options set
295 memcpy(options, dhcp_magic, 4);
299 switch (opt_struct -> msg_type) {
305 options[0] = DHCP_MSG_TYPE;
307 options[2] = opt_struct -> msg_type;
311 return 0; // Unsupported DHCP-message
314 if (opt_struct -> overload) {
315 options[0] = DHCP_OVERLOAD;
317 options[2] = opt_struct -> overload;
321 if (opt_struct -> flag[DHCP_REQUESTED_IP]) {
322 options[0] = DHCP_REQUESTED_IP;
324 * (uint32_t *) (options + 2) = htonl (opt_struct -> requested_IP);
328 if (opt_struct -> flag[DHCP_SERVER_ID]) {
329 options[0] = DHCP_SERVER_ID;
331 * (uint32_t *) (options + 2) = htonl (opt_struct -> server_ID);
336 for (i = 0; i < 256; i++)
337 sum += opt_struct -> request_list[i];
340 options[0] = DHCP_REQUEST_LIST;
343 for (i = 0; i < 256; i++) {
344 if (opt_struct -> request_list[i]) {
345 options[0] = i; options++;
350 if (opt_struct -> flag[DHCP_TFTP_SERVER]) {
351 options[0] = DHCP_TFTP_SERVER;
352 options[1] = strlen((char *) opt_struct -> tftp_server) + 1;
353 memcpy(options + 2, opt_struct -> tftp_server, options[1]);
354 options += options[1] + 2;
357 if (opt_struct -> flag[DHCP_BOOTFILE]) {
358 options[0] = DHCP_BOOTFILE;
359 options[1] = strlen((char *) opt_struct -> bootfile) + 1;
360 memcpy(options + 2, opt_struct -> bootfile, options[1]);
361 options += options[1] + 2;
364 if (opt_struct -> flag[DHCP_CLIENT_ARCH]) {
365 options[0] = DHCP_CLIENT_ARCH;
367 options[2] = (DHCPARCH >> 8);
368 options[3] = DHCPARCH & 0xff;
380 * DHCP: Extracts encoded options from DHCP-message into the structure.
381 * For more information about option coding see dhcp_options_t.
383 * @param opt_field Points to the "options" field of DHCP-message
385 * @param opt_len Length of "options" field.
386 * @param opt_struct this structure stores info about the options which
387 * was extracted from DHCP-message (destination).
388 * @return TRUE - options extracted;
389 * FALSE - error condition occurs.
390 * @see dhcp_options_t
393 dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len,
394 dhcp_options_t * opt_struct) {
397 memset(opt_struct, 0, sizeof(dhcp_options_t));
400 if (memcmp(opt_field, dhcp_magic, 4)) {
405 while (offset < opt_len) {
406 opt_struct -> flag[opt_field[offset]] = 1;
407 switch(opt_field[offset]) {
409 opt_struct -> overload = opt_field[offset + 2];
410 offset += 2 + opt_field[offset + 1];
413 case DHCP_REQUESTED_IP :
414 opt_struct -> requested_IP = htonl(* (uint32_t *) (opt_field + offset + 2));
415 offset += 2 + opt_field[offset + 1];
419 opt_struct -> flag[DHCP_MASK] = 1;
420 opt_struct -> subnet_mask = htonl(* (uint32_t *) (opt_field + offset + 2));
421 offset += 2 + opt_field[offset + 1];
425 opt_struct -> flag[DHCP_DNS] = 1;
426 opt_struct -> dns_IP = htonl(* (uint32_t *) (opt_field + offset + 2));
427 offset += 2 + opt_field[offset + 1];
431 opt_struct -> flag[DHCP_ROUTER] = 1;
432 opt_struct -> router_IP = htonl(* (uint32_t *) (opt_field + offset + 2));
433 offset += 2 + opt_field[offset + 1];
437 if ((opt_field[offset + 2] > 0) && (opt_field[offset + 2] < 9))
438 opt_struct -> msg_type = opt_field[offset + 2];
441 offset += 2 + opt_field[offset + 1];
444 case DHCP_SERVER_ID :
445 opt_struct -> server_ID = htonl(* (uint32_t *) (opt_field + offset + 2));
446 offset += 2 + opt_field[offset + 1];
449 case DHCP_TFTP_SERVER :
450 memcpy(opt_struct -> tftp_server, opt_field + offset + 2, opt_field[offset + 1]);
451 (opt_struct -> tftp_server)[opt_field[offset + 1]] = 0;
452 offset += 2 + opt_field[offset + 1];
456 memcpy(opt_struct -> bootfile, opt_field + offset + 2, opt_field[offset + 1]);
457 (opt_struct -> bootfile)[opt_field[offset + 1]] = 0;
458 offset += 2 + opt_field[offset + 1];
461 case DHCP_CLIENT_ARCH :
462 opt_struct -> client_arch = ((opt_field[offset + 2] << 8) & 0xFF00) | (opt_field[offset + 3] & 0xFF);
470 case DHCP_ENDOPT : // End of options
474 offset += 2 + opt_field[offset + 1]; // Unsupported opt. - do nothing
477 if (offset == opt_len)
478 return 1; // options finished without 0xFF
484 * DHCP: Appends information from source "options" into dest "options".
485 * This function is used to support "file/sname" overloading.
487 * @param dst_options destanation "options" field
488 * @param dst_len size of dst_options (modified by this function)
489 * @param src_options source "options" field
490 * @param src_len size of src_options
491 * @return TRUE - options merged;
492 * FALSE - error condition occurs.
494 static int8_t dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len,
495 uint8_t src_options[], uint32_t src_len) {
496 int32_t dst_offset, src_offset = 0;
498 // remove ENDOPT if presented
499 if (dhcp_find_option(dst_options, * dst_len, DHCP_ENDOPT, (uint32_t *) &dst_offset))
500 * dst_len = dst_offset;
502 while (src_offset < src_len) {
503 switch(src_options[src_offset]) {
510 if (dhcp_find_option(dst_options, * dst_len,
511 src_options[src_offset],
512 (uint32_t *) &dst_offset)) {
513 dhcp_combine_option(dst_options, dst_len,
515 (uint8_t *) src_options +
519 dhcp_append_option(dst_options, dst_len, src_options + src_offset);
521 src_offset += 2 + src_options[src_offset + 1];
525 if (src_offset == src_len)
531 * DHCP: Finds given occurrence of the option with the given code (op_code)
532 * in "options" field of DHCP-message.
534 * @param options "options" field of DHCP-message
535 * @param len length of the "options" field
536 * @param op_code code of the option to find
537 * @param op_offset SUCCESS - offset to an option occurrence;
538 * FAULT - offset is set to zero.
539 * @return TRUE - option was find;
540 * FALSE - option wasn't find.
542 static int8_t dhcp_find_option(uint8_t options[], uint32_t len,
543 uint8_t op_code, uint32_t * op_offset) {
544 uint32_t srch_offset = 0;
547 while (srch_offset < len) {
548 if (options[srch_offset] == op_code) {
549 * op_offset = srch_offset;
552 if (options[srch_offset] == DHCP_ENDOPT)
555 if (options[srch_offset] == DHCP_PADOPT)
558 srch_offset += 2 + options[srch_offset + 1];
564 * DHCP: Appends new option from one list (src) into the tail
565 * of another option list (dst)
567 * @param dst_options "options" field of DHCP-message
568 * @param dst_len length of the "options" field (modified)
569 * @param new_option points to an option in another list (src)
572 dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len,
573 uint8_t * new_option) {
574 memcpy(dst_options + ( * dst_len), new_option, 2 + (* (new_option + 1)));
575 * dst_len += 2 + *(new_option + 1);
579 * DHCP: This function is used when options with the same code are
580 * presented in both merged lists. In this case information
581 * about the option from one list (src) is combined (complemented)
582 * with information about the option in another list (dst).
584 * @param dst_options "options" field of DHCP-message
585 * @param dst_len length of the "options" field (modified)
586 * @param dst_offset offset of the option from beginning of the list
587 * @param new_option points to an option in another list (src)
590 dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len,
591 uint32_t dst_offset, uint8_t * new_option) {
593 uint8_t tmp_buffer[1024]; // use to provide safe memcpy
596 // move all subsequent options (allocate size for additional info)
597 tail_len = (* dst_len) - dst_offset - 2 - dst_options[dst_offset + 1];
599 memcpy(tmp_buffer, dst_options + (* dst_len) - tail_len, tail_len);
600 memcpy(dst_options + (* dst_len) - tail_len + (* (new_option + 1)),
601 tmp_buffer, tail_len);
603 // add new_content to option
604 memcpy(dst_options + (* dst_len) - tail_len, new_option + 2,
606 dst_options[dst_offset + 1] += * (new_option + 1);
609 * dst_len += * (new_option + 1);
613 * DHCP: Sends DHCP-Discover message. Looks for DHCP servers.
616 dhcp_send_discover(int fd) {
617 uint32_t packetsize = sizeof(struct iphdr) +
618 sizeof(struct udphdr) + sizeof(struct btphdr);
622 memset(ether_packet, 0, packetsize);
624 btph = (struct btphdr *) (ðer_packet[
625 sizeof(struct iphdr) + sizeof(struct udphdr)]);
630 memcpy(btph -> chaddr, get_mac_address(), 6);
632 memset(&opt, 0, sizeof(dhcp_options_t));
634 opt.msg_type = DHCPDISCOVER;
636 opt.request_list[DHCP_MASK] = 1;
637 opt.request_list[DHCP_DNS] = 1;
638 opt.request_list[DHCP_ROUTER] = 1;
639 opt.request_list[DHCP_TFTP_SERVER] = 1;
640 opt.request_list[DHCP_BOOTFILE] = 1;
641 opt.request_list[DHCP_CLIENT_ARCH] = USE_DHCPARCH;
643 dhcp_encode_options(btph -> vend, &opt);
645 fill_udphdr(ðer_packet[sizeof(struct iphdr)],
646 sizeof(struct btphdr) + sizeof(struct udphdr),
647 UDPPORT_BOOTPC, UDPPORT_BOOTPS);
648 fill_iphdr(ether_packet, sizeof(struct btphdr) +
649 sizeof(struct udphdr) + sizeof(struct iphdr),
650 IPTYPE_UDP, dhcp_own_ip, 0xFFFFFFFF);
652 send_ipv4(fd, ether_packet, packetsize);
656 * DHCP: Sends DHCP-Request message. Asks for acknowledgment to occupy IP.
659 dhcp_send_request(int fd) {
660 uint32_t packetsize = sizeof(struct iphdr) +
661 sizeof(struct udphdr) + sizeof(struct btphdr);
665 memset(ether_packet, 0, packetsize);
667 btph = (struct btphdr *) (ðer_packet[
668 sizeof(struct iphdr) + sizeof(struct udphdr)]);
673 memcpy(btph -> chaddr, get_mac_address(), 6);
675 memset(&opt, 0, sizeof(dhcp_options_t));
677 opt.msg_type = DHCPREQUEST;
678 memcpy(&(opt.requested_IP), &dhcp_own_ip, 4);
679 opt.flag[DHCP_REQUESTED_IP] = 1;
680 memcpy(&(opt.server_ID), &dhcp_server_ip, 4);
681 opt.flag[DHCP_SERVER_ID] = 1;
683 opt.request_list[DHCP_MASK] = 1;
684 opt.request_list[DHCP_DNS] = 1;
685 opt.request_list[DHCP_ROUTER] = 1;
686 opt.request_list[DHCP_TFTP_SERVER] = 1;
687 opt.request_list[DHCP_BOOTFILE] = 1;
688 opt.request_list[DHCP_CLIENT_ARCH] = USE_DHCPARCH;
689 opt.flag[DHCP_CLIENT_ARCH] = USE_DHCPARCH;
691 dhcp_encode_options(btph -> vend, &opt);
693 fill_udphdr(ðer_packet[sizeof(struct iphdr)],
694 sizeof(struct btphdr) + sizeof(struct udphdr),
695 UDPPORT_BOOTPC, UDPPORT_BOOTPS);
696 fill_iphdr(ether_packet, sizeof(struct btphdr) +
697 sizeof(struct udphdr) + sizeof(struct iphdr),
698 IPTYPE_UDP, 0, 0xFFFFFFFF);
700 send_ipv4(fd, ether_packet, packetsize);
705 * DHCP: Sends DHCP-Release message. Releases occupied IP.
707 void dhcp_send_release(int fd) {
708 uint32_t packetsize = sizeof(struct iphdr) +
709 sizeof(struct udphdr) + sizeof(struct btphdr);
713 btph = (struct btphdr *) (ðer_packet[
714 sizeof(struct iphdr) + sizeof(struct udphdr)]);
716 memset(ether_packet, 0, packetsize);
721 strcpy((char *) btph -> file, "");
722 memcpy(btph -> chaddr, get_mac_address(), 6);
723 btph -> ciaddr = htonl(dhcp_own_ip);
725 memset(&opt, 0, sizeof(dhcp_options_t));
727 opt.msg_type = DHCPRELEASE;
728 opt.server_ID = dhcp_server_ip;
729 opt.flag[DHCP_SERVER_ID] = 1;
731 dhcp_encode_options(btph -> vend, &opt);
733 fill_udphdr(ðer_packet[sizeof(struct iphdr)],
734 sizeof(struct btphdr) + sizeof(struct udphdr),
735 UDPPORT_BOOTPC, UDPPORT_BOOTPS);
736 fill_iphdr(ether_packet, sizeof(struct btphdr) +
737 sizeof(struct udphdr) + sizeof(struct iphdr), IPTYPE_UDP,
738 dhcp_own_ip, dhcp_server_ip);
740 send_ipv4(fd, ether_packet, packetsize);
744 * DHCP: Handles DHCP-messages according to Receive-handle diagram.
745 * Changes the state of DHCP-client.
747 * @param fd socket descriptor
748 * @param packet BootP/DHCP-packet to be handled
749 * @param packetsize length of the packet
750 * @return ZERO - packet handled successfully;
751 * NON ZERO - packet was not handled (e.g. bad format)
757 handle_dhcp(int fd, uint8_t * packet, int32_t packetsize) {
758 struct btphdr * btph;
762 memset(&opt, 0, sizeof(dhcp_options_t));
763 btph = (struct btphdr *) packet;
764 iph = (struct iphdr *) packet - sizeof(struct udphdr) -
765 sizeof(struct iphdr);
767 return -1; // it is not Boot Reply
769 if (memcmp(btph -> vend, dhcp_magic, 4)) {
770 // It is BootP - RFC 951
771 dhcp_own_ip = htonl(btph -> yiaddr);
772 dhcp_siaddr_ip = htonl(btph -> siaddr);
773 dhcp_server_ip = htonl(iph -> ip_src);
775 if (strlen((char *) btph -> sname) && !dhcp_siaddr_ip) {
776 strncpy((char *) dhcp_tftp_name, (char *) btph -> sname,
777 sizeof(btph -> sname));
778 dhcp_tftp_name[sizeof(btph -> sname)] = 0;
781 if (strlen((char *) btph -> file)) {
782 strncpy((char *) dhcp_filename, (char *) btph -> file, sizeof(btph -> file));
783 dhcp_filename[sizeof(btph -> file)] = 0;
786 dhcp_state = DHCP_STATE_SUCCESS;
792 if (!dhcp_decode_options(btph -> vend, packetsize -
793 sizeof(struct btphdr) + sizeof(btph -> vend),
795 return -1; // can't decode options
799 int16_t decode_res = 0;
800 uint8_t options[1024]; // buffer for merged options
803 // move 1-st part of options from vend field into buffer
804 opt_len = packetsize - sizeof(struct btphdr) +
805 sizeof(btph -> vend) - 4;
806 memcpy(options, btph -> vend, opt_len + 4);
809 switch (opt.overload) {
810 case DHCP_OVERLOAD_FILE:
811 decode_res = dhcp_merge_options(options + 4, &opt_len,
813 sizeof(btph -> file));
815 case DHCP_OVERLOAD_SNAME:
816 decode_res = dhcp_merge_options(options + 4, &opt_len,
818 sizeof(btph -> sname));
820 case DHCP_OVERLOAD_BOTH:
821 decode_res = dhcp_merge_options(options + 4, &opt_len,
823 sizeof(btph -> file));
826 decode_res = dhcp_merge_options(options + 4, &opt_len,
828 sizeof(btph -> sname));
833 return -1; // bad options in sname/file fields
835 // decode merged options
836 if (!dhcp_decode_options(options, opt_len + 4, &opt)) {
837 return -1; // can't decode options
842 // It is BootP with Extensions - RFC 1497
843 // retrieve conf. settings from BootP - reply
844 dhcp_own_ip = htonl(btph -> yiaddr);
845 dhcp_siaddr_ip = htonl(btph -> siaddr);
846 if (strlen((char *) btph -> sname) && !dhcp_siaddr_ip) {
847 strncpy((char *) dhcp_tftp_name, (char *) btph -> sname, sizeof(btph -> sname));
848 dhcp_tftp_name[sizeof(btph -> sname)] = 0;
851 if (strlen((char *) btph -> file)) {
852 strncpy((char *) dhcp_filename, (char *) btph -> file, sizeof(btph -> file));
853 dhcp_filename[sizeof(btph -> file)] = 0;
856 // retrieve DHCP-server IP from IP-header
857 dhcp_server_ip = iph -> htonl(ip_src);
859 dhcp_state = DHCP_STATE_SUCCESS;
862 // It is DHCP - RFC 2131 & RFC 2132
863 // opt contains parameters from server
864 switch (dhcp_state) {
865 case DHCP_STATE_SELECT :
866 if (opt.msg_type == DHCPOFFER) {
867 dhcp_own_ip = htonl(btph -> yiaddr);
868 dhcp_server_ip = opt.server_ID;
869 dhcp_send_request(fd);
870 dhcp_state = DHCP_STATE_REQUEST;
873 case DHCP_STATE_REQUEST :
874 switch (opt.msg_type) {
878 dhcp_state = DHCP_STATE_FAULT;
881 dhcp_own_ip = htonl(btph -> yiaddr);
882 dhcp_server_ip = opt.server_ID;
883 dhcp_siaddr_ip = htonl(btph -> siaddr);
884 if (opt.flag[DHCP_TFTP_SERVER]) {
885 strcpy((char *) dhcp_tftp_name, (char *) opt.tftp_server);
888 strcpy((char *) dhcp_tftp_name, "");
889 if ((opt.overload != DHCP_OVERLOAD_SNAME &&
890 opt.overload != DHCP_OVERLOAD_BOTH) &&
892 strncpy((char *) dhcp_tftp_name,
893 (char *) btph->sname,
894 sizeof(btph -> sname));
895 dhcp_tftp_name[sizeof(btph->sname)] = 0;
899 if (opt.flag[DHCP_BOOTFILE]) {
900 strcpy((char *) dhcp_filename, (char *) opt.bootfile);
903 strcpy((char *) dhcp_filename, "");
904 if (opt.overload != DHCP_OVERLOAD_FILE &&
905 opt.overload != DHCP_OVERLOAD_BOTH &&
906 strlen((char *) btph -> file)) {
907 strncpy((char *) dhcp_filename,
910 dhcp_filename[sizeof(btph -> file)] = 0;
914 dhcp_state = DHCP_STATE_SUCCESS;
917 break; // Unused DHCP-message - do nothing
921 return -1; // Illegal DHCP-client state
925 if (dhcp_state == DHCP_STATE_SUCCESS) {
927 // initialize network entity with real own_ip
928 // to be able to answer for foreign requests
929 set_ipv4_address(dhcp_own_ip);
931 if(response_buffer) {
932 if(packetsize <= 1720)
933 memcpy(response_buffer, packet, packetsize);
935 memcpy(response_buffer, packet, 1720);
939 if (opt.flag[DHCP_MASK]) {
941 if (opt.flag[DHCP_ROUTER]) {
942 set_ipv4_router(opt.router_IP);
943 set_ipv4_netmask(opt.subnet_mask);
948 if (opt.flag[DHCP_DNS]) {
949 dns_init(opt.dns_IP, 0, 4);
957 * DHCP: Converts "255.255.255.255" -> 32-bit long IP
959 * @param str string to be converted
960 * @param ip in case of SUCCESS - 32-bit long IP
961 in case of FAULT - zero
962 * @return TRUE - IP converted successfully;
963 * FALSE - error condition occurs (e.g. bad format)
966 strtoip(int8_t * str, uint32_t * ip) {
967 int8_t ** ptr = &str;
968 int16_t i = 0, res, len;
974 if (i > 3 || !isdigit(**ptr))
976 if (strstr((char *) * ptr, ".") != NULL) {
977 len = (int16_t) ((int8_t *) strstr((char *) * ptr, ".") -
979 strncpy(octet, (char *) * ptr, len); octet[len] = 0;
983 strcpy(octet, (char *) * ptr);
984 * ptr += strlen(octet);
986 res = strtol(octet, NULL, 10);
987 if ((res > 255) || (res < 0))
989 * ip = ((* ip) << 8) + res;