public inbox for linux-ia64@vger.kernel.org
 help / color / mirror / Atom feed
From: "Tolentino, Matthew E" <matthew.e.tolentino@intel.com>
To: linux-ia64@vger.kernel.org
Subject: RE: [Linux-ia64] PXE Boot
Date: Wed, 16 Jan 2002 19:29:33 +0000	[thread overview]
Message-ID: <marc-linux-ia64-105590698805856@msgid-missing> (raw)
In-Reply-To: <marc-linux-ia64-105590698805846@msgid-missing>

Mike,

I just tested this functionality last week on a Lion.  Using the ISC DHCP
3.0 with the attached patch I was able to remotely install and boot Lion
systems.  I used the tftpd that comes with Redhat 7.2 as well...

I hope this helps..

matt

diff -ruN ../dhcp-3.0/Makefile.conf ./Makefile.conf
--- ../dhcp-3.0/Makefile.conf	Tue Jun 26 11:31:36 2001
+++ ./Makefile.conf	Fri Oct  5 10:19:10 2001
@@ -286,7 +286,8 @@
 ## Linux 2.0
 ##--linux-2.0--
 #COPTS = -DLINUX_MAJOR=$(MAJORVERSION) -DLINUX_MINOR=$(MINORVERSION) \
-#        $(BINDDEF) $(CC_OPTIONS)
+#        $(BINDDEF) $(CC_OPTIONS) -DDLL
+#LIBS = -ldl
 #CF = cf/linux.h
 #ADMMANDIR = /usr/man/man8
 #ADMMANEXT = .8
@@ -305,7 +306,8 @@
 ## Linux 2.1
 ##--linux-2.1--
 #COPTS = -DLINUX_MAJOR=$(MAJORVERSION) -DLINUX_MINOR=$(MINORVERSION) \
-#        $(BINDDEF) $(CC_OPTIONS)
+#        $(BINDDEF) $(CC_OPTIONS) -DDLL
+#LIBS = -ldl
 #CF = cf/linux.h
 #ADMMANDIR = /usr/man/man8
 #ADMMANEXT = .8
@@ -324,7 +326,8 @@
 ## Linux 2.2
 ##--linux-2.2--
 #COPTS = -DLINUX_MAJOR=$(MAJORVERSION) -DLINUX_MINOR=$(MINORVERSION) \
-#        $(BINDDEF) $(CC_OPTIONS)
+#        $(BINDDEF) $(CC_OPTIONS) -DDLL
+#LIBS = -ldl
 #CF = cf/linux.h
 #ADMMANDIR = /usr/man/man8
 #ADMMANEXT = .8
@@ -421,6 +424,7 @@
 #FFMANEXT = .5
 #LIBMANDIR = /opt/man/man3
 #LIBMANEXT = .3
+#LIBS = -ldl
 #MANCAT = man
 #COPTS=-w3 -Dlint $(BINDDEF)
 #LFLAGS=-l socket
diff -ruN ../dhcp-3.0/client/dhclient.c ./client/dhclient.c
--- ../dhcp-3.0/client/dhclient.c	Wed Aug  8 07:46:14 2001
+++ ./client/dhclient.c	Fri Oct  5 10:16:41 2001
@@ -89,6 +89,12 @@
 
 void do_release(struct client_state *);
 
+/* %%PXE begin */
+int dhcpd_operation = NORMAL;
+int bootserver_operation = 0;
+struct iaddr mcast_discovery_addr = { 0, 0 };
+/* %%PXE end */
+
 int main (argc, argv, envp)
 	int argc;
 	char **argv, **envp;
@@ -335,7 +341,13 @@
 	inaddr_any.s_addr = INADDR_ANY;
 
 	/* Discover all the network interfaces. */
+/* %%PXE begin */
+#if 0
 	discover_interfaces (DISCOVER_UNCONFIGURED);
+#else
+	discover_interfaces(DISCOVER_UNCONFIGURED, 0);
+#endif
+/* %%PXE end */
 
 	/* Parse the dhclient.conf file. */
 	read_client_conf ();
@@ -388,9 +400,16 @@
 	   are relevant should be running, so now we once again call
 	   discover_interfaces(), and this time ask it to actually set
 	   up the interfaces. */
+/* %%PXE begin */
+#if 0
 	discover_interfaces (interfaces_requested
 			     ? DISCOVER_REQUESTED
 			     : DISCOVER_RUNNING);
+#else
+	discover_interfaces((interfaces_requested ?
+		DISCOVER_REQUESTED : DISCOVER_RUNNING), 0);;
+#endif
+/* %%PXE end */
 
 	/* Make up a seed for the random number generator from current
 	   time plus the sum of the last four bytes of each
@@ -2876,7 +2895,13 @@
 	}
 	interface_reference (&interfaces, interface, MDL);
 
+/* %%PXE begin */
+#if 0
 	discover_interfaces (DISCOVER_UNCONFIGURED);
+#else
+	discover_interfaces (DISCOVER_UNCONFIGURED, 0);
+#endif
+/* %%PXE end */
 
 	for (ip = interfaces; ip; ip = ip -> next) {
 		/* If interfaces were specified, don't configure
@@ -2893,10 +2918,18 @@
 					     ip -> client -> alias);
 		script_go (ip -> client);
 	}
-	
+
+/* %%PXE begin */
+#if 0
 	discover_interfaces (interfaces_requested
 			     ? DISCOVER_REQUESTED
 			     : DISCOVER_RUNNING);
+#else
+	discover_interfaces ((interfaces_requested
+			     ? DISCOVER_REQUESTED
+			     : DISCOVER_RUNNING), 0);
+#endif
+/* %%PXE end */
 
 	for (ip = interfaces; ip; ip = ip -> next) {
 		if (ip -> flags & INTERFACE_RUNNING)
diff -ruN ../dhcp-3.0/common/bpf.c ./common/bpf.c
--- ../dhcp-3.0/common/bpf.c	Sun Apr  8 14:12:49 2001
+++ ./common/bpf.c	Fri Oct  5 10:16:41 2001
@@ -183,6 +183,8 @@
    XXX Changes to the filter program may require changes to the constant
    offsets used in if_register_send to patch the BPF program! XXX */
 
+/* %%PXE begin */
+#if 0
 struct bpf_insn dhcp_bpf_filter [] = {
 	/* Make sure this is an IP packet... */
 	BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12),
@@ -209,6 +211,40 @@
 	/* Otherwise, drop it. */
 	BPF_STMT(BPF_RET+BPF_K, 0),
 };
+#else
+struct bpf_insn dhcp_bpf_filter [] = {
+	/* Make sure this is an IP packet... */
+	BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12),
+	BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 11),
+
+	/* Make sure it's a UDP packet... */
+	BPF_STMT (BPF_LD + BPF_B + BPF_ABS, 23),
+	BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 9),
+
+	/* Make sure this isn't a fragment... */
+	BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20),
+	BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 7, 0),
+
+	/* Get the IP header length... */
+	BPF_STMT (BPF_LDX + BPF_B + BPF_MSH, 14),
+
+	/* Make sure it's to the right port... */
+	BPF_STMT (BPF_LD + BPF_H + BPF_IND, 16),
+	BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 67, 3, 0),             /* patch
*/
+
+	/* try the PXE unicast port, too... */
+	BPF_STMT (BPF_LDX + BPF_B + BPF_MSH, 14),
+	BPF_STMT (BPF_LD + BPF_H + BPF_IND, 16),
+	BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 4011, 0, 1),
+
+	/* If we passed all the tests, ask for the whole packet. */
+	BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
+
+	/* Otherwise, drop it. */
+	BPF_STMT(BPF_RET+BPF_K, 0),
+};
+#endif
+/* %%PXE end */
 
 #if defined (DEC_FDDI)
 struct bpf_insn *bpf_fddi_filter;
@@ -397,7 +433,15 @@
 #endif /* USE_BPF_SEND */
 
 #ifdef USE_BPF_RECEIVE
+/* %%PXE begin */
+#if 0
 ssize_t receive_packet (interface, buf, len, from, hfrom)
+#else
+ssize_t
+receive_packet(interface, buf, len, from, to, hfrom)
+	struct sockaddr_in *to;
+#endif
+/* %%PXE end */
 	struct interface_info *interface;
 	unsigned char *buf;
 	size_t len;
@@ -490,6 +534,9 @@
 					       interface -> rbuf,
 					       interface -> rbuf_offset,
 					       from,
+/* %%PXE begin */
+						to,
+/* %%PXE end */
 					       (unsigned char *)0,
 					       hdr.bh_caplen);
 
@@ -542,11 +589,25 @@
 	return 1;
 }
 
+/* %%PXE begin */
+#if 0
 void maybe_setup_fallback ()
+#else
+void
+maybe_setup_fallback(int bootserver)
+#endif
+/* %%PXE end */
 {
 	isc_result_t status;
 	struct interface_info *fbi = (struct interface_info *)0;
+
+/* %%PXE begin */
+#if 0
 	if (setup_fallback (&fbi, MDL)) {
+#else
+	if (setup_fallback(&fbi, MDL, bootserver)) {
+#endif
+/* %%PXE end */
 		if_register_fallback (fbi);
 		status = omapi_register_io_object ((omapi_object_t *)fbi,
 						   if_readsocket, 0,
diff -ruN ../dhcp-3.0/common/conflex.c ./common/conflex.c
--- ../dhcp-3.0/common/conflex.c	Mon Jun  4 14:18:39 2001
+++ ./common/conflex.c	Fri Oct  5 10:16:41 2001
@@ -558,6 +558,15 @@
 			return BALANCE;
 		if (!strcasecmp (atom + 1, "ound"))
 			return BOUND;
+/* %%PXE begin */
+		if (!strcasecmp(atom + 1, "ootserver")) {
+			return BOOTSERVER;
+		}
+
+		if (!strcasecmp(atom + 1, "ootserver-operation")) {
+			return BOOTSERVER_OPERATION;
+		}
+/* %%PXE end */
 		break;
 	      case 'c':
 		if (!strcasecmp (atom + 1, "ase"))
@@ -646,6 +655,21 @@
 			if (!atom [6])
 				return DEFINE;
 		}
+/* %%PXE begin */
+		if (!strcasecmp(atom + 1, "isable")) {
+			return DISABLE;
+		}
+
+		if (!strcasecmp(atom + 1, "hcpd-operation")) {
+			return DHCPD_OPERATION;
+		}
+
+#ifdef DLL
+		if (!strcasecmp(atom + 1, "ll")) {
+			return TOKEN_DLL;
+		}
+#endif /* DLL */
+/* %%PXE end */
 		break;
 	      case 'e':
 		if (isascii (atom [1]) && tolower (atom [1]) = 'x') {
@@ -801,6 +825,11 @@
 			return MY;
 		if (!strcasecmp (atom + 1, "clt"))
 			return MCLT;
+/* %%PXE begin */
+		if (!strcasecmp(atom + 1, "cast-discovery-addr")) {
+			return MCAST_DISCOVERY_ADDR;
+		}
+/* %%PXE end */
 		break;
 	      case 'n':
 		if (!strcasecmp (atom + 1, "ormal"))
@@ -884,6 +913,11 @@
 			return PICK;
 		if (!strcasecmp (atom + 1, "aused"))
 			return PAUSED;
+/* %%PXE begin */
+		if (!strcasecmp(atom + 1, "roxy")) {
+			return PROXY;
+		}
+/* %%PXE end */
 		break;
 	      case 'r':
 		if (!strcasecmp (atom + 1, "esolution-interrupted"))
diff -ruN ../dhcp-3.0/common/ctrace.c ./common/ctrace.c
--- ../dhcp-3.0/common/ctrace.c	Mon Feb 26 14:21:07 2001
+++ ./common/ctrace.c	Fri Oct  5 10:16:41 2001
@@ -200,6 +200,9 @@
 				 (struct dhcp_packet *)(tip + 1),
 				 len - sizeof *tip,
 				 tip -> from_port,
+/* %%PXE begin */
+				tip->to_port,
+/* %%PXE end */
 				 tip -> from,
 				 (tip -> havehfrom ?
 				  &tip -> hfrom
diff -ruN ../dhcp-3.0/common/dhcp-eval.5 ./common/dhcp-eval.5
--- ../dhcp-3.0/common/dhcp-eval.5	Thu Oct  4 13:40:47 2001
+++ ./common/dhcp-eval.5	Fri Oct  5 10:16:41 2001
@@ -165,6 +165,7 @@
 The \fBexists\fR expression returns true if the specified option
 exists in the incoming DHCP packet being processed.
 .RE
+.PP
 .B known
 .PP
 .RS 0.25i
@@ -172,6 +173,7 @@
 currently being processed is known - that is, if there's a host
 declaration for it.
 .RE
+.PP
 .B static
 .PP
 .RS 0.25i
diff -ruN ../dhcp-3.0/common/discover.c ./common/discover.c
--- ../dhcp-3.0/common/discover.c	Thu Jun 21 09:46:09 2001
+++ ./common/discover.c	Fri Oct  5 10:16:41 2001
@@ -62,10 +62,22 @@
 struct in_addr limited_broadcast;
 struct in_addr local_address;
 
+/* %%PXE begin */
+#if 0
 void (*bootp_packet_handler) PROTO ((struct interface_info *,
 				     struct dhcp_packet *, unsigned,
 				     unsigned int,
 				     struct iaddr, struct hardware *));
+#else
+void (*bootp_packet_handler) PROTO ((struct interface_info *,
+				     struct dhcp_packet *,
+				     unsigned,
+				     unsigned int,
+				     unsigned int,
+				     struct iaddr,
+				     struct hardware *));
+#endif
+/* %%PXE end */
 
 omapi_object_type_t *dhcp_type_interface;
 #if defined (TRACING)
@@ -122,6 +134,10 @@
 {
 	struct interface_info *ip = (struct interface_info *)ipo;
 	ip -> rfdesc = ip -> wfdesc = -1;
+/* %%PXE begin */
+	ip->bootserver = 0;
+	ip->pxe_rfdesc = ip->pxe_wfdesc = -1;
+/* %%PXE end */
 	return ISC_R_SUCCESS;
 }
 
@@ -130,7 +146,28 @@
    register that interface with the network I/O software, figure out what
    subnet it's on, and add it to the list of interfaces. */
 
+/* %%PXE begin */
+int
+if_pxe_readsocket(omapi_object_t *h)
+{
+	struct interface_info *ip;
+
+	if (h->type != dhcp_type_interface) {
+		return -1;
+	}
+
+	ip = (struct interface_info *)h;
+
+	return ip->pxe_rfdesc;
+}
+
+#if 0
 void discover_interfaces (state)
+#else
+void discover_interfaces(state, bootserver)
+	int bootserver;
+#endif
+/* %%PXE end */
 	int state;
 {
 	struct interface_info *tmp, *ip;
@@ -628,6 +665,10 @@
 		tmp -> index = -1;
 
 		/* Register the interface... */
+/* %%PXE begin */
+		tmp->bootserver = bootserver;
+		tmp->pxe_rfdesc = tmp->pxe_wfdesc = -1;
+/* %%PXE end */
 		if_register_receive (tmp);
 		if_register_send (tmp);
 
@@ -642,6 +683,14 @@
 				log_error ("Can't set close-on-exec on %s:
%m",
 					   tmp -> name);
 		}
+
+/* %%PXE begin */
+		if (tmp->pxe_rfdesc != -1) {
+			if (fcntl(tmp->pxe_rfdesc, F_SETFD, 1) < 0) {
+				log_error("Cannot set close-on-exec on PXE
%s: %m", tmp->name);
+			}
+		}
+/* %%PXE end */
 #endif
 	      next:
 		interface_dereference (&tmp, MDL);
@@ -662,6 +711,36 @@
 		if (status != ISC_R_SUCCESS)
 			log_fatal ("Can't register I/O handle for %s: %s",
 				   tmp -> name, isc_result_totext (status));
+
+/* %%PXE begin */
+		{
+			ip = 0;
+			status = interface_allocate(&ip, MDL);
+			if (status != ISC_R_SUCCESS) {
+				log_fatal("Cannott allocate PXE interface
%s: %s",
+					   tmp->name,
isc_result_totext(status));
+			}
+			
+			*ip = *tmp;
+			ip->outer = 0;
+			ip->inner = (void *)ip;
+			ip->rfdesc = ip->pxe_rfdesc;
+			ip->wfdesc = ip->pxe_wfdesc;
+			ip->flags &= ~INTERFACE_RUNNING;
+			ip->bootserver = 2;
+
+			tmp->next = ip;
+			tmp = ip;
+		}
+
+		status = omapi_register_io_object((omapi_object_t *)tmp,
+			if_readsocket, 0, got_one, 0, 0);
+
+		if (status != ISC_R_SUCCESS) {
+			log_fatal("Cannot register PXE I/O handle for %s:
%s",
+				tmp->name, isc_result_totext(status));
+		}
+/* %%PXE end */
 	}
 
 	close (sock);
@@ -673,7 +752,13 @@
 
 	if (!setup_fallback) {
 		setup_fallback = 1;
+/* %%PXE begin */
+#if 0
 		maybe_setup_fallback ();
+#else
+		maybe_setup_fallback(bootserver);
+#endif
+/* %%PXE end */
 	}
 
 #if defined (HAVE_SETFD)
@@ -699,7 +784,13 @@
 	return ip -> rfdesc;
 }
 
+/* %%PXE begin */
+#if 0
 int setup_fallback (struct interface_info **fp, const char *file, int line)
+#else
+int setup_fallback (struct interface_info **fp, const char *file, int line,
int bootserver)
+#endif
+/* %%PXE end */
 {
 	isc_result_t status;
 
@@ -708,6 +799,9 @@
 		log_fatal ("Error allocating fallback interface: %s",
 			   isc_result_totext (status));
 	strcpy (fallback_interface -> name, "fallback");
+/* %%PXE begin */
+	fallback_interface->bootserver = bootserver;
+/* %%PXE end */
 	if (dhcp_interface_setup_hook)
 		(*dhcp_interface_setup_hook) (fallback_interface,
 					      (struct iaddr *)0);
@@ -747,6 +841,9 @@
 		struct dhcp_packet packet;
 	} u;
 	struct interface_info *ip;
+/* %%PXE begin */
+	struct sockaddr_in to;
+/* %%PXE end */
 
 	if (h -> type != dhcp_type_interface)
 		return ISC_R_INVALIDARG;
@@ -754,7 +851,13 @@
 
       again:
 	if ((result +/* %%PXE begin */
+#if 0
 	     receive_packet (ip, u.packbuf, sizeof u, &from, &hfrom)) < 0) {
+#else
+	     receive_packet(ip, u.packbuf, sizeof u, &from, &to, &hfrom)) <
0) {
+#endif
+/* %%PXE end */
 		log_error ("receive_packet failed on %s: %m", ip -> name);
 		return ISC_R_UNEXPECTED;
 	}
@@ -773,8 +876,20 @@
 		ifrom.len = 4;
 		memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len);
 
+/* %%PXE begin */
+#if 0
 		(*bootp_packet_handler) (ip, &u.packet, (unsigned)result,
 					 from.sin_port, ifrom, &hfrom);
+#else
+		(*bootp_packet_handler)(ip,
+					&u.packet,
+					(unsigned)result,
+					from.sin_port,
+					to.sin_port,
+					ifrom,
+					&hfrom);
+#endif
+/* %%PXE end */
 	}
 
 	/* If there is buffered data, read again.    This is for, e.g.,
diff -ruN ../dhcp-3.0/common/dlpi.c ./common/dlpi.c
--- ../dhcp-3.0/common/dlpi.c	Thu Apr  5 13:53:01 2001
+++ ./common/dlpi.c	Fri Oct  5 10:16:41 2001
@@ -613,7 +613,14 @@
 #endif /* USE_DLPI_SEND */
 
 #ifdef USE_DLPI_RECEIVE
+/* %%PXE begin */
+#if 0
 ssize_t receive_packet (interface, buf, len, from, hfrom)
+#else
+ssize_t receive_packet(interface, buf, len, from, to, hfrom)
+	struct sockaddr_in *to;
+#endif
+/* %%PXE end */
 	struct interface_info *interface;
 	unsigned char *buf;
 	size_t len;
@@ -687,8 +694,20 @@
 	bufix += offset;
 	length -= offset;
 #endif
+/* %%PXE begin */
+#if 0
 	offset = decode_udp_ip_header (interface, dbuf, bufix,
 				       from, (unsigned char *)0, length);
+#else
+	offset = decode_udp_ip_header(interface,
+				      dbuf,
+				      bufix,
+				      from,
+				      to,
+				      (unsigned char *)0,
+				      length);
+#endif
+/* %%PXE end */
 
 	/* If the IP or UDP checksum was bad, skip the packet... */
 	if (offset < 0) {
diff -ruN ../dhcp-3.0/common/lpf.c ./common/lpf.c
--- ../dhcp-3.0/common/lpf.c	Mon Apr 23 17:36:00 2001
+++ ./common/lpf.c	Fri Oct  5 10:16:41 2001
@@ -336,7 +336,14 @@
 #endif /* USE_LPF_SEND */
 
 #ifdef USE_LPF_RECEIVE
+/* %%PXE begin */
+#if 0
 ssize_t receive_packet (interface, buf, len, from, hfrom)
+#else
+ssize_t receive_packet(interface, buf, len, from, to, hfrom)
+	struct sockaddr_in *to;
+#endif
+/* %%PXE end */
 	struct interface_info *interface;
 	unsigned char *buf;
 	size_t len;
@@ -368,8 +375,20 @@
 	length -= offset;
 
 	/* Decode the IP and UDP headers... */
+/* %%PXE begin */
+#if 0
 	offset = decode_udp_ip_header (interface, ibuf, bufix, from,
 				       (unsigned char *)0,
(unsigned)length);
+#else
+	offset = decode_udp_ip_header(interface,
+				      ibuf,
+				      bufix,
+				      from,
+				      to,
+				      (unsigned char *)0,
+				      (unsigned)length);
+#endif
+/* %%PXE end */
 
 	/* If the IP or UDP checksum was bad, skip the packet... */
 	if (offset < 0)
@@ -401,11 +420,24 @@
 	return 1;
 }
 
+/* %%PXE begin */
+#if 0
 void maybe_setup_fallback ()
+#else
+void maybe_setup_fallback(int bootserver)
+#endif
+/* %%PXE end */
 {
 	isc_result_t status;
 	struct interface_info *fbi = (struct interface_info *)0;
+
+/* %%PXE begin */
+#if 0
 	if (setup_fallback (&fbi, MDL)) {
+#else
+	if (setup_fallback(&fbi, MDL, bootserver)) {
+#endif
+/* %%PXE end */
 		if_register_fallback (fbi);
 		status = omapi_register_io_object ((omapi_object_t *)fbi,
 						   if_readsocket, 0,
diff -ruN ../dhcp-3.0/common/nit.c ./common/nit.c
--- ../dhcp-3.0/common/nit.c	Sat Feb 17 13:17:25 2001
+++ ./common/nit.c	Fri Oct  5 10:16:41 2001
@@ -347,7 +347,14 @@
 #endif /* USE_NIT_SEND */
 
 #ifdef USE_NIT_RECEIVE
+/* %%PXE begin */
+#if 0
 ssize_t receive_packet (interface, buf, len, from, hfrom)
+#else
+ssize_t receive_packet(interface, buf, len, from, to, hfrom)
+	struct sockaddr_in *to;
+#endif
+/* %%PXE end */
 	struct interface_info *interface;
 	unsigned char *buf;
 	size_t len;
@@ -378,8 +385,20 @@
 	length -= offset;
 
 	/* Decode the IP and UDP headers... */
+/* %%PXE begin */
+#if 0
 	offset = decode_udp_ip_header (interface, ibuf, bufix,
 				       from, (unsigned char *)0, length);
+#else
+	offset = decode_udp_ip_header(interface,
+				      ibuf,
+				      bufix,
+				      from,
+				      to,
+				      (unsigned char *)0,
+				      length);
+#endif
+/* %%PXE end */
 
 	/* If the IP or UDP checksum was bad, skip the packet... */
 	if (offset < 0)
diff -ruN ../dhcp-3.0/common/options.c ./common/options.c
--- ../dhcp-3.0/common/options.c	Thu Aug 23 09:11:34 2001
+++ ./common/options.c	Fri Oct  5 10:16:41 2001
@@ -162,6 +162,19 @@
 			return 0;
 		}
 
+/* %%PXE begin */
+		if (universe->is_vendor) {
+			/*
+			 * When parsing (or trying to parse) vendor option
+			 * space; if we do not know what the option is,
+			 * just skip it and say everything is kosher.
+			 */
+			if (!universe->options[code]) {
+				return 1;
+			}
+		}
+/* %%PXE end */
+
 		/* If the option contains an encapsulation, parse it.   If
 		   the parse fails, or the option isn't an encapsulation (by
 		   far the most common case), or the option isn't entirely
@@ -175,6 +188,37 @@
 		    save_option_buffer (universe, options, bp,
 					&bp -> data [offset + 2], len,
 					universe -> options [code], 1);
+
+/* %%PXE begin */
+			/*
+			 * This is probably very PXE specific and there is
+			 * probably a better way to do this, but this hack
+			 * seems to work.  Basically, if we are paring the
+			 * DHCP options and we find a vendor encapsulated
+			 * option, send it back through the option parser
+			 * for every vendor option space that exists.
+			 */
+			if (universe = &dhcp_universe &&
+				code = DHO_VENDOR_ENCAPSULATED_OPTIONS)
+			{
+				unsigned n;
+
+				for (n = 0; n < universe_count; ++n) {
+					if (!universes[n]->is_vendor) {
+						continue;
+					}
+
+					if (!parse_option_buffer(
+						options,
+						&bp->data[offset+2],
+						len,
+						universes[n]))
+					{
+						return 0;
+					}	
+				}
+			}
+/* %%PXE end */
 		}
 		offset += len + 2;
 	}
@@ -506,6 +550,10 @@
 	priority_list [priority_len++] = DHO_DHCP_MESSAGE_TYPE;
 	priority_list [priority_len++] = DHO_DHCP_SERVER_IDENTIFIER;
 	priority_list [priority_len++] = DHO_DHCP_LEASE_TIME;
+/* %%PXE begin */
+	priority_list [priority_len++] = DHO_DHCP_RENEWAL_TIME;
+	priority_list [priority_len++] = DHO_DHCP_REBINDING_TIME;
+/* %%PXE end */
 	priority_list [priority_len++] = DHO_DHCP_MESSAGE;
 	priority_list [priority_len++] = DHO_DHCP_REQUESTED_ADDRESS;
 
@@ -607,8 +655,15 @@
 				     inpacket, lease, client_state,
 				     in_options, cfg_options, scope,
 				     priority_list, priority_len,
+/* %%PXE begin */
+#if 0
 				     main_buffer_size,
 				     (main_buffer_size +
+#else
+				     (main_buffer_size - 7),
+				     ((main_buffer_size - 7) +
+#endif
+/* %%PXE end */
 				      ((overload & 1) ? DHCP_FILE_LEN : 0)),
 				     terminate, vuname);
 
@@ -696,6 +751,40 @@
 
 /* Store all the requested options into the requested buffer. */
 
+/* %%PXE begin */
+/* Used to qsort() vendor-encapsulated-options by size. */
+
+struct s_optcmp {
+	unsigned ix;
+	int len;
+};
+
+int
+_optcmp(const void *left, const void *right)
+{
+	int s;
+
+	/* Sort first by size.  Longer options are first in list.
+	 */
+	s = ((struct s_optcmp *)left)->len - ((struct s_optcmp
*)right)->len;
+
+	if (s < 0) {
+		return 1;
+	} else if (s > 0) {
+		return -1;
+	}
+
+	/* If options are same length, sort by location.  If the
+	 * option came first, it is still first.
+	 */
+	if (((struct s_optcmp *)left)->ix < ((struct s_optcmp *)right)->ix)
{
+		return 1;
+	} else {
+		return -1;
+	}	
+}
+/* %%PXE end */
+
 int store_options (buffer, buflen, packet, lease, client_state,
 		   in_options, cfg_options, scope, priority_list,
priority_len,
 		   first_cutoff, second_cutoff, terminate, vuname)
@@ -756,7 +845,31 @@
 
 	    /* Code for next option to try to store. */
 	    code = priority_list [i];
-	    
+
+/* %%PXE begin */
+		if (lease) {
+			if (lease->flags & PXE_LEASE) {
+				switch (code) {
+					case DHO_DHCP_LEASE_TIME:
+					case DHO_DHCP_RENEWAL_TIME:
+					case DHO_DHCP_REBINDING_TIME:
+					continue;
+				}
+			}
+		}
+		
+		if (packet) {
+			if (packet->proxy || packet->bootserver) {
+				switch (code) {
+					case DHO_DHCP_LEASE_TIME:
+					case DHO_DHCP_RENEWAL_TIME:
+					case DHO_DHCP_REBINDING_TIME:
+					continue;
+				}
+			}
+		}
+/* %%PXE end */
+
 	    /* Look up the option in the site option space if the code
 	       is above the cutoff, otherwise in the DHCP option space. */
 	    if (code >= cfg_options -> site_code_min)
@@ -880,7 +993,231 @@
 	    }
 
 	    /* Try to store the option. */
-	    
+
+/* %%PXE begin */
+/* Special check for vendor-encapsulated-options with a total length that
+ * is greater than 255 bytes or that will cross a buffer boundary.  This
+ * is done because the existing PXE clients only know how to parse
+ * sub-options when they are contiguous.  This also means that PXE clients
+ * do not know how to handle a single sub-option that is longer than 255
+ * bytes, but since that really is not defined and is already not handled
+ * cleanly by this code, we are not going to worry about that.
+ *
+ * NOTE - The parse code should barf if a single option or sub-option
+ * exceeds 255 bytes.  Right now it just takes and the option stuffing
+ * code fills the buffer with an invalid length byte.
+ */
+	if (code = DHO_VENDOR_ENCAPSULATED_OPTIONS && (length > 255 ||
+		(bufix < first_cutoff && bufix + length > first_cutoff) ||
+		(bufix < second_cutoff && bufix + length > second_cutoff)))
+	{
+		struct s_optcmp *subcmp;
+		unsigned subcnt;  /* number of sub-options */
+		unsigned subix;   /* index into subcmp[] array */
+		unsigned left;    /* space left in buffer */
+
+		/* Skip into next buffer if we are right on a buffer
+		 * boundary.  If this would cause our option to go
+		 * past the end of the buffer, skip it.
+		 */
+		optstart = bufix;
+
+		if (optstart < first_cutoff && first_cutoff - optstart < 5)
{
+			optstart = first_cutoff;
+		}
+
+		if (optstart < second_cutoff && second_cutoff - optstart <
5) {
+			optstart = second_cutoff;
+		}
+
+		if (optstart + 2 + length > buflen) {
+			/* Option would go past end of buffer, skip it.
+			 */
+	    		data_string_forget (&od, MDL);
+			return bufix;
+		}
+
+		/* Count number of sub-options in the option.
+		 */
+		for (subcnt = 0, ix = 0; ix < length; ) {
+			++subcnt;
+
+			switch (od.data[ix]) {
+			case 0:
+			case 255:
+				++ix;
+				break;
+
+			default:
+				ix += 2 + od.data[ix + 1];
+			}
+		}
+
+		/* Allocate buffer to hold starting position and length
+		 * of each sub-option.
+		 */
+		if (!(subcmp = calloc(subcnt, sizeof(struct s_optcmp)))) {
+			/* Craps.  Skip this option.
+			 */
+	    		data_string_forget (&od, MDL);
+			return bufix;
+		}
+
+		/* Get the starting positions of each sub-option.
+		 */
+		for (subix = 0, ix = 0; ix < length; ) {
+			if (subix = subcnt) {
+				/* We had more sub-options the second time
+				 * through the option?!?  Craps.  Skip it.
+				 */
+				free(subcmp);
+	    			data_string_forget (&od, MDL);
+				return bufix;
+			}
+
+			/* Keep track of starting position and length.
+			 */
+			subcmp[subix].ix = ix;
+
+			switch (od.data[ix]) {
+			case 0:
+			case 255:
+				subcmp[subix].len = 1;
+				++ix;
+				break;
+
+			default:
+				subcmp[subix].len = 2 + od.data[ix + 1];
+				ix += 2 + od.data[ix + 1];
+			}
+
+			++subix;
+		}
+
+		/* Now, put our sub-options into the buffer.  Create new
+		 * encapsulating options if the encapsulating option would
+		 * grow past 255 bytes or a sub-option would split across
+		 * buffer boundaries.
+		 */
+		for (;;) {
+			/* Incremented everytime a sub-option gets placed
+			 * into the buffer.
+			 */
+			unsigned placed = 0;
+
+			/* Now sort them from longest sub-option to
shortest.
+			 * End if all options have been placed.
+			 */
+			qsort(subcmp, subcnt, sizeof(struct s_optcmp),
+				&_optcmp);
+
+			if (!subcmp[0].len) {
+				break;
+			}	
+
+			/* So, now we have a list of options sorted by
length.
+			 * Start placing the first encapsulating option.
+			 */
+			buffer[optstart] = code;
+			buffer[optstart + 1] = 0;
+			ix = optstart + 2;
+
+			/* Compute amount of space left before end of
buffer.
+			 */
+			if (ix < first_cutoff) {
+				left = first_cutoff - ix;
+			} else if (ix < second_cutoff) {
+				left = second_cutoff - ix;
+			} else {
+				left = buflen - ix;
+			}
+
+			if (left > 255) {
+				left = 255;
+			}
+
+			/* Place as many sub-options as we can, starting
+			 * with the largest one that will fit.
+			 */
+			for (subix = 0; left && subix < subcnt; ++subix) {
+				/* Skip sub-options that have already been
+				 * placed into the buffer.
+				 */
+				if (!subcmp[subix].len) {
+					continue;
+				}
+
+				/* If this sub-option does not fit here,
+				 * try the next sub-option, it might be
+				 * shorter.
+				 */
+				if (left < subcmp[subix].len) {
+					continue;
+				}
+
+				/* Copy this sub-option into the buffer.
+				 */
+				memcpy(&buffer[ix], 
+					&od.data[subcmp[subix].ix],
+					subcmp[subix].len);
+
+				/* Update length of encapsulating option,
+				 * buffer index and space left.
+				 */
+				buffer[optstart + 1] += subcmp[subix].len;
+				ix += subcmp[subix].len;	
+				left -= subcmp[subix].len;
+
+				/* Mark this sub-option placed.
+				 */
+				subcmp[subix].len = 0;
+				++placed;
+			}
+
+			if (!placed) {
+				/* No options were placed, wipe out the
+				 * encapsulating option code in the buffer.
+				 */
+				buffer[optstart] = 0;
+			} else {	
+				/* Options were placed, update the option
+				 * start index.
+				 */
+				optstart = ix;
+			}
+
+			/* Possibly update the option start index again.
+			 * If we are near the end of a buffer or if nothing
+			 * got placed in the current buffer, skip to the
+			 * beginning of the next buffer.  When the last
+			 * buffer is skipped, we are done.
+			 */
+			if (optstart < first_cutoff) {
+				if (!placed || first_cutoff - optstart < 5)
{
+					optstart = first_cutoff;
+				}
+			} else if (optstart < second_cutoff) {
+				if (!placed || second_cutoff - optstart < 5)
{
+					optstart = second_cutoff;
+				}
+			} else {
+				/* If we finish the third buffer, we are
+				 * as done as we are gonna get.
+				 */
+				break;
+			}	
+		}
+
+		/* Done w/ sub-options.  Free up storage and return
+		 * updated buffer index.
+		 */
+		free(subcmp);
+	    	data_string_forget (&od, MDL);
+
+		return bufix = optstart;
+	}
+/* %%PXE end */
+
 	    /* If the option's length is more than 255, we must store it
 	       in multiple hunks.   Store 255-byte hunks first.  However,
 	       in any case, if the option data will cross a buffer
@@ -2128,7 +2465,14 @@
 	}
 }
 
+/* %%PXE begin */
+#if 0
 void do_packet (interface, packet, len, from_port, from, hfrom)
+#else
+void do_packet(interface, packet, len, from_port, to_port, from, hfrom)
+	unsigned int to_port;
+#endif
+/* %%PXE end */
 	struct interface_info *interface;
 	struct dhcp_packet *packet;
 	unsigned len;
@@ -2158,7 +2502,10 @@
 	decoded_packet -> client_addr = from;
 	interface_reference (&decoded_packet -> interface, interface, MDL);
 	decoded_packet -> haddr = hfrom;
-	
+/* %%PXE begin */
+	decoded_packet->server_port = to_port;
+/* %%PXE end */
+
 	if (packet -> hlen > sizeof packet -> chaddr) {
 		packet_dereference (&decoded_packet, MDL);
 		log_info ("Discarding packet with bogus hlen.");
diff -ruN ../dhcp-3.0/common/packet.c ./common/packet.c
--- ../dhcp-3.0/common/packet.c	Thu May 31 12:28:51 2001
+++ ./common/packet.c	Fri Oct  5 10:16:41 2001
@@ -170,7 +170,13 @@
 	*bufix += sizeof ip;
 
 	/* Fill out the UDP header */
+/* %%PXE begin */
+#if 0
 	udp.uh_sport = local_port;		/* XXX */
+#else
+	udp.uh_sport = (port = htons((short)4011)) ? port : local_port;
+#endif
+/* %%PXE end */
 	udp.uh_dport = port;			/* XXX */
 	udp.uh_ulen = htons(sizeof(udp) + len);
 	memset (&udp.uh_sum, 0, sizeof udp.uh_sum);
@@ -219,7 +225,14 @@
 
 /* UDP header and IP header decoded together for convenience. */
 
+/* %%PXE begin */
+#if 0
 ssize_t decode_udp_ip_header (interface, buf, bufix, from, data, buflen)
+#else
+ssize_t decode_udp_ip_header(interface, buf, bufix, from, to, data, buflen)
+	struct sockaddr_in *to;
+#endif
+/* %%PXE end */
 	struct interface_info *interface;
 	unsigned char *buf;
 	unsigned bufix;
@@ -286,6 +299,10 @@
   /* Copy out the IP source address... */
   memcpy (&from -> sin_addr, &ip -> ip_src, 4);
 
+/* %%PXE begin */
+	memcpy(&to->sin_addr, &ip->ip_dst, 4);
+/* %%PXE end */
+
   /* Compute UDP checksums, including the ``pseudo-header'', the UDP
      header and the data.   If the UDP checksum field is zero, we're
      not supposed to do a checksum. */
@@ -342,6 +359,10 @@
 
   /* Copy out the port... */
   memcpy (&from -> sin_port, &udp -> uh_sport, sizeof udp -> uh_sport);
+
+/* %%PXE begin */
+	memcpy(&to->sin_port, &udp->uh_dport, sizeof udp->uh_dport);
+/* %%PXE end */
 
   return ip_len + sizeof *udp;
 }
diff -ruN ../dhcp-3.0/common/parse.c ./common/parse.c
--- ../dhcp-3.0/common/parse.c	Tue Jun 26 11:33:32 2001
+++ ./common/parse.c	Fri Oct  5 10:16:41 2001
@@ -48,6 +48,10 @@
 
 #include "dhcpd.h"
 
+/* %%PXE begin */
+#include <dlfcn.h>
+/* %%PXE end */
+
 /* Enumerations can be specified in option formats, and are used for
    parsing, so we define the routines that manage them here. */
 
@@ -980,6 +984,10 @@
 		log_fatal ("Can't allocate %s option hash table.", nu ->
name);
 	universe_hash_add (universe_hash, nu -> name, 0, nu, MDL);
 	parse_semi (cfile);
+
+/* %%PXE begin */
+	nu->is_vendor = 1;
+/* %%PXE end */
 }
 
 /* This is faked up to look good right now.   Ideally, this should do a
@@ -1031,7 +1039,10 @@
 	int is_signed;
 	char *s;
 	int has_encapsulation = 0;
-	
+/* %%PXE begin */
+	int  array_in_array = 0;
+/* %%PXE end */
+
 	/* Parse the option code. */
 	token = next_token (&val, (unsigned *)0, cfile);
 	if (token != NUMBER) {
@@ -1077,7 +1088,13 @@
 
 	switch (token) {
 	      case ARRAY:
+/* %%PXE begin */
+#if 0
 		if (arrayp) {
+#else
+		if (arrayp && recordp && array_in_array) {
+#endif
+/* %%PXE end */
 			parse_warn (cfile, "no nested arrays.");
 			skip_to_rbrace (cfile, recordp);
 			if (recordp)
@@ -1099,6 +1116,9 @@
 			skip_to_semi (cfile);
 			return 0;
 		}
+/* %%PXE begin */
+		array_in_array = no_more_in_record = 1;
+/* %%PXE end */
 		goto next_type;
 	      case BOOLEAN:
 		type = 'f';
@@ -1158,7 +1178,13 @@
 	      case TEXT:
 		type = 't';
 	      no_arrays:
+/* %%PXE begin */
+#if 0
 		if (arrayp) {
+#else
+		if (arrayp && array_in_array) {
+#endif
+/* %%PXE end */
 			parse_warn (cfile, "arrays of text strings not %s",
 				    "yet supported.");
 			skip_to_rbrace (cfile, recordp);
@@ -1166,7 +1192,11 @@
 				skip_to_semi (cfile);
 			return 0;
 		}
+/* %%PXE begin */
+#if 0
 		no_more_in_record = 1;
+#endif
+/* %%PXE end */
 		break;
 	      case STRING_TOKEN:
 		type = 'X';
@@ -1222,6 +1252,11 @@
 		}
 		if (token = COMMA) {
 			if (no_more_in_record) {
+/* %%PXE begin */
+				if (arrayp && array_in_array)
+					parse_warn(cfile, "array must be at
end of record.");
+				else
+/* %%PXE end */
 				parse_warn (cfile,
 					    "%s must be at end of record.",
 					    type = 't' ? "text" :
"string");
@@ -1257,6 +1292,9 @@
 		has_encapsulation = 0;
 	s = dmalloc (tokix +
 		     (arrayp ? 1 : 0) +
+/* %%PXE begin */
+			(array_in_array ? 1 : 0) +
+/* %%PXE end */
 		     (has_encapsulation ? 1 : 0) + 1, MDL);
 	if (!s)
 		log_fatal ("no memory for option format.");
@@ -1264,6 +1302,11 @@
 		s [0] = 'e';
 	memcpy (s + has_encapsulation, tokbuf, tokix);
 	tokix += has_encapsulation;
+/* %%PXE begin */
+	if (arrayp && array_in_array) {
+		s[tokix++] = 'a';
+	}
+/* %%PXE end */
 	if (arrayp)
 		s [tokix++] = (arrayp > recordp) ? 'a' : 'A';
 	s [tokix] = 0;
@@ -2656,6 +2699,11 @@
 
 	if (!is_boolean_expression (*expr) &&
 	    (*expr) -> op != expr_variable_reference &&
+/* %%PXE begin */
+#ifdef DLL
+		(*expr)->op != expr_dll &&
+#endif /* DLL */
+/* %%PXE end */
 	    (*expr) -> op != expr_funcall) {
 		parse_warn (cfile, "Expecting a boolean expression.");
 		*lose = 1;
@@ -2693,6 +2741,11 @@
 
 	if (!is_data_expression (*expr) &&
 	    (*expr) -> op != expr_variable_reference &&
+/* %%PXE begin */
+#ifdef DLL
+		(*expr)->op != expr_dll &&
+#endif /* DLL */
+/* %%PXE end */
 	    (*expr) -> op != expr_funcall) {
 		parse_warn (cfile, "Expecting a data expression.");
 		*lose = 1;
@@ -2719,6 +2772,11 @@
 
 	if (!is_numeric_expression (*expr) &&
 	    (*expr) -> op != expr_variable_reference &&
+/* %%PXE begin */
+#ifdef DLL
+		(*expr)->op != expr_dll &&
+#endif /* DLL */
+/* %%PXE end */
 	    (*expr) -> op != expr_funcall) {
 		parse_warn (cfile, "Expecting a numeric expression.");
 		*lose = 1;
@@ -2753,6 +2811,11 @@
 
 	if (!is_dns_expression (*expr) &&
 	    (*expr) -> op != expr_variable_reference &&
+/* %%PXE begin */
+#ifdef DLL
+		(*expr)->op != expr_dll &&
+#endif /* DLL */
+/* %%PXE end */
 	    (*expr) -> op != expr_funcall) {
 		parse_warn (cfile, "Expecting a dns update subexpression.");
 		*lose = 1;
@@ -3819,6 +3882,164 @@
 		if (token != RPAREN)
 			goto norparen;
 		break;
+
+/* %%PXE begin */
+		case PROXY:
+	      		token = next_token(&val, (unsigned *)0, cfile);
+			if (!expression_allocate(expr, MDL)) {
+				log_fatal("can't allocate expression");
+			}
+
+			(*expr)->op = expr_proxy;
+			break;
+
+		case BOOTSERVER:
+	      		token = next_token(&val, (unsigned *)0, cfile);
+			if (!expression_allocate(expr, MDL)) {
+				log_fatal("can't allocate expression");
+			}
+
+			(*expr)->op = expr_bootserver;
+			break;
+
+#ifdef DLL
+		case TOKEN_DLL:
+			/* Skip 'dll' token. */
+			token = next_token(&val, (unsigned *)0, cfile);
+
+			/* Allocate expression storage. */
+			if (!expression_allocate(expr, MDL)) {
+				log_fatal("can't allocate expression");
+			}
+
+			(*expr)->op = expr_dll;
+
+			/* Need left parenthesis. */
+			if ((token = next_token(&val, (unsigned *)0, cfile))
!= LPAREN) {
+				parse_warn(cfile, "expecting left
parenthesis.");
+				*lose = 1;
+
+				skip_to_semi(cfile);
+				expression_dereference(expr, MDL);
+				return 0;
+			}
+
+			/* Need DLL library name. */
+			if ((token = next_token(&val, (unsigned *)0, cfile))
!= STRING) {
+				parse_warn(cfile, "expecting DLL library
name.");
+				*lose = 1;
+
+				skip_to_semi(cfile);
+				expression_dereference(expr, MDL);
+				return 0;
+			}
+
+			if (!((*expr)->data.dll.libname +				dmalloc(strlen(val) + 1, MDL)))
+			{
+				log_fatal("cannot allocate DLL library
name");
+			}
+
+			strcpy((*expr)->data.dll.libname, val);
+
+			/* Open DLL library. */
+			(*expr)->data.dll.libhnd +				dlopen((*expr)->data.dll.libname, RTLD_NOW);
+
+			if (val = dlerror()) {
+				parse_warn(cfile, val);
+				*lose = 1;
+
+				skip_to_semi(cfile);
+				expression_dereference(expr, MDL);
+				return 0;
+			}
+
+			/* Need comma. */
+			if ((token = next_token(&val, (unsigned *)0, cfile))
!= COMMA) {
+				parse_warn(cfile, "expecting comma.");
+				*lose = 1;
+
+				skip_to_semi(cfile);
+				expression_dereference(expr, MDL);
+				return 0;
+			}
+
+			/* Need DLL function name. */
+			if ((token = next_token(&val, (unsigned *)0, cfile))
!= STRING) {
+				parse_warn(cfile, "expecting DLL function
name.");
+				*lose = 1;
+
+				skip_to_semi(cfile);
+				expression_dereference(expr, MDL);
+				return 0;
+			}
+
+			if (!((*expr)->data.dll.funcname +				dmalloc(strlen(val) + 1, MDL)))
+			{
+				log_fatal("cannot allocate DLL function
name");
+			}
+
+			strcpy((*expr)->data.dll.funcname, val);
+
+			/* Load DLL function. */
+			(*expr)->data.dll.funcptr +				dlsym((*expr)->data.dll.libhnd,
+					(*expr)->data.dll.funcname);
+
+			if (val = dlerror()) {
+				parse_warn(cfile, val);
+				*lose = 1;
+
+				skip_to_semi(cfile);
+				expression_dereference(expr, MDL);
+				return 0;
+			}
+
+			/* Parse function call parameters. */
+			(*expr)->data.dll.argcnt = 0;
+			ep = &(*expr)->data.dll.arglist;
+
+			while ((token = next_token(&val, (unsigned *)0,
cfile)) = COMMA) {
+				if (!expression_allocate(ep, MDL)) {
+					log_fatal("cannot allocate
expression");
+				}
+
+				(*ep)->op = expr_arg;
+
+				if (!parse_expression(&(*ep)->data.arg.val,
+					cfile, lose, context_any,
+					(struct expression **)0, expr_none))
+				{
+					if (!*lose) {
+						parse_warn(cfile, "expecting
expression.");
+						*lose = 1;
+					}
+
+					skip_to_semi(cfile);
+					expression_dereference(ep, MDL);
+					return 0;
+				}
+
+				++(*expr)->data.dll.argcnt;
+
+				ep = &((*ep)->data.arg.next);
+			}
+
+			/* Need right parenthesis. */
+			if (token != RPAREN) {
+				parse_warn(cfile, "expecting right
parenthesis.");
+				*lose = 1;
+
+				skip_to_semi(cfile);
+				expression_dereference(expr, MDL);
+				return 0;
+			}
+
+			break;
+#endif /* DLL */
+/* %%PXE end */
 
 		/* Not a valid start to an expression... */
 	      default:
diff -ruN ../dhcp-3.0/common/print.c ./common/print.c
--- ../dhcp-3.0/common/print.c	Wed Aug  8 07:49:20 2001
+++ ./common/print.c	Fri Oct  5 10:16:41 2001
@@ -1001,6 +1001,17 @@
 			buf [rv++] = 0;
 			return rv;
 		}
+/* %%PXE begin */
+			break;
+
+		case expr_proxy:
+			s = "proxy";
+			break;
+
+		case expr_bootserver:
+			s = "bootserver";
+			break;
+/* %%PXE end */
 	}
 	return 0;
 }
diff -ruN ../dhcp-3.0/common/socket.c ./common/socket.c
--- ../dhcp-3.0/common/socket.c	Fri Sep 29 18:24:55 2000
+++ ./common/socket.c	Fri Oct  5 10:16:41 2001
@@ -151,13 +151,73 @@
 
 #if defined (HAVE_SO_BINDTODEVICE)
 	/* Bind this socket to this interface. */
-	if (info -> ifp &&
-	    setsockopt (sock, SOL_SOCKET, SO_BINDTODEVICE,
-			(char *)(info -> ifp), sizeof *(info -> ifp)) < 0) {
-		log_fatal ("setsockopt: SO_BINDTODEVICE: %m");
+	if (info->ifp) {
+		if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE,
+			(char *)(info->ifp), sizeof *(info->ifp)) < 0)
+		{
+			log_fatal("setsockopt: SO_BINDTODEVICE: %m");
+		}
 	}
 #endif
 
+/* %%PXE begin */
+	if (info->bootserver) {
+		struct ip_mreq ipmreq;
+
+		name.sin_port = htons(4011);
+
+		info->pxe_rfdesc = info->pxe_wfdesc +			socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+
+		if (info->pxe_rfdesc < 0) {
+			log_fatal("Cannot create PXE socket: %m");
+		}
+
+		flag = 1;
+
+		if (setsockopt(info->pxe_rfdesc, SOL_SOCKET, SO_REUSEADDR,
+			(char *)&flag, sizeof flag) < 0)
+		{
+			log_fatal("Cannot set SO_REUSEADDR option on PXE
socket: %m");
+		}
+
+		if (bind(info->pxe_rfdesc, (struct sockaddr *)&name,
+			sizeof name) < 0)
+		{
+			log_fatal("Can't bind to PXE address: %m");
+		}
+
+		if (mcast_discovery_addr.len) {
+			memcpy(&ipmreq.imr_multiaddr,
+				mcast_discovery_addr.iabuf,
+				sizeof ipmreq.imr_multiaddr);
+
+			memcpy(&ipmreq.imr_interface,
+				&info->primary_address,
+				sizeof ipmreq.imr_interface);
+
+			if (setsockopt(info->pxe_rfdesc, IPPROTO_IP,
+				IP_ADD_MEMBERSHIP, (char *)&ipmreq,
+				sizeof ipmreq) < 0)
+			{
+				log_error("Cannot join multicast session:
%m");
+			}
+		}
+
+#if defined (HAVE_SO_BINDTODEVICE)
+	/* Bind this socket to this interface. */
+	if (info->ifp) {
+		if (setsockopt(info->pxe_rfdesc, SOL_SOCKET,
SO_BINDTODEVICE,
+			(char *)(info->ifp), sizeof *(info->ifp)) < 0)
+		{
+			log_fatal("setsockopt: SO_BINDTODEVICE: pxe %m");
+		}
+	}
+#endif
+
+	}
+/* %%PXE end */
+
 	return sock;
 }
 #endif /* USE_SOCKET_SEND || USE_SOCKET_RECEIVE || USE_SOCKET_FALLBACK */
@@ -248,8 +308,31 @@
 	int retry = 0;
 	do {
 #endif
+/* %%PXE begin */
+#if 0
 		result = sendto (interface -> wfdesc, (char *)raw, len, 0,
 				 (struct sockaddr *)to, sizeof *to);
+#else
+		if (to->sin_port = htons((short)4011) &&
+			interface->pxe_wfdesc != -1)
+		{
+			result = sendto(interface->pxe_wfdesc,
+					(char *)raw,
+					len,
+					0,
+					(struct sockaddr *)to,
+					sizeof *to);
+		} else {
+			result = sendto(interface->wfdesc,
+					(char *)raw,
+					len,
+					0,
+					(struct sockaddr *)to,
+					sizeof *to);
+		}
+#endif
+/* %%PXE end */
+
 #ifdef IGNORE_HOSTUNREACH
 	} while (to -> sin_addr.s_addr = htonl (INADDR_BROADCAST) &&
 		 result < 0 &&
@@ -268,7 +351,15 @@
 #endif /* USE_SOCKET_SEND || USE_SOCKET_FALLBACK */
 
 #ifdef USE_SOCKET_RECEIVE
+/* %%PXE begin */
+#if 0
 ssize_t receive_packet (interface, buf, len, from, hfrom)
+#else
+ssize_t
+receive_packet(interface, buf, len, from, to, hfrom)
+	struct sockaddr_in *to;
+#endif
+/* %%PXE end */
 	struct interface_info *interface;
 	unsigned char *buf;
 	size_t len;
@@ -284,6 +375,17 @@
 #endif
 		result = recvfrom (interface -> rfdesc, (char *)buf, len, 0,
 				   (struct sockaddr *)from, &flen);
+
+/* %%PXE begin */
+		if (to) {
+			if (interface->rfdesc != interface->pxe_rfdesc) {
+				to->sin_port = local_port;
+			} else {
+				to->sin_port = htons(4011);
+			}
+		}
+/* %%PXE end */
+
 #ifdef IGNORE_HOSTUNREACH
 	} while (result < 0 &&
 		 (errno = EHOSTUNREACH ||
@@ -350,14 +452,29 @@
 /* If we have SO_BINDTODEVICE, set up a fallback interface; otherwise,
    do not. */
 
+/* %%PXE begin */
+#if 0
 void maybe_setup_fallback ()
+#else
+void
+maybe_setup_fallback(int bootserver)
+#endif
+/* %%PXE end */
 {
 #if defined (USE_SOCKET_FALLBACK)
 	isc_result_t status;
 	struct interface_info *fbi = (struct interface_info *)0;
+
+/* %%PXE begin */
+#if 0
 	if (setup_fallback (&fbi, MDL)) {
+#else
+	if (setup_fallback(&fbi, MDL, bootserver)) {
+#endif
+/* %%PXE end */
 		fbi -> wfdesc = if_register_socket (fbi);
 		fbi -> rfdesc = fbi -> wfdesc;
+
 		log_info ("Sending on   Socket/%s%s%s",
 		      fbi -> name,
 		      (fbi -> shared_network ? "/" : ""),
@@ -370,6 +487,7 @@
 		if (status != ISC_R_SUCCESS)
 			log_fatal ("Can't register I/O handle for %s: %s",
 				   fbi -> name, isc_result_totext (status));
+
 		interface_dereference (&fbi, MDL);
 	}
 #endif
diff -ruN ../dhcp-3.0/common/tables.c ./common/tables.c
--- ../dhcp-3.0/common/tables.c	Thu Jun 21 16:50:51 2001
+++ ./common/tables.c	Fri Oct  5 10:16:41 2001
@@ -1180,6 +1180,9 @@
 				 dhcp_options [i].name, 0,
 				 &dhcp_options [i], MDL);
 	}
+/* %%PXE begin */
+	dhcp_universe.is_vendor = 0;
+/* %%PXE end */
 
 	/* Set up the Novell option universe (for option 63)... */
 	nwip_universe.name = "nwip";
@@ -1207,6 +1210,9 @@
 				 nwip_options [i].name, 0,
 				 &nwip_options [i], MDL);
 	}
+/* %%PXE begin */
+	nwip_universe.is_vendor = 0;
+/* %%PXE end */
 
 	/* Set up the FQDN option universe... */
 	fqdn_universe.name = "fqdn";
@@ -1234,6 +1240,9 @@
 				 fqdn_options [i].name, 0,
 				 &fqdn_options [i], MDL);
 	}
+/* %%PXE begin */
+	fqdn_universe.is_vendor = 0;
+/* %%PXE end */
 
 	/* Set up the hash of universes. */
 	universe_hash = new_hash (0, 0, 1, MDL);
diff -ruN ../dhcp-3.0/common/tree.c ./common/tree.c
--- ../dhcp-3.0/common/tree.c	Thu Oct  4 13:38:22 2001
+++ ./common/tree.c	Fri Oct  5 10:26:23 2001
@@ -444,8 +444,9 @@
 	bv = (struct binding_value *)0;
 
 	if (expr -> op = expr_variable_reference) {
-		if (!scope || !*scope)
+		if (!scope || !*scope) {
 			return 0;
+		}
 
 		binding = find_binding (*scope, expr -> data.variable);
 
@@ -455,8 +456,9 @@
 							 binding -> value,
 							 file, line);
 			return 1;
-		} else
+		} else {
 			return 0;
+		}
 	} else if (expr -> op = expr_funcall) {
 		struct string_list *s;
 		struct expression *arg;
@@ -544,6 +546,211 @@
 
 		if (!bv)
 			return 1;
+/* %%PXE begin */
+#ifdef DLL
+	} else if (expr->op = expr_dll) {
+		struct dll_value **arglist;
+		struct dll_value *rval;
+
+		if (!expr->data.dll.libhnd) {
+			log_error("%s: DLL library handle is NULL.",
+				expr->data.dll.libname);
+
+			return 0;
+		}
+
+		if (!expr->data.dll.funcptr) {
+			log_error("%s:%s: DLL function pointer is NULL.",
+				expr->data.dll.libname,
+				expr->data.dll.funcname);
+
+			return 0;
+		}
+
+		if (expr->data.dll.argcnt) {
+			struct expression *e;
+			unsigned n;
+
+			if (!(arglist = dmalloc(expr->data.dll.argcnt *
+				sizeof(struct dll_value *), MDL)))
+			{
+				log_error("%s:%s: Cannot allocate argument
list.",
+					expr->data.dll.libname,
+					expr->data.dll.funcname);
+
+				return 0;
+			}
+
+		/* %%TBD - evaluate arglist */
+			e = expr->data.dll.arglist;
+
+			for (n = 0; n < expr->data.dll.argcnt; ++n) {
+				struct binding_value *b = 0;
+
+				if (!(status = evaluate_expression(&b,
packet,
+					lease, client_state, in_options,
+					cfg_options, scope, e->data.arg.val,
+					file, line)))
+				{
+					log_error("%s:%s: Cannot evaluate
argument %u.",
+						expr->data.dll.libname,
+						expr->data.dll.funcname,
+						n + 1);
+
+					break;
+				}
+
+				switch (b->type) {
+				case binding_boolean:
+					if (!(arglist[n] dmalloc(sizeof(struct dll_value), MDL))) {
+						log_error("%s:%s: Cannot
allocate argument %u.",
+
expr->data.dll.libname,
+
expr->data.dll.funcname,
+							n + 1);
+
+						status = 0;
+						break;
+					}
+
+					arglist[n]->type = dll_type_boolean;
+
+					arglist[n]->value.boolean +						b->value.boolean ? 1 : 0;
+
+					break;
+
+				case binding_numeric:
+					if (!(arglist[n] dmalloc(sizeof(struct dll_value), MDL))) {
+						log_error("%s:%s: Cannot
allocate argument %u.",
+
expr->data.dll.libname,
+
expr->data.dll.funcname,
+							n + 1);
+
+						status = 0;
+						break;
+					}
+
+					arglist[n]->type = dll_type_numeric;
+
+					arglist[n]->value.numeric +						b->value.intval;
+
+					break;
+
+				case binding_data:
+					if (!(arglist[n] dmalloc(sizeof(struct dll_value) + b->value.data.len, MDL))) {
+						log_error("%s:%s: Cannot
allocate argument %u.",
+
expr->data.dll.libname,
+
expr->data.dll.funcname,
+							n + 1);
+
+						status = 0;
+						break;
+					}
+
+					arglist[n]->type = dll_type_data;
+
+					if (arglist[n]->value.data.len b->value.data.len) {
+
memcpy(arglist[n]->value.data.buf, b->value.data.data, b->value.data.len);
+					}
+
+					break;
+
+				default:
+					status = 0;
+				}
+
+				binding_value_dereference(&b, MDL);
+
+				if (!status) {
+					break;
+				}	
+
+				e = e->data.arg.next;
+			}
+		} else {
+			arglist = NULL;
+		}
+
+		if (status) {
+			rval = (expr->data.dll.funcptr)(
+				expr->data.dll.argcnt, (void *)arglist);
+		}
+
+		if (arglist) {
+			unsigned n;
+
+			for (n = 0; n < expr->data.dll.argcnt; ++n) {
+				if (arglist[n]) {
+					dfree(arglist[n], MDL);
+				}
+			}
+
+			dfree(arglist, MDL);
+		}
+
+		if (!status) {
+			return 0;
+		}
+
+		if (!rval) {
+			log_error("%s:%s: DLL function returned NULL.",
+				expr->data.dll.libname,
+				expr->data.dll.funcname);
+
+			return 0;
+		}
+
+		if (!binding_value_allocate(&bv, MDL)) {
+			return 0;
+		}
+
+		switch (rval->type) {
+		case dll_type_boolean:
+			bv->type = binding_boolean;
+			bv->value.boolean = rval->value.boolean;
+			break;
+
+		case dll_type_data:
+			bv->type = binding_data;
+			bv->value.data.len = rval->value.data.len;
+			bv->value.data.terminated = 0;
+
+			if (!buffer_allocate(&bv->value.data.buffer,
+				bv->value.data.len, MDL))
+			{
+				log_error("%s:%s: Could not allocate return
value storage",
+					expr->data.dll.libname,
+					expr->data.dll.funcname);
+
+				status = 0;
+				break;
+			}
+
+			bv->value.data.data = bv->value.data.buffer->data;
+
+			memcpy(bv->value.data.buffer->data,
+				rval->value.data.buf, bv->value.data.len);
+
+			break;
+
+		case dll_type_numeric:
+			bv->type = binding_numeric;
+			bv->value.intval = rval->value.numeric;
+			break;
+
+		default:
+			log_error("%s:%s: DLL function returned bad type:
%u",
+				expr->data.dll.libname,
+				expr->data.dll.funcname,
+				rval->type);
+
+			status = 0;
+		}
+
+		free(rval);
+#endif /* DLL */
+/* %%PXE end */
         } else if (is_boolean_expression (expr)) {
 		if (!binding_value_allocate (&bv, MDL))
 			return 0;
@@ -832,6 +1039,10 @@
 	      case expr_known:
 	      case expr_exists:
 	      case expr_variable_exists:
+/* %%PXE begin */
+		case expr_proxy:
+		case expr_bootserver:
+/* %%PXE end */
 		log_error ("Boolean opcode in evaluate_dns_expression: %d",
 		      expr -> op);
 		return 0;
@@ -1198,6 +1409,71 @@
 #endif
 		break;
 
+/* %%PXE begin */
+		case expr_proxy:
+			if (!packet) {
+#if defined (DEBUG_EXPRESSIONS)
+				log_debug("bool: NULL->proxy = FALSE");
+#endif
+				return 0;
+			}
+
+#if defined (DEBUG_EXPRESSIONS)
+			log_debug("bool: packet->proxy = %s",
+			  	packet->proxy ? "true" : "false");
+#endif
+
+			*result = packet->proxy;
+			return 1;
+
+		case expr_bootserver:
+			if (!packet) {
+#if defined (DEBUG_EXPRESSIONS)
+				log_debug("bool: NULL->bootserver = FALSE");
+#endif
+				return 0;
+			}
+
+#if defined (DEBUG_EXPRESSIONS)
+			log_debug("bool: packet->bootserver = %s",
+			  	packet->bootserver ? "true" : "false");
+#endif
+
+			*result = packet->bootserver;
+			return 1;
+
+#ifdef DLL
+		case expr_dll:
+			bv = (struct binding_value *)0;
+			sleft = evaluate_expression(&bv, packet, lease,
+				client_state, in_options, cfg_options,
+				scope, expr, MDL);
+
+			if (sleft) {
+				if (bv->type != binding_boolean) {
+					log_error("dll('%s', '%s') returned
type %d in %s.",
+						expr->data.dll.libname,
+						expr->data.dll.funcname,
+						bv->type,
+
"evaluate_boolean_expression");
+				} else {
+					*result = bv -> value.boolean;
+				}
+
+				binding_value_dereference(&bv, MDL);
+			}
+
+#if defined (DEBUG_EXPRESSIONS)
+			log_debug("boolean: dll('%s', '%s') = %s",
+				expr->data.dll.libname,
+				expr->data.dll.funcname,
+			   	sleft ? (*result ? "true" : "false") :
"NULL");
+#endif
+
+			return sleft;
+#endif /* DLL */
+/* %%PXE end */
+
 	      case expr_none:
 	      case expr_match:
 	      case expr_substring:
@@ -2083,6 +2359,10 @@
 	      case expr_none:
 	      case expr_exists:
 	      case expr_variable_exists:
+/* %%PXE begin */
+		case expr_proxy:
+		case expr_bootserver:
+/* %%PXE end */
 		log_error ("Boolean opcode in evaluate_data_expression: %d",
 		      expr -> op);
 		return 0;
@@ -2161,6 +2441,10 @@
 	      case expr_none:
 	      case expr_exists:
 	      case expr_variable_exists:
+/* %%PXE begin */
+		case expr_proxy:
+		case expr_bootserver:
+/* %%PXE end */
 		log_error ("Boolean opcode in evaluate_numeric_expression:
%d",
 		      expr -> op);
 		return 0;
@@ -2947,6 +3231,10 @@
 	      case expr_exists:
 	      case expr_known:
 	      case expr_null:
+/* %%PXE begin */
+		case expr_proxy:
+		case expr_bootserver:
+/* %%PXE end */
 		break;
 
 	      default:
@@ -2976,6 +3264,10 @@
 		expr -> op = expr_or ||
 		expr -> op = expr_not ||
 		expr -> op = expr_known ||
+/* %%PXE begin */
+		expr->op = expr_proxy ||
+		expr->op = expr_bootserver ||
+/* %%PXE end */
 		expr -> op = expr_static);
 }
 
@@ -3098,6 +3390,10 @@
 	      case expr_arg:
 	      case expr_funcall:
 	      case expr_function:
+/* %%PXE begin */
+		case expr_proxy:
+		case expr_bootserver:
+/* %%PXE end */
 		/* XXXDPN: Need to assign sane precedences to these. */
 	      case expr_binary_and:
 	      case expr_binary_or:
@@ -3192,6 +3488,10 @@
 	      case expr_arg:
 	      case expr_funcall:
 	      case expr_function:
+/* %%PXE begin */
+		case expr_proxy:
+		case expr_bootserver:
+/* %%PXE end */
 		return context_any;
 
 	      case expr_equal:
@@ -3698,6 +3998,18 @@
 		col = token_print_indent (file, col, indent, "", "", ")");
 		break;
 
+/* %%PXE begin */
+		case expr_proxy:
+			col = token_print_indent(file, col, indent, "", "",
+				"proxy");
+			break;
+
+		case expr_bootserver:
+			col = token_print_indent(file, col, indent, "", "",
+				"bootserver");
+			break;
+/* %%PXE end */
+
 	      default:
 		log_fatal ("invalid expression type in print_expression:
%d",
 			   expr -> op);
@@ -3944,6 +4256,10 @@
 	      case expr_binary_or:
 	      case expr_binary_xor:
 	      case expr_client_state:
+/* %%PXE begin */
+		case expr_proxy:
+		case expr_bootserver:
+/* %%PXE end */
 		return 0;
 	}
 	return 0;
diff -ruN ../dhcp-3.0/common/upf.c ./common/upf.c
--- ../dhcp-3.0/common/upf.c	Fri Sep  1 16:03:39 2000
+++ ./common/upf.c	Fri Oct  5 10:16:41 2001
@@ -299,7 +299,14 @@
 #endif /* USE_UPF_SEND */
 
 #ifdef USE_UPF_RECEIVE
+/* %%PXE begin */
+#if 0
 ssize_t receive_packet (interface, buf, len, from, hfrom)
+#else
+ssize_t receive_packet (interface, buf, len, from, to, hfrom)
+	struct sockaddr_in *to;
+#endif
+/* %%PXE end */
 	struct interface_info *interface;
 	unsigned char *buf;
 	size_t len;
@@ -331,8 +338,20 @@
 	length -= offset;
 
 	/* Decode the IP and UDP headers... */
+/* %%PXE begin */
+#if 0
 	offset = decode_udp_ip_header (interface, ibuf, bufix,
 				       from, (unsigned char *)0, length);
+#else
+	offset = decode_udp_ip_header(interface,
+				      ibuf,
+				      bufix,
+				      from,
+				      to,
+				      (unsigned char *)0,
+				      length);
+#endif
+/* %%PXE end */
 
 	/* If the IP or UDP checksum was bad, skip the packet... */
 	if (offset < 0)
diff -ruN ../dhcp-3.0/dhcpctl/dhcpctl.c ./dhcpctl/dhcpctl.c
--- ../dhcp-3.0/dhcpctl/dhcpctl.c	Sat May 19 00:29:20 2001
+++ ./dhcpctl/dhcpctl.c	Fri Oct  5 10:16:41 2001
@@ -47,6 +47,11 @@
 omapi_object_type_t *dhcpctl_callback_type;
 omapi_object_type_t *dhcpctl_remote_type;
 
+/* %%PXE begin */
+#include "inet.h"
+struct iaddr mcast_discovery_addr = { 0, 0 };
+/* %%PXE end */
+
 /* dhcpctl_initialize ()
 
    Must be called before any other dhcpctl function. */
diff -ruN ../dhcp-3.0/includes/ctrace.h ./includes/ctrace.h
--- ../dhcp-3.0/includes/ctrace.h	Mon Feb 12 13:21:56 2001
+++ ./includes/ctrace.h	Fri Oct  5 10:16:41 2001
@@ -50,6 +50,9 @@
 	u_int32_t index;
 	struct iaddr from;
 	u_int16_t from_port;
+/* %%PXE begin */
+	u_int16_t to_port;
+/* %%PXE end */
 	struct hardware hfrom;
 	u_int8_t havehfrom;
 } trace_inpacket_t;
diff -ruN ../dhcp-3.0/includes/dhcp.h ./includes/dhcp.h
--- ../dhcp-3.0/includes/dhcp.h	Thu Oct  4 15:02:01 2001
+++ ./includes/dhcp.h	Fri Oct  5 10:16:41 2001
@@ -158,6 +158,11 @@
 #define DHO_USER_CLASS			77
 #define DHO_FQDN			81
 #define DHO_DHCP_AGENT_OPTIONS		82
+/* %%PXE begin */
+#define DHO_PXE_CLIENT_ARCHITECTURE	93
+#define DHO_PXE_NETWORK_INTERFACE	94
+#define DHO_PXE_CLIENT_GUID		97
+/* %%PXE end */
 #define DHO_SUBNET_SELECTION		118 /* RFC3011! */
 /* The DHO_AUTHENTICATE option is not a standard yet, so I've
    allocated an option out of the "local" option space for it on a
diff -ruN ../dhcp-3.0/includes/dhcpd.h ./includes/dhcpd.h
--- ../dhcp-3.0/includes/dhcpd.h	Thu Jun 21 16:57:40 2001
+++ ./includes/dhcpd.h	Fri Oct  5 10:16:41 2001
@@ -232,6 +232,11 @@
 
 	int known;
 	int authenticated;
+/* %%PXE begin */
+	int server_port;
+	int proxy;
+	int bootserver;
+/* %%PXE end */
 };
 
 /* A network interface's MAC address. */
@@ -293,7 +298,15 @@
 	unsigned char uid_buf [7];
 	struct hardware hardware_addr;
 
+/* %%PXE begin */
+#if 0
 	u_int8_t flags;
+#else
+	u_int16_t flags;
+#	define PXE_LEASE		512
+#endif
+/* %%PXE end */
+
 #       define STATIC_LEASE		1
 #	define PERSISTENT_FLAGS		(ON_ACK_QUEUE | ON_UPDATE_QUEUE)
 #	define MS_NULL_TERMINATION	8
@@ -777,6 +790,13 @@
 
 	/* Only used by DHCP client code. */
 	struct client_state *client;
+
+/* %%PXE begin */
+	int bootserver;
+	int pxe_rfdesc;
+	int pxe_wfdesc;
+/* %%PXE end */
+
 # if defined (USE_DLPI_SEND) || defined (USE_DLPI_RECEIVE)
 	int dlpi_sap_length;
 	struct hardware dlpi_broadcast_addr;
@@ -1087,9 +1107,21 @@
 void delete_linked_option (struct universe *, struct option_state *, int);
 struct option_cache *lookup_linked_option (struct universe *,
 					   struct option_state *, unsigned);
+/* %%PXE begin */
+#if 0
 void do_packet PROTO ((struct interface_info *,
 		       struct dhcp_packet *, unsigned,
 		       unsigned int, struct iaddr, struct hardware *));
+#else
+void do_packet PROTO ((struct interface_info *,
+		       struct dhcp_packet *,
+		       unsigned,
+		       unsigned int,
+		       unsigned int,
+		       struct iaddr,
+		       struct hardware *));
+#endif
+/* %%PXE end */
 
 /* dhcpd.c */
 extern TIME cur_time;
@@ -1114,6 +1146,12 @@
 isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
 				     control_object_state_t newstate);
 
+/* %%PXE begin */
+extern int dhcpd_operation;
+extern int bootserver_operation;
+extern struct iaddr mcast_discovery_addr;
+/* %%PXE end */
+
 /* conflex.c */
 isc_result_t new_parse PROTO ((struct parse **, int,
 			       char *, unsigned, const char *, int));
@@ -1550,9 +1588,22 @@
 void if_reinitialize_receive PROTO ((struct interface_info *));
 void if_register_receive PROTO ((struct interface_info *));
 void if_deregister_receive PROTO ((struct interface_info *));
+
+/* %%PXE begin */
+#if 0
 ssize_t receive_packet PROTO ((struct interface_info *,
 			       unsigned char *, size_t,
 			       struct sockaddr_in *, struct hardware *));
+#else
+ssize_t receive_packet PROTO ((struct interface_info *,
+			       unsigned char *,
+			       size_t,
+			       struct sockaddr_in *,
+			       struct sockaddr_in *,
+			       struct hardware *));
+#endif
+/* %%PXE end */
+
 #endif
 
 #if defined (USE_SOCKET_FALLBACK)
@@ -1563,7 +1614,13 @@
 int can_unicast_without_arp PROTO ((struct interface_info *));
 int can_receive_unicast_unconfigured PROTO ((struct interface_info *));
 int supports_multiple_interfaces (struct interface_info *);
+/* %%PXE begin */
+#if 0
 void maybe_setup_fallback PROTO ((void));
+#else
+void maybe_setup_fallback PROTO ((int));
+#endif
+/* %%PXE end */
 #endif
 
 /* bpf.c */
@@ -1583,15 +1640,34 @@
 void if_reinitialize_receive PROTO ((struct interface_info *));
 void if_register_receive PROTO ((struct interface_info *));
 void if_deregister_receive PROTO ((struct interface_info *));
+
+/* %%PXE begin */
+#if 0
 ssize_t receive_packet PROTO ((struct interface_info *,
 			       unsigned char *, size_t,
 			       struct sockaddr_in *, struct hardware *));
+#else
+ssize_t receive_packet PROTO ((struct interface_info *,
+			       unsigned char *,
+			       size_t,
+			       struct sockaddr_in *,
+			       struct sockaddr_in *,
+			       struct hardware *));
+#endif
+/* %%PXE end */
+
 #endif
 #if defined (USE_BPF_SEND)
 int can_unicast_without_arp PROTO ((struct interface_info *));
 int can_receive_unicast_unconfigured PROTO ((struct interface_info *));
 int supports_multiple_interfaces (struct interface_info *);
+/* %%PXE begin */
+#if 0
 void maybe_setup_fallback PROTO ((void));
+#else
+void maybe_setup_fallback PROTO ((int));
+#endif
+/* %%PXE end */
 #endif
 
 /* lpf.c */
@@ -1611,15 +1687,34 @@
 void if_reinitialize_receive PROTO ((struct interface_info *));
 void if_register_receive PROTO ((struct interface_info *));
 void if_deregister_receive PROTO ((struct interface_info *));
+
+/* %%PXE begin */
+#if 0
 ssize_t receive_packet PROTO ((struct interface_info *,
 			       unsigned char *, size_t,
 			       struct sockaddr_in *, struct hardware *));
+#else
+ssize_t receive_packet PROTO ((struct interface_info *,
+			       unsigned char *,
+			       size_t,
+			       struct sockaddr_in *,
+			       struct sockaddr_in *,
+			       struct hardware *));
+#endif
+/* %%PXE end */
+
 #endif
 #if defined (USE_LPF_SEND)
 int can_unicast_without_arp PROTO ((struct interface_info *));
 int can_receive_unicast_unconfigured PROTO ((struct interface_info *));
 int supports_multiple_interfaces (struct interface_info *);
+/* %%PXE begin */
+#if 0
 void maybe_setup_fallback PROTO ((void));
+#else
+void maybe_setup_fallback PROTO ((int));
+#endif
+/* %%PXE end */
 #endif
 
 /* nit.c */
@@ -1640,15 +1735,34 @@
 void if_reinitialize_receive PROTO ((struct interface_info *));
 void if_register_receive PROTO ((struct interface_info *));
 void if_deregister_receive PROTO ((struct interface_info *));
+
+/* %%PXE begin */
+#if 0
 ssize_t receive_packet PROTO ((struct interface_info *,
 			       unsigned char *, size_t,
 			       struct sockaddr_in *, struct hardware *));
+#else
+ssize_t receive_packet PROTO ((struct interface_info *,
+			       unsigned char *,
+			       size_t,
+			       struct sockaddr_in *,
+			       struct sockaddr_in *,
+			       struct hardware *));
+#endif
+/* %%PXE end */
+
 #endif
 #if defined (USE_NIT_SEND)
 int can_unicast_without_arp PROTO ((struct interface_info *));
 int can_receive_unicast_unconfigured PROTO ((struct interface_info *));
 int supports_multiple_interfaces (struct interface_info *);
+/* %%PXE begin */
+#if 0
 void maybe_setup_fallback PROTO ((void));
+#else
+void maybe_setup_fallback PROTO ((int));
+#endif
+/* %%PXE end */
 #endif
 
 /* dlpi.c */
@@ -1669,9 +1783,22 @@
 void if_reinitialize_receive PROTO ((struct interface_info *));
 void if_register_receive PROTO ((struct interface_info *));
 void if_deregister_receive PROTO ((struct interface_info *));
+
+/* %%PXE begin */
+#if 0
 ssize_t receive_packet PROTO ((struct interface_info *,
 			       unsigned char *, size_t,
 			       struct sockaddr_in *, struct hardware *));
+#else
+ssize_t receive_packet PROTO ((struct interface_info *,
+			       unsigned char *,
+			       size_t,
+			       struct sockaddr_in *,
+			       struct sockaddr_in *,
+			       struct hardware *));
+#endif
+/* %%PXE end */
+
 #endif
 
 
@@ -1687,7 +1814,13 @@
 int can_unicast_without_arp PROTO ((struct interface_info *));
 int can_receive_unicast_unconfigured PROTO ((struct interface_info *));
 int supports_multiple_interfaces (struct interface_info *);
+/* %%PXE begin */
+#if 0
 void maybe_setup_fallback PROTO ((void));
+#else
+void maybe_setup_fallback PROTO ((int));
+#endif
+/* %%PXE end */
 #endif
 
 /* discover.c */
@@ -1708,10 +1841,22 @@
 extern int (*dhcp_interface_discovery_hook) (struct interface_info *);
 isc_result_t (*dhcp_interface_startup_hook) (struct interface_info *);
 
+/* %%PXE begin */
+#if 0
 extern void (*bootp_packet_handler) PROTO ((struct interface_info *,
 					    struct dhcp_packet *, unsigned,
 					    unsigned int,
 					    struct iaddr, struct hardware
*));
+#else
+extern void (*bootp_packet_handler) PROTO ((struct interface_info *,
+					    struct dhcp_packet *,
+					    unsigned,
+					    unsigned int,
+					    unsigned int,
+					    struct iaddr,
+					    struct hardware *));
+#endif
+/* %%PXE end */
 extern struct timeout *timeouts;
 extern omapi_object_type_t *dhcp_type_interface;
 #if defined (TRACING)
@@ -1723,8 +1868,15 @@
 extern int interface_count;
 extern int interface_max;
 isc_result_t interface_initialize (omapi_object_t *, const char *, int);
+/* %%PXE begin */
+#if 0
 void discover_interfaces PROTO ((int));
 int setup_fallback (struct interface_info **, const char *, int);
+#else
+void discover_interfaces PROTO ((int, int));
+int setup_fallback (struct interface_info **, const char *, int, int);
+#endif
+/* %%PXE end */
 int if_readsocket PROTO ((omapi_object_t *));
 void reinitialize_interfaces PROTO ((void));
 
@@ -1904,9 +2056,22 @@
 				    u_int32_t, unsigned char *, unsigned));
 ssize_t decode_hw_header PROTO ((struct interface_info *, unsigned char *,
 				 unsigned, struct hardware *));
+
+/* %%PXE begin */
+#if 0
 ssize_t decode_udp_ip_header PROTO ((struct interface_info *, unsigned char
*,
 				     unsigned, struct sockaddr_in *,
 				     unsigned char *, unsigned));
+#else
+ssize_t decode_udp_ip_header PROTO ((struct interface_info *,
+				     unsigned char *,
+				     unsigned,
+				     struct sockaddr_in *,
+				     struct sockaddr_in *,
+				     unsigned char *,
+				     unsigned));
+#endif
+/* %%PXE end */
 
 /* ethernet.c */
 void assemble_ethernet_header PROTO ((struct interface_info *, unsigned
char *,
@@ -1986,8 +2151,22 @@
 void parse_reject_statement PROTO ((struct parse *, struct client_config
*));
 
 /* dhcrelay.c */
+
+/* %%PXE begin */
+#if 0
 void relay PROTO ((struct interface_info *, struct dhcp_packet *, unsigned,
 		   unsigned int, struct iaddr, struct hardware *));
+#else
+void relay PROTO ((struct interface_info *,
+		   struct dhcp_packet *,
+		   unsigned,
+		   unsigned int,
+		   unsigned int,
+		   struct iaddr,
+		   struct hardware *));
+#endif
+/* %%PXE end */
+
 int strip_relay_agent_options PROTO ((struct interface_info *,
 				      struct interface_info **,
 				      struct dhcp_packet *, unsigned));
diff -ruN ../dhcp-3.0/includes/dhctoken.h ./includes/dhctoken.h
--- ../dhcp-3.0/includes/dhctoken.h	Mon Jun  4 14:18:40 2001
+++ ./includes/dhctoken.h	Fri Oct  5 10:16:41 2001
@@ -316,6 +316,16 @@
 	REMOVE = 611,
 	REFRESH = 612,
 	DOMAIN_NAME = 613
+/* %%PXE begin */
+	,
+	DHCPD_OPERATION,
+	BOOTSERVER_OPERATION,
+	PROXY,
+	DISABLE,
+	BOOTSERVER,
+	MCAST_DISCOVERY_ADDR,
+	TOKEN_DLL,
+/* %%PXE end */
 };
 
 #define is_identifier(x)	((x) >= FIRST_TOKEN &&	\
diff -ruN ../dhcp-3.0/includes/dll.h ./includes/dll.h
--- ../dhcp-3.0/includes/dll.h	Wed Dec 31 16:00:00 1969
+++ ./includes/dll.h	Fri Oct  5 10:16:41 2001
@@ -0,0 +1,36 @@
+/* %%PXE begin */
+
+struct dll_value {
+	enum {
+		dll_type_unused = 0,
+		dll_type_boolean,
+		dll_type_data,
+		dll_type_numeric,
+		dll_type_last
+	} type;
+
+	union {
+		struct {
+			unsigned len;
+			char buf[1];
+		} data;
+		unsigned long numeric;
+		int boolean;
+	} value;
+};
+
+/*
+ * DLL library functions must be defined thusly:
+ *	struct dll_value *funcname(const unsigned argcnt, const struct
dll_value *arglist[])
+ *
+ * The DLL library functions must allocate the return value storage
+ * using the C library malloc() call.  A return value of NULL will
+ * be treated as an error.
+ *
+ * After consuming the result data the DHCP daemon will release
+ * the return value storage using the C library free() call.
+ *
+ * argcnt will be set to the number of arguments in the argument list.
+ * If there are no arguments, argcnt will be zero and arglist will be NULL.
+ */
+/* %%PXE end */
diff -ruN ../dhcp-3.0/includes/tree.h ./includes/tree.h
--- ../dhcp-3.0/includes/tree.h	Thu Jan 25 00:26:04 2001
+++ ./includes/tree.h	Fri Oct  5 10:16:41 2001
@@ -41,6 +41,12 @@
  * ``http://www.nominum.com''.
  */
 
+/* %%PXE begin */
+#ifdef DLL
+# include "dll.h"
+#endif /* DLL */
+/* %%PXE end */
+
 /* A pair of pointers, suitable for making a linked list. */
 typedef struct _pair {
 	caddr_t car;
@@ -99,7 +105,7 @@
 	context_numeric,
 	context_dns,
 	context_data_or_numeric, /* indefinite */
-	context_function
+	context_function,
 };
 
 struct fundef {
@@ -115,7 +121,7 @@
 		binding_data,
 		binding_numeric,
 		binding_dns,
-		binding_function
+		binding_function,
 	} type;
 	union value {
 		struct data_string data;
@@ -199,7 +205,14 @@
 	expr_binary_and,
 	expr_binary_or,
 	expr_binary_xor,
-	expr_client_state
+	expr_client_state,
+/* %%PXE begin */
+	expr_proxy,
+	expr_bootserver,
+#ifdef DLL
+	expr_dll,
+#endif /* DLL */
+/* %%PXE end */
 };
 
 struct expression {
@@ -280,6 +293,18 @@
 			struct expression *arglist;
 		} funcall;
 		struct fundef *func;
+/* %%PXE begin */
+#ifdef DLL
+		struct {
+			char *libname;
+			void *libhnd;
+			char *funcname;
+			struct dll_value *(*funcptr)(const unsigned argcnt,
const struct dll_value *arglist[]);
+			unsigned argcnt;
+			struct expression *arglist;
+		} dll;
+#endif /* DLL */
+/* %%PXE end */
 	} data;
 	int flags;
 #	define EXPR_EPHEMERAL	1
@@ -336,6 +361,9 @@
 	struct option *options [256];
 	struct option *enc_opt;
 	int index;
+/* %%PXE begin */
+	int is_vendor;
+/* %%PXE end */
 };
 
 struct option {
diff -ruN ../dhcp-3.0/includes/version.h ./includes/version.h
--- ../dhcp-3.0/includes/version.h	Thu Oct  4 20:58:38 2001
+++ ./includes/version.h	Fri Oct  5 10:17:53 2001
@@ -1,3 +1,3 @@
 /* Current version of ISC DHCP Distribution. */
 
-#define DHCP_VERSION	"V3.0"
+#define DHCP_VERSION	"V3.0pxe1"
diff -ruN ../dhcp-3.0/omapip/dispatch.c ./omapip/dispatch.c
--- ../dhcp-3.0/omapip/dispatch.c	Thu May 31 12:45:55 2001
+++ ./omapip/dispatch.c	Fri Oct  5 10:16:41 2001
@@ -78,8 +78,9 @@
 		
 	obj = (omapi_io_object_t *)0;
 	status = omapi_io_allocate (&obj, MDL);
-	if (status != ISC_R_SUCCESS)
+	if (status != ISC_R_SUCCESS) {
 		return status;
+	}
 
 	status = omapi_object_reference (&obj -> inner, h, MDL);
 	if (status != ISC_R_SUCCESS) {
@@ -414,9 +415,10 @@
 		   see if we got input on that socket. */
 		if (io -> readfd &&
 		    (desc = (*(io -> readfd)) (tmp)) >= 0) {
-			if (FD_ISSET (desc, &r))
+			if (FD_ISSET (desc, &r)) {
 				status = ((*(io -> reader)) (tmp));
 				/* XXX what to do with status? */
+			}
 		}
 		
 		/* Same deal for write descriptors. */
diff -ruN ../dhcp-3.0/relay/dhcrelay.c ./relay/dhcrelay.c
--- ../dhcp-3.0/relay/dhcrelay.c	Thu Apr 19 09:48:53 2001
+++ ./relay/dhcrelay.c	Fri Oct  5 10:16:41 2001
@@ -112,6 +112,12 @@
 static char message [] = "Internet Software Consortium DHCP Relay Agent";
 static char url [] = "For info, please visit
http://www.isc.org/products/DHCP";
 
+/* %%PXE begin */
+int dhcpd_operation = NORMAL;
+int bootserver_operation = 0;
+struct iaddr mcast_discovery_addr = { 0, 0 };
+/* %%PXE end */
+
 int main (argc, argv, envp)
 	int argc;
 	char **argv, **envp;
@@ -277,7 +283,13 @@
 	GET_TIME (&cur_time);
 
 	/* Discover all the network interfaces. */
+/* %%PXE begin */
+#if 0
 	discover_interfaces (DISCOVER_RELAY);
+#else
+	discover_interfaces(DISCOVER_RELAY, 0);
+#endif
+/* %%PXE end */
 
 	/* Set up the bootp packet handler... */
 	bootp_packet_handler = relay;
@@ -324,7 +336,14 @@
 	return 0;
 }
 
+/* %%PXE begin */
+#if 0
 void relay (ip, packet, length, from_port, from, hfrom)
+#else
+void relay (ip, packet, length, from_port, to_port, from, hfrom)
+	unsigned int to_port;
+#endif
+/* %%PXE end */
 	struct interface_info *ip;
 	struct dhcp_packet *packet;
 	unsigned length;
diff -ruN ../dhcp-3.0/server/Makefile.dist ./server/Makefile.dist
--- ../dhcp-3.0/server/Makefile.dist	Wed Mar 14 07:34:06 2001
+++ ./server/Makefile.dist	Fri Oct  5 10:16:41 2001
@@ -17,14 +17,19 @@
 # http://www.isc.org for more information.
 #
 
-CATMANPAGES = dhcpd.cat8 dhcpd.conf.cat5 dhcpd.leases.cat5
-SEDMANPAGES = dhcpd.man8 dhcpd.conf.man5 dhcpd.leases.man5
+# CATMANPAGES = dhcpd.cat8 dhcpd.conf.cat5 dhcpd.leases.cat5
+# SEDMANPAGES = dhcpd.man8 dhcpd.conf.man5 dhcpd.leases.man5
+CATMANPAGES = dhcpd.cat8 dhcpd.conf.cat5 dhcpd.leases.cat5 dhcpd.pxe.cat5
+SEDMANPAGES = dhcpd.man8 dhcpd.conf.man5 dhcpd.leases.man5 dhcpd.pxe.man5
+
 SRCS   = dhcpd.c dhcp.c bootp.c confpars.c db.c class.c failover.c \
 	 omapi.c mdb.c stables.c salloc.c ddns.c
 OBJS   = dhcpd.o dhcp.o bootp.o confpars.o db.o class.o failover.o \
 	 omapi.o mdb.o stables.o salloc.o ddns.o
 PROG   = dhcpd
-MAN    = dhcpd.8 dhcpd.conf.5 dhcpd.leases.5
+
+# MAN    = dhcpd.8 dhcpd.conf.5 dhcpd.leases.5
+MAN    = dhcpd.8 dhcpd.conf.5 dhcpd.leases.5 dhcpd.pxe.5
 
 INCLUDES = -I$(TOP) $(BINDINC) -I$(TOP)/includes
 DHCPLIB = ../common/libdhcp.a $(BINDLIB) ../omapip/libomapi.a
../dst/libdst.a
@@ -51,6 +56,8 @@
 			$(DESTDIR)$(FFMANDIR)/dhcpd.conf$(FFMANEXT)
 	$(MANINSTALL) $(MANFROM) dhcpd.leases.$(MANCAT)5 $(MANTO) \
 			$(DESTDIR)$(FFMANDIR)/dhcpd.leases$(FFMANEXT)
+	$(MANINSTALL) $(MANFRMO) dhcpd.leases.$(MANCAT)5 $(MANTO) \
+			$(DESTDIR)$(FFMANDIR).dhcpd.pxe$(FFMANEXT)
 
 depend:
 	$(MKDEP) $(INCLUDES) $(PREDEFINES) $(SRCS)
@@ -96,6 +103,13 @@
 dhcpd.leases.man5:	dhcpd.leases.5
 	sed -e "s#ETCDIR#$(ETC)#g" -e "s#DBDIR#$(VARDB)#g" \
 		-e "s#RUNDIR#$(VARRUN)#g" < dhcpd.leases.5
>dhcpd.leases.man5
+
+dhcpd.pxe.cat5:	dhcpd.pxe.man5
+	nroff -man dhcpd.pxe.man5 >dhcpd.pxe.cat5
+
+dhcpd.pxe.man5:	dhcpd.pxe.5
+	sed -e "s#ETCDIR#$(ETC)#g" -e "s#DBDIR#$(VARDB)#g" \
+		-e "s#RUNDIR#$(VARRUN)#g" < dhcpd.pxe.5 >dhcpd.pxe.man5
 
 dhcpd:	$(OBJS) $(COBJ) $(DHCPLIB)
 	$(CC) $(LFLAGS) -o dhcpd $(OBJS) $(DHCPLIB) $(LIBS)
diff -ruN ../dhcp-3.0/server/bootserver.conf ./server/bootserver.conf
--- ../dhcp-3.0/server/bootserver.conf	Wed Dec 31 16:00:00 1969
+++ ./server/bootserver.conf	Fri Oct  5 10:16:41 2001
@@ -0,0 +1,268 @@
+#
+# /etc/dhcpd.conf - PXE bootserver configuration file.
+#
+# More information about bootserver and client operation and bootserver
+# request and reply packet contents can be found in the PXE specification
+# at: http://developer.intel.com/ial/wfm/wfmspecs.htm
+#
+
+#
+# Briefly, PXE bootservers are intended to be placed about a network as
+# needed and provide PXE clients with remote boot services.  Bootsevers
+# do not provide IP addresses to clients and do not do IP lease management.
+#
+
+#
+# Bootserver request packets are accepted from PXE clients if they meet
+# the following requirements:
+#
+#   - The client IP address (ciaddr) field in the packet header is
+#     filled in with a valid unicast IP address.
+#
+#   - The packet contains a vendor-class-identifier (option 60) that is
+#     at least 9 octets in length with the first 9 characters set to
+#     "PXEClient" (without the quotes).
+#
+#  - The packet contains a client-architecture (option 93) that is 2 octets
+#    in length.
+#
+#  - The packet contains a network-interface-identifier (option 94) that
+#    is 3 octets in length.
+#
+#  - The packet contains vendor-encapsulated-options (option 43) that
+#    contains an encapsulated pxe.boot-item (sub-option 71) that is
+#    4 octets in length.
+#
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
+# Disable proxyDHCP operation.
+#
+
+dhcpd-operation disable;
+# dhcpd-operation normal;
+# dhcpd-operation proxy;
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
+# Enable bootserver operation.
+#
+
+bootserver-operation on;
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
+# Respond to multicast bootserver discover request packets.
+#
+
+mcast-discovery-addr 224.0.1.2;
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
+# Needed by DHCP daemon.
+#
+
+ddns-update-style ad-hoc;
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
+# Define PXE client options.
+#
+# Values for these options are defined in the PXE specification.
+# http://developer.intel.com/ial/wfm/wfmspecs.htm
+#
+# Additional values can be found in the EFI specification.
+# http://developer.intel.com/technology/efi/index.htm
+#
+
+#
+# This option is used to determine the client boot-time binary runtime
+# environment.
+#
+
+option client-architecture code 93 +	unsigned integer 16;
+
+#
+# This option is used to determine the version of the UNDI (Universal
+# Network Driver Interface) implemented in the client.
+#
+
+option network-interface-identifier code 94 +	{ unsigned integer 8, unsigned integer 8, unsigned integer 8 };
+
+#
+# This option is used to uniquely identify the booting client.  When
+# possible GUIDs should be used instead of MAC address to identify a
+# client machine.  Think of a docking station with a NIC:  Every laptop
+# inserted into the docking station will have the same MAC address but
+# each laptop will have its own GUID.
+#
+
+option client-guid code 97 +	{ unsigned integer 8, string };
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
+# Descibe bootserver vendor-option-space.
+#
+# Values and more detailed descriptions for these sub-options can be found
+# in the PXE specification.
+#
+
+option space bs;
+
+#
+# MTFTP (Multicast Trivial File Transfer Protocol) IP address.
+# This is the MTFTP multicast IP address that is associated with
+# this file.  If MTFTP is not used, do not return this sub-option.
+#
+
+option bs.mtftp-ip code 1 = ip-address;
+
+#
+# MTFTP client listening port.  This is the UDP port that the client
+# must use to listen for and receive MTFTP data packets.  If MTFTP
+# is not used, do not return this sub-option.
+#
+
+option bs.mtftp-cport code 2 = unsigned integer 16;
+
+#
+# MTFTP server listening port.  This is the UDP port that the server
+# must use to accept MTFTP open requests.  If MTFTP is not used, do
+# not return this sub-option.
+#
+
+option bs.mtftp-sport code 3 = unsigned integer 16;
+
+#
+# MTFTP client timeout.  This is the number of seconds that a client
+# must listen for its file before starting a new MTFTP download session.
+# This is also the number of seconds the client must wait before
+# retransmitting an acknowledgement packet if a data packet is not
+# received.  If MTFTP is not used, do not return this sub-option.
+#
+
+option bs.mtftp-tmout code 4 = unsigned integer 8;
+
+#
+# MTFTP client restart delay.  This is the maximum number of seconds
+# that a client must listen before requesting a new MTFTP download
+# sesson of the file it was listening to.  If MTFTP is not used, do
+# not return this sub-options.
+#
+
+option bs.mtftp-delay code 5 = unsigned integer 8;
+
+#
+# This sub-option is sent to the proxyDHCP server if the client supports
+# remote boot security.  The client must send a list of all of the
+# credential types it supports.  More information about remote boot
+# security can be found in the BIS specification.
+# http://developer.intel.com/ial/WfM/tools/BIS/Index.htm
+#
+
+option bs.credential-types code 12 +	{ unsigned integer 16, unsigned integer 16 };
+
+#
+# This sub-option is sent by the client to request a specific bootserver
+# type and image number.  This sub-option is also sent back by the
+# bootserver.  The bootserver type cannot be changed but the image number
+# may be changed.
+#
+
+option bs.boot-item code 71 +	{ unsigned integer 16, unsigned integer 16 };
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
+# Simple sample scope.
+#
+
+subnet 192.168.13.0 netmask 255.255.255.0 {
+	range 192.168.13.1 192.168.13.10;
+
+	#
+	# If this is not a valid bootserver packet, do not reply
+	# to the client.
+	#
+
+	if not bootserver {
+		deny booting;
+	}
+
+	#
+	# Send back different information based on client-architecture.
+	# This configuration file is for a bootserver that sends back
+	# images for Intel x86 PC/AT architecture clients.
+	#
+
+	if not (option client-architecture = 00:00) {
+		deny booting;
+	}
+
+	#
+	# Send back different information based on bootserver type.
+	# This configuration file is for a bootserver that sends back
+	# DOS/UNDI remote boot images.
+	#
+
+	if not (substring(option bs.boot-item, 0, 2) = 00:03) {
+		deny booting;
+	}
+
+	#
+	# Only two image layer numbers are supported.
+	#
+
+	if substring(option bs.boot-item, 2, 2) = 00:00 {
+
+		#
+		# Send back the filename for layer zero.
+		#
+
+		filename "X86PC/UNDI/DOSUNDI/dosundi.0";
+
+		#
+		# Send back "PXEClient" so the reply is not ignored by
+		# the client.
+		#
+
+		option vendor-class-identifier "PXEClient";
+
+		#
+		# Send back the image number so the reply is not ignored
+		# by the client.
+		#
+
+		option bs.boot-item 3 0;
+
+		#
+		# Send back the vendor option space.
+		#
+
+		vendor-option-space bs;
+	} else if substring(option bs.boot-item, 2, 2) = 00:01 {
+
+		#
+		# Send back the filename for layer one.
+		#
+
+		filename "X86PC/UNDI/DOSUNDI/dosundi.1";
+
+		#
+		# Send back "PXEClient" so the reply is not ignored by
+		# the client.
+		#
+
+		option vendor-class-identifier "PXEClient";
+
+		#
+		# Send back the image number so the reply is not ignored
+		# by the client.
+		#
+
+		option bs.boot-item 3 1;
+
+		#
+		# Send back the vendor option space.
+		#
+
+		vendor-option-space bs;
+	}
+}
diff -ruN ../dhcp-3.0/server/confpars.c ./server/confpars.c
--- ../dhcp-3.0/server/confpars.c	Thu Oct  4 15:08:35 2001
+++ ./server/confpars.c	Fri Oct  5 10:16:41 2001
@@ -318,6 +318,11 @@
 	       | USE_LEASE_ADDR_FOR_DEFAULT_ROUTE boolean
 	       | AUTHORITATIVE
 	       | NOT AUTHORITATIVE
+%%PXE begin
+		| DHCPD-OPERATION  NORMAL / PROXY / DISABLE  SEMI
+		| BOOTSERVER-OPERATION boolean SEMI
+		| MCAST-DISCOVERY-ADDR ip-addr SEMI
+%%PXE end
 
    declaration := host-declaration
 		 | group-declaration
@@ -348,10 +353,83 @@
 	struct data_string key_id;
 	int known;
 	isc_result_t status;
+/* %%PXE begin */
+	static int had_dhcpd_operation = 0;
+	static int had_bootserver_operation = 0;
+	static int had_mcast_discovery_addr = 0;
+/* %%PXE end */
 
 	token = peek_token (&val, (unsigned *)0, cfile);
 
 	switch (token) {
+/* %%PXE begin */
+		case DHCPD_OPERATION:
+			if (had_dhcpd_operation) {
+				parse_warn(cfile,
+					"already parsed dhcpd-operation.");
+
+				skip_to_semi(cfile);
+				return 1;
+			}
+
+			/* skip dhcpd-operation token */
+		      	next_token(&val, (unsigned *)0, cfile);
+
+			token = next_token(&val, (unsigned *)0, cfile);
+
+			if (token = NORMAL) {
+				dhcpd_operation = NORMAL;
+				parse_semi(cfile);
+			} else if (token = PROXY) {
+				dhcpd_operation = PROXY;
+				parse_semi(cfile);
+			} else if (token = DISABLE) {
+				dhcpd_operation = DISABLE;
+				parse_semi(cfile);
+			} else {
+				parse_warn(cfile,
+					"normal/proxy/disable expected.");
+
+				skip_to_semi(cfile);
+			}
+
+			return had_dhcpd_operation = 1;
+
+		case BOOTSERVER_OPERATION:
+			if (had_bootserver_operation) {
+				parse_warn(cfile,
+					"already parsed
bootserver-operation.");
+
+				skip_to_semi(cfile);
+				return 1;
+			}
+
+			next_token(&val, (unsigned *)0, cfile);
+
+			bootserver_operation = parse_boolean(cfile);
+
+			return had_bootserver_operation = 1;
+
+		case MCAST_DISCOVERY_ADDR:
+			if (had_mcast_discovery_addr) {
+				parse_warn(cfile,
+					"already parsed
mcast-discovery-addr.");
+
+				skip_to_semi(cfile);
+				return 1;
+			}
+
+			next_token(&val, (unsigned *)0, cfile);
+
+			if (parse_ip_addr(cfile, &mcast_discovery_addr)) {
+				parse_semi(cfile);
+			} else {
+				parse_warn(cfile, "expected ip-address.");
+			}
+
+			return had_mcast_discovery_addr = 1;
+/* %%PXE end */
+
 	      case INCLUDE:
 		next_token (&val, (unsigned *)0, cfile);
 		token = next_token (&val, (unsigned *)0, cfile);
diff -ruN ../dhcp-3.0/server/db.c ./server/db.c
--- ../dhcp-3.0/server/db.c	Fri Jun 22 16:58:08 2001
+++ ./server/db.c	Fri Oct  5 10:16:41 2001
@@ -75,6 +75,12 @@
 		if (!new_lease_file ())
 			return 0;
 
+/* %%PXE begin */
+	if (lease->flags & PXE_LEASE) {
+		return 1;
+	}
+/* %%PXE end */
+
 	if (counting)
 		++count;
 	errno = 0;
diff -ruN ../dhcp-3.0/server/dhcp.c ./server/dhcp.c
--- ../dhcp-3.0/server/dhcp.c	Thu Oct  4 15:21:00 2001
+++ ./server/dhcp.c	Fri Oct  5 10:16:41 2001
@@ -111,6 +111,125 @@
 		goto out;
 	}
 
+/* %%PXE begin */
+	packet->proxy = packet->bootserver = 0;
+
+	/*
+	 * Do simple (quick) checks first.  Most non-PXE packets will be
+	 * thrown out by these few checks.
+	 */
+	if (
+		(!packet->raw->ciaddr.s_addr &&
+			(packet->packet_type = DHCPDISCOVER ||
+				packet->packet_type = DHCPREQUEST)) ||
+
+		(packet->raw->ciaddr.s_addr &&
+			(packet->packet_type = DHCPREQUEST ||
+				packet->packet_type = DHCPINFORM))
+	) {
+		unsigned n;
+
+		/*
+		 * All PXE client packets must have a
vendor-class-identifier
+		 * with the first nine characters set to "PXEClient".
+		 */
+		oc = lookup_option(&dhcp_universe, packet->options,
+			DHO_VENDOR_CLASS_IDENTIFIER);
+
+		if (!oc || oc->expression || oc->data.len < 9 ||
+			strncmp(oc->data.data, "PXEClient", 9))
+		{
+			goto pxe_out;
+		}
+
+		/*
+		 * All PXE client packets must have a two-byte client
+		 * architecture option.
+		 */
+		oc = lookup_option(&dhcp_universe, packet->options,
+			DHO_PXE_CLIENT_ARCHITECTURE);
+
+		if (!oc || oc->expression || oc->data.len != 2) {
+			goto pxe_out;
+		}
+
+		/*
+		 * All PXE client packets must have a three-byte network
+		 * interface option.
+		 */
+		oc = lookup_option(&dhcp_universe, packet->options,
+			DHO_PXE_NETWORK_INTERFACE);
+
+		if (!oc || oc->expression || oc->data.len != 3) {
+			goto pxe_out;
+		}
+
+		/*
+		 * PXE clients may have included some PXE vendor data
+		 * in the incoming packet.  Proxy packets will not have
+		 * a PXE boot-item (41) sub-option.
+		 */
+		oc = lookup_option(&dhcp_universe, packet->options,
+			DHO_VENDOR_ENCAPSULATED_OPTIONS);
+
+		if (!oc) {
+			/*
+			 * This may be a proxy packet.
+			 */
+			switch (packet->packet_type) {
+			case DHCPDISCOVER:
+			case DHCPREQUEST:
+				packet->proxy = !packet->raw->ciaddr.s_addr;
+			}
+
+			goto pxe_out;
+		}
+
+		if (oc->expression) {
+			/*
+			 * M(f)J - I do not know what this means so I am
+			 * going to assume that this is not a valid PXE
+			 * packet since I have never seen this happen in
+			 * my testing.
+			 */
+			goto pxe_out;
+		}
+
+		for (n = 0; n < oc->data.len && oc->data.data[n] != 255; ) {
+			switch (oc->data.data[n]) {
+			case 0:
+				++n;
+				continue;
+
+			case 71:
+				switch (packet->packet_type) {
+				case DHCPREQUEST:
+				case DHCPINFORM:
+					packet->bootserver +						(oc->data.data[n + 1] = 4);
+				}
+
+				goto pxe_out;
+
+			default:
+				n += 2 + oc->data.data[n + 1];
+				continue;
+			}
+		}
+
+		packet->proxy = 1;
+	}
+pxe_out:
+
+	if (dhcpd_operation != NORMAL) {
+		goto nolease;
+	}
+
+	if (packet->server_port = htons((short)4011)) {
+		goto nolease;
+	}
+/* %%PXE end */
+
 	/* There is a problem with the relay agent information option,
 	   which is that in order for a normal relay agent to append
 	   this option, the relay agent has to have been involved in
@@ -220,10 +339,6 @@
 		dhcpdiscover (packet, ms_nulltp);
 		break;
 
-	      case DHCPREQUEST:
-		dhcprequest (packet, ms_nulltp, lease);
-		break;
-
 	      case DHCPRELEASE:
 		dhcprelease (packet, ms_nulltp);
 		break;
@@ -232,10 +347,61 @@
 		dhcpdecline (packet, ms_nulltp);
 		break;
 
+/* %%PXE begin */
+#if 0
+	      case DHCPREQUEST:
+		dhcprequest (packet, ms_nulltp, lease);
+		break;
+
 	      case DHCPINFORM:
 		dhcpinform (packet, ms_nulltp);
 		break;
+#else
+	      case DHCPREQUEST:
+		if (packet->server_port = htons((short)4011)) {
+			if (bootserver_operation && packet->bootserver) {
+				dhcpinform(packet, ms_nulltp);
+			}
+
+			break;
+		}
+
+		if (dhcpd_operation != NORMAL && bootserver_operation &&
+			packet->bootserver)
+		{
+			dhcpinform(packet, ms_nulltp);
+			break;
+		}
+
+		if (dhcpd_operation = NORMAL) {
+			dhcprequest(packet, ms_nulltp, lease);
+		}
+
+		break;
 
+	      case DHCPINFORM:
+		if (packet->server_port = htons((short)4011)) {
+			if (bootserver_operation && packet->bootserver) {
+				dhcpinform(packet, ms_nulltp);
+			}
+
+			break;
+		}
+
+		if (dhcpd_operation != NORMAL && bootserver_operation &&
+			packet->bootserver)
+		{
+			dhcpinform(packet, ms_nulltp);
+			break;
+		}
+
+		if (dhcpd_operation = NORMAL) {
+			dhcpinform(packet, ms_nulltp);
+		}
+
+		break;
+#endif
+/* %%PXE end */
 
 	      case DHCPACK:
 	      case DHCPOFFER:
@@ -265,8 +431,17 @@
 	dhcp_failover_state_t *peer;
 #endif
 
+/* %%PXE begin */
+#if 0
 	find_lease (&lease, packet, packet -> shared_network,
 		    0, &allocatedp, (struct lease *)0, MDL);
+#else
+	if (dhcpd_operation = NORMAL) {
+		find_lease(&lease, packet, packet -> shared_network,
+			0, &allocatedp, (struct lease *)0, MDL);
+	}
+#endif
+/* %%PXE end */
 
 	if (lease && lease -> client_hostname &&
 	    db_printable (lease -> client_hostname))
@@ -440,9 +615,18 @@
 
 	subnet = (struct subnet *)0;
 	lease = (struct lease *)0;
+/* %%PXE begin */
+#if 0
 	if (find_subnet (&subnet, cip, MDL))
 		find_lease (&lease, packet,
 			    subnet -> shared_network, &ours, 0, ip_lease,
MDL);
+#else
+	if (find_subnet(&subnet, cip, MDL) && dhcpd_operation = NORMAL) {
+		find_lease(&lease, packet, subnet->shared_network,
+			&ours, 0, ip_lease, MDL);
+	}
+#endif
+/* %%PXE end */
 	/* XXX consider using allocatedp arg to find_lease to see
 	   XXX that this isn't a compliant DHCPREQUEST. */
 
@@ -484,6 +668,22 @@
 		  ? inet_ntoa (packet -> raw -> giaddr)
 		  : packet -> interface -> name);
 
+/* %%PXE begin */
+	if (dhcpd_operation = DISABLE) {
+		log_info("%s: dhcpd-operation disable", msgbuf);
+		return;
+	}
+/* %%PXE end */
+
+/* %%PXE begin */
+	if (dhcpd_operation != NORMAL) {
+		log_info("%s: dhcpd-operation %s", msgbuf,
+			((dhcpd_operation = PROXY) ? "proxy" :
"disabled"));
+
+		return;
+	}
+/* %%PXE end */
+
 #if defined (FAILOVER_PROTOCOL)
 	if (lease && lease -> pool && lease -> pool -> failover_peer) {
 		peer = lease -> pool -> failover_peer;
@@ -915,8 +1115,17 @@
 		memcpy (cip.iabuf, &packet -> raw -> ciaddr, 4);
 	}
 
+/* %%PXE begin */
+#if 0
 	sprintf (msgbuf, "DHCPINFORM from %s via %s",
 		 piaddr (cip), packet -> interface -> name);
+#else
+	sprintf(msgbuf, "%s from %s via %s",
+		 (packet->bootserver ? "BOOTSERVERREQUEST" : "DHCPINFORM"),
+		 piaddr(cip),
+		 packet->interface->name);
+#endif
+/* %%PXE end */
 
 	/* If the IP source address is zero, don't respond. */
 	if (!memcmp (cip.iabuf, "\0\0\0", 4)) {
@@ -939,7 +1148,13 @@
 	   It would be nice if a per-host value could override this, but
 	   there's overhead involved in checking this, so let's see how
people
 	   react first. */
+/* %%PXE begin */
+#if 0
 	if (subnet && !subnet -> group -> authoritative) {
+#else
+	if (subnet && !subnet->group->authoritative && !packet->bootserver)
{
+#endif
+/* %%PXE end */
 		static int eso = 0;
 		log_info ("%s: not authoritative for subnet %s",
 			  msgbuf, piaddr (subnet -> net));
@@ -966,6 +1181,10 @@
 	memset (&raw, 0, sizeof raw);
 	outgoing.raw = &raw;
 
+/* %%PXE begin */
+	outgoing.bootserver = packet->bootserver;
+/* %%PXE end */
+
 	/* Execute statements in scope starting with the subnet scope. */
 	if (subnet)
 		execute_statements_in_scope ((struct binding_value **)0,
@@ -1194,7 +1413,15 @@
 	raw.op = BOOTREPLY;
 
 	/* Report what we're sending... */
+/* %%PXE begin */
+#if 0
 	log_info ("DHCPACK to %s", inet_ntoa (raw.ciaddr));
+#else
+	log_info("%s to %s",
+		(outgoing.bootserver ? "BOOTSERVERREPLY" : "DHCPACK"),
+		inet_ntoa(raw.ciaddr));
+#endif
+/* %%PXE end */
 
 #ifdef DEBUG_PACKET
 	dump_packet (&outgoing);
@@ -1210,7 +1437,13 @@
 
 	/* Use the IP address we derived for the client. */
 	memcpy (&to.sin_addr, cip.iabuf, 4);
+/* %%PXE begin */
+#if 0
 	to.sin_port = remote_port;
+#else
+	to.sin_port = outgoing.bootserver ? htons((short)4011) :
remote_port;
+#endif
+/* %%PXE end */
 
 	errno = 0;
 	send_packet ((fallback_interface
@@ -2565,6 +2798,17 @@
 	/* Hang the packet off the lease state. */
 	packet_reference (&lease -> state -> packet, packet, MDL);
 
+/* %%PXE begin */
+	if (lease->flags & PXE_LEASE) {
+		lease->timestamp = cur_time;
+		/* static_lease_dereference(lease, MDL); */
+		lease_dereference(&lease, MDL); /* M(f)J %% */
+		dhcp_reply(lease);
+		dissociate_lease(lease);
+		return;
+	}
+/* %%PXE end */
+
 	/* If this is a DHCPOFFER, ping the lease address before actually
 	   sending the offer. */
 	if (offer = DHCPOFFER && !(lease -> flags & STATIC_LEASE) &&
@@ -3447,6 +3691,13 @@
 		host_dereference (&host, MDL);
 
 	if (lease) {
+/* %%PXE begin */
+		if (dhcpd_operation = PROXY) {
+			lease->flags |= PXE_LEASE;
+			memset(&lease->ip_addr, 0, sizeof lease->ip_addr);
+		}
+/* %%PXE end */
+
 #if defined (DEBUG_FIND_LEASE)
 		log_info ("Returning lease: %s.",
 		      piaddr (lease -> ip_addr));
@@ -3502,8 +3753,14 @@
 	lease -> binding_state = FTS_FREE;
 	lease_reference (lp, lease, MDL);
 	lease_dereference (&lease, MDL);
+/* %%PXE begin */
+	if (dhcpd_operation = PROXY) {
+		lease->flags |= PXE_LEASE;
+		memset(&lease->ip_addr, 0, sizeof lease->ip_addr);
+	}
+/* %%PxE end */
 	host_dereference (&rhp, MDL);
-	return 1;
+  	return 1;
 }
 
 /* Look through all the pools in a list starting with the specified pool
@@ -3588,6 +3845,14 @@
 			      piaddr (lease -> ip_addr));
 			lease_reference (lp, lease, MDL);
 		}
+
+/* %%PXE begin */
+		if (dhcpd_operation = PROXY) {
+			lease->flags |= PXE_LEASE;
+			memset(&lease->ip_addr, 0, sizeof lease->ip_addr);
+		}
+/* %%PXE end */
+
 		return 1;
 	}
 
@@ -3602,11 +3867,32 @@
 					       peer_has_leases);
 
 		allocate_lease (lp, packet, pool -> next, peer_has_leases);
+/* %%PXE begin */
+#if 0
 		if (*lp)
 			return 1;
+#else
+		if (*lp) {
+			if (dhcpd_operation = PROXY) {
+				lease->flags |= PXE_LEASE;
+				memset(&lease->ip_addr, 0, sizeof
lease->ip_addr);
+			}
+
+			return 1;
+		}
+#endif
+/* %%PXE end */
 	}
 
 	lease_reference (lp, lease, MDL);
+
+/* %%PXE begin */
+	if (dhcpd_operation = PROXY) {
+		lease->flags |= PXE_LEASE;
+		memset(&lease->ip_addr, 0, sizeof lease->ip_addr);
+	}
+/* %%PXE end */
+
 	return 1;
 }
 
diff -ruN ../dhcp-3.0/server/dhcpd.c ./server/dhcpd.c
--- ../dhcp-3.0/server/dhcpd.c	Thu Jun 21 19:12:58 2001
+++ ./server/dhcpd.c	Fri Oct  5 10:16:41 2001
@@ -63,6 +63,12 @@
 struct iaddr server_identifier;
 int server_identifier_matched;
 
+/* %%PXE begin */
+int dhcpd_operation = NORMAL;
+int bootserver_operation = 0;
+struct iaddr mcast_discovery_addr = { 0, 0 };
+/* %%PXE end */
+
 #if defined (NSUPDATE)
 
 /* This stuff is always executed to figure the default values for certain
@@ -513,7 +519,13 @@
 		exit (0);
 
 	/* Discover all the network interfaces and initialize them. */
+/* %%PXE begin */
+#if 0
 	discover_interfaces (DISCOVER_SERVER);
+#else
+	discover_interfaces(DISCOVER_SERVER, bootserver_operation);
+#endif
+/* %%PXE end */
 
 	/* Make up a seed for the random number generator from current
 	   time plus the sum of the last four bytes of each
diff -ruN ../dhcp-3.0/server/dhcpd.pxe.5 ./server/dhcpd.pxe.5
--- ../dhcp-3.0/server/dhcpd.pxe.5	Wed Dec 31 16:00:00 1969
+++ ./server/dhcpd.pxe.5	Fri Oct  5 10:16:41 2001
@@ -0,0 +1,215 @@
+.\"	dhcpd.pxe.5
+.\"
+.TH dhcpd.pxe 5
+.SH NAME
+dhcpd.pxe - pxe extensions in the dhcpd server daemon and configuration
file
+.SH DESCRIPTION
+This document describes the extensions that have been added to the ISC DHCP
+daemon and configuration file to support PXE proxyDHCP and bootserver
+operation.  More information about the DHCP options required for proper
+PXE operation and PXE client/server inter-operation can be found in the
+PXE 2.1 specification located at:
+.PP
+.RS 0.25i
+http://developer.intel.com/ial/wfm/wfmspecs.htm
+.PP
+.RE
+The DHCP options required for PXE operation are:
+.PP
+.RS 0.25i
+.B option client-architecture code 93 +.RS 0.25i
+.B unsigned integer 16;
+.PP
+.RE
+The \fBclient-architecute\fR option identifies the runtime environment
+of the client machine.
+.PP
+.B option network-interface-identifier code 94 +.RS 0.25i
+.B { unsigned integer 8, unsigned integer 8,
+.RS 0.25i
+.B unsigned integer 8 };
+.PP
+.RE
+.RE
+.RE
+The \fBnetwork-interface-identifier\fR option identifies the version of
+the UNDI (Universal Network Driver Interface) that is running on the
+client machine.
+.PP
+Another option that should be present in all DHCPDISCOVER, DHCPREQUEST
+and DHCPINFORM packets sent out by PXE clients is:
+.PP
+.RS 0.25i
+.B option client-guid code 97 +.RS 0.25i
+.B { unsigned integer 8, string };
+.PP
+.RE
+.RE
+The \fBclient-guid\fR option is a unique identifier that should be
+present on all WfM (Wired for Management) compliant systems.  This
+value should be used to uniquely identify a machine instead of a MAC
+address since the MAC address is not always unique.
+.RS .25i
+(e.g.: A laptop docking station with a network adapter installed in it
+will identify each laptopn inserted into the docking station with the 
+same MAC address.)
+.PP
+.RE
+.SH PXE STATEMENTS
+The \fIdhcpd-operation\fR statement
+.RS 0.25i
+.PP
+.B dhcpd-operation \fIstate\fB ;\fR
+.PP
+This statement defines how the DHCP daemon will respond to DHCPDISCOVER
+and DHCPREQUEST packets.  \fIstate\fR must be \fBnormal\fR, \fBproxy\fR or
+\fBdisabled\fR.  If the \fBdhcpd-operation\fR statement is not present in
+the dhcpd.conf file, default state is \fBnormal\fR.  The
\fBdhcpd-operation\fR
+statemant may only appear once in the dhcpd.conf file.
+.PP
+In the \fBnormal\fR state the DHCP daemon will process all valid
+DHCPDISCOVER packets and perform IP lease management as described
+in the dhcpd.conf.5 and dhcpd.leases.5 man pages.
+.PP
+In the \fBproxy\fR state, the daemon will respond to valid DHCPDISCOVER
+packets that contain the required DHCP options for PXE operation.
+DHCPOFFER packets that are sent back will not contain any IP lease
+management information (the client IP address fields will be set to
+0.0.0.0).
+.PP
+In the \fBdisabled\fR state, the daemon will not respond to any
DHCPDISCOVER
+packets.
+.PP
+.RE
+The \fIbootserver-operation\fR statement
+.RS 0.25i
+.PP
+.B bootserver-operation \fIflag\fB ;\fR
+.PP
+This statement controls how the DHCP daemon will respond to PXE bootserver
+request packets.  (A bootserver request packet is a DHCPREQUEST or
DHCPINFORM
+packet with the required PXE DHCP options described above and a
+\fBboot-item\fR DHCP vendor option.  This statement may only appear once
+in the dhcpd.conf file.
+.PP
+.I flag\fR can be set to \fBon\fR or \fBoff\fR.  The default state is
+\fBoff\fR.
+.PP
+In the \fBoff\fR state, the DHCP daemon will not respond to PXE bootserver
+request packets that are multicast or unicast to port 4011.  PXE bootserver
+request packets that are broadcast or unicast to the DHCP daemon local port
+will be treated like normal DHCPREQUEST and DHCPINFORM packets.
+.PP
+In the \fBon\fR state, the DHCP daemon will respond to bootserver packets
+that are multicast and unicast port 4011.  PXE bootserver request packets
+that are broadcast or unicast to the DHCP daemon local port will only be
+processed as bootserver request packets if the \fBdhcpd-operation\fR is
+NOT \fBnormal\fR.
+.PP
+.RE
+The \fImcast-discovery-addr\fR statement
+.RS 0.25i
+.PP
+.B mcast-discovery-addr \fImcast-ip-addr\fB ;\fR
+.PP
+This statement defines the multicast IP address that will be used to 
+listen for multicast bootserver requests.  If this statement is not
+present, multicast bootserver requests will be ignored.  This statement
+can appear only once in the dhcpd.conf file.
+.RE
+.SH PXE EXPRESSIONS
+.B proxy
+.RS 0.25i
+.PP
+This boolean expression returns true if the DHCPDISCOVER or DHCPREQUEST
+packet being processed has come from a client that is not bound (does not
+have an IP address) and the packet contains the required DHCP options
+mentioned above and the packet does not contain a boot-item (sub-option 71)
+in the vendor-encapsulated-options (option 43).
+.PP
+When this expression returns true, the dhcpd.conf file should return
+the PXE client boot information (menu, prompt, etc.) defined in the
+PXE specification.
+.PP
+.RE
+.B bootserver
+.RS 0.25i
+.PP
+This boolean expression returns true if the bootserver request packet
+received is valid (contains the required options and contains a boot-item
+in the vendor-encapsulated-options).
+.PP
+When this expression returns true, the dhcpd.conf file should return
+the requested boot-item if it is available.  If the requested boot-item
+is not available, the dhcpd.conf file should \fBdeny booting\fR.
+.RE
+.SH DLL FUNCTION CALL
+.B dll ( \fIlibname\fB , \fIfuncname\fR [ \fB, \fIarg-list\fR ] \fB)\fR
+.RS 0.25i
+.PP
+A DLL function can be passed and return boolean, data or numeric values.
+DLL functions are called using the above syntax.  \fIlibname\fR is a data
+string that contains the name of a dynamic library (see the \fBdlopen()\fR
+man page).  \fIfuncname\fR is the name of a symbol in the dynamic library.
+Additional parameters are optional and may be boolean, data or numeric
+data types.
+.PP
+DLL function parameters and return values are defined using this structure:
+.nf
+.PP
+.RS 0.25i
+.B struct dll_value {
+.RS 0.25i
+.B   enum {
+.RS 0.25i
+.B     dll_type_unused = 0,
+.B     dll_type_boolean,
+.B     dll_type_data,
+.B     dll_type_numeric,
+.B     dll_type_last
+.RE
+.B   } type;
+.PP
+.B   union {
+.RS 0.25i
+.B     struct {
+.RS 0.25i
+.B       unsigned len;
+.B       char buf[1];
+.RE
+.B     } data;
+
+.B     unsigned long numeric;
+.B     int boolean;
+.RE
+.B   } value;
+.RE
+.B };
+.RE
+.fi
+.PP
+DLL functions must be defined thusly:
+.nf
+.RS 0.25i
+.PP
+.B struct dll_value *funcname(
+.B   const unsigned argcnt,
+.B   const struct dll_value *arglist[]);
+.fi
+.PP
+.RE
+Additional parameters in the DLL function call are evaluated from
+left to right and placed into the \fBarglist\fR.  The third
+parameter is \fBarglist[0]\fR, the fourth is \fBarglist[1]\fR, etc.
+If no additional parameters are given in the DLL function call,
+\fBargcnt\fR will be set to zero and \fBarglist\fR will be set to
+NULL.
+.PP
+DLL library functions must allocate the return value storage using
+the C library call \fBmalloc()\fR.  A return value of NULL will be
+treated as an error.  After consuming the return value, the DHCP
+daemon will release the return value storage using the C library
+call \fBfree()\fR.
diff -ruN ../dhcp-3.0/server/proxydhcp.conf ./server/proxydhcp.conf
--- ../dhcp-3.0/server/proxydhcp.conf	Wed Dec 31 16:00:00 1969
+++ ./server/proxydhcp.conf	Fri Oct  5 10:16:41 2001
@@ -0,0 +1,260 @@
+#
+# /etc/dhcpd.conf - Sample PXE proxyDHCP configuration file.
+#
+# More information about proxyDHCP server and client operation and
+# proxyDHCPOFFER packet contents can be found in the PXE specification
+# at: http://developer.intel.com/ial/wfm/wfmspecs.htm
+#
+
+#
+# Briefly, a proxyDHCP server is intended to sit next to a DHCP server
+# and provide PXE clients with additional remote information.  The
+# difference between a proxyDHCP server and a DHCP server is that the
+# proxyDHCP server does not return IP address or IP lease information
+# and that proxyDHCP servers only respond to DHCPDISCOVER packets that
+# have come from PXE clients.
+#
+# A DHCPDISCOVER packet from a PXE client meets the following requirements:
+#
+#   - Contains a vendor-class-identifier (option 60) that is at least
+#     9 octets in length with the first 9 characters set to "PXEClient"
+#     (without the quotes).
+#
+#  - Contains a client-architecture (option 93) that is 2 octets in length.
+#
+#  - Contains a network-interface-identifier (option 94) that is 3 octets
+#    in length.
+#
+#  - Does not contain vendor-encapsulated-options (option 43) or if it
+#    does contain vendor-encapsulated-options an encapsulated pxe.boot-item
+#    (sub-option 71) is not present in the encapsulated option.
+#
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
+# Enable proxyDHCP operation.
+#
+
+dhcpd-operation proxy;
+# dhcpd-operation normal;
+# dhcpd-operation disable;
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
+# Do not enable bootserver operation.
+#
+
+bootserver-operation off;
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
+# Do not respond to multicast bootserver discover request packets.
+#
+
+# mcast-discovery-addr 224.0.1.2;
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
+# Needed by DHCP daemon.
+#
+
+ddns-update-style ad-hoc;
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
+# Define PXE client options.
+#
+# Values for these options are defined in the PXE specification.
+# http://developer.intel.com/ial/wfm/wfmspecs.htm
+#
+# Additional values can be found in the EFI specification.
+# http://developer.intel.com/technology/efi/index.htm
+#
+
+#
+# This option is used to determine the client boot-time binary runtime
+# environment.
+#
+
+option client-architecture code 93 +	unsigned integer 16;
+
+#
+# This option is used to determine the version of the UNDI (Universal
+# Network Driver Interface) implemented in the client.
+#
+
+option network-interface-identifier code 94 +	{ unsigned integer 8, unsigned integer 8, unsigned integer 8 };
+
+#
+# This option is used to uniquely identify the booting client.  When
+# possible GUIDs should be used instead of MAC address to identify a
+# client machine.  Think of a docking station with a NIC:  Every laptop
+# inserted into the docking station will have the same MAC address but
+# each laptop will have its own GUID.
+#
+
+option client-guid code 97 +	{ unsigned integer 8, string };
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
+# Describe proxyDHCP vendor-option-space.
+#
+# Values and more detailed descriptions for these sub-options can be found
+# in the PXE specification.
+#
+
+option space proxy;
+
+#
+# This sub-option is a bitfield that defines the types of bootserver
+# discovery requests that can be made by the PXE client.  This sub-option
+# does not need to be present.  If this sub-option is not present, PXE
+# clients assume a default discovery-control of zero (00h).
+#
+# Bit 0 (01h): If set, the client must not do broadcast discovery.
+#
+# Bit 1 (02h): If set, the client must not do multicast discovery.
+# If not set, mcast-discovery-addr must be present.
+#
+# Bit 2 (04h): If set, only accept responses from servers in the
+# boot-servers sub-option.
+#
+# Bit 3 (08h): If set and a bootfile is present in the DHCPACK or
+# proxyDHCPOFFER packet, just download the file using TFTP and run it.
+# Do not try to display a boot-prompt or boot-menu.
+#
+
+option proxy.discovery-control code 6 = unsigned integer 8;
+
+#
+# This sub-option defines the multicast IP address that is being used
+# by all of the bootservers.  When a PXE client transmits a multicast
+# bootserver discovery request it sends the packet to this IP address.
+#
+
+option proxy.mcast-discovery-addr code 7 = ip-address;
+
+#
+# This sub-option serves two purposes.  If the client cannot find a
+# bootserver using multicast and broadcast discovery and this sub-option
+# is present, the client will transmit unicast discovery packets to each
+# bootserver in this list.  If bit 3 in discovery-control is set the
+# client will only accept bootserver discovery replies  if the bootserver
+# IP address is in this list.
+
+option proxy.boot-servers code 8 = array of
+	{ unsigned integer 16, unsigned integer 8, array of ip-address };
+
+#
+# This sub-option provides a boot menu of one or more items that can be
+# displayed by the PXE Client.
+#
+
+option proxy.boot-menu code 9 = array of
+	{ unsigned integer 16, unsigned integer 8, text };
+
+#
+# This sub-option provides the client with an option remote boot prompt
+# and timeout.  A timeout of zero means to auto-select the first item
+# in the remote boot menu.  A timeout of 255 means to display the prompt
+# and the remote boot menu and wait for the user to select (no timeout).
+# All other values are the number of seconds (1 to 254) to wait for
+# user selection.  If no selection is made before the timeout expires
+# the first item in the remote boot menu is auto-selected.
+#
+
+option proxy.boot-prompt code 10 +	{ unsigned integer 8, text };
+
+#
+# This sub-option is sent to the proxyDHCP server if the client supports
+# remote boot security.  The client must send a list of all of the
+# credential types it supports.  More information about remote boot
+# security can be found in the BIS specification.
+# http://developer.intel.com/ial/WfM/tools/BIS/Index.htm
+#
+
+option proxy.credential-types code 12 +	{ unsigned integer 16, unsigned integer 16 };
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
+# Simple sample scope.
+#
+
+subnet 192.168.13.0 netmask 255.255.255.0 {
+	range 192.168.13.1 192.168.13.10;
+
+	#
+	# If this is not a valid proxy packet, do not reply to
+	# the client.
+	#
+
+	if not proxy {
+		deny booting;
+	}
+
+	#
+	# Send back different information based on client-architecture.
+	#
+
+	if option client-architecture = 00:00 {
+
+		#
+		# For really old PXE clients we must send back a valid
+		# bootstrap program that will display the remote boot
+		# menu because the old clients do not do this inside
+		# the boot ROM.
+		#
+
+		if option network-interface-identifier = 01:02:00 {
+			filename "X86PC/UNDI/bstrap/bstrap.0";
+		}
+
+		#
+		# We must send back "PXEClient" or the client will
+		# ignore us.
+		#
+
+		option vendor-class-identifier "PXEClient";
+
+		#
+		# All bootserver discovery methods supported.
+		#
+
+		option proxy.discovery-control 0;
+
+		#
+		# All of our bootservers are listening on this multicast
+		# address.
+		#
+
+		option proxy.mcast-discovery-addr 224.0.1.2;
+
+		#
+		# This bootserver list will be used for unicast discovery
+		# if the client does not get any response to its multicast
+		# and broadcast discovery requests.
+		#
+
+		option proxy.boot-servers
+			3 2 192.168.13.253, 192.168.13.252;
+
+		#
+		# Remote boot prompt and timeout.
+		#
+
+		option proxy.boot-prompt
+			30 "Press <F8> or <M> for menu.  Press <Esc> or
<Ctrl+C> to local boot.";
+
+		#
+		# Menu that will be displayed when <F8> or <M> is pressed.
+		#
+
+		option proxy.boot-menu
+			0 10 "Local boot",
+			3 8 "DOS/UNDI";
+
+		#
+		# Include vendor options in reply to client.
+		#
+
+		vendor-option-space proxy;
+	}
+}
diff -ruN ../dhcp-3.0/server/stables.c ./server/stables.c
--- ../dhcp-3.0/server/stables.c	Thu Jun 21 19:35:08 2001
+++ ./server/stables.c	Fri Oct  5 10:16:41 2001
@@ -816,7 +816,9 @@
 				 &agent_options [i], MDL);
 	}
 	agent_universe.enc_opt = &dhcp_options [DHO_DHCP_AGENT_OPTIONS];
-
+/* %%PXE begin */
+	agent_universe.is_vendor = 0;
+/* %%PXE end */
 
 	/* Set up the server option universe... */
 	server_universe.name = "server";
@@ -842,6 +844,9 @@
 				 server_options [i].name, 0,
 				 &server_options [i], MDL);
 	}
+/* %%PXE begin */
+	server_universe.is_vendor = 0;
+/* %%PXE end */
 
 	/* Add the server and agent option spaces to the option space hash.
*/
 	universe_hash_add (universe_hash,
diff -ruN ../dhcp-3.0/server/superdhcp.conf ./server/superdhcp.conf
--- ../dhcp-3.0/server/superdhcp.conf	Wed Dec 31 16:00:00 1969
+++ ./server/superdhcp.conf	Fri Oct  5 10:16:41 2001
@@ -0,0 +1,619 @@
+#
+# /etc/dhcpd.conf - Configuration file that implements DHCP,
+# proxyDHCP and bootserver functionality.
+#
+# More information about proxyDHCP server, bootserver and PXE client
+# operation, proxyDHCPOFFER packet contents and bootserver request and
+# reply packet contents can be found in the PXE specification
+# at: http://developer.intel.com/ial/wfm/wfmspecs.htm
+#
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
+#
+# Briefly, a proxyDHCP server is intended to sit next to a DHCP server
+# and provide PXE clients with additional remote information.  The
+# difference between a proxyDHCP server and a DHCP server is that the
+# proxyDHCP server does not return IP address or IP lease information
+# and that proxyDHCP servers only respond to DHCPDISCOVER packets that
+# have come from PXE clients.
+#
+# A DHCPDISCOVER packet from a PXE client meets the following requirements:
+#
+#   - Contains a vendor-class-identifier (option 60) that is at least
+#     9 octets in length with the first 9 characters set to "PXEClient"
+#     (without the quotes).
+#
+#  - Contains a client-architecture (option 93) that is 2 octets in length.
+#
+#  - Contains a network-interface-identifier (option 94) that is 3 octets
+#    in length.
+#
+#  - Does not contain vendor-encapsulated-options (option 43) or if it
+#    does contain vendor-encapsulated-options an encapsulated pxe.boot-item
+#    (sub-option 71) is not present in the encapsulated option.
+#
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
+# Enable proxyDHCP operation.
+#
+
+dhcpd-operation normal;
+# dhcpd-operation proxy;
+# dhcpd-operation disable;
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
+# Enable bootserver operation.
+#
+
+bootserver-operation on;
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
+# Respond to multicast bootserver discover request packets.
+#
+
+mcast-discovery-addr 224.0.1.2;
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
+# Needed by DHCP daemon.
+#
+
+ddns-update-style ad-hoc;
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
+# Define PXE client options.
+#
+# Values for these options are defined in the PXE specification.
+# http://developer.intel.com/ial/wfm/wfmspecs.htm
+#
+# Additional values can be found in the EFI specification.
+# http://developer.intel.com/technology/efi/index.htm
+#
+
+#
+# This option is used to determine the client boot-time binary runtime
+# environment.
+#
+
+option client-architecture code 93 +	unsigned integer 16;
+
+#
+# This option is used to determine the version of the UNDI (Universal
+# Network Driver Interface) implemented in the client.
+#
+
+option network-interface-identifier code 94 +	{ unsigned integer 8, unsigned integer 8, unsigned integer 8 };
+
+#
+# This option is used to uniquely identify the booting client.  When
+# possible GUIDs should be used instead of MAC address to identify a
+# client machine.  Think of a docking station with a NIC:  Every laptop
+# inserted into the docking station will have the same MAC address but
+# each laptop will have its own GUID.
+#
+
+option client-guid code 97 +	{ unsigned integer 8, string };
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
+# Describe proxyDHCP vendor-option-space.
+#
+# Values and more detailed descriptions for these sub-options can be found
+# in the PXE specification.
+#
+
+option space proxy;
+
+#
+# This sub-option is a bitfield that defines the types of bootserver
+# discovery requests that can be made by the PXE client.  This sub-option
+# does not need to be present.  If this sub-option is not present, PXE
+# clients assume a default discovery-control of zero (00h).
+#
+# Bit 0 (01h): If set, the client must not do broadcast discovery.
+#
+# Bit 1 (02h): If set, the client must not do multicast discovery.
+# If not set, mcast-discovery-addr must be present.
+#
+# Bit 2 (04h): If set, only accept responses from servers in the
+# boot-servers sub-option.
+#
+# Bit 3 (08h): If set and a bootfile is present in the DHCPACK or
+# proxyDHCPOFFER packet, just download the file using TFTP and run it.
+# Do not try to display a boot-prompt or boot-menu.
+#
+
+option proxy.discovery-control code 6 = unsigned integer 8;
+
+#
+# This sub-option defines the multicast IP address that is being used
+# by all of the bootservers.  When a PXE client transmits a multicast
+# bootserver discovery request it sends the packet to this IP address.
+#
+
+option proxy.mcast-discovery-addr code 7 = ip-address;
+
+#
+# This sub-option serves two purposes.  If the client cannot find a
+# bootserver using multicast and broadcast discovery and this sub-option
+# is present, the client will transmit unicast discovery packets to each
+# bootserver in this list.  If bit 3 in discovery-control is set the
+# client will only accept bootserver discovery replies  if the bootserver
+# IP address is in this list.
+
+option proxy.boot-servers code 8 = array of
+	{ unsigned integer 16, unsigned integer 8, array of ip-address };
+
+#
+# This sub-option provides a boot menu of one or more items that can be
+# displayed by the PXE Client.
+#
+
+option proxy.boot-menu code 9 = array of
+	{ unsigned integer 16, unsigned integer 8, text };
+
+#
+# This sub-option provides the client with an option remote boot prompt
+# and timeout.  A timeout of zero means to auto-select the first item
+# in the remote boot menu.  A timeout of 255 means to display the prompt
+# and the remote boot menu and wait for the user to select (no timeout).
+# All other values are the number of seconds (1 to 254) to wait for
+# user selection.  If no selection is made before the timeout expires
+# the first item in the remote boot menu is auto-selected.
+#
+
+option proxy.boot-prompt code 10 +	{ unsigned integer 8, text };
+
+#
+# This sub-option is sent to the proxyDHCP server if the client supports
+# remote boot security.  The client must send a list of all of the
+# credential types it supports.  More information about remote boot
+# security can be found in the BIS specification.
+# http://developer.intel.com/ial/WfM/tools/BIS/Index.htm
+#
+
+option proxy.credential-types code 12 +	{ unsigned integer 16, unsigned integer 16 };
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
+#
+# Bootserver request packets are accepted from PXE clients if they meet
+# the following requirements:
+#
+#   - The client IP address (ciaddr) field in the packet header is
+#     filled in with a valid unicast IP address.
+#
+#   - The packet contains a vendor-class-identifier (option 60) that is
+#     at least 9 octets in length with the first 9 characters set to
+#     "PXEClient" (without the quotes).
+#
+#  - The packet contains a client-architecture (option 93) that is 2 octets
+#    in length.
+#
+#  - The packet contains a network-interface-identifier (option 94) that
+#    is 3 octets in length.
+#
+#  - The packet contains vendor-encapsulated-options (option 43) that
+#    contains an encapsulated pxe.boot-item (sub-option 71) that is
+#    4 octets in length.
+#
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
+# Descibe bootserver vendor-option-space.
+#
+# Values and more detailed descriptions for these sub-options can be found
+# in the PXE specification.
+#
+
+option space bs;
+
+#
+# MTFTP (Multicast Trivial File Transfer Protocol) IP address.
+# This is the MTFTP multicast IP address that is associated with
+# this file.  If MTFTP is not used, do not return this sub-option.
+#
+
+option bs.mtftp-ip code 1 = ip-address;
+
+#
+# MTFTP client listening port.  This is the UDP port that the client
+# must use to listen for and receive MTFTP data packets.  If MTFTP
+# is not used, do not return this sub-option.
+#
+
+option bs.mtftp-cport code 2 = unsigned integer 16;
+
+#
+# MTFTP server listening port.  This is the UDP port that the server
+# must use to accept MTFTP open requests.  If MTFTP is not used, do
+# not return this sub-option.
+#
+
+option bs.mtftp-sport code 3 = unsigned integer 16;
+
+#
+# MTFTP client timeout.  This is the number of seconds that a client
+# must listen for its file before starting a new MTFTP download session.
+# This is also the number of seconds the client must wait before
+# retransmitting an acknowledgement packet if a data packet is not
+# received.  If MTFTP is not used, do not return this sub-option.
+#
+
+option bs.mtftp-tmout code 4 = unsigned integer 8;
+
+#
+# MTFTP client restart delay.  This is the maximum number of seconds
+# that a client must listen before requesting a new MTFTP download
+# sesson of the file it was listening to.  If MTFTP is not used, do
+# not return this sub-options.
+#
+
+option bs.mtftp-delay code 5 = unsigned integer 8;
+
+#
+# This sub-option is sent to the proxyDHCP server if the client supports
+# remote boot security.  The client must send a list of all of the
+# credential types it supports.  More information about remote boot
+# security can be found in the BIS specification.
+# http://developer.intel.com/ial/WfM/tools/BIS/Index.htm
+#
+
+option bs.credential-types code 12 +	{ unsigned integer 16, unsigned integer 16 };
+
+#
+# This sub-option is sent by the client to request a specific bootserver
+# type and image number.  This sub-option is also sent back by the
+# bootserver.  The bootserver type cannot be changed but the image number
+# may be changed.
+#
+
+option bs.boot-item code 71 +	{ unsigned integer 16, unsigned integer 16 };
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
+# Simple sample scope.
+#
+
+subnet 192.168.13.0 netmask 255.255.255.0 {
+	range 192.168.13.1 192.168.13.10;
+
+	#
+	# Check for DHCPDISCOVER and DHCPREQUEST packets that may also
+	# need proxyDHCP information appended to them.
+	#
+
+	if proxy {
+		#
+		# Provide proxyDHCP information for Intel x86 PC/AT
+		# architecture PCs.
+		#
+
+		if option client-architecture = 00:00 {
+
+			#
+			# For really old PXE clients we must send back a
valid
+			# bootstrap program that will display the remote
boot
+			# menu because the old clients do not do this inside
+			# the boot ROM.
+			#
+
+			if option network-interface-identifier = 01:02:00 {
+				filename "X86PC/UNDI/bstrap/bstrap.0";
+			}
+
+			#
+			# We must send back "PXEClient" or the client will
+			# ignore us.
+			#
+
+			option vendor-class-identifier "PXEClient";
+
+			#
+			# With only one machine running DHCP w/ proxyDHCP
+			# and bootserver functionality, broadcast discovery
+			# cannot be used.  This is because the broadcast
+			# bootserver packets look too much like DHCPREQUEST
+			# or DHCPINFORM packets.  This still leaves us
+			# multicast and unicast discovery mechanisms.
+			#
+
+			option proxy.discovery-control 1;
+
+			#
+			# All of our bootservers are listening on this
+			# multicast address.
+			#
+
+			option proxy.mcast-discovery-addr 224.0.1.2;
+
+			#
+			# This bootserver list will be used for unicast
+			# discovery if the client does not get any response
+			# to its multicast discovery requests.
+			#
+
+			option proxy.boot-servers
+				3 2 192.168.13.253, 192.168.13.252;
+
+			#
+			# Remote boot prompt and timeout.
+			#
+
+			option proxy.boot-prompt
+				30 "Press <F8> or <M> for menu.  Press <Esc>
or <Ctrl+C> to local boot.";
+
+			#
+			# Menu that will be displayed when <F8> or <M> is
+			# pressed.
+			#
+
+			option proxy.boot-menu
+				0 10 "Local boot",
+				3 8 "DOS/UNDI";
+
+			#
+			# Include vendor options in reply to client.
+			#
+
+			vendor-option-space proxy;
+		} else
+
+		#
+		# Provide proxyDHCP information for Intel ia64
+		# architecture machines.
+		#
+
+		if option client-architecture = 00:02 {
+
+			#
+			# We must send back "PXEClient" or the client will
+			# ignore us.
+			#
+
+			option vendor-class-identifier "PXEClient";
+
+			#
+			# With only one machine running DHCP w/ proxyDHCP
+			# and bootserver functionality, broadcast discovery
+			# cannot be used.  This is because the broadcast
+			# bootserver packets look too much like DHCPREQUEST
+			# or DHCPINFORM packets.  This still leaves us
+			# multicast and unicast discovery mechanisms.
+			#
+
+			option proxy.discovery-control 1;
+
+			#
+			# All of our bootservers are listening on this
+			# multicast address.
+			#
+
+			option proxy.mcast-discovery-addr 224.0.1.2;
+
+			#
+			# This bootserver list will be used for unicast
+			# discovery if the client does not get any response
+			# to its multicast discovery requests.
+			#
+
+			option proxy.boot-servers
+				3 2 192.168.13.253, 192.168.13.252;
+
+			#
+			# Remote boot prompt and timeout.
+			#
+
+			option proxy.boot-prompt
+				30 "Press <F8> or <M> for menu.  Press <Esc>
or <Ctrl+C> to local boot.";
+
+			#
+			# Menu that will be displayed when <F8> or <M> is
+			# pressed.
+			#
+
+			option proxy.boot-menu
+				0 10 "Local boot",
+				14 8 "RedHat Linux64 Remote Boot";
+
+			#
+			# Include vendor options in reply to client.
+			#
+
+			vendor-option-space proxy;
+		}
+	} else if bootserver {
+		#
+		# Send back different information based on
client-architecture.
+		# This configuration file is for a bootserver that sends
back
+		# images for Intel x86 PC/AT and ia64 architecture clients.
+		#
+
+		if option client-architecture = 00:00 {
+			#
+			# Send back different information based on
bootserver
+			# type.  This configuration file is for a bootserver
+			# that sends back DOS/UNDI remote boot images.
+			#
+
+			if not (substring(option bs.boot-item, 0, 2) 00:03) {
+				deny booting;
+			}
+
+			#
+			# Only two image layer numbers are supported.
+			#
+
+			if substring(option bs.boot-item, 2, 2) = 00:00 {
+
+				#
+				# Send back the filename for layer zero.
+				#
+
+				filename "X86PC/UNDI/DOSUNDI/dosundi.0";
+
+				#
+				# Send back "PXEClient" so the reply is not
+				# ignored by the client.
+				#
+
+				option vendor-class-identifier "PXEClient";
+
+				#
+				# Send back the image number so the reply is
not
+				# ignored by the client.
+				#
+
+				option bs.boot-item 3 0;
+
+				#
+				# Send back the vendor option space.
+				#
+
+				vendor-option-space bs;
+			} else if substring(option bs.boot-item, 2, 2) 00:01 {
+
+				#
+				# Send back the filename for layer one.
+				#
+
+				filename "X86PC/UNDI/DOSUNDI/dosundi.1";
+
+				#
+				# Send back "PXEClient" so the reply is not
+				# ignored by the client.
+				#
+
+				option vendor-class-identifier "PXEClient";
+
+				#
+				# Send back the image number so the reply is
not
+				# ignored by the client.
+				#
+
+				option bs.boot-item 3 1;
+
+				#
+				# Send back the vendor option space.
+				#
+
+				vendor-option-space bs;
+			}
+		} else if option client-architecture = 00:02 {
+			#
+			# Send back different information based on
bootserver
+			# type.  This configuration file is for a bootserver
+			# that sends back RedHat Linux64 remote boot images.
+			#
+
+			if not (substring(option bs.boot-item, 0, 2) 00:0E) {
+				deny booting;
+			}
+
+			#
+			# Only three image layer numbers are supported.
+			#
+
+			if substring(option bs.boot-item, 2, 2) = 00:00 {
+
+				#
+				# Send back the filename for layer zero.
+				# This is the just the eli.efi or lilo.efi
+				# application renamed to linux.0.
+				#
+
+				filename
"ia64-efi/undi/redhat-linux64/linux.0";
+
+				#
+				# Send back "PXEClient" so the reply is not
+				# ignored by the client.
+				#
+
+				option vendor-class-identifier "PXEClient";
+
+				#
+				# Send back the image number so the reply is
not
+				# ignored by the client.
+				#
+
+				option bs.boot-item 14 0;
+
+				#
+				# Send back the vendor option space.
+				#
+
+				vendor-option-space bs;
+			} else if substring(option bs.boot-item, 2, 2) 00:01 {
+
+				#
+				# Send back the filename for layer one.
+				# This is the Linux kernel renamed to
linux.1.
+				#
+
+				filename
"ia64-efi/undi/redhat-linux64/linux.1";
+
+				#
+				# Send back "PXEClient" so the reply is not
+				# ignored by the client.
+				#
+
+				option vendor-class-identifier "PXEClient";
+
+				#
+				# Send back the image number so the reply is
not
+				# ignored by the client.
+				#
+
+				option bs.boot-item 14 1;
+
+				#
+				# Send back the vendor option space.
+				#
+
+				vendor-option-space bs;
+			} else if substring(option bs.boot-item, 2, 2) 00:02 {
+				#
+				# If you do not use initrd then comment out
this
+				# else-if code, if the client gets a reply
for
+				# the linux.2 request it assumes that an
initrd
+				# image is required for remote boot to
succeed.
+				#
+
+				#
+				# Send back the filename for layer one.
+				# This is the Linux initrd renamed to
linux.2.
+				#
+
+				filename
"ia64-efi/undi/redhat-linux64/linux.2";
+
+				#
+				# Send back "PXEClient" so the reply is not
+				# ignored by the client.
+				#
+
+				option vendor-class-identifier "PXEClient";
+
+				#
+				# Send back the image number so the reply is
not
+				# ignored by the client.
+				#
+
+				option bs.boot-item 14 2;
+
+				#
+				# Send back the vendor option space.
+				#
+
+				vendor-option-space bs;
+			}
+		} else {
+			deny booting;
+		}
+	} else {
+		#
+		# Any other normal DHCP stuff can be done here.
+		#
+	}
+}

-----Original Message-----
From: Michael Madore [mailto:mmadore@turbolinux.com]
Sent: Wednesday, January 16, 2002 10:57 AM
To: eranian@hpl.hp.com
Cc: linux-ia64@linuxia64.org
Subject: Re: [Linux-ia64] PXE Boot


Stephane Eranian wrote:
> 
> Mike,
> 
> On Wed, Jan 16, 2002 at 10:57:25AM -0800, Michael Madore wrote:
> >
> > I'm trying to boot a Big Sur workstation (Firmware 117C) via the
> > network.  The workstation receives an address via dhcp and when starting
> > to download elilo.efi I get the following error message:
> >
> > PXE-E05: Download buffer is smaller than requested file.
> > Load of PXE boot failed:  File not found
> >
> Do you get this everytime? I have already seen this problem but it
disappears
> if you retry, if I recall correctly.

I get the same message when I retry.
 
> > Does this message really indicate the buffer is to small, or is this a
> > symptom of a different problem?
> >
> Are you using a PXE-aware DHCP server or a standard DHCP server?

I am using ISC dhcp 3.  I'm not sure if it is exactly PXE aware, but it
does allow vendor options to be specified.  For example, if I put the
following in my dhcpd.conf file:

set client-id=option vendor-class-identifier;

subnet 192.168.1.0 netmask 255.255.255.0 {
   range 192.168.1.100 192.168.1.200;
   filename "/tftpboot/elilo.efi";
}

I get the following in dhcpd.leases (along with the usual info):

set client-id="PXEClient:Arch:00002:UNDI:003000"

Mike

_______________________________________________
Linux-IA64 mailing list
Linux-IA64@linuxia64.org
http://lists.linuxia64.org/lists/listinfo/linux-ia64


  parent reply	other threads:[~2002-01-16 19:29 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-01-16 18:21 [Linux-ia64] PXE Boot Luck, Tony
2002-01-16 18:23 ` Stephane Eranian
2002-01-16 18:24 ` Michael Madore
2002-01-16 18:49 ` Stephane Eranian
2002-01-16 18:56 ` Michael Madore
2002-01-16 18:57 ` Michael Madore
2002-01-16 18:59 ` Egan Ford
2002-01-16 19:13 ` Michael Madore
2002-01-16 19:15 ` Michael Madore
2002-01-16 19:21 ` Stephane Eranian
2002-01-16 19:29 ` Tolentino, Matthew E [this message]
2002-01-16 19:36 ` Dick Brown
2002-01-16 19:58 ` Michael Madore
2002-01-16 20:01 ` Michael Madore

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=marc-linux-ia64-105590698805856@msgid-missing \
    --to=matthew.e.tolentino@intel.com \
    --cc=linux-ia64@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox