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.c112
1 files changed, 88 insertions, 24 deletions
diff --git a/mdk-stage1/dhcp.c b/mdk-stage1/dhcp.c
index 44877fd8a..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>
@@ -44,8 +45,11 @@
#include "stage1.h"
#include "log.h"
+#include "tools.h"
+#include "utils.h"
#include "network.h"
#include "frontend.h"
+#include "automatic.h"
#include "dhcp.h"
@@ -67,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
@@ -207,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];
@@ -250,13 +263,6 @@ static void parse_reply(struct bootp_request * breq, struct interface_info * int
log_message("got gateway %s", inet_ntoa(gateway));
break;
- case BOOTP_OPTION_HOSTNAME:
- memcpy(tmp_str, chptr, length);
- tmp_str[length] = '\0';
- hostname = strdup(tmp_str);
- log_message("got hostname %s", hostname);
- break;
-
}
chptr += length;
@@ -286,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);
@@ -303,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)
@@ -322,11 +328,11 @@ static int get_vendor_code(struct bootp_request * bresp, unsigned char option, v
}
-static 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. */
@@ -340,7 +346,7 @@ static int currticks(void)
#define BACKOFF_LIMIT 7
#define TICKS_PER_SEC 18
-#define MAX_ARP_RETRIES 4
+#define MAX_ARP_RETRIES 7
static void rfc951_sleep(int exp)
{
@@ -415,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;
@@ -479,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++;
@@ -495,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)
{
@@ -508,11 +516,7 @@ enum return_type perform_dhcp(struct interface_info * intf)
short aShort;
int num_options;
char requested_options[50];
-
- if (strncmp(intf->device, "eth", 3)) {
- stg1_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) {
@@ -520,6 +524,35 @@ 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;
@@ -533,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 */
@@ -572,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);