diff options
Diffstat (limited to 'mdk-stage1/dhcp.c')
| -rw-r--r-- | mdk-stage1/dhcp.c | 160 |
1 files changed, 115 insertions, 45 deletions
diff --git a/mdk-stage1/dhcp.c b/mdk-stage1/dhcp.c index e2013994a..678031e85 100644 --- a/mdk-stage1/dhcp.c +++ b/mdk-stage1/dhcp.c @@ -1,7 +1,7 @@ /* - * Guillaume Cottenceau (gc@mandrakesoft.com) + * Guillaume Cottenceau (gc) * - * Copyright 2000 MandrakeSoft + * Copyright 2000 Mandriva * * This software may be freely redistributed under the terms of the GNU * public license. @@ -27,6 +27,7 @@ #include <stdlib.h> #include <unistd.h> +#include <stdio.h> #include <string.h> #include <sys/socket.h> #include <sys/ioctl.h> @@ -40,18 +41,19 @@ #include <sys/time.h> #include <time.h> #include <fcntl.h> +#include <sys/poll.h> #include "stage1.h" #include "log.h" +#include "tools.h" +#include "utils.h" #include "network.h" #include "frontend.h" +#include "automatic.h" #include "dhcp.h" -#define NUM_RETRIES 5 - - typedef int bp_int32; typedef short bp_int16; @@ -69,6 +71,8 @@ typedef short bp_int16; #define DHCP_OPTION_OPTIONREQ 55 #define DHCP_OPTION_MAXSIZE 57 +#define DHCP_OPTION_CLIENT_IDENTIFIER 61 + #define BOOTP_CLIENT_PORT 68 #define BOOTP_SERVER_PORT 67 @@ -176,6 +180,13 @@ static int initial_setup_interface(char * device, int s) { return -1; } + /* I need to sleep a bit in order for kernel to finish init of the + network device; this would allow to not send further multiple + dhcp requests when only one is needed. */ + wait_message("Bringing up networking..."); + sleep(2); + remove_wait_message(); + return 0; } @@ -202,9 +213,16 @@ static void parse_reply(struct bootp_request * breq, struct interface_info * int unsigned char * chptr; unsigned char option, length; + if (strlen(breq->bootfile) > 0) { + if (IS_NETAUTO) + add_to_env("KICKSTART", breq->bootfile); + else + log_message("warning: ignoring `bootfile' DHCP server parameter, since `netauto' boot parameter was not given; reboot with `linux netauto' (and anymore useful boot parameters) if you want `bootfile' to be used as a `auto_inst.cfg.pl' stage2 configuration file"); + } + memcpy(&intf->ip, &breq->yiaddr, 4); - chptr = breq->vendor; + chptr = (unsigned char *) breq->vendor; chptr += 4; while (*chptr != 0xFF && (void *) chptr < (void *) breq->vendor + DHCP_VENDOR_LENGTH) { char tmp_str[500]; @@ -216,33 +234,33 @@ static void parse_reply(struct bootp_request * breq, struct interface_info * int switch (option) { case BOOTP_OPTION_DNS: memcpy(&dns_server, chptr, sizeof(dns_server)); - if (length >= sizeof(dns_server)*2) + log_message("got dns %s", inet_ntoa(dns_server)); + if (length >= sizeof(dns_server)*2) { memcpy(&dns_server2, chptr+sizeof(dns_server), sizeof(dns_server2)); + log_message("got dns2 %s", inet_ntoa(dns_server2)); + } break; case BOOTP_OPTION_NETMASK: - memcpy(&intf->netmask, chptr, 4); + memcpy(&intf->netmask, chptr, sizeof(intf->netmask)); + log_message("got netmask %s", inet_ntoa(intf->netmask)); break; case BOOTP_OPTION_DOMAIN: memcpy(tmp_str, chptr, length); tmp_str[length] = '\0'; domain = strdup(tmp_str); + log_message("got domain %s", domain); break; case BOOTP_OPTION_BROADCAST: - memcpy(&intf->broadcast, chptr, 4); + memcpy(&intf->broadcast, chptr, sizeof(intf->broadcast)); + log_message("got broadcast %s", inet_ntoa(intf->broadcast)); break; case BOOTP_OPTION_GATEWAY: - memcpy(&gateway, chptr, 4); - break; - - case BOOTP_OPTION_HOSTNAME: - memcpy(tmp_str, chptr, length); - tmp_str[length] = '\0'; - hostname = strdup(tmp_str); - log_message("DHCP: got hostname %s", hostname); + memcpy(&gateway, chptr, sizeof(gateway)); + log_message("got gateway %s", inet_ntoa(gateway)); break; } @@ -260,7 +278,7 @@ static void init_vendor_codes(struct bootp_request * breq) { static char gen_hwaddr[16]; -static int prepare_request(struct bootp_request * breq, int sock, char * device, time_t startTime) +static int prepare_request(struct bootp_request * breq, int sock, char * device) { struct ifreq req; @@ -274,7 +292,7 @@ static int prepare_request(struct bootp_request * breq, int sock, char * device, return -1; } - breq->hw = 1; /* ethernet */ + breq->hw = req.ifr_hwaddr.sa_family; breq->hwlength = IFHWADDRLEN; memcpy(breq->hwaddr, req.ifr_hwaddr.sa_data, IFHWADDRLEN); memcpy(gen_hwaddr, req.ifr_hwaddr.sa_data, IFHWADDRLEN); @@ -291,7 +309,7 @@ static int get_vendor_code(struct bootp_request * bresp, unsigned char option, v unsigned char * chptr; unsigned int length, theOption; - chptr = bresp->vendor + 4; + chptr = (unsigned char*) bresp->vendor + 4; while (*chptr != 0xFF && *chptr != option) { theOption = *chptr++; if (!theOption) @@ -310,12 +328,11 @@ static int get_vendor_code(struct bootp_request * bresp, unsigned char option, v } -int -currticks (void) +static unsigned long currticks(void) { struct timeval tv; - long csecs; - int ticks_per_csec, ticks_per_usec; + unsigned long csecs; + unsigned long ticks_per_csec, ticks_per_usec; /* Note: 18.2 ticks/sec. */ @@ -329,10 +346,9 @@ currticks (void) #define BACKOFF_LIMIT 7 #define TICKS_PER_SEC 18 -#define MAX_ARP_RETRIES 4 +#define MAX_ARP_RETRIES 7 -void -rfc951_sleep (int exp) +static void rfc951_sleep(int exp) { static long seed = 0; long q; @@ -365,8 +381,7 @@ rfc951_sleep (int exp) static int handle_transaction(int s, struct bootp_request * breq, struct bootp_request * bresp, struct sockaddr_in * server_addr, int dhcp_type) { - struct timeval tv; - fd_set readfs; + struct pollfd polls; int i, j; int retry = 1; int sin; @@ -395,12 +410,10 @@ static int handle_transaction(int s, struct bootp_request * breq, struct bootp_r return -1; } - FD_ZERO(&readfs); - FD_SET(sin, &readfs); - tv.tv_usec = 0; - tv.tv_sec = timeout; + polls.fd = sin; + polls.events = POLLIN; - while (select(sin + 1, &readfs, NULL, NULL, &tv) == 1) { + while (poll(&polls, 1, timeout*1000) == 1) { if ((j = recv(sin, eth_packet, sizeof(eth_packet), 0)) == -1) { log_perror("recv"); @@ -408,7 +421,7 @@ static int handle_transaction(int s, struct bootp_request * breq, struct bootp_r } /* We need to do some basic sanity checking of the header */ - if (j < (sizeof(*ip_hdr) + sizeof(*udp_hdr))) + if (j < (signed)(sizeof(*ip_hdr) + sizeof(*udp_hdr))) continue; ip_hdr = (void *) eth_packet; @@ -464,7 +477,6 @@ static int handle_transaction(int s, struct bootp_request * breq, struct bootp_r timeout = 5; } - error_message("No DHCP reply received."); return -1; } @@ -473,7 +485,7 @@ static void add_vendor_code(struct bootp_request * breq, unsigned char option, u unsigned char * chptr; int theOption, theLength; - chptr = breq->vendor; + chptr = (unsigned char*) breq->vendor; chptr += 4; while (*chptr != 0xFF && *chptr != option) { theOption = *chptr++; @@ -489,6 +501,8 @@ static void add_vendor_code(struct bootp_request * breq, unsigned char option, u } +char * dhcp_hostname = NULL; +char * dhcp_domain = NULL; enum return_type perform_dhcp(struct interface_info * intf) { @@ -499,15 +513,10 @@ enum return_type perform_dhcp(struct interface_info * intf) struct bootp_request breq, bresp; unsigned char messageType; unsigned int lease; - time_t startTime = time(NULL); short aShort; int num_options; char requested_options[50]; - - if (strncmp(intf->device, "eth", 3)) { - error_message("DHCP available only for Ethernet networking."); - return RETURN_ERROR; - } + char * client_id_str, * client_id_hwaddr; s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { @@ -515,12 +524,41 @@ enum return_type perform_dhcp(struct interface_info * intf) return RETURN_ERROR; } + { + enum return_type results; + char * questions[] = { "Host name", "Domain name", NULL }; + char * questions_auto[] = { "hostname", "domain" }; + static char ** answers = NULL; + char * boulet; + + client_id_str = client_id_hwaddr = NULL; + + results = ask_from_entries_auto("If the DHCP server needs to know you by name; please fill in this information. " + "Valid answers are for example: `mybox' for hostname and `mynetwork.com' for " + "domain name, for a machine called `mybox.mynetwork.com' on the Internet.", + questions, &answers, 32, questions_auto, NULL); + if (results == RETURN_OK) + { + dhcp_hostname = answers[0]; + if ((boulet = strchr(dhcp_hostname, '.')) != NULL) + boulet[0] = '\0'; + dhcp_domain = answers[1]; + + if (*dhcp_hostname && *dhcp_domain) { + /* if we have both, then create client id from them */ + client_id_str = malloc(1 + strlen(dhcp_hostname) + 1 + strlen(dhcp_domain) + 1); + client_id_str[0] = '\0'; + sprintf(client_id_str+1, "%s.%s", dhcp_hostname, dhcp_domain); + } + } + } + if (initial_setup_interface(intf->device, s) != 0) { close(s); return RETURN_ERROR; } - if (prepare_request(&breq, s, intf->device, startTime) != 0) { + if (prepare_request(&breq, s, intf->device) != 0) { close(s); return RETURN_ERROR; } @@ -528,7 +566,28 @@ enum return_type perform_dhcp(struct interface_info * intf) messageType = DHCP_TYPE_DISCOVER; add_vendor_code(&breq, DHCP_OPTION_TYPE, 1, &messageType); - memset(&client_addr.sin_addr, 0, sizeof(&client_addr.sin_addr)); + /* add pieces needed to have DDNS/DHCP IP selection based on requested name */ + if (dhcp_hostname && *dhcp_hostname) { /* pick client id form based on absence or presence of domain name */ + if (*dhcp_domain) /* alternate style <hostname>.<domainname> */ + add_vendor_code(&breq, DHCP_OPTION_CLIENT_IDENTIFIER, strlen(client_id_str+1)+1, client_id_str); + else { /* usual style (aka windows / dhcpcd) */ + /* but put MAC in form required for client identifier first */ + client_id_hwaddr = malloc(IFHWADDRLEN+2); + /* (from pump-0.8.22/dhcp.c) + * Microsoft uses a client identifier field of the 802.3 address with a + * pre-byte of a "1". In order to re-use the DHCP address that they set + * for this interface, we have to mimic their identifier. + */ + client_id_hwaddr[0] = 1; /* set flag for ethernet */ + memcpy(client_id_hwaddr+1, gen_hwaddr, IFHWADDRLEN); + add_vendor_code(&breq, DHCP_OPTION_CLIENT_IDENTIFIER, IFHWADDRLEN+1, client_id_hwaddr); + } + /* this is the one that the dhcp server really wants for DDNS updates */ + add_vendor_code(&breq, BOOTP_OPTION_HOSTNAME, strlen(dhcp_hostname), dhcp_hostname); + log_message("DHCP: telling server to use name = %s", dhcp_hostname); + } + + memset(&client_addr.sin_addr, 0, sizeof(client_addr.sin_addr)); client_addr.sin_family = AF_INET; client_addr.sin_port = htons(BOOTP_CLIENT_PORT); /* bootp client */ @@ -548,6 +607,7 @@ enum return_type perform_dhcp(struct interface_info * intf) remove_wait_message(); if (i != 0) { + stg1_error_message("No DHCP reply received."); close(s); return RETURN_ERROR; } @@ -566,6 +626,16 @@ enum return_type perform_dhcp(struct interface_info * intf) add_vendor_code(&breq, DHCP_OPTION_SERVER, 4, &server_addr.sin_addr); add_vendor_code(&breq, DHCP_OPTION_REQADDR, 4, &bresp.yiaddr); + /* if used the first time, then have to use it again */ + if (dhcp_hostname && *dhcp_hostname) { /* add pieces needed to have DDNS/DHCP IP selection based on requested name */ + if (dhcp_domain && *dhcp_domain) /* alternate style */ + add_vendor_code(&breq, DHCP_OPTION_CLIENT_IDENTIFIER, strlen(client_id_str+1)+1, client_id_str); + else /* usual style (aka windows / dhcpcd) */ + add_vendor_code(&breq, DHCP_OPTION_CLIENT_IDENTIFIER, IFHWADDRLEN+1, client_id_hwaddr); + /* this is the one that the dhcp server really wants for DDNS updates */ + add_vendor_code(&breq, BOOTP_OPTION_HOSTNAME, strlen(dhcp_hostname), dhcp_hostname); + } + aShort = ntohs(sizeof(struct bootp_request)); add_vendor_code(&breq, DHCP_OPTION_MAXSIZE, 2, &aShort); |
