RE: [Linux-ia64] PXE Boot

Tolentino, Matthew E
2002-01-16T19:29:33Z

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