diff options
Diffstat (limited to 'qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.c')
-rw-r--r-- | qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.c | 955 |
1 files changed, 0 insertions, 955 deletions
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.c deleted file mode 100644 index 7e2e88ccf..000000000 --- a/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.c +++ /dev/null @@ -1,955 +0,0 @@ -/****************************************************************************** - * Copyright (c) 2004, 2008 IBM Corporation - * All rights reserved. - * This program and the accompanying materials - * are made available under the terms of the BSD License - * which accompanies this distribution, and is available at - * http://www.opensource.org/licenses/bsd-license.php - * - * Contributors: - * IBM Corporation - initial implementation - *****************************************************************************/ - - -/******************************* ALGORITHMS ******************************/ - -/** \file dhcp.c <pre> - * **************** State-transition diagram for DHCP client ************* - * - * +---------+ Note: DHCP-server msg / DHCP-client msg - * | INIT | - * +---------+ - * | - * | - / Discover - * V - * +---------+ - * | SELECT | Timeout - * +---------+ | - * | | - * | Offer / Request | - * | | - * V V - * +---------+ NACK / - *********** - * | REQUEST | ----------------> * FAULT * - * +---------+ *********** - * | - * | ACK / - *********** - * +----------------------> * SUCCESS * - * *********** - * - * ************************************************************************ - * </pre> */ - - -/********************** DEFINITIONS & DECLARATIONS ***********************/ - -#include <dhcp.h> -#include <ethernet.h> -#include <ipv4.h> -#include <udp.h> -#include <dns.h> -#include <netapps/args.h> - -#include <stdio.h> -#include <string.h> -#include <time.h> -#include <sys/socket.h> -#include <ctype.h> -#include <stdlib.h> - -/* DHCP Message Types */ -#define DHCPDISCOVER 1 -#define DHCPOFFER 2 -#define DHCPREQUEST 3 -#define DHCPDECLINE 4 -#define DHCPACK 5 -#define DHCPNACK 6 -#define DHCPRELEASE 7 -#define DHCPINFORM 8 - -/* DHCP Option Codes */ -#define DHCP_MASK 1 -#define DHCP_ROUTER 3 -#define DHCP_DNS 6 -#define DHCP_REQUESTED_IP 50 -#define DHCP_OVERLOAD 52 -#define DHCP_MSG_TYPE 53 -#define DHCP_SERVER_ID 54 -#define DHCP_REQUEST_LIST 55 -#define DHCP_TFTP_SERVER 66 -#define DHCP_BOOTFILE 67 -#define DHCP_CLIENT_ARCH 93 -#define DHCP_ENDOPT 0xFF -#define DHCP_PADOPT 0x00 - -/* "file/sname" overload option values */ -#define DHCP_OVERLOAD_FILE 1 -#define DHCP_OVERLOAD_SNAME 2 -#define DHCP_OVERLOAD_BOTH 3 - -/* DHCP states codes */ -#define DHCP_STATE_SELECT 1 -#define DHCP_STATE_REQUEST 2 -#define DHCP_STATE_SUCCESS 3 -#define DHCP_STATE_FAULT 4 - -/* DHCP Client Architecture */ -#ifndef DHCPARCH -#define USE_DHCPARCH 0 -#define DHCPARCH 0 -#else -#define USE_DHCPARCH 1 -#endif - -static uint8_t dhcp_magic[] = {0x63, 0x82, 0x53, 0x63}; -/**< DHCP_magic is a cookie, that identifies DHCP options (see RFC 2132) */ - -/** \struct dhcp_options_t - * This structure is used to fill options in DHCP-msg during transmitting - * or to retrieve options from DHCP-msg during receiving. - * <p> - * If flag[i] == TRUE then field for i-th option retains valid value and - * information from this field may retrived (in case of receiving) or will - * be transmitted (in case of transmitting). - * - */ -typedef struct { - uint8_t flag[256]; /**< Show if corresponding opt. is valid */ - uint8_t request_list[256]; /**< o.55 If i-th member is TRUE, then i-th - option will be requested from server */ - uint32_t server_ID; /**< o.54 Identifies DHCP-server */ - uint32_t requested_IP; /**< o.50 Must be filled in DHCP-Request */ - uint32_t dns_IP; /**< o. 6 DNS IP */ - uint32_t router_IP; /**< o. 3 Router IP */ - uint32_t subnet_mask; /**< o. 1 Subnet mask */ - uint8_t msg_type; /**< o.53 DHCP-message type */ - uint8_t overload; /**< o.52 Overload sname/file fields */ - int8_t tftp_server[256]; /**< o.66 TFTP server name */ - int8_t bootfile[256]; /**< o.67 Boot file name */ - uint16_t client_arch; /**< o.93 Client architecture type */ -} dhcp_options_t; - -/** Stores state of DHCP-client (refer to State-transition diagram) */ -static uint8_t dhcp_state; - - -/***************************** PROTOTYPES ********************************/ - -static int32_t dhcp_attempt(int fd); - -static int32_t dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct); - -static int32_t dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len, - dhcp_options_t * opt_struct); - -static int8_t dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len, - uint8_t src_options[], uint32_t src_len); - -static int8_t dhcp_find_option(uint8_t options[], uint32_t len, - uint8_t op_code, uint32_t * op_offset); - -static void dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len, - uint8_t * new_option); - -static void dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len, - uint32_t dst_offset, uint8_t * new_option); - -static void dhcp_send_discover(int fd); - -static void dhcp_send_request(int fd); - -/***************************** LOCAL VARIABLES ***************************/ - -static uint8_t ether_packet[ETH_MTU_SIZE]; -static uint32_t dhcp_own_ip = 0; -static uint32_t dhcp_server_ip = 0; -static uint32_t dhcp_siaddr_ip = 0; -static char dhcp_filename[256]; -static char dhcp_tftp_name[256]; -static uint32_t dhcp_xid; - -static char * response_buffer; - -/***************************** IMPLEMENTATION ****************************/ - -void dhcpv4_generate_transaction_id(void) -{ - dhcp_xid = (rand() << 16) ^ rand(); -} - -int32_t dhcpv4(char *ret_buffer, filename_ip_t *fn_ip) -{ - uint32_t dhcp_tftp_ip = 0; - int fd = fn_ip->fd; - - strcpy(dhcp_filename, ""); - strcpy(dhcp_tftp_name, ""); - - response_buffer = ret_buffer; - - if (dhcp_attempt(fd) == 0) - return -1; - - if (fn_ip->own_ip) { - dhcp_own_ip = fn_ip->own_ip; - } - if (fn_ip->server_ip) { - dhcp_siaddr_ip = fn_ip->server_ip; - } - if(fn_ip->filename[0] != 0) { - strcpy(dhcp_filename, (char *) fn_ip->filename); - } - - // TFTP SERVER - if (!strlen(dhcp_tftp_name)) { - if (!dhcp_siaddr_ip) { - // ERROR: TFTP name is not presented - return -3; - } - - // take TFTP-ip from siaddr field - dhcp_tftp_ip = dhcp_siaddr_ip; - } - else { - // TFTP server defined by its name - if (!strtoip(dhcp_tftp_name, (char *)&dhcp_tftp_ip)) { - if (!dns_get_ip(fd, dhcp_tftp_name, (uint8_t *)&dhcp_tftp_ip, 4)) { - // DNS error - can't obtain TFTP-server name - // Use TFTP-ip from siaddr field, if presented - if (dhcp_siaddr_ip) { - dhcp_tftp_ip = dhcp_siaddr_ip; - } - else { - // ERROR: Can't obtain TFTP server IP - return -4; - } - } - } - } - - // Store configuration info into filename_ip strucutre - fn_ip -> own_ip = dhcp_own_ip; - fn_ip -> server_ip = dhcp_tftp_ip; - strcpy((char *) fn_ip -> filename, dhcp_filename); - - return 0; -} - -/** - * DHCP: Tries o obtain DHCP parameters, refer to state-transition diagram - */ -static int32_t dhcp_attempt(int fd) -{ - int sec; - - // Send DISCOVER message and switch DHCP-client to SELECT state - dhcp_send_discover(fd); - - dhcp_state = DHCP_STATE_SELECT; - - // setting up a timer with a timeout of two seconds - for (sec = 0; sec < 2; sec++) { - set_timer(TICKS_SEC); - do { - receive_ether(fd); - - // Wait until client will switch to Final state or Timeout occurs - switch (dhcp_state) { - case DHCP_STATE_SUCCESS : - return 1; - case DHCP_STATE_FAULT : - return 0; - } - } while (get_timer() > 0); - } - - // timeout - return 0; -} - -/** - * DHCP: Supplements DHCP-message with options stored in structure. - * For more information about option coding see dhcp_options_t. - * - * @param opt_field Points to the "vend" field of DHCP-message - * (destination) - * @param opt_struct this structure stores info about the options which - * will be added to DHCP-message (source) - * @return TRUE - options packed; - * FALSE - error condition occurs. - * @see dhcp_options_t - */ -static int32_t dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct) -{ - uint8_t * options = opt_field; - uint16_t i, sum; // used to define is any options set - - // magic - memcpy(options, dhcp_magic, 4); - options += 4; - - // fill message type - switch (opt_struct -> msg_type) { - case DHCPDISCOVER : - case DHCPREQUEST : - case DHCPDECLINE : - case DHCPINFORM : - case DHCPRELEASE : - options[0] = DHCP_MSG_TYPE; - options[1] = 1; - options[2] = opt_struct -> msg_type; - options += 3; - break; - default : - return 0; // Unsupported DHCP-message - } - - if (opt_struct -> overload) { - options[0] = DHCP_OVERLOAD; - options[1] = 0x01; - options[2] = opt_struct -> overload; - options +=3; - } - - if (opt_struct -> flag[DHCP_REQUESTED_IP]) { - options[0] = DHCP_REQUESTED_IP; - options[1] = 0x04; - * (uint32_t *) (options + 2) = htonl (opt_struct -> requested_IP); - options +=6; - } - - if (opt_struct -> flag[DHCP_SERVER_ID]) { - options[0] = DHCP_SERVER_ID; - options[1] = 0x04; - * (uint32_t *) (options + 2) = htonl (opt_struct -> server_ID); - options +=6; - } - - sum = 0; - for (i = 0; i < 256; i++) - sum += opt_struct -> request_list[i]; - - if (sum) { - options[0] = DHCP_REQUEST_LIST; - options[1] = sum; - options += 2; - for (i = 0; i < 256; i++) { - if (opt_struct -> request_list[i]) { - options[0] = i; options++; - } - } - } - - if (opt_struct -> flag[DHCP_TFTP_SERVER]) { - options[0] = DHCP_TFTP_SERVER; - options[1] = strlen((char *) opt_struct -> tftp_server) + 1; - memcpy(options + 2, opt_struct -> tftp_server, options[1]); - options += options[1] + 2; - } - - if (opt_struct -> flag[DHCP_BOOTFILE]) { - options[0] = DHCP_BOOTFILE; - options[1] = strlen((char *) opt_struct -> bootfile) + 1; - memcpy(options + 2, opt_struct -> bootfile, options[1]); - options += options[1] + 2; - } - - if (opt_struct -> flag[DHCP_CLIENT_ARCH]) { - options[0] = DHCP_CLIENT_ARCH; - options[1] = 2; - options[2] = (DHCPARCH >> 8); - options[3] = DHCPARCH & 0xff; - options += 4; - } - - // end options - options[0] = 0xFF; - options++; - - return 1; -} - -/** - * DHCP: Extracts encoded options from DHCP-message into the structure. - * For more information about option coding see dhcp_options_t. - * - * @param opt_field Points to the "options" field of DHCP-message - * (source). - * @param opt_len Length of "options" field. - * @param opt_struct this structure stores info about the options which - * was extracted from DHCP-message (destination). - * @return TRUE - options extracted; - * FALSE - error condition occurs. - * @see dhcp_options_t - */ -static int32_t dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len, - dhcp_options_t * opt_struct) -{ - uint32_t offset = 0; - - memset(opt_struct, 0, sizeof(dhcp_options_t)); - - // magic - if (memcmp(opt_field, dhcp_magic, 4)) { - return 0; - } - - offset += 4; - while (offset < opt_len) { - opt_struct -> flag[opt_field[offset]] = 1; - switch(opt_field[offset]) { - case DHCP_OVERLOAD : - opt_struct -> overload = opt_field[offset + 2]; - offset += 2 + opt_field[offset + 1]; - break; - - case DHCP_REQUESTED_IP : - opt_struct -> requested_IP = htonl(* (uint32_t *) (opt_field + offset + 2)); - offset += 2 + opt_field[offset + 1]; - break; - - case DHCP_MASK : - opt_struct -> flag[DHCP_MASK] = 1; - opt_struct -> subnet_mask = htonl(* (uint32_t *) (opt_field + offset + 2)); - offset += 2 + opt_field[offset + 1]; - break; - - case DHCP_DNS : - opt_struct -> flag[DHCP_DNS] = 1; - opt_struct -> dns_IP = htonl(* (uint32_t *) (opt_field + offset + 2)); - offset += 2 + opt_field[offset + 1]; - break; - - case DHCP_ROUTER : - opt_struct -> flag[DHCP_ROUTER] = 1; - opt_struct -> router_IP = htonl(* (uint32_t *) (opt_field + offset + 2)); - offset += 2 + opt_field[offset + 1]; - break; - - case DHCP_MSG_TYPE : - if ((opt_field[offset + 2] > 0) && (opt_field[offset + 2] < 9)) - opt_struct -> msg_type = opt_field[offset + 2]; - else - return 0; - offset += 2 + opt_field[offset + 1]; - break; - - case DHCP_SERVER_ID : - opt_struct -> server_ID = htonl(* (uint32_t *) (opt_field + offset + 2)); - offset += 2 + opt_field[offset + 1]; - break; - - case DHCP_TFTP_SERVER : - memcpy(opt_struct -> tftp_server, opt_field + offset + 2, opt_field[offset + 1]); - (opt_struct -> tftp_server)[opt_field[offset + 1]] = 0; - offset += 2 + opt_field[offset + 1]; - break; - - case DHCP_BOOTFILE : - memcpy(opt_struct -> bootfile, opt_field + offset + 2, opt_field[offset + 1]); - (opt_struct -> bootfile)[opt_field[offset + 1]] = 0; - offset += 2 + opt_field[offset + 1]; - break; - - case DHCP_CLIENT_ARCH : - opt_struct -> client_arch = ((opt_field[offset + 2] << 8) & 0xFF00) | (opt_field[offset + 3] & 0xFF); - offset += 4; - break; - - case DHCP_PADOPT : - offset++; - break; - - case DHCP_ENDOPT : // End of options - return 1; - - default : - offset += 2 + opt_field[offset + 1]; // Unsupported opt. - do nothing - } - } - if (offset == opt_len) - return 1; // options finished without 0xFF - - return 0; -} - -/** - * DHCP: Appends information from source "options" into dest "options". - * This function is used to support "file/sname" overloading. - * - * @param dst_options destanation "options" field - * @param dst_len size of dst_options (modified by this function) - * @param src_options source "options" field - * @param src_len size of src_options - * @return TRUE - options merged; - * FALSE - error condition occurs. - */ -static int8_t dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len, - uint8_t src_options[], uint32_t src_len) -{ - uint32_t dst_offset, src_offset = 0; - - // remove ENDOPT if presented - if (dhcp_find_option(dst_options, * dst_len, DHCP_ENDOPT, &dst_offset)) - * dst_len = dst_offset; - - while (src_offset < src_len) { - switch(src_options[src_offset]) { - case DHCP_PADOPT: - src_offset++; - break; - case DHCP_ENDOPT: - return 1; - default: - if (dhcp_find_option(dst_options, * dst_len, - src_options[src_offset], - &dst_offset)) { - dhcp_combine_option(dst_options, dst_len, - dst_offset, - (uint8_t *) src_options + - src_offset); - } - else { - dhcp_append_option(dst_options, dst_len, src_options + src_offset); - } - src_offset += 2 + src_options[src_offset + 1]; - } - } - - if (src_offset == src_len) - return 1; - return 0; -} - -/** - * DHCP: Finds given occurrence of the option with the given code (op_code) - * in "options" field of DHCP-message. - * - * @param options "options" field of DHCP-message - * @param len length of the "options" field - * @param op_code code of the option to find - * @param op_offset SUCCESS - offset to an option occurrence; - * FAULT - offset is set to zero. - * @return TRUE - option was find; - * FALSE - option wasn't find. - */ -static int8_t dhcp_find_option(uint8_t options[], uint32_t len, - uint8_t op_code, uint32_t * op_offset) -{ - uint32_t srch_offset = 0; - * op_offset = 0; - - while (srch_offset < len) { - if (options[srch_offset] == op_code) { - * op_offset = srch_offset; - return 1; - } - if (options[srch_offset] == DHCP_ENDOPT) - return 0; - - if (options[srch_offset] == DHCP_PADOPT) - srch_offset++; - else - srch_offset += 2 + options[srch_offset + 1]; - } - return 0; -} - -/** - * DHCP: Appends new option from one list (src) into the tail - * of another option list (dst) - * - * @param dst_options "options" field of DHCP-message - * @param dst_len length of the "options" field (modified) - * @param new_option points to an option in another list (src) - */ -static void dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len, - uint8_t * new_option) -{ - memcpy(dst_options + ( * dst_len), new_option, 2 + (* (new_option + 1))); - * dst_len += 2 + *(new_option + 1); -} - -/** - * DHCP: This function is used when options with the same code are - * presented in both merged lists. In this case information - * about the option from one list (src) is combined (complemented) - * with information about the option in another list (dst). - * - * @param dst_options "options" field of DHCP-message - * @param dst_len length of the "options" field (modified) - * @param dst_offset offset of the option from beginning of the list - * @param new_option points to an option in another list (src) - */ -static void dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len, - uint32_t dst_offset, uint8_t * new_option) -{ - uint8_t tmp_buffer[1024]; // use to provide safe memcpy - uint32_t tail_len; - - // move all subsequent options (allocate size for additional info) - tail_len = (* dst_len) - dst_offset - 2 - dst_options[dst_offset + 1]; - - memcpy(tmp_buffer, dst_options + (* dst_len) - tail_len, tail_len); - memcpy(dst_options + (* dst_len) - tail_len + (* (new_option + 1)), - tmp_buffer, tail_len); - - // add new_content to option - memcpy(dst_options + (* dst_len) - tail_len, new_option + 2, - * (new_option + 1)); - dst_options[dst_offset + 1] += * (new_option + 1); - - // correct dst_len - * dst_len += * (new_option + 1); -} - -/** - * DHCP: Sends DHCP-Discover message. Looks for DHCP servers. - */ -static void dhcp_send_discover(int fd) -{ - uint32_t packetsize = sizeof(struct iphdr) + - sizeof(struct udphdr) + sizeof(struct btphdr); - struct btphdr *btph; - dhcp_options_t opt; - - memset(ether_packet, 0, packetsize); - - btph = (struct btphdr *) (ðer_packet[ - sizeof(struct iphdr) + sizeof(struct udphdr)]); - - btph -> op = 1; - btph -> htype = 1; - btph -> hlen = 6; - btph -> xid = dhcp_xid; - memcpy(btph -> chaddr, get_mac_address(), 6); - - memset(&opt, 0, sizeof(dhcp_options_t)); - - opt.msg_type = DHCPDISCOVER; - - opt.request_list[DHCP_MASK] = 1; - opt.request_list[DHCP_DNS] = 1; - opt.request_list[DHCP_ROUTER] = 1; - opt.request_list[DHCP_TFTP_SERVER] = 1; - opt.request_list[DHCP_BOOTFILE] = 1; - opt.request_list[DHCP_CLIENT_ARCH] = USE_DHCPARCH; - - dhcp_encode_options(btph -> vend, &opt); - - fill_udphdr(ðer_packet[sizeof(struct iphdr)], - sizeof(struct btphdr) + sizeof(struct udphdr), - UDPPORT_BOOTPC, UDPPORT_BOOTPS); - fill_iphdr(ether_packet, sizeof(struct btphdr) + - sizeof(struct udphdr) + sizeof(struct iphdr), - IPTYPE_UDP, dhcp_own_ip, 0xFFFFFFFF); - - send_ipv4(fd, ether_packet, packetsize); -} - -/** - * DHCP: Sends DHCP-Request message. Asks for acknowledgment to occupy IP. - */ -static void dhcp_send_request(int fd) -{ - uint32_t packetsize = sizeof(struct iphdr) + - sizeof(struct udphdr) + sizeof(struct btphdr); - struct btphdr *btph; - dhcp_options_t opt; - - memset(ether_packet, 0, packetsize); - - btph = (struct btphdr *) (ðer_packet[ - sizeof(struct iphdr) + sizeof(struct udphdr)]); - - btph -> op = 1; - btph -> htype = 1; - btph -> hlen = 6; - btph -> xid = dhcp_xid; - memcpy(btph -> chaddr, get_mac_address(), 6); - - memset(&opt, 0, sizeof(dhcp_options_t)); - - opt.msg_type = DHCPREQUEST; - memcpy(&(opt.requested_IP), &dhcp_own_ip, 4); - opt.flag[DHCP_REQUESTED_IP] = 1; - memcpy(&(opt.server_ID), &dhcp_server_ip, 4); - opt.flag[DHCP_SERVER_ID] = 1; - - opt.request_list[DHCP_MASK] = 1; - opt.request_list[DHCP_DNS] = 1; - opt.request_list[DHCP_ROUTER] = 1; - opt.request_list[DHCP_TFTP_SERVER] = 1; - opt.request_list[DHCP_BOOTFILE] = 1; - opt.request_list[DHCP_CLIENT_ARCH] = USE_DHCPARCH; - opt.flag[DHCP_CLIENT_ARCH] = USE_DHCPARCH; - - dhcp_encode_options(btph -> vend, &opt); - - fill_udphdr(ðer_packet[sizeof(struct iphdr)], - sizeof(struct btphdr) + sizeof(struct udphdr), - UDPPORT_BOOTPC, UDPPORT_BOOTPS); - fill_iphdr(ether_packet, sizeof(struct btphdr) + - sizeof(struct udphdr) + sizeof(struct iphdr), - IPTYPE_UDP, 0, 0xFFFFFFFF); - - send_ipv4(fd, ether_packet, packetsize); -} - - -/** - * DHCP: Sends DHCP-Release message. Releases occupied IP. - */ -void dhcp_send_release(int fd) -{ - uint32_t packetsize = sizeof(struct iphdr) + - sizeof(struct udphdr) + sizeof(struct btphdr); - struct btphdr *btph; - dhcp_options_t opt; - - btph = (struct btphdr *) (ðer_packet[ - sizeof(struct iphdr) + sizeof(struct udphdr)]); - - memset(ether_packet, 0, packetsize); - - btph -> op = 1; - btph -> htype = 1; - btph -> hlen = 6; - btph -> xid = dhcp_xid; - strcpy((char *) btph -> file, ""); - memcpy(btph -> chaddr, get_mac_address(), 6); - btph -> ciaddr = htonl(dhcp_own_ip); - - memset(&opt, 0, sizeof(dhcp_options_t)); - - opt.msg_type = DHCPRELEASE; - opt.server_ID = dhcp_server_ip; - opt.flag[DHCP_SERVER_ID] = 1; - - dhcp_encode_options(btph -> vend, &opt); - - fill_udphdr(ðer_packet[sizeof(struct iphdr)], - sizeof(struct btphdr) + sizeof(struct udphdr), - UDPPORT_BOOTPC, UDPPORT_BOOTPS); - fill_iphdr(ether_packet, sizeof(struct btphdr) + - sizeof(struct udphdr) + sizeof(struct iphdr), IPTYPE_UDP, - dhcp_own_ip, dhcp_server_ip); - - send_ipv4(fd, ether_packet, packetsize); -} - -/** - * DHCP: Handles DHCP-messages according to Receive-handle diagram. - * Changes the state of DHCP-client. - * - * @param fd socket descriptor - * @param packet BootP/DHCP-packet to be handled - * @param packetsize length of the packet - * @return ZERO - packet handled successfully; - * NON ZERO - packet was not handled (e.g. bad format) - * @see receive_ether - * @see btphdr - */ - -int8_t handle_dhcp(int fd, uint8_t * packet, int32_t packetsize) -{ - struct btphdr * btph; - struct iphdr * iph; - dhcp_options_t opt; - - memset(&opt, 0, sizeof(dhcp_options_t)); - btph = (struct btphdr *) packet; - iph = (struct iphdr *) packet - sizeof(struct udphdr) - - sizeof(struct iphdr); - - if (btph->op != 2) - return -1; /* It is not a Bootp/DHCP reply */ - if (btph->xid != dhcp_xid) - return -1; /* The transaction ID does not match */ - - if (memcmp(btph -> vend, dhcp_magic, 4)) { - // It is BootP - RFC 951 - dhcp_own_ip = htonl(btph -> yiaddr); - dhcp_siaddr_ip = htonl(btph -> siaddr); - dhcp_server_ip = htonl(iph -> ip_src); - - if (strlen((char *) btph -> sname) && !dhcp_siaddr_ip) { - strncpy((char *) dhcp_tftp_name, (char *) btph -> sname, - sizeof(btph -> sname)); - dhcp_tftp_name[sizeof(btph -> sname)] = 0; - } - - if (strlen((char *) btph -> file)) { - strncpy((char *) dhcp_filename, (char *) btph -> file, sizeof(btph -> file)); - dhcp_filename[sizeof(btph -> file)] = 0; - } - - dhcp_state = DHCP_STATE_SUCCESS; - return 0; - } - - - // decode options - if (!dhcp_decode_options(btph -> vend, packetsize - - sizeof(struct btphdr) + sizeof(btph -> vend), - &opt)) { - return -1; // can't decode options - } - - if (opt.overload) { - int16_t decode_res = 0; - uint8_t options[1024]; // buffer for merged options - uint32_t opt_len; - - // move 1-st part of options from vend field into buffer - opt_len = packetsize - sizeof(struct btphdr) + - sizeof(btph -> vend) - 4; - memcpy(options, btph -> vend, opt_len + 4); - - // add other parts - switch (opt.overload) { - case DHCP_OVERLOAD_FILE: - decode_res = dhcp_merge_options(options + 4, &opt_len, - btph -> file, - sizeof(btph -> file)); - break; - case DHCP_OVERLOAD_SNAME: - decode_res = dhcp_merge_options(options + 4, &opt_len, - btph -> sname, - sizeof(btph -> sname)); - break; - case DHCP_OVERLOAD_BOTH: - decode_res = dhcp_merge_options(options + 4, &opt_len, - btph -> file, - sizeof(btph -> file)); - if (!decode_res) - break; - decode_res = dhcp_merge_options(options + 4, &opt_len, - btph -> sname, - sizeof(btph -> sname)); - break; - } - - if (!decode_res) - return -1; // bad options in sname/file fields - - // decode merged options - if (!dhcp_decode_options(options, opt_len + 4, &opt)) { - return -1; // can't decode options - } - } - - if (!opt.msg_type) { - // It is BootP with Extensions - RFC 1497 - // retrieve conf. settings from BootP - reply - dhcp_own_ip = htonl(btph -> yiaddr); - dhcp_siaddr_ip = htonl(btph -> siaddr); - if (strlen((char *) btph -> sname) && !dhcp_siaddr_ip) { - strncpy((char *) dhcp_tftp_name, (char *) btph -> sname, sizeof(btph -> sname)); - dhcp_tftp_name[sizeof(btph -> sname)] = 0; - } - - if (strlen((char *) btph -> file)) { - strncpy((char *) dhcp_filename, (char *) btph -> file, sizeof(btph -> file)); - dhcp_filename[sizeof(btph -> file)] = 0; - } - - // retrieve DHCP-server IP from IP-header - dhcp_server_ip = iph -> htonl(ip_src); - - dhcp_state = DHCP_STATE_SUCCESS; - } - else { - // It is DHCP - RFC 2131 & RFC 2132 - // opt contains parameters from server - switch (dhcp_state) { - case DHCP_STATE_SELECT : - if (opt.msg_type == DHCPOFFER) { - dhcp_own_ip = htonl(btph -> yiaddr); - dhcp_server_ip = opt.server_ID; - dhcp_send_request(fd); - dhcp_state = DHCP_STATE_REQUEST; - } - return 0; - case DHCP_STATE_REQUEST : - switch (opt.msg_type) { - case DHCPNACK : - dhcp_own_ip = 0; - dhcp_server_ip = 0; - dhcp_state = DHCP_STATE_FAULT; - break; - case DHCPACK : - dhcp_own_ip = htonl(btph -> yiaddr); - dhcp_server_ip = opt.server_ID; - dhcp_siaddr_ip = htonl(btph -> siaddr); - if (opt.flag[DHCP_TFTP_SERVER]) { - strcpy((char *) dhcp_tftp_name, (char *) opt.tftp_server); - } - else { - strcpy((char *) dhcp_tftp_name, ""); - if ((opt.overload != DHCP_OVERLOAD_SNAME && - opt.overload != DHCP_OVERLOAD_BOTH) && - !dhcp_siaddr_ip) { - strncpy((char *) dhcp_tftp_name, - (char *) btph->sname, - sizeof(btph -> sname)); - dhcp_tftp_name[sizeof(btph->sname)] = 0; - } - } - - if (opt.flag[DHCP_BOOTFILE]) { - strcpy((char *) dhcp_filename, (char *) opt.bootfile); - } - else { - strcpy((char *) dhcp_filename, ""); - if (opt.overload != DHCP_OVERLOAD_FILE && - opt.overload != DHCP_OVERLOAD_BOTH && - strlen((char *) btph -> file)) { - strncpy((char *) dhcp_filename, - (char *) btph->file, - sizeof(btph->file)); - dhcp_filename[sizeof(btph -> file)] = 0; - } - } - - dhcp_state = DHCP_STATE_SUCCESS; - break; - default: - break; // Unused DHCP-message - do nothing - } - break; - default : - return -1; // Illegal DHCP-client state - } - } - - if (dhcp_state == DHCP_STATE_SUCCESS) { - - // initialize network entity with real own_ip - // to be able to answer for foreign requests - set_ipv4_address(dhcp_own_ip); - - if(response_buffer) { - if(packetsize <= 1720) - memcpy(response_buffer, packet, packetsize); - else - memcpy(response_buffer, packet, 1720); - } - - /* Subnet mask */ - if (opt.flag[DHCP_MASK]) { - /* Router */ - if (opt.flag[DHCP_ROUTER]) { - set_ipv4_router(opt.router_IP); - set_ipv4_netmask(opt.subnet_mask); - } - } - - /* DNS-server */ - if (opt.flag[DHCP_DNS]) { - dns_init(opt.dns_IP, 0, 4); - } - } - - return 0; -} |