[Prev][Next][Index][Thread]

Re: some bugs in netboot



Here's the patch relative to oskit-990402

hope it works. more tomorrow.

-- 
Klaus Espenlaub                      Email:  espenlaub@informatik.uni-ulm.de
Universitaet Ulm                     Phone:  +49 731 50-24178
Abteilung Rechnerstrukturen          Fax:    +49 731 50-24182
D-89069 Ulm                          Office: Building O27, Room 316
diff -rNup oskit-990402/boot/net/GNUmakerules oskit-0.97/boot/net/GNUmakerules
--- oskit-990402/boot/net/GNUmakerules	Sat Feb 27 13:17:44 1999
+++ oskit-0.97/boot/net/GNUmakerules	Thu May 27 13:21:00 1999
@@ -49,7 +49,7 @@ DEPENDLIBS = $(filter %.a, $(foreach DIR
 DEPS = $(OBJDIR)/lib/multiboot.o $(OBJFILES) $(DEPENDLIBS) $(OBJDIR)/lib/crtn.o
 
 version.c: $(filter-out version.o,$(DEPS))
-	echo >$@ "char version[] = \"NetBoot metakernel v2.6.0\";"
+	echo >$@ "char version[] = \"OSKit NetBoot metakernel v2.7\";"
 	echo >>$@ "char build_info[] = \"Built `date +%d-%b-%Y` by `id -nu`@`hostname | sed 's/\..*//'`:`pwd`\nwith options: $(OSKIT_OPTIONS)\";"
 CLEAN_FILES += version.c
 
diff -rNup oskit-990402/boot/net/NEWS oskit-0.97/boot/net/NEWS
--- oskit-990402/boot/net/NEWS	Thu Jan 21 00:26:22 1999
+++ oskit-0.97/boot/net/NEWS	Tue Jul 13 18:39:36 1999
@@ -63,4 +63,66 @@
 	- Fixed to not call strlen(0).  This is bad.  More specifically,
 	  if the program before us stored a bunch of poo at addr 0, then
 	  we can blow our stack in build_cmdline, which allocates
-	  a dynmaic stack array.
+	  a dynamic stack array.
+
+2.5.1 -> 2.6
+	- Added NFS readahead code.
+
+2.6 -> 2.7
+	New code/fixes by Klaus Espenlaub <espenlaub@informatik.uni-ulm.de>
+	- Added code to answer ARP queries sent to us.  Previously there was
+	  no code to answer ARP queries for our address.  This worked, because
+	  all serious server systems (that is, *BSD and Linux at least) use
+	  the information passed to them on the ARP sent to the server.  In
+	  the following sequence this doesn't work any more.
+	  Test case: Machine C runs netboot kernel, machine S is NFS server.
+		C				S
+	  S:/this/does/notexist
+					arp -d C
+	  S:/this/does/exist
+
+	  After this sequence NFS booting stops working - C sends out NFS
+	  packets, but S will no longer reply, because it doesn't know where
+	  to send the packets.  This also happened to me when I let netboot
+	  sit there for a whole day and machine S dropped the ARP entry for C.
+	- Pass the multiboot magic number in register %eax.  It seems that my
+	  kernel (not oskit based) is the only one arund that really checks
+	  the magic.  I know it's bad to actually read the specs.
+	- Change the ELF loader to load stuff to the load memory address of
+	  the section.  What else should this value be used for?  Again it
+	  seems that I'm the first one using different values for VMA and LMA.
+	  But don't worry, GNU binutils 2.9.1 (especially objcopy) also have a
+	  few annoying bugs in this area.
+	- Change the checks done on the multiboot image.  Mostly changes from
+	  calling panic() to some sensible error message and then back to the
+	  input loop.
+	- Change input handling so that it is more robust.  The code is rather
+	  inefficient cpu-wise, but it has less buffer overruns and underruns.
+	- Add code to properly number the IP packets sent out.  There's just
+	  one thing missing in the IP code: checksums.
+
+	The following stuff mostly requires passing at least some of the IP
+	configuration by the kernel command line (using kernel environment
+	variables).  The code should be generalized to support bootp
+	configuration.  However I'm using etherboot...
+	- Added Linux-style IP/NFS/ethernet card autoconfig.  If the
+	  environment variables "nfsroot" and "nfsaddrs" are set properly, no
+	  bootp request will be sent out.  This saves some time and a few log
+	  entries.  The value of "nfsroot" may contain "%s", which will be
+	  replaced by the client IP number.
+	- Added DNS lookup code.  Ugly, but working.  Currently requires
+	  the kernel environment variable "dnsaddrs" to contain an IP address
+	  for a working DNS server.
+	- The NFS autoconfig allows just to specify a file name if it is
+	  stored on the NFS root filesystem server.  You are no longer forced
+	  to type 192.168.254.254:/clients/192.168.254.253/crash.mb, just
+	  crash.mb, if the NFS autoconfig parameters are set properly.  If you
+	  need a complete network boot solution for multiboot kernels, have
+	  a look at etherboot (version 4.2 and higher).  I'm using it with
+	  great success.  It generates the command line automatically from the
+	  bootp request it needs to get its info.
+	- Added code to pass Linux-style boot configuration, if present, to
+	  the loaded kernel.
+	- Added a kernel environment variable "bogomips".  You'll no longer
+	  have to wait for that #$%& loop to finish.  But be careful what you
+	  pass to the kernel - it's your machine that may crash.
diff -rNup oskit-990402/boot/net/await.c oskit-0.97/boot/net/await.c
--- oskit-990402/boot/net/await.c	Thu Feb 18 19:11:09 1999
+++ oskit-0.97/boot/net/await.c	Tue May 18 13:41:40 1999
@@ -47,7 +47,7 @@ await_reply(int type, int ival, void *pt
 	unsigned long time;
 	struct	iphdr *ip;
 	struct	udphdr *udp;
-	struct	arprequest *arpreply;
+	struct	arprequest *arp;
 	struct	rpc_t *rpc;
 
 	int	protohdrlen = ETHER_HDR_SIZE + sizeof(struct iphdr) +
@@ -56,18 +56,18 @@ await_reply(int type, int ival, void *pt
 	while(time > currticks()) {
 /*		pollkbd();*/
 		if (eth_poll()) {	/* We have something! */
+
 					/* Check for ARP - No IP hdr */
 			if ((type == AWAIT_ARP) &&
 			   (packetlen >= ETHER_HDR_SIZE +
 				sizeof(struct arprequest)) &&
 			   (((packet[12] << 8) | packet[13]) == ETHERTYPE_ARP)) {
-				arpreply = (struct arprequest *)
+				arp = (struct arprequest *)
 					&packet[ETHER_HDR_SIZE];
-				if ((arpreply->opcode == ntohs(ARPOP_REPLY))
-				    && memcmp(arpreply->sipaddr, ptr, 4) == 0) {
+				if ((arp->opcode == ntohs(ARPOP_REPLY))
+				    && memcmp(arp->sipaddr, ptr, 4) == 0) {
 					memcpy(arptable[ival].node,
-						arpreply->shwaddr,
-						ETHER_ADDR_SIZE);
+						arp->shwaddr, ETHER_ADDR_SIZE);
 					return(1);
 				}
 				continue;
@@ -83,6 +83,10 @@ await_reply(int type, int ival, void *pt
 				(ip->protocol != IP_UDP)) continue;
 			udp = (struct udphdr *)&packet[ETHER_HDR_SIZE +
 				sizeof(struct iphdr)];
+
+					/* DNS ? */
+			if ((type == AWAIT_DNS) &&
+				(ntohs(udp->dest) == ival)) return(1);
 
 					/* TFTP ? */
 			if ((type == AWAIT_TFTP) &&
diff -rNup oskit-990402/boot/net/await.h oskit-0.97/boot/net/await.h
--- oskit-990402/boot/net/await.h	Sun Jun  1 01:32:03 1997
+++ oskit-0.97/boot/net/await.h	Fri May 14 15:11:32 1999
@@ -14,6 +14,7 @@ Author: Martin Renters
 #define AWAIT_BOOTP	1
 #define AWAIT_TFTP	2
 #define AWAIT_RPC	3
+#define AWAIT_DNS	4
 
 int await_reply(int type, int ival, void *ptrv);
 
diff -rNup oskit-990402/boot/net/base_multiboot_main.c oskit-0.97/boot/net/base_multiboot_main.c
--- oskit-990402/boot/net/base_multiboot_main.c	Tue Feb  9 18:05:04 1999
+++ oskit-0.97/boot/net/base_multiboot_main.c	Tue Jul 13 18:19:55 1999
@@ -223,7 +223,7 @@ multiboot_main(oskit_addr_t boot_info_pa
 	char *info_string;
 
 	/* Copy the multiboot_info structure into our pre-reserved area.
-	   This avoids one loose fragment of memory that has to be avoided.  */
+	 * This avoids one loose fragment of memory that has to be avoided.  */
 	boot_info = *(struct multiboot_info*)phystokv(boot_info_pa);
 
 	/*
diff -rNup oskit-990402/boot/net/boot.h oskit-0.97/boot/net/boot.h
--- oskit-990402/boot/net/boot.h	Thu Apr  9 00:42:15 1998
+++ oskit-0.97/boot/net/boot.h	Tue Jul 13 18:20:19 1999
@@ -27,7 +27,7 @@ struct kerninfo {
 
 	struct multiboot_header ki_mbhdr; /* things like load address, entry */
 
-	void *ki_imgaddr;		  /* where it is in memory */
+	void *ki_imgaddr;		/* where it is in memory */
 
 	struct multiboot_info *ki_mbinfo;  /* stuff we are passing to it */
 };
diff -rNup oskit-990402/boot/net/dns.c oskit-0.97/boot/net/dns.c
--- oskit-990402/boot/net/dns.c	Thu Jan  1 01:00:00 1970
+++ oskit-0.97/boot/net/dns.c	Tue May 18 10:23:50 1999
@@ -0,0 +1,145 @@
+/* "Complete" rewrite of the basic resolver function. */
+/**************************************************************************
+ -  BOOTP/TFTP Bootstrap Program
+
+Author: Klaus Espenlaub
+  Date: May/99
+
+**************************************************************************/
+
+#include <oskit/c/arpa/inet.h>		/* htonl */
+#include <oskit/c/string.h>		/* memcpy */
+#include <oskit/c/stdio.h>		/* putchar */
+#include <oskit/c/stdlib.h>		/* getenv */
+#include <oskit/c/netinet/in.h>		/* INADDR_NONE */
+
+#include "ip.h"
+#include "udp.h"
+#include "await.h"
+#include "ether.h"
+#include "driver.h"
+#include "netboot.h"
+
+#define MAX_DNS_RETRIES 15
+#define DNS_SSOCKET 52
+#define DNS_DSOCKET 53
+#define DNS_RECURSIVE 0x0100
+#define DNS_ATYPE 1
+#define DNS_IN 1
+#define DNS_SREPLYMASK 0xfa8f
+#define DNS_SREPLY 0x8080
+
+struct dns_t {
+	struct iphdr ip;
+	struct udphdr udp;
+
+	unsigned short id;
+	unsigned short qtype;
+	unsigned short qdcount, ancount, nscount, arcount;
+	char data[100];
+};
+
+/*
+ * Host lookup.
+ */
+unsigned long
+hostlookup(const char *host_or_ip)
+{
+	extern char domainname[];
+	int retries = MAX_DNS_RETRIES;
+	static unsigned short idcounter = 7325;
+	unsigned short qtype, qclass;
+	struct dns_t dns;
+	struct dns_t *reply;
+	char name[80];
+	const char *c;
+	char *data;
+	unsigned int ip;
+
+	if (strchr(host_or_ip, '.')) {
+		/* shortcut for dotted decimal notation */
+		for (c = host_or_ip;
+		    (*c == '.') || ((*c >= '0') && (*c <= '9'));
+		    c++) /* Nothing */;
+		if (*c == '\0') {
+			return ntohl(inet_addr(host_or_ip));
+		}
+		/* Have a name with '.' in it.  Assume that it is a FQDN.  */
+		strcpy(name, host_or_ip);
+	} else {
+		/* No '.' in the name.  Use domainname if properly set.  */
+		strcpy(name, host_or_ip);
+		if (strlen(domainname) == 0) {
+			return INADDR_NONE;
+		}
+		strcat(name, ".");
+		strcat(name, domainname);
+	}
+	if (arptable[ARP_NS].ipaddr == 0) {
+		return INADDR_NONE;
+	}
+	/* Now look up the IP for the machine called "name".  */
+	dns.id = ntohs(idcounter);
+	idcounter++;
+	dns.qtype = htons(DNS_RECURSIVE);
+	dns.qdcount = htons(1);
+	dns.ancount = htons(0);
+	dns.nscount = htons(0);
+	dns.arcount = htons(0);
+	data = dns.data;
+	while (name[0] != '\0') {
+		c = strchr(name, '.');
+		if (c != NULL) {
+			*data++ = c-name;
+			memcpy(data, name, c-name);
+			data += c-name;
+			memmove(name, c+1, strlen(c+1)+1);
+		} else {
+			*data++ = strlen(name);
+			strcpy(data, name);
+			data += strlen(name);
+			name[0] = '\0';
+		}
+	}
+	*data++ = '\0';
+	qtype = htons(DNS_ATYPE);
+	memcpy(data, &qtype, 2);
+	data += 2;
+	qclass = htons(DNS_IN);
+	memcpy(data, &qclass, 2);
+	data += 2;
+	while (retries--) {
+		udp_transmit(arptable[ARP_NS].ipaddr, DNS_SSOCKET, DNS_DSOCKET,
+		             data - (char *)&dns, &dns);
+		if (await_reply(AWAIT_DNS, DNS_SSOCKET, NULL)) {
+			reply = (struct dns_t *)&packet[ETHER_HDR_SIZE];
+			if ((ntohl(*(unsigned int *)reply->ip.src) != arptable[ARP_NS].ipaddr) ||
+			    (ntohs(reply->id) != idcounter - 1) ||
+			    (ntohs(reply->qdcount) != 1) ||
+			    (ntohs(reply->ancount) != 1) ||
+			    ((ntohs(reply->qtype) & DNS_SREPLYMASK) != DNS_SREPLY)) {
+				continue;
+			}
+			c = reply->data;
+			/* skip over "query" */
+			while (*c != '\0') {
+				c += 1 + *c;
+			}
+			c += 1 + 4;
+			/* now the answer is read */
+			/* skip over name */
+			while (*c != '\0') {
+				if (((*c) & 0xc0) == 0xc0) {
+					c += 2;
+					break;
+				} else {
+					c += 1 + *c;
+				}
+			}
+			c += 2 + 2 + 4 + 2;
+			memcpy(&ip, c, 4);
+			return ntohl(ip);
+		}
+	}
+	return INADDR_NONE;
+}
diff -rNup oskit-990402/boot/net/dns.h oskit-0.97/boot/net/dns.h
--- oskit-990402/boot/net/dns.h	Thu Jan  1 01:00:00 1970
+++ oskit-0.97/boot/net/dns.h	Mon May 17 15:12:36 1999
@@ -0,0 +1,16 @@
+/* Resolver function
+ */
+/**************************************************************************
+NETBOOT -  BOOTP/TFTP Bootstrap Program
+
+Author: Klaus Espenlaub
+  Date: May/99
+
+**************************************************************************/
+
+#ifndef __DNS_H_INCLUDED__
+#define __DNS_H_INCLUDED__
+
+unsigned long hostlookup(const char *host_or_ip);
+
+#endif /* __DNS_H_INCLUDED__ */
diff -rNup oskit-990402/boot/net/do_boot.S oskit-0.97/boot/net/do_boot.S
--- oskit-990402/boot/net/do_boot.S	Thu Apr  9 00:42:15 1998
+++ oskit-0.97/boot/net/do_boot.S	Fri May 28 16:48:33 1999
@@ -20,6 +20,7 @@
  */
 
 #include <oskit/machine/asm.h>
+#include <oskit/x86/multiboot.h>
 
 	.text
 
@@ -42,6 +43,10 @@ ENTRY(do_boot)
 	rep
 	movsb
 
-	jmp	*%eax
+	/* copy the entry point to %ecx and put multiboot magic into %eax */
+	movl	%eax,%ecx
+	movl	$MULTIBOOT_VALID,%eax
+
+	jmp	*%ecx
 ENTRY(do_boot_end)
 
diff -rNup oskit-990402/boot/net/dprintf.c oskit-0.97/boot/net/dprintf.c
--- oskit-990402/boot/net/dprintf.c	Thu Apr  9 00:42:16 1998
+++ oskit-0.97/boot/net/dprintf.c	Tue Jul 13 18:14:27 1999
@@ -25,7 +25,7 @@ void _doprnt(
 	register	const char *fmt,
 	va_list		args,
 	int		radix,		/* default radix - for '%r' */
- 	void		(*putc)(),	/* character output */
+	void		(*putc)(),	/* character output */
 	char		*putc_arg);	/* argument for putc */
 
 static void
diff -rNup oskit-990402/boot/net/driver.c oskit-0.97/boot/net/driver.c
--- oskit-990402/boot/net/driver.c	Wed Mar 31 00:47:13 1999
+++ oskit-0.97/boot/net/driver.c	Tue Jul 13 17:51:57 1999
@@ -36,6 +36,7 @@
 #include "timer.h"
 #include "ether.h"
 #include "netboot.h"
+#include "driver.h"
 
 struct etherdev {
 	oskit_etherdev_t	*dev;
@@ -48,6 +49,7 @@ struct etherdev {
 unsigned long netmask;			/* in host order */
 char *hostname;
 int hostnamelen;			/* word aligned length of hostname */
+char domainname[MAXHOSTNAMELEN];
 static struct etherdev ed;
 static volatile oskit_queue_t *packq;
 #define PACKQ_MAX 32
@@ -65,9 +67,9 @@ static oskit_error_t
 net_receive(void *data, oskit_bufio_t *b, oskit_size_t pkt_size)
 {
 	unsigned char bcastaddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-	unsigned char dhost[6];
+	unsigned char *frame;
+	struct ether_header *eth;
 	int err;
-	oskit_size_t got;
 	struct etherdev *dev = (struct etherdev *)data;
 	unsigned flags;
 
@@ -79,19 +81,59 @@ net_receive(void *data, oskit_bufio_t *b
 	/*
 	 * Check the Ethernet header to see if it is addressed to us.
 	 */
-	err = oskit_bufio_read(b, dhost,
-			       offsetof(struct ether_header, ether_dhost),
-			       sizeof dhost,
-			       &got);
+	err = oskit_bufio_map(b, (void **)&frame, 0, pkt_size);
 	assert(err == 0);
-	assert(got == sizeof dhost);
-	if (memcmp(dhost, &dev->haddr, sizeof dev->haddr) != 0
-	    && memcmp(dhost, bcastaddr, sizeof bcastaddr) != 0)
+
+	eth = (struct ether_header *)frame;
+
+	if (memcmp(eth->ether_dhost, &dev->haddr, sizeof dev->haddr) != 0
+	    && memcmp(eth->ether_dhost, bcastaddr, sizeof bcastaddr) != 0)
 		return 0;		/* not for us */
 
+	/* First check for ARP request for our IP */
+	if (ntohs(eth->ether_type) == ETHERTYPE_ARP) {
+		oskit_bufio_t *our_buf;
+		struct arprequest *arp;
+		struct in_addr ip;
+
+		arp = (struct arprequest *)(frame + sizeof(struct ether_header));
+		ip.s_addr = *(unsigned long *)arp->tipaddr;
+		if ((ntohs(arp->hwtype) != ARPHRD_ETHER) ||
+		    (ntohs(arp->protocol) != ETHERTYPE_IP) ||
+		    (ntohs(arp->opcode) != ARPOP_REQUEST) ||
+		    (ntohl(ip.s_addr) != arptable[ARP_CLIENT].ipaddr))
+			goto enqueue;	/* not for us - put it into the queue */
+
+		/* Send the reply. */
+		arp->opcode = htons(ARPOP_REPLY);
+		memcpy(arp->tipaddr, arp->sipaddr, sizeof(arp->tipaddr));
+		memcpy(arp->thwaddr, arp->shwaddr, sizeof(arp->thwaddr));
+		memcpy(arp->sipaddr, &(ip.s_addr), sizeof(arp->sipaddr));
+		memcpy(arp->shwaddr, dev->haddr, sizeof(arp->shwaddr));
+
+		/* Fill in the ethernet addresses. */
+		memcpy(eth->ether_dhost, arp->thwaddr, sizeof(arp->shwaddr));
+		memcpy(eth->ether_shost, dev->haddr, sizeof(arp->shwaddr));
+
+		our_buf = oskit_bufio_create(ETHER_HDR_SIZE + sizeof(struct arprequest));
+		if (b != NULL) {
+			oskit_size_t got;
+
+			oskit_bufio_write(our_buf, frame, 0, pkt_size, &got);
+			assert(got == ETHER_HDR_SIZE + sizeof(struct arprequest));
+			oskit_netio_push(dev->send_nio, our_buf,
+			                 ETHER_HDR_SIZE + sizeof(struct arprequest));
+			oskit_bufio_release(our_buf);
+		} else {
+			printf("couldn't allocate bufio for ARP reply\n");
+		}
+		return 0;
+	}
+
 	/*
 	 * Try to add it to the queue.
 	 */
+enqueue:
 	flags = get_eflags();
 	cli();
 	oskit_queue_enqueue(packq, b, 0);
@@ -201,12 +243,16 @@ net_init()
 {
 #define BUFSIZE 128
 	static char buf[BUFSIZE];
+	char ipcfgstr[BUFSIZE];
 	struct bootp_net_info bpi;
 	oskit_error_t err;
 	oskit_etherdev_t **alldevs;
 	int ndev;
 	int i;
 	unsigned required_flags;
+	char *dnsaddrs, *nfsaddrs, *ip, *cp, *dot;
+	int num;
+	struct in_addr ic_ns, ic_myaddr, ic_servaddr, ic_netmask, ic_gwaddr;
 
 	/* The cast is needed to make it non-volatile. */
 /**/	err = oskit_bounded_com_queue_create(PACKQ_MAX, (oskit_queue_t **)&packq);
@@ -221,6 +267,115 @@ net_init()
 	ndev = osenv_device_lookup(&oskit_etherdev_iid, (void ***)&alldevs);
 	if (ndev <= 0)
 		panic("no Ethernet adaptors found!");
+
+	/*
+	 * XXX This code currently only handles autoconfiguration of the first
+	 * dev from what the bootloader passes to us.  On systems with multiple
+	 * interfaces this has to be turned off explicitly, unless the first
+	 * interface in the autodetect order is what you want.  Could be fixed
+	 * by using field 5 of the nfsaddrs variable (if existent).
+	 */
+	dnsaddrs = getenv("dnsaddrs");
+	if (dnsaddrs != NULL) {
+		strcpy(ipcfgstr, dnsaddrs);
+		cp = strchr(ipcfgstr, ':');
+		if (cp) *cp = '\0';
+		if (inet_aton(ipcfgstr, &ic_ns) == 0) {
+			ic_ns.s_addr = INADDR_NONE;
+		}
+		arptable[ARP_NS].ipaddr = ntohl(ic_ns.s_addr);
+	}
+	nfsaddrs = getenv("nfsaddrs");
+	if ((nfsaddrs != NULL) && (strchr(nfsaddrs, ':') == NULL)) {
+		/* Either "off" or a protocol specification */
+		nfsaddrs = NULL;
+	}
+	if (nfsaddrs != NULL) {
+		/* Parse the whole string */
+		strcpy(ipcfgstr, nfsaddrs);	/* don't clobber environment */
+		ip = ipcfgstr;
+		num = 0;
+		while (ip && *ip) {
+			if ((cp = strchr(ip, ':')))
+				*cp++ = '\0';
+			if (strlen(ip) > 0) {
+				switch (num) {
+				case 0:
+					if (inet_aton(ip, &ic_myaddr) == 0)
+						ic_myaddr.s_addr = INADDR_NONE;
+					break;
+				case 1:
+					if (inet_aton(ip, &ic_servaddr) == 0)
+						ic_servaddr.s_addr = INADDR_NONE;
+					break;
+				case 2:
+					if (inet_aton(ip, &ic_gwaddr) == 0)
+						ic_gwaddr.s_addr = INADDR_NONE;
+					break;
+				case 3:
+					if (inet_aton(ip, &ic_netmask) == 0)
+						ic_netmask.s_addr = INADDR_NONE;
+					break;
+				case 4:
+					/* hostnamelen must be word aligned. */
+					if ((dot = strchr(ip, '.'))) {
+						*dot++ = '\0';
+						strcpy(domainname, dot);
+					}
+					hostname = (char *)mustcalloc(strlen(ip) + 3, 1);
+					strcpy(hostname, ip);
+					hostnamelen = (strlen(hostname) + 3) & ~3;
+					break;
+				case 5:
+					/* device name - not implemented */
+					break;
+				case 6:
+					/* protocol to use for getting remaining info */
+					/* XXXX not implemented yet */
+					break;
+				}
+			}
+			ip = cp;
+			num++;
+		}
+		ed.dev = alldevs[0];
+		if ((ic_myaddr.s_addr != INADDR_NONE) &&
+		    (ic_servaddr.s_addr != INADDR_NONE) &&
+		    (ic_netmask.s_addr != INADDR_NONE) &&
+		    (ic_gwaddr.s_addr != INADDR_NONE) &&
+		    (ed.dev != NULL)) {
+			ic_myaddr.s_addr = ntohl(ic_myaddr.s_addr);
+			memcpy(&arptable[ARP_CLIENT].ipaddr, &ic_myaddr.s_addr,
+			       sizeof ic_myaddr.s_addr);
+			ic_netmask.s_addr = ntohl(ic_netmask.s_addr);
+			memcpy(&netmask, &ic_netmask.s_addr,
+			       sizeof ic_netmask.s_addr);
+			ic_gwaddr.s_addr = ntohl(ic_gwaddr.s_addr);
+			memcpy(&arptable[ARP_GATEWAY].ipaddr, &ic_gwaddr.s_addr,
+			       sizeof ic_gwaddr.s_addr);
+			/*
+			 * Fill in `ed' with info about this dev.
+			 */
+/**/			ed.recv_nio = oskit_netio_create(net_receive, &ed);
+			if (ed.recv_nio == NULL)
+				panic("unable to create recv_nio\n");
+			oskit_etherdev_getaddr(ed.dev, ed.haddr);
+			memcpy(arptable[ARP_CLIENT].node, ed.haddr, sizeof(ed.haddr));
+			err = oskit_etherdev_getinfo(ed.dev, &ed.info);
+			if (err)
+				panic("Error(0x%08x) getting info from first autodetected ethercard", err);
+
+			/*
+			 * Open it.
+			 */
+/**/			err = oskit_etherdev_open(ed.dev, 0, ed.recv_nio, &ed.send_nio);
+			if (err)
+				panic("Error(0x%08x) opening first autodetected ethercard", err);
+
+			return 0;
+		}
+		printf("IP config by kernel env failed - reverting to bootp\n");
+	}
 
 	/*
 	 * Try bootp on each dev and use the first one that succeeds.
diff -rNup oskit-990402/boot/net/driver.h oskit-0.97/boot/net/driver.h
--- oskit-990402/boot/net/driver.h	Tue Oct 13 08:31:05 1998
+++ oskit-0.97/boot/net/driver.h	Fri May 14 15:14:34 1999
@@ -20,8 +20,11 @@
 
 #include <oskit/error.h>
 
+#define MAXHOSTNAMELEN 80
+
 extern char eth_driver[];
 extern char packet[];
+extern char domainname[MAXHOSTNAMELEN];
 extern oskit_size_t packetlen;
 extern unsigned long netmask;		/* in host order */
 extern char *hostname;
diff -rNup oskit-990402/boot/net/ether.h oskit-0.97/boot/net/ether.h
--- oskit-990402/boot/net/ether.h	Thu Apr  9 00:42:17 1998
+++ oskit-0.97/boot/net/ether.h	Tue May 18 16:54:42 1999
@@ -53,6 +53,8 @@ struct arprequest {
 	char tipaddr[4];
 };
 
+#define ARPHRD_ETHER	1
+
 #define ARPOP_REQUEST	1
 #define ARPOP_REPLY	2
 
diff -rNup oskit-990402/boot/net/getkernel_net.c oskit-0.97/boot/net/getkernel_net.c
--- oskit-990402/boot/net/getkernel_net.c	Wed Mar 31 00:48:41 1999
+++ oskit-0.97/boot/net/getkernel_net.c	Thu May 20 15:19:37 1999
@@ -52,6 +52,7 @@ kimg_read(void *handle_notused,
 	char *bufp = buf;
 	int chunk_size;
 	int readahead;
+
 #if 0
 	printf("kimg_read: file_ofs %x, size %x\n", file_ofs, size);
 #endif
@@ -86,9 +87,8 @@ kimg_read(void *handle_notused,
  * Copies data from the NFS file into ki->ki_imgaddr.
  */
 static int
-kimg_load(void *handle,
-	  oskit_addr_t file_ofs, oskit_size_t file_size,
-	  oskit_addr_t mem_addr, oskit_size_t mem_size,
+kimg_load(void *handle, oskit_addr_t file_ofs, oskit_size_t file_size,
+	  oskit_addr_t load_addr, oskit_addr_t mem_addr, oskit_size_t mem_size,
 	  exec_sectype_t section_type)
 {
 	struct kerninfo *ki = handle;
@@ -97,7 +97,7 @@ kimg_load(void *handle,
 
 #if 0
 	printf("** load: file_ofs %x, file_size %x\n", file_ofs, file_size);
-	printf("-- load: mem_addr %x, mem_size %x\n", mem_addr, mem_size);
+	printf("-- load: phys_mem_addr %x, mem_size %x\n", load_addr, mem_size);
 	printf("-- load: sectype = %b\n", section_type, EXEC_SECTYPE_FORMAT);
 #endif
 
@@ -105,7 +105,7 @@ kimg_load(void *handle,
                 return 0;
 
 	if ((err = kimg_read(ki, file_ofs,
-			     ki->ki_imgaddr + mem_addr - ki->ki_mbhdr.load_addr,
+			     ki->ki_imgaddr + load_addr - ki->ki_mbhdr.load_addr,
 			     file_size, &got)) != 0)
 		return err;
 	if (got != file_size)
@@ -118,16 +118,15 @@ kimg_load(void *handle,
  * Callback for the exec library that just tallys up the sizes.
  */
 static int
-kimg_tally(void *handle,
-	   oskit_addr_t file_ofs, oskit_size_t file_size,
-	   oskit_addr_t mem_addr, oskit_size_t mem_size,
+kimg_tally(void *handle, oskit_addr_t file_ofs, oskit_size_t file_size,
+	   oskit_addr_t load_addr, oskit_addr_t mem_addr, oskit_size_t mem_size,
 	   exec_sectype_t section_type)
 {
 	struct multiboot_header *h = handle;
 
 #if 0
 	printf("** tally: file_ofs %x, file_size %x\n", file_ofs, file_size);
-	printf("-- tally: mem_addr %x, mem_size %x\n", mem_addr, mem_size);
+	printf("-- tally: phys_mem_addr %x, mem_size %x\n", load_addr, mem_size);
 	printf("-- tally: sectype = %b\n", section_type, EXEC_SECTYPE_FORMAT);
 #endif
 
@@ -135,12 +134,12 @@ kimg_tally(void *handle,
 		return 0;
 
 	assert(mem_size > 0);
-	if (mem_addr < h->load_addr)
-		h->load_addr = mem_addr;
-	if (mem_addr+file_size > h->load_end_addr)
-		h->load_end_addr = mem_addr+file_size;
-	if (mem_addr+mem_size > h->bss_end_addr)
-		h->bss_end_addr = mem_addr+mem_size;
+	if (load_addr < h->load_addr)
+		h->load_addr = load_addr;
+	if (load_addr+file_size > h->load_end_addr)
+		h->load_end_addr = load_addr+file_size;
+	if (load_addr+mem_size > h->bss_end_addr)
+		h->bss_end_addr = load_addr+mem_size;
 
 	return 0;
 }
@@ -284,19 +283,25 @@ getkernel_net(struct kerninfo *ki /* IN/
 	/*
 	 * Do a bunch of checks on the kernel load ranges.
 	 */
-	assert(ki->ki_mbhdr.load_addr < ki->ki_mbhdr.load_end_addr);
-	assert(ki->ki_mbhdr.load_end_addr < ki->ki_mbhdr.bss_end_addr);
 	printf("Kernel will be at %08x-%08x text+data %d bss %d\n",
 		ki->ki_mbhdr.load_addr, ki->ki_mbhdr.bss_end_addr,
 		ki->ki_mbhdr.load_end_addr - ki->ki_mbhdr.load_addr,
 		ki->ki_mbhdr.bss_end_addr - ki->ki_mbhdr.load_end_addr);
-	if (ki->ki_mbhdr.load_addr < 0x1000)
-		panic("kernel wants to be loaded too low!");
-	if (ki->ki_mbhdr.bss_end_addr > phys_mem_max)
-		panic("kernel wants to be loaded beyond available physical memory!");
+	assert(ki->ki_mbhdr.load_addr < ki->ki_mbhdr.load_end_addr);
+	assert(ki->ki_mbhdr.load_end_addr < ki->ki_mbhdr.bss_end_addr);
+	if (ki->ki_mbhdr.load_addr < 0x1000) {
+		printf("kernel wants to be loaded too low!\n");
+		return 1;
+	}
+	if (ki->ki_mbhdr.bss_end_addr > phys_mem_max) {
+		printf("kernel wants to be loaded beyond available physical memory!\n");
+		return 1;
+	}
 	if ((ki->ki_mbhdr.load_addr < 0x100000)
-	    && (ki->ki_mbhdr.bss_end_addr > 0xa0000))
-		panic("kernel wants to be loaded on top of I/O space!");
+	    && (ki->ki_mbhdr.bss_end_addr > 0xa0000)) {
+		printf("kernel wants to be loaded on top of I/O space!\n");
+		return 1;
+	}
 
 	/*
 	 * Now, read the whole thing in somewhere.
diff -rNup oskit-990402/boot/net/loadkernel.c oskit-0.97/boot/net/loadkernel.c
--- oskit-990402/boot/net/loadkernel.c	Thu Apr  1 23:22:27 1999
+++ oskit-0.97/boot/net/loadkernel.c	Wed May 26 17:49:25 1999
@@ -95,6 +95,7 @@ loadkernel(struct kerninfo *ki)
 	entry = ki->ki_mbhdr.entry;
 	load_addr = ki->ki_mbhdr.load_addr;
 
+	dprintf("entry = %p, phys entry = %p\n", entry, kvtophys(entry));
 	dprintf("ki->ki_mbinfo = %p-%p\n",
 		kvtophys(ki->ki_mbinfo),
 		kvtophys(ki->ki_mbinfo) + sizeof(ki->ki_mbinfo));
diff -rNup oskit-990402/boot/net/main.c oskit-0.97/boot/net/main.c
--- oskit-990402/boot/net/main.c	Thu Mar 18 22:49:28 1999
+++ oskit-0.97/boot/net/main.c	Tue Jul 13 17:53:52 1999
@@ -52,15 +52,28 @@ extern char version[], build_info[];
 static void
 init_default_args(int bootargc, char *bootargv[], char *default_args[])
 {
+	extern char **environ;
+	char **e;
 	char **p;
 	int i;
 
 	p = &default_args[0];
 	for (i = 0; i < bootargc; i++)
-#define NDEFAULT_ARGS 2
+#define NDEFAULT_ARGS 10
 		if (strcmp(bootargv[i], "-h") == 0 ||
 		    strcmp(bootargv[i], "-f") == 0)
 			*p++ = bootargv[i];
+
+	/* boottype is omitted from the list of environment paramters to
+	   pass, because a netboot boot is never automatic.  */
+	for (e = environ; *e != NULL; e++) {
+		if ((strncmp(*e, "bogomips=", 9) == 0) ||
+		    (strncmp(*e, "dnsaddrs=", 9) == 0) ||
+		    (strncmp(*e, "nfsroot=", 8) == 0) ||
+		    (strncmp(*e, "nfsaddrs=", 9) == 0)) {
+			*p++ = *e;
+		}
+	}
 	*p = NULL;
 }
 
@@ -166,15 +179,14 @@ build_cmdline(char *progname, char *defa
 	return cmdline;
 }
 
-void
+int
 main(int argc, char *argv[])
 {
-	char buf[512];
+	char input[512];
 	oskit_error_t err;
 	int done = 0;
 	struct kerninfo kinfo;
 	struct multiboot_info *mbi;
-	char *input = buf;
 	char *cmdline = NULL;
 	int i;
 	char *default_args[NDEFAULT_ARGS+1] = {0};
@@ -204,7 +216,7 @@ reprompt:
 	getline(input, 512);
 	input[strlen(input) - 1] = '\0';	/* chop \n */
 	while (input[0] && isspace(input[0]))
-		input++;
+		memmove(input, input+1, sizeof(input)-1);
 	if (strcmp(input, "help") == 0) {
 		printf("\n");
 		printf("%s\n", version);
@@ -217,8 +229,7 @@ reprompt:
 		       "or\n"
 		       "\tmyhost:/home/foo/kernel -x -y file1 file2\n"
 		       "The directory must be an NFS exported directory.\n"
-		       "The kernel must be a MultiBoot kernel.\n"
-		       "Hostnames are currently limited to \"marker\" and \"fast\".\n");
+		       "The kernel must be a MultiBoot kernel.\n");
 		printf("\n");
 		printf("Type \"quit\" or \"exit\" to %s.\n",
 		       return_address? "return to caller" : "reboot");
@@ -239,7 +250,7 @@ reprompt:
 	}
 	if (input[0] == '\0')
 		goto reprompt;
-	if (! parse_cmdline(input,
+	if (! parse_cmdline(input, sizeof(input),
 			    &kinfo.ki_ip.s_addr,
 			    &kinfo.ki_dirname,
 			    &kinfo.ki_filename,
@@ -307,4 +318,5 @@ reprompt:
 	/* Load it. */
 	loadkernel(&kinfo);
 	panic("loadkernel returned");
+	return 0;
 }
diff -rNup oskit-990402/boot/net/misc.c oskit-0.97/boot/net/misc.c
--- oskit-990402/boot/net/misc.c	Wed Dec 23 13:58:22 1998
+++ oskit-0.97/boot/net/misc.c	Mon May 17 15:10:19 1999
@@ -28,8 +28,10 @@ Author: Martin Renters
 #include <oskit/c/strings.h>		/* strsep */
 #include <oskit/c/stdarg.h>		/* va_list */
 #include <oskit/c/stdio.h>		/* putchar */
+#include <oskit/c/stdlib.h>		/* getenv */
 #include <oskit/c/netinet/in.h>		/* INADDR_NONE */
 
+#include "dns.h"
 #include "netboot.h"
 
 /*
@@ -186,39 +188,51 @@ netprintf(char *fmt, ...)
 }
 
 /*
- * Host lookup kludge since it is hard to use the oskit's gethostbyname
- * since we don't use the BSD socket stuff.
- * If you fix this, fix the helpstring in main.c too.
- */
-static unsigned long
-hostlookup(char *host_or_ip)
-{
-	/* These are padded with NULs so the binary can be patched... */
-	if (!strcmp(host_or_ip, "marker") || !strcmp(host_or_ip, "marker.cs"))
-		host_or_ip = "155.99.212.61\0\0";
-	else if (!strcmp(host_or_ip, "fast") || !strcmp(host_or_ip, "fast.cs"))
-		host_or_ip = "155.99.212.1\0\0\0";
-	else if (!strcmp(host_or_ip, "golden"))
-		host_or_ip = "198.252.55.133\0";
-	return ntohl(inet_addr(host_or_ip));
-}
-
-/*
  * Take the command line and set the IP, dir, and name components.
  * The cmdline is modified and things point into it.
  * The cmdline looks like "ip:/dir/file -foo bar", eg "155.99.212.1:/tmp/foo -l"
  */
 int
-parse_cmdline(char *cmdline, unsigned int *ip, char **dir, char **name,
-	      char **rest)
+parse_cmdline(char *cmdline, int cmdsize, unsigned int *ip, char **dir,
+	      char **name, char **rest)
 {
-	char *p = cmdline;
+	char *p, *op;
 	char *host_or_ip;
+	char *nfsroot, *nfsaddrs;
+	char *myipstr, *srvipstr;
+	char ipcfg[512], *q;
+	char effroot[512];
+	char cmdprefix[512];
+	int len;
 
 	p = strsep(&cmdline, " \t");
 	*rest = cmdline;		/* ok if NULL */
 
+	nfsroot = getenv("nfsroot");
+	nfsaddrs = getenv("nfsaddrs");
+	op = p;
 	host_or_ip = strsep(&p, ":");
+	if (!p && nfsroot && nfsaddrs) {
+		strcpy(ipcfg, nfsaddrs);	/* don't clobber environment */
+		q = ipcfg;
+		myipstr = q;
+		q = strchr(q, ':');
+		*q++ = '\0';
+		srvipstr = q;
+		q = strchr(q, ':');
+		*q++ = '\0';
+		sprintf(effroot, nfsroot, myipstr);
+		sprintf(cmdprefix, "%s:%s/", srvipstr, effroot);
+		len = strlen(cmdprefix);
+		memmove(op + len, op, cmdsize - len);
+		op[cmdsize-1] = '\0';
+		memmove(op, cmdprefix, len);
+		if (*rest != NULL)
+			*rest += len;
+
+		p = op;
+		host_or_ip = strsep(&p, ":");
+	}
 	if (! p)
 		return 0;
 
diff -rNup oskit-990402/boot/net/netboot.h oskit-0.97/boot/net/netboot.h
--- oskit-990402/boot/net/netboot.h	Tue Apr  7 03:27:58 1998
+++ oskit-0.97/boot/net/netboot.h	Tue May 11 09:40:39 1999
@@ -36,5 +36,5 @@ Author: Martin Renters
 void convert_ipaddr(void *d, void *s);
 char *netsprintf(char *buf, char *fmt, ...);
 void netprintf(char *fmt, ...);
-int parse_cmdline(char *cmdline, unsigned int *ip, char **dir, char **name,
+int parse_cmdline(char *cmdline, int cmdsize, unsigned int *ip, char **dir, char **name,
 		  char **rest);
diff -rNup oskit-990402/boot/net/rpc.c oskit-0.97/boot/net/rpc.c
--- oskit-990402/boot/net/rpc.c	Sun Feb 28 17:43:41 1999
+++ oskit-0.97/boot/net/rpc.c	Fri May 14 09:55:25 1999
@@ -35,6 +35,7 @@ void
 rpc_init()
 {
 	int i;
+
 	rpc_id = currticks();
 	for (i = 0; i < BUFMAX; i++) {
 		read_cache[i].valid = 0;
@@ -179,9 +180,9 @@ nfs_read(int server, int port, char *fh,
 	char	*rpcptr;
 	int	retries = MAX_RPC_RETRIES;
 	int	rlen;
-	int     i, curoff, pktcount = 0;
-	int     saved_rpc_id;
-	int     rid;
+	int	i, curoff, pktcount = 0;
+	int	saved_rpc_id;
+	int	rid;
 	struct rpc_buf *cache;
 
 	rlen = check_read_cache(offset, len, buffer);
@@ -210,10 +211,10 @@ nfs_read(int server, int port, char *fh,
 		cache->id  = rpc_id;
 
 		rpcptr = netsprintf(buf.u.data,
-		        "%L%L%L%L%L%L%L%L%L%S%L%L%L%L%L%L%L%M%L%L%L",
+			"%L%L%L%L%L%L%L%L%L%S%L%L%L%L%L%L%L%M%L%L%L",
 			rpc_id, MSG_CALL, 2, PROG_NFS, 2, NFS_READ,
-		        1, hostnamelen + 28,0,hostname,0,0,2,0,0,0,0,
-		        32, fh, curoff, len, 0);
+			1, hostnamelen + 28,0,hostname,0,0,2,0,0,0,0,
+			32, fh, curoff, len, 0);
 		curoff += len;
 		readahead--;
 		pktcount++;
@@ -269,10 +270,10 @@ nfs_read(int server, int port, char *fh,
 
 	while(retries--) {
 		rpcptr = netsprintf(buf.u.data,
-		        "%L%L%L%L%L%L%L%L%L%S%L%L%L%L%L%L%L%M%L%L%L",
+			"%L%L%L%L%L%L%L%L%L%S%L%L%L%L%L%L%L%M%L%L%L",
 			rpc_id, MSG_CALL, 2, PROG_NFS, 2, NFS_READ,
-		        1, hostnamelen + 28,0,hostname,0,0,2,0,0,0,0,
-		        32, fh, offset, len, 0);
+			1, hostnamelen + 28,0,hostname,0,0,2,0,0,0,0,
+			32, fh, offset, len, 0);
 		udp_transmit(arptable[server].ipaddr, RPC_SOCKET,
 			port, rpcptr - (char *)&buf, &buf);
 		if (await_reply(AWAIT_RPC, rpc_id, NULL)) {
diff -rNup oskit-990402/boot/net/rpc.h oskit-0.97/boot/net/rpc.h
--- oskit-990402/boot/net/rpc.h	Thu Feb 18 19:11:09 1999
+++ oskit-0.97/boot/net/rpc.h	Fri May 14 09:58:25 1999
@@ -33,7 +33,7 @@ struct rpc_t {
 
 struct rpc_buf {
 	int valid;
-	int sent;		   /* Is the request on the wire? */
+	int sent;		/* Is the request on the wire? */
 	unsigned long offset;
 	unsigned long len;
 	unsigned long id;
diff -rNup oskit-990402/boot/net/udp.c oskit-0.97/boot/net/udp.c
--- oskit-990402/boot/net/udp.c	Tue Apr  7 03:27:59 1998
+++ oskit-0.97/boot/net/udp.c	Mon May 17 13:29:47 1999
@@ -24,6 +24,7 @@ udp_transmit(unsigned long destip,
 	     unsigned short srcsock, unsigned short destsock,
 	     int len, void *bufv)
 {
+	static unsigned short id_count = 0;
 	char *buf = bufv;
 	struct iphdr *ip;
 	struct udphdr *udp;
@@ -36,7 +37,8 @@ udp_transmit(unsigned long destip,
 	ip->verhdrlen = 0x45;
 	ip->service = 0;
 	ip->len = htons(len);
-	ip->ident = 0;
+	ip->ident = htons(id_count);
+	id_count++;
 	ip->frags = 0;
 	ip->ttl = 60;
 	ip->protocol = IP_UDP;

Follow-Ups: References: