summaryrefslogtreecommitdiffstats
path: root/mdk-stage1/dhcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'mdk-stage1/dhcp.c')
-rw-r--r--mdk-stage1/dhcp.c160
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);