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 ***********************/
51 #include <netapps/args.h>
56 #include <sys/socket.h>
60 /* DHCP Message Types */
61 #define DHCPDISCOVER 1
70 /* DHCP Option Codes */
74 #define DHCP_REQUESTED_IP 50
75 #define DHCP_OVERLOAD 52
76 #define DHCP_MSG_TYPE 53
77 #define DHCP_SERVER_ID 54
78 #define DHCP_REQUEST_LIST 55
79 #define DHCP_TFTP_SERVER 66
80 #define DHCP_BOOTFILE 67
81 #define DHCP_CLIENT_ARCH 93
82 #define DHCP_ENDOPT 0xFF
83 #define DHCP_PADOPT 0x00
85 /* "file/sname" overload option values */
86 #define DHCP_OVERLOAD_FILE 1
87 #define DHCP_OVERLOAD_SNAME 2
88 #define DHCP_OVERLOAD_BOTH 3
90 /* DHCP states codes */
91 #define DHCP_STATE_SELECT 1
92 #define DHCP_STATE_REQUEST 2
93 #define DHCP_STATE_SUCCESS 3
94 #define DHCP_STATE_FAULT 4
96 /* DHCP Client Architecture */
98 #define USE_DHCPARCH 0
101 #define USE_DHCPARCH 1
104 static uint8_t dhcp_magic[] = {0x63, 0x82, 0x53, 0x63};
105 /**< DHCP_magic is a cookie, that identifies DHCP options (see RFC 2132) */
107 /** \struct dhcp_options_t
108 * This structure is used to fill options in DHCP-msg during transmitting
109 * or to retrieve options from DHCP-msg during receiving.
111 * If flag[i] == TRUE then field for i-th option retains valid value and
112 * information from this field may retrived (in case of receiving) or will
113 * be transmitted (in case of transmitting).
117 uint8_t flag[256]; /**< Show if corresponding opt. is valid */
118 uint8_t request_list[256]; /**< o.55 If i-th member is TRUE, then i-th
119 option will be requested from server */
120 uint32_t server_ID; /**< o.54 Identifies DHCP-server */
121 uint32_t requested_IP; /**< o.50 Must be filled in DHCP-Request */
122 uint32_t dns_IP; /**< o. 6 DNS IP */
123 uint32_t router_IP; /**< o. 3 Router IP */
124 uint32_t subnet_mask; /**< o. 1 Subnet mask */
125 uint8_t msg_type; /**< o.53 DHCP-message type */
126 uint8_t overload; /**< o.52 Overload sname/file fields */
127 int8_t tftp_server[256]; /**< o.66 TFTP server name */
128 int8_t bootfile[256]; /**< o.67 Boot file name */
129 uint16_t client_arch; /**< o.93 Client architecture type */
132 /** Stores state of DHCP-client (refer to State-transition diagram) */
133 static uint8_t dhcp_state;
136 /***************************** PROTOTYPES ********************************/
138 static int32_t dhcp_attempt(int fd);
140 static int32_t dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct);
142 static int32_t dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len,
143 dhcp_options_t * opt_struct);
145 static int8_t dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len,
146 uint8_t src_options[], uint32_t src_len);
148 static int8_t dhcp_find_option(uint8_t options[], uint32_t len,
149 uint8_t op_code, uint32_t * op_offset);
151 static void dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len,
152 uint8_t * new_option);
154 static void dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len,
155 uint32_t dst_offset, uint8_t * new_option);
157 static void dhcp_send_discover(int fd);
159 static void dhcp_send_request(int fd);
161 /***************************** LOCAL VARIABLES ***************************/
163 static uint8_t ether_packet[ETH_MTU_SIZE];
164 static uint32_t dhcp_own_ip = 0;
165 static uint32_t dhcp_server_ip = 0;
166 static uint32_t dhcp_siaddr_ip = 0;
167 static char dhcp_filename[256];
168 static char dhcp_tftp_name[256];
169 static uint32_t dhcp_xid;
171 static char * response_buffer;
173 /***************************** IMPLEMENTATION ****************************/
175 void dhcpv4_generate_transaction_id(void)
177 dhcp_xid = (rand() << 16) ^ rand();
180 int32_t dhcpv4(char *ret_buffer, filename_ip_t *fn_ip)
182 uint32_t dhcp_tftp_ip = 0;
185 strcpy(dhcp_filename, "");
186 strcpy(dhcp_tftp_name, "");
188 response_buffer = ret_buffer;
190 if (dhcp_attempt(fd) == 0)
194 dhcp_own_ip = fn_ip->own_ip;
196 if (fn_ip->server_ip) {
197 dhcp_siaddr_ip = fn_ip->server_ip;
199 if(fn_ip->filename[0] != 0) {
200 strcpy(dhcp_filename, (char *) fn_ip->filename);
204 if (!strlen(dhcp_tftp_name)) {
205 if (!dhcp_siaddr_ip) {
206 // ERROR: TFTP name is not presented
210 // take TFTP-ip from siaddr field
211 dhcp_tftp_ip = dhcp_siaddr_ip;
214 // TFTP server defined by its name
215 if (!strtoip(dhcp_tftp_name, (char *)&dhcp_tftp_ip)) {
216 if (!dns_get_ip(fd, dhcp_tftp_name, (uint8_t *)&dhcp_tftp_ip, 4)) {
217 // DNS error - can't obtain TFTP-server name
218 // Use TFTP-ip from siaddr field, if presented
219 if (dhcp_siaddr_ip) {
220 dhcp_tftp_ip = dhcp_siaddr_ip;
223 // ERROR: Can't obtain TFTP server IP
230 // Store configuration info into filename_ip strucutre
231 fn_ip -> own_ip = dhcp_own_ip;
232 fn_ip -> server_ip = dhcp_tftp_ip;
233 strcpy((char *) fn_ip -> filename, dhcp_filename);
239 * DHCP: Tries o obtain DHCP parameters, refer to state-transition diagram
241 static int32_t dhcp_attempt(int fd)
245 // Send DISCOVER message and switch DHCP-client to SELECT state
246 dhcp_send_discover(fd);
248 dhcp_state = DHCP_STATE_SELECT;
250 // setting up a timer with a timeout of two seconds
251 for (sec = 0; sec < 2; sec++) {
252 set_timer(TICKS_SEC);
256 // Wait until client will switch to Final state or Timeout occurs
257 switch (dhcp_state) {
258 case DHCP_STATE_SUCCESS :
260 case DHCP_STATE_FAULT :
263 } while (get_timer() > 0);
271 * DHCP: Supplements DHCP-message with options stored in structure.
272 * For more information about option coding see dhcp_options_t.
274 * @param opt_field Points to the "vend" field of DHCP-message
276 * @param opt_struct this structure stores info about the options which
277 * will be added to DHCP-message (source)
278 * @return TRUE - options packed;
279 * FALSE - error condition occurs.
280 * @see dhcp_options_t
282 static int32_t dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct)
284 uint8_t * options = opt_field;
285 uint16_t i, sum; // used to define is any options set
288 memcpy(options, dhcp_magic, 4);
292 switch (opt_struct -> msg_type) {
298 options[0] = DHCP_MSG_TYPE;
300 options[2] = opt_struct -> msg_type;
304 return 0; // Unsupported DHCP-message
307 if (opt_struct -> overload) {
308 options[0] = DHCP_OVERLOAD;
310 options[2] = opt_struct -> overload;
314 if (opt_struct -> flag[DHCP_REQUESTED_IP]) {
315 options[0] = DHCP_REQUESTED_IP;
317 * (uint32_t *) (options + 2) = htonl (opt_struct -> requested_IP);
321 if (opt_struct -> flag[DHCP_SERVER_ID]) {
322 options[0] = DHCP_SERVER_ID;
324 * (uint32_t *) (options + 2) = htonl (opt_struct -> server_ID);
329 for (i = 0; i < 256; i++)
330 sum += opt_struct -> request_list[i];
333 options[0] = DHCP_REQUEST_LIST;
336 for (i = 0; i < 256; i++) {
337 if (opt_struct -> request_list[i]) {
338 options[0] = i; options++;
343 if (opt_struct -> flag[DHCP_TFTP_SERVER]) {
344 options[0] = DHCP_TFTP_SERVER;
345 options[1] = strlen((char *) opt_struct -> tftp_server) + 1;
346 memcpy(options + 2, opt_struct -> tftp_server, options[1]);
347 options += options[1] + 2;
350 if (opt_struct -> flag[DHCP_BOOTFILE]) {
351 options[0] = DHCP_BOOTFILE;
352 options[1] = strlen((char *) opt_struct -> bootfile) + 1;
353 memcpy(options + 2, opt_struct -> bootfile, options[1]);
354 options += options[1] + 2;
357 if (opt_struct -> flag[DHCP_CLIENT_ARCH]) {
358 options[0] = DHCP_CLIENT_ARCH;
360 options[2] = (DHCPARCH >> 8);
361 options[3] = DHCPARCH & 0xff;
373 * DHCP: Extracts encoded options from DHCP-message into the structure.
374 * For more information about option coding see dhcp_options_t.
376 * @param opt_field Points to the "options" field of DHCP-message
378 * @param opt_len Length of "options" field.
379 * @param opt_struct this structure stores info about the options which
380 * was extracted from DHCP-message (destination).
381 * @return TRUE - options extracted;
382 * FALSE - error condition occurs.
383 * @see dhcp_options_t
385 static int32_t dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len,
386 dhcp_options_t * opt_struct)
390 memset(opt_struct, 0, sizeof(dhcp_options_t));
393 if (memcmp(opt_field, dhcp_magic, 4)) {
398 while (offset < opt_len) {
399 opt_struct -> flag[opt_field[offset]] = 1;
400 switch(opt_field[offset]) {
402 opt_struct -> overload = opt_field[offset + 2];
403 offset += 2 + opt_field[offset + 1];
406 case DHCP_REQUESTED_IP :
407 opt_struct -> requested_IP = htonl(* (uint32_t *) (opt_field + offset + 2));
408 offset += 2 + opt_field[offset + 1];
412 opt_struct -> flag[DHCP_MASK] = 1;
413 opt_struct -> subnet_mask = htonl(* (uint32_t *) (opt_field + offset + 2));
414 offset += 2 + opt_field[offset + 1];
418 opt_struct -> flag[DHCP_DNS] = 1;
419 opt_struct -> dns_IP = htonl(* (uint32_t *) (opt_field + offset + 2));
420 offset += 2 + opt_field[offset + 1];
424 opt_struct -> flag[DHCP_ROUTER] = 1;
425 opt_struct -> router_IP = htonl(* (uint32_t *) (opt_field + offset + 2));
426 offset += 2 + opt_field[offset + 1];
430 if ((opt_field[offset + 2] > 0) && (opt_field[offset + 2] < 9))
431 opt_struct -> msg_type = opt_field[offset + 2];
434 offset += 2 + opt_field[offset + 1];
437 case DHCP_SERVER_ID :
438 opt_struct -> server_ID = htonl(* (uint32_t *) (opt_field + offset + 2));
439 offset += 2 + opt_field[offset + 1];
442 case DHCP_TFTP_SERVER :
443 memcpy(opt_struct -> tftp_server, opt_field + offset + 2, opt_field[offset + 1]);
444 (opt_struct -> tftp_server)[opt_field[offset + 1]] = 0;
445 offset += 2 + opt_field[offset + 1];
449 memcpy(opt_struct -> bootfile, opt_field + offset + 2, opt_field[offset + 1]);
450 (opt_struct -> bootfile)[opt_field[offset + 1]] = 0;
451 offset += 2 + opt_field[offset + 1];
454 case DHCP_CLIENT_ARCH :
455 opt_struct -> client_arch = ((opt_field[offset + 2] << 8) & 0xFF00) | (opt_field[offset + 3] & 0xFF);
463 case DHCP_ENDOPT : // End of options
467 offset += 2 + opt_field[offset + 1]; // Unsupported opt. - do nothing
470 if (offset == opt_len)
471 return 1; // options finished without 0xFF
477 * DHCP: Appends information from source "options" into dest "options".
478 * This function is used to support "file/sname" overloading.
480 * @param dst_options destanation "options" field
481 * @param dst_len size of dst_options (modified by this function)
482 * @param src_options source "options" field
483 * @param src_len size of src_options
484 * @return TRUE - options merged;
485 * FALSE - error condition occurs.
487 static int8_t dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len,
488 uint8_t src_options[], uint32_t src_len)
490 uint32_t dst_offset, src_offset = 0;
492 // remove ENDOPT if presented
493 if (dhcp_find_option(dst_options, * dst_len, DHCP_ENDOPT, &dst_offset))
494 * dst_len = dst_offset;
496 while (src_offset < src_len) {
497 switch(src_options[src_offset]) {
504 if (dhcp_find_option(dst_options, * dst_len,
505 src_options[src_offset],
507 dhcp_combine_option(dst_options, dst_len,
509 (uint8_t *) src_options +
513 dhcp_append_option(dst_options, dst_len, src_options + src_offset);
515 src_offset += 2 + src_options[src_offset + 1];
519 if (src_offset == src_len)
525 * DHCP: Finds given occurrence of the option with the given code (op_code)
526 * in "options" field of DHCP-message.
528 * @param options "options" field of DHCP-message
529 * @param len length of the "options" field
530 * @param op_code code of the option to find
531 * @param op_offset SUCCESS - offset to an option occurrence;
532 * FAULT - offset is set to zero.
533 * @return TRUE - option was find;
534 * FALSE - option wasn't find.
536 static int8_t dhcp_find_option(uint8_t options[], uint32_t len,
537 uint8_t op_code, uint32_t * op_offset)
539 uint32_t srch_offset = 0;
542 while (srch_offset < len) {
543 if (options[srch_offset] == op_code) {
544 * op_offset = srch_offset;
547 if (options[srch_offset] == DHCP_ENDOPT)
550 if (options[srch_offset] == DHCP_PADOPT)
553 srch_offset += 2 + options[srch_offset + 1];
559 * DHCP: Appends new option from one list (src) into the tail
560 * of another option list (dst)
562 * @param dst_options "options" field of DHCP-message
563 * @param dst_len length of the "options" field (modified)
564 * @param new_option points to an option in another list (src)
566 static void dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len,
567 uint8_t * new_option)
569 memcpy(dst_options + ( * dst_len), new_option, 2 + (* (new_option + 1)));
570 * dst_len += 2 + *(new_option + 1);
574 * DHCP: This function is used when options with the same code are
575 * presented in both merged lists. In this case information
576 * about the option from one list (src) is combined (complemented)
577 * with information about the option in another list (dst).
579 * @param dst_options "options" field of DHCP-message
580 * @param dst_len length of the "options" field (modified)
581 * @param dst_offset offset of the option from beginning of the list
582 * @param new_option points to an option in another list (src)
584 static void dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len,
585 uint32_t dst_offset, uint8_t * new_option)
587 uint8_t tmp_buffer[1024]; // use to provide safe memcpy
590 // move all subsequent options (allocate size for additional info)
591 tail_len = (* dst_len) - dst_offset - 2 - dst_options[dst_offset + 1];
593 memcpy(tmp_buffer, dst_options + (* dst_len) - tail_len, tail_len);
594 memcpy(dst_options + (* dst_len) - tail_len + (* (new_option + 1)),
595 tmp_buffer, tail_len);
597 // add new_content to option
598 memcpy(dst_options + (* dst_len) - tail_len, new_option + 2,
600 dst_options[dst_offset + 1] += * (new_option + 1);
603 * dst_len += * (new_option + 1);
607 * DHCP: Sends DHCP-Discover message. Looks for DHCP servers.
609 static void dhcp_send_discover(int fd)
611 uint32_t packetsize = sizeof(struct iphdr) +
612 sizeof(struct udphdr) + sizeof(struct btphdr);
616 memset(ether_packet, 0, packetsize);
618 btph = (struct btphdr *) (ðer_packet[
619 sizeof(struct iphdr) + sizeof(struct udphdr)]);
624 btph -> xid = dhcp_xid;
625 memcpy(btph -> chaddr, get_mac_address(), 6);
627 memset(&opt, 0, sizeof(dhcp_options_t));
629 opt.msg_type = DHCPDISCOVER;
631 opt.request_list[DHCP_MASK] = 1;
632 opt.request_list[DHCP_DNS] = 1;
633 opt.request_list[DHCP_ROUTER] = 1;
634 opt.request_list[DHCP_TFTP_SERVER] = 1;
635 opt.request_list[DHCP_BOOTFILE] = 1;
636 opt.request_list[DHCP_CLIENT_ARCH] = USE_DHCPARCH;
638 dhcp_encode_options(btph -> vend, &opt);
640 fill_udphdr(ðer_packet[sizeof(struct iphdr)],
641 sizeof(struct btphdr) + sizeof(struct udphdr),
642 UDPPORT_BOOTPC, UDPPORT_BOOTPS);
643 fill_iphdr(ether_packet, sizeof(struct btphdr) +
644 sizeof(struct udphdr) + sizeof(struct iphdr),
645 IPTYPE_UDP, dhcp_own_ip, 0xFFFFFFFF);
647 send_ipv4(fd, ether_packet, packetsize);
651 * DHCP: Sends DHCP-Request message. Asks for acknowledgment to occupy IP.
653 static void dhcp_send_request(int fd)
655 uint32_t packetsize = sizeof(struct iphdr) +
656 sizeof(struct udphdr) + sizeof(struct btphdr);
660 memset(ether_packet, 0, packetsize);
662 btph = (struct btphdr *) (ðer_packet[
663 sizeof(struct iphdr) + sizeof(struct udphdr)]);
668 btph -> xid = dhcp_xid;
669 memcpy(btph -> chaddr, get_mac_address(), 6);
671 memset(&opt, 0, sizeof(dhcp_options_t));
673 opt.msg_type = DHCPREQUEST;
674 memcpy(&(opt.requested_IP), &dhcp_own_ip, 4);
675 opt.flag[DHCP_REQUESTED_IP] = 1;
676 memcpy(&(opt.server_ID), &dhcp_server_ip, 4);
677 opt.flag[DHCP_SERVER_ID] = 1;
679 opt.request_list[DHCP_MASK] = 1;
680 opt.request_list[DHCP_DNS] = 1;
681 opt.request_list[DHCP_ROUTER] = 1;
682 opt.request_list[DHCP_TFTP_SERVER] = 1;
683 opt.request_list[DHCP_BOOTFILE] = 1;
684 opt.request_list[DHCP_CLIENT_ARCH] = USE_DHCPARCH;
685 opt.flag[DHCP_CLIENT_ARCH] = USE_DHCPARCH;
687 dhcp_encode_options(btph -> vend, &opt);
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);
696 send_ipv4(fd, ether_packet, packetsize);
701 * DHCP: Sends DHCP-Release message. Releases occupied IP.
703 void dhcp_send_release(int fd)
705 uint32_t packetsize = sizeof(struct iphdr) +
706 sizeof(struct udphdr) + sizeof(struct btphdr);
710 btph = (struct btphdr *) (ðer_packet[
711 sizeof(struct iphdr) + sizeof(struct udphdr)]);
713 memset(ether_packet, 0, packetsize);
718 btph -> xid = dhcp_xid;
719 strcpy((char *) btph -> file, "");
720 memcpy(btph -> chaddr, get_mac_address(), 6);
721 btph -> ciaddr = htonl(dhcp_own_ip);
723 memset(&opt, 0, sizeof(dhcp_options_t));
725 opt.msg_type = DHCPRELEASE;
726 opt.server_ID = dhcp_server_ip;
727 opt.flag[DHCP_SERVER_ID] = 1;
729 dhcp_encode_options(btph -> vend, &opt);
731 fill_udphdr(ðer_packet[sizeof(struct iphdr)],
732 sizeof(struct btphdr) + sizeof(struct udphdr),
733 UDPPORT_BOOTPC, UDPPORT_BOOTPS);
734 fill_iphdr(ether_packet, sizeof(struct btphdr) +
735 sizeof(struct udphdr) + sizeof(struct iphdr), IPTYPE_UDP,
736 dhcp_own_ip, dhcp_server_ip);
738 send_ipv4(fd, ether_packet, packetsize);
742 * DHCP: Handles DHCP-messages according to Receive-handle diagram.
743 * Changes the state of DHCP-client.
745 * @param fd socket descriptor
746 * @param packet BootP/DHCP-packet to be handled
747 * @param packetsize length of the packet
748 * @return ZERO - packet handled successfully;
749 * NON ZERO - packet was not handled (e.g. bad format)
754 int8_t handle_dhcp(int fd, uint8_t * packet, int32_t packetsize)
756 struct btphdr * btph;
760 memset(&opt, 0, sizeof(dhcp_options_t));
761 btph = (struct btphdr *) packet;
762 iph = (struct iphdr *) packet - sizeof(struct udphdr) -
763 sizeof(struct iphdr);
766 return -1; /* It is not a Bootp/DHCP reply */
767 if (btph->xid != dhcp_xid)
768 return -1; /* The transaction ID does not match */
770 if (memcmp(btph -> vend, dhcp_magic, 4)) {
771 // It is BootP - RFC 951
772 dhcp_own_ip = htonl(btph -> yiaddr);
773 dhcp_siaddr_ip = htonl(btph -> siaddr);
774 dhcp_server_ip = htonl(iph -> ip_src);
776 if (strlen((char *) btph -> sname) && !dhcp_siaddr_ip) {
777 strncpy((char *) dhcp_tftp_name, (char *) btph -> sname,
778 sizeof(btph -> sname));
779 dhcp_tftp_name[sizeof(btph -> sname)] = 0;
782 if (strlen((char *) btph -> file)) {
783 strncpy((char *) dhcp_filename, (char *) btph -> file, sizeof(btph -> file));
784 dhcp_filename[sizeof(btph -> file)] = 0;
787 dhcp_state = DHCP_STATE_SUCCESS;
793 if (!dhcp_decode_options(btph -> vend, packetsize -
794 sizeof(struct btphdr) + sizeof(btph -> vend),
796 return -1; // can't decode options
800 int16_t decode_res = 0;
801 uint8_t options[1024]; // buffer for merged options
804 // move 1-st part of options from vend field into buffer
805 opt_len = packetsize - sizeof(struct btphdr) +
806 sizeof(btph -> vend) - 4;
807 memcpy(options, btph -> vend, opt_len + 4);
810 switch (opt.overload) {
811 case DHCP_OVERLOAD_FILE:
812 decode_res = dhcp_merge_options(options + 4, &opt_len,
814 sizeof(btph -> file));
816 case DHCP_OVERLOAD_SNAME:
817 decode_res = dhcp_merge_options(options + 4, &opt_len,
819 sizeof(btph -> sname));
821 case DHCP_OVERLOAD_BOTH:
822 decode_res = dhcp_merge_options(options + 4, &opt_len,
824 sizeof(btph -> file));
827 decode_res = dhcp_merge_options(options + 4, &opt_len,
829 sizeof(btph -> sname));
834 return -1; // bad options in sname/file fields
836 // decode merged options
837 if (!dhcp_decode_options(options, opt_len + 4, &opt)) {
838 return -1; // can't decode options
843 // It is BootP with Extensions - RFC 1497
844 // retrieve conf. settings from BootP - reply
845 dhcp_own_ip = htonl(btph -> yiaddr);
846 dhcp_siaddr_ip = htonl(btph -> siaddr);
847 if (strlen((char *) btph -> sname) && !dhcp_siaddr_ip) {
848 strncpy((char *) dhcp_tftp_name, (char *) btph -> sname, sizeof(btph -> sname));
849 dhcp_tftp_name[sizeof(btph -> sname)] = 0;
852 if (strlen((char *) btph -> file)) {
853 strncpy((char *) dhcp_filename, (char *) btph -> file, sizeof(btph -> file));
854 dhcp_filename[sizeof(btph -> file)] = 0;
857 // retrieve DHCP-server IP from IP-header
858 dhcp_server_ip = iph -> htonl(ip_src);
860 dhcp_state = DHCP_STATE_SUCCESS;
863 // It is DHCP - RFC 2131 & RFC 2132
864 // opt contains parameters from server
865 switch (dhcp_state) {
866 case DHCP_STATE_SELECT :
867 if (opt.msg_type == DHCPOFFER) {
868 dhcp_own_ip = htonl(btph -> yiaddr);
869 dhcp_server_ip = opt.server_ID;
870 dhcp_send_request(fd);
871 dhcp_state = DHCP_STATE_REQUEST;
874 case DHCP_STATE_REQUEST :
875 switch (opt.msg_type) {
879 dhcp_state = DHCP_STATE_FAULT;
882 dhcp_own_ip = htonl(btph -> yiaddr);
883 dhcp_server_ip = opt.server_ID;
884 dhcp_siaddr_ip = htonl(btph -> siaddr);
885 if (opt.flag[DHCP_TFTP_SERVER]) {
886 strcpy((char *) dhcp_tftp_name, (char *) opt.tftp_server);
889 strcpy((char *) dhcp_tftp_name, "");
890 if ((opt.overload != DHCP_OVERLOAD_SNAME &&
891 opt.overload != DHCP_OVERLOAD_BOTH) &&
893 strncpy((char *) dhcp_tftp_name,
894 (char *) btph->sname,
895 sizeof(btph -> sname));
896 dhcp_tftp_name[sizeof(btph->sname)] = 0;
900 if (opt.flag[DHCP_BOOTFILE]) {
901 strcpy((char *) dhcp_filename, (char *) opt.bootfile);
904 strcpy((char *) dhcp_filename, "");
905 if (opt.overload != DHCP_OVERLOAD_FILE &&
906 opt.overload != DHCP_OVERLOAD_BOTH &&
907 strlen((char *) btph -> file)) {
908 strncpy((char *) dhcp_filename,
911 dhcp_filename[sizeof(btph -> file)] = 0;
915 dhcp_state = DHCP_STATE_SUCCESS;
918 break; // Unused DHCP-message - do nothing
922 return -1; // Illegal DHCP-client state
926 if (dhcp_state == DHCP_STATE_SUCCESS) {
928 // initialize network entity with real own_ip
929 // to be able to answer for foreign requests
930 set_ipv4_address(dhcp_own_ip);
932 if(response_buffer) {
933 if(packetsize <= 1720)
934 memcpy(response_buffer, packet, packetsize);
936 memcpy(response_buffer, packet, 1720);
940 if (opt.flag[DHCP_MASK]) {
942 if (opt.flag[DHCP_ROUTER]) {
943 set_ipv4_router(opt.router_IP);
944 set_ipv4_netmask(opt.subnet_mask);
949 if (opt.flag[DHCP_DNS]) {
950 dns_init(opt.dns_IP, 0, 4);