Index: lib/libstand/arp.c
===================================================================
--- lib/libstand/arp.c
+++ lib/libstand/arp.c
@@ -65,17 +65,16 @@
 
 /* Local forwards */
 static	ssize_t arpsend(struct iodesc *, void *, size_t);
-static	ssize_t arprecv(struct iodesc *, void *, size_t, time_t);
+static	ssize_t arprecv(struct iodesc *, void **, void **, time_t);
 
 /* Broadcast an ARP packet, asking who has addr on interface d */
 u_char *
-arpwhohas(d, addr)
-	struct iodesc *d;
-	struct in_addr addr;
+arpwhohas(struct iodesc *d, struct in_addr addr)
 {
 	int i;
 	struct ether_arp *ah;
 	struct arp_list *al;
+	void *pkt;
 	struct {
 		struct ether_header eh;
 		struct {
@@ -83,13 +82,6 @@
 			u_char pad[18]; 	/* 60 - sizeof(...) */
 		} data;
 	} wbuf;
-	struct {
-		struct ether_header eh;
-		struct {
-			struct ether_arp arp;
-			u_char pad[24]; 	/* extra space */
-		} data;
-	} rbuf;
 
 	/* Try for cached answer first */
 	for (i = 0, al = arp_list; i < arp_num; ++i, ++al)
@@ -122,20 +114,24 @@
 	/* Store ip address in cache (incomplete entry). */
 	al->addr = addr;
 
+	pkt = NULL;
+	ah = NULL;
 	i = sendrecv(d,
 	    arpsend, &wbuf.data, sizeof(wbuf.data),
-	    arprecv, &rbuf.data, sizeof(rbuf.data));
+	    arprecv, &pkt, (void **)&ah);
 	if (i == -1) {
 		panic("arp: no response for %s\n",
 			  inet_ntoa(addr));
 	}
 
 	/* Store ethernet address in cache */
-	ah = &rbuf.data.arp;
 #ifdef ARP_DEBUG
  	if (debug) {
+		struct ether_header *eh;
+
+		eh = (struct ether_header *)((uintptr_t)pkt + 2);
 		printf("arp: response from %s\n",
-		    ether_sprintf(rbuf.eh.ether_shost));
+		    ether_sprintf(eh->ether_shost));
 		printf("arp: cacheing %s --> %s\n",
 		    inet_ntoa(addr), ether_sprintf(ah->arp_sha));
 	}
@@ -143,14 +139,12 @@
 	MACPY(ah->arp_sha, al->ea);
 	++arp_num;
 
+	free(pkt);
 	return (al->ea);
 }
 
 static ssize_t
-arpsend(d, pkt, len)
-	struct iodesc *d;
-	void *pkt;
-	size_t len;
+arpsend(struct iodesc *d, void *pkt, size_t len)
 {
 
 #ifdef ARP_DEBUG
@@ -166,28 +160,27 @@
  * else -1 (and errno == 0)
  */
 static ssize_t
-arprecv(d, pkt, len, tleft)
-	struct iodesc *d;
-	void *pkt;
-	size_t len;
-	time_t tleft;
+arprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft)
 {
 	ssize_t n;
 	struct ether_arp *ah;
 	u_int16_t etype;	/* host order */
+	void *ptr;
 
 #ifdef ARP_DEBUG
  	if (debug)
 		printf("arprecv: ");
 #endif
 
-	n = readether(d, pkt, len, tleft, &etype);
+	ptr = NULL;
+	n = readether(d, &ptr, (void **)&ah, tleft, &etype);
 	errno = 0;	/* XXX */
 	if (n == -1 || n < sizeof(struct ether_arp)) {
 #ifdef ARP_DEBUG
 		if (debug)
 			printf("bad len=%d\n", n);
 #endif
+		free(ptr);
 		return (-1);
 	}
 
@@ -196,12 +189,11 @@
 		if (debug)
 			printf("not arp type=%d\n", etype);
 #endif
+		free(ptr);
 		return (-1);
 	}
 
 	/* Ethernet address now checked in readether() */
-
-	ah = (struct ether_arp *)pkt;
 	if (ah->arp_hrd != htons(ARPHRD_ETHER) ||
 	    ah->arp_pro != htons(ETHERTYPE_IP) ||
 	    ah->arp_hln != sizeof(ah->arp_sha) ||
@@ -211,6 +203,7 @@
 		if (debug)
 			printf("bad hrd/pro/hln/pln\n");
 #endif
+		free(ptr);
 		return (-1);
 	}
 
@@ -220,6 +213,7 @@
 			printf("is request\n");
 #endif
 		arp_reply(d, ah);
+		free(ptr);
 		return (-1);
 	}
 
@@ -228,6 +222,7 @@
 		if (debug)
 			printf("not ARP reply\n");
 #endif
+		free(ptr);
 		return (-1);
 	}
 
@@ -239,6 +234,7 @@
 		if (debug)
 			printf("unwanted address\n");
 #endif
+		free(ptr);
 		return (-1);
 	}
 	/* We don't care who the reply was sent to. */
@@ -248,6 +244,8 @@
  	if (debug)
 		printf("got it\n");
 #endif
+	*pkt = ptr;
+	*payload = ah;
 	return (n);
 }
 
@@ -256,9 +254,7 @@
  * Notes:  Re-uses buffer.  Pad to length = 46.
  */
 void
-arp_reply(d, pkt)
-	struct iodesc *d;
-	void *pkt;		/* the request */
+arp_reply(struct iodesc *d, void *pkt)
 {
 	struct ether_arp *arp = pkt;
 
Index: lib/libstand/bootp.h
===================================================================
--- lib/libstand/bootp.h
+++ lib/libstand/bootp.h
@@ -148,6 +148,10 @@
 /* v_flags values */
 #define VF_SMASK	1	/* Subnet mask field contains valid data */
 
+/* cached bootp response/dhcp ack */
+extern struct bootp *bootp_response;
+extern size_t bootp_response_size;
+
 int	dhcp_try_rfc1048(u_char *cp, u_int len);
 
 #endif /* _BOOTP_H_ */
Index: lib/libstand/bootp.c
===================================================================
--- lib/libstand/bootp.c
+++ lib/libstand/bootp.c
@@ -38,6 +38,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include <stddef.h>
 #include <sys/types.h>
 #include <sys/limits.h>
 #include <sys/endian.h>
@@ -72,7 +73,7 @@
 
 /* Local forwards */
 static	ssize_t bootpsend(struct iodesc *, void *, size_t);
-static	ssize_t bootprecv(struct iodesc *, void *, size_t, time_t);
+static	ssize_t bootprecv(struct iodesc *, void **, void **, time_t);
 static	int vend_rfc1048(u_char *, u_int);
 #ifdef BOOTP_VEND_CMU
 static	void vend_cmu(u_char *);
@@ -89,23 +90,21 @@
 static char expected_dhcpmsgtype = -1, dhcp_ok;
 struct in_addr dhcp_serverip;
 #endif
+struct bootp *bootp_response;
+size_t bootp_response_size;
 
 /* Fetch required bootp infomation */
 void
-bootp(sock, flag)
-	int sock;
-	int flag;
+bootp(int sock, int flag)
 {
+	void *pkt;
 	struct iodesc *d;
 	struct bootp *bp;
 	struct {
 		u_char header[HEADER_SIZE];
 		struct bootp wbootp;
 	} wbuf;
-	struct {
-		u_char header[HEADER_SIZE];
-		struct bootp rbootp;
-	} rbuf;
+	struct bootp *rbootp;
 
 #ifdef BOOTP_DEBUG
  	if (debug)
@@ -176,8 +175,7 @@
 
 	if(sendrecv(d,
 		    bootpsend, bp, sizeof(*bp),
-		    bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp))
-	   == -1) {
+		    bootprecv, &pkt, (void **)&rbootp) == -1) {
 	    printf("bootp: no reply\n");
 	    return;
 	}
@@ -188,7 +186,7 @@
 		bp->bp_vend[6] = DHCPREQUEST;
 		bp->bp_vend[7] = TAG_REQ_ADDR;
 		bp->bp_vend[8] = 4;
-		bcopy(&rbuf.rbootp.bp_yiaddr, &bp->bp_vend[9], 4);
+		bcopy(&rbootp->bp_yiaddr, &bp->bp_vend[9], 4);
 		bp->bp_vend[13] = TAG_SERVERID;
 		bp->bp_vend[14] = 4;
 		bcopy(&dhcp_serverip.s_addr, &bp->bp_vend[15], 4);
@@ -206,20 +204,21 @@
 
 		expected_dhcpmsgtype = DHCPACK;
 
+		free(pkt);
 		if(sendrecv(d,
 			    bootpsend, bp, sizeof(*bp),
-			    bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp))
-		   == -1) {
+			    bootprecv, &pkt, (void **)&rbootp) == -1) {
 			printf("DHCPREQUEST failed\n");
 			return;
 		}
 	}
 #endif
 
-	myip = d->myip = rbuf.rbootp.bp_yiaddr;
-	servip = rbuf.rbootp.bp_siaddr;
-	if(rootip.s_addr == INADDR_ANY) rootip = servip;
-	bcopy(rbuf.rbootp.bp_file, bootfile, sizeof(bootfile));
+	myip = d->myip = rbootp->bp_yiaddr;
+	servip = rbootp->bp_siaddr;
+	if (rootip.s_addr == INADDR_ANY)
+		rootip = servip;
+	bcopy(rbootp->bp_file, bootfile, sizeof(bootfile));
 	bootfile[sizeof(bootfile) - 1] = '\0';
 
 	if (!netmask) {
@@ -259,14 +258,12 @@
 
 	/* Bump xid so next request will be unique. */
 	++d->xid;
+	free(pkt);
 }
 
 /* Transmit a bootp request */
 static ssize_t
-bootpsend(d, pkt, len)
-	struct iodesc *d;
-	void *pkt;
-	size_t len;
+bootpsend(struct iodesc *d, void *pkt, size_t len)
 {
 	struct bootp *bp;
 
@@ -287,30 +284,25 @@
 }
 
 static ssize_t
-bootprecv(d, pkt, len, tleft)
-struct iodesc *d;
-void *pkt;
-size_t len;
-time_t tleft;
+bootprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft)
 {
 	ssize_t n;
 	struct bootp *bp;
+	void *ptr;
 
-#ifdef BOOTP_DEBUGx
+#ifdef BOOTP_DEBUG
 	if (debug)
 		printf("bootp_recvoffer: called\n");
 #endif
 
-	n = readudp(d, pkt, len, tleft);
+	ptr = NULL;
+	n = readudp(d, &ptr, (void **)&bp, tleft);
 	if (n == -1 || n < sizeof(struct bootp) - BOOTP_VENDSIZE)
 		goto bad;
 
-	bp = (struct bootp *)pkt;
-	
 #ifdef BOOTP_DEBUG
 	if (debug)
-		printf("bootprecv: checked.  bp = 0x%lx, n = %d\n",
-		    (long)bp, (int)n);
+		printf("bootprecv: checked.  bp = %p, n = %zd\n", bp, n);
 #endif
 	if (bp->bp_xid != htonl(d->xid)) {
 #ifdef BOOTP_DEBUG
@@ -329,8 +321,21 @@
 
 	/* Suck out vendor info */
 	if (bcmp(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)) == 0) {
-		if(vend_rfc1048(bp->bp_vend, sizeof(bp->bp_vend)) != 0)
+		int vsize = n - offsetof(struct bootp, bp_vend);
+		if (vend_rfc1048(bp->bp_vend, vsize) != 0)
 		    goto bad;
+
+		/* Save copy of bootp reply or DHCP ACK message */
+		if (bp->bp_op == BOOTREPLY &&
+		    ((dhcp_ok == 1 && expected_dhcpmsgtype == DHCPACK) ||
+		    dhcp_ok == 0)) {
+			free(bootp_response);
+			bootp_response = malloc(n);
+			if (bootp_response != NULL) {
+				bootp_response_size = n;
+				bcopy(bp, bootp_response, bootp_response_size);
+			}
+		}
 	}
 #ifdef BOOTP_VEND_CMU
 	else if (bcmp(vm_cmu, bp->bp_vend, sizeof(vm_cmu)) == 0)
@@ -339,8 +344,11 @@
 	else
 		printf("bootprecv: unknown vendor 0x%lx\n", (long)bp->bp_vend);
 
-	return(n);
+	*pkt = ptr;
+	*payload = bp;
+	return (n);
 bad:
+	free(ptr);
 	errno = 0;
 	return (-1);
 }
@@ -357,9 +365,7 @@
 }
 
 static int
-vend_rfc1048(cp, len)
-	u_char *cp;
-	u_int len;
+vend_rfc1048(u_char *cp, u_int len)
 {
 	u_char *ep;
 	int size;
@@ -450,8 +456,7 @@
 
 #ifdef BOOTP_VEND_CMU
 static void
-vend_cmu(cp)
-	u_char *cp;
+vend_cmu(u_char *cp)
 {
 	struct cmu_vend *vp;
 
Index: lib/libstand/bootparam.c
===================================================================
--- lib/libstand/bootparam.c
+++ lib/libstand/bootparam.c
@@ -104,8 +104,7 @@
  * know about us (don't want to broadcast a getport call).
  */
 int
-bp_whoami(sockfd)
-	int sockfd;
+bp_whoami(int sockfd)
 {
 	/* RPC structures for PMAPPROC_CALLIT */
 	struct args {
@@ -126,22 +125,19 @@
 		n_long	h[RPC_HEADER_WORDS];
 		struct args d;
 	} sdata;
-	struct {
-		n_long	h[RPC_HEADER_WORDS];
-		struct repl d;
-	} rdata;
 	char *send_tail, *recv_head;
 	struct iodesc *d;
-	int len, x;
+	void *pkt;
+	int len, x, rc;
 
 	RPC_PRINTF(("bp_whoami: myip=%s\n", inet_ntoa(myip)));
 
+	rc = -1;
 	if (!(d = socktodesc(sockfd))) {
 		RPC_PRINTF(("bp_whoami: bad socket. %d\n", sockfd));
-		return (-1);
+		return (rc);
 	}
 	args = &sdata.d;
-	repl = &rdata.d;
 
 	/*
 	 * Build request args for PMAPPROC_CALLIT.
@@ -156,19 +152,19 @@
 	 * append encapsulated data (client IP address)
 	 */
 	if (xdr_inaddr_encode(&send_tail, myip))
-		return (-1);
+		return (rc);
 
 	/* RPC: portmap/callit */
 	d->myport = htons(--rpc_port);
 	d->destip.s_addr = INADDR_BROADCAST;	/* XXX: subnet bcast? */
 	/* rpc_call will set d->destport */
 
+	pkt = NULL;
 	len = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT,
-				  args, send_tail - (char*)args,
-				  repl, sizeof(*repl));
+	    args, send_tail - (char*)args, (void **)&repl, &pkt);
 	if (len < 8) {
 		printf("bootparamd: 'whoami' call failed\n");
-		return (-1);
+		goto done;
 	}
 
 	/* Save bootparam server address (from IP header). */
@@ -196,7 +192,7 @@
 	x = ntohl(repl->encap_len);
 	if (len < x) {
 		printf("bp_whoami: short reply, %d < %d\n", len, x);
-		return (-1);
+		goto done;
 	}
 	recv_head = (char*) repl->capsule;
 
@@ -204,24 +200,27 @@
 	hostnamelen = MAXHOSTNAMELEN-1;
 	if (xdr_string_decode(&recv_head, hostname, &hostnamelen)) {
 		RPC_PRINTF(("bp_whoami: bad hostname\n"));
-		return (-1);
+		goto done;
 	}
 
 	/* domain name */
 	domainnamelen = MAXHOSTNAMELEN-1;
 	if (xdr_string_decode(&recv_head, domainname, &domainnamelen)) {
 		RPC_PRINTF(("bp_whoami: bad domainname\n"));
-		return (-1);
+		goto done;
 	}
 
 	/* gateway address */
 	if (xdr_inaddr_decode(&recv_head, &gateip)) {
 		RPC_PRINTF(("bp_whoami: bad gateway\n"));
-		return (-1);
+		goto done;
 	}
 
 	/* success */
-	return(0);
+	rc = 0;
+done:
+	free(pkt);
+	return (rc);
 }
 
 
@@ -233,25 +232,18 @@
  *	server pathname
  */
 int
-bp_getfile(sockfd, key, serv_addr, pathname)
-	int sockfd;
-	char *key;
-	char *pathname;
-	struct in_addr *serv_addr;
+bp_getfile(int sockfd, char *key, struct in_addr *serv_addr, char *pathname)
 {
 	struct {
 		n_long	h[RPC_HEADER_WORDS];
 		n_long  d[64];
 	} sdata;
-	struct {
-		n_long	h[RPC_HEADER_WORDS];
-		n_long  d[128];
-	} rdata;
+	void *pkt;
 	char serv_name[FNAME_SIZE];
-	char *send_tail, *recv_head;
+	char *rdata, *send_tail;
 	/* misc... */
 	struct iodesc *d;
-	int sn_len, path_len, rlen;
+	int rc = -1, sn_len, path_len, rlen;
 
 	if (!(d = socktodesc(sockfd))) {
 		RPC_PRINTF(("bp_getfile: bad socket. %d\n", sockfd));
@@ -259,7 +251,6 @@
 	}
 
 	send_tail = (char*) sdata.d;
-	recv_head = (char*) rdata.d;
 
 	/*
 	 * Build request message.
@@ -281,17 +272,16 @@
 	d->myport = htons(--rpc_port);
 	d->destip   = bp_server_addr;
 	/* rpc_call will set d->destport */
-
+	pkt = NULL;
 	rlen = rpc_call(d,
 		BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_GETFILE,
 		sdata.d, send_tail - (char*)sdata.d,
-		rdata.d, sizeof(rdata.d));
+		(void **)&rdata, &pkt);
 	if (rlen < 4) {
 		RPC_PRINTF(("bp_getfile: short reply\n"));
 		errno = EBADRPC;
-		return (-1);
+		goto done;
 	}
-	recv_head = (char*) rdata.d;
 
 	/*
 	 * Parse result message.
@@ -299,26 +289,29 @@
 
 	/* server name */
 	sn_len = FNAME_SIZE-1;
-	if (xdr_string_decode(&recv_head, serv_name, &sn_len)) {
+	if (xdr_string_decode(&rdata, serv_name, &sn_len)) {
 		RPC_PRINTF(("bp_getfile: bad server name\n"));
-		return (-1);
+		goto done;
 	}
 
 	/* server IP address (mountd/NFS) */
-	if (xdr_inaddr_decode(&recv_head, serv_addr)) {
+	if (xdr_inaddr_decode(&rdata, serv_addr)) {
 		RPC_PRINTF(("bp_getfile: bad server addr\n"));
-		return (-1);
+		goto done;
 	}
 
 	/* server pathname */
 	path_len = MAXPATHLEN-1;
-	if (xdr_string_decode(&recv_head, pathname, &path_len)) {
+	if (xdr_string_decode(&rdata, pathname, &path_len)) {
 		RPC_PRINTF(("bp_getfile: bad server path\n"));
-		return (-1);
+		goto done;
 	}
 
 	/* success */
-	return(0);
+	rc = 0;
+done:
+	free(pkt);
+	return (rc);
 }
 
 
@@ -329,17 +322,14 @@
 
 
 int
-xdr_string_encode(pkt, str, len)
-	char **pkt;
-	char *str;
-	int len;
+xdr_string_encode(char **pkt, char *str, int len)
 {
-	u_int32_t *lenp;
+	uint32_t *lenp;
 	char *datap;
 	int padlen = (len + 3) & ~3;	/* padded length */
 
 	/* The data will be int aligned. */
-	lenp = (u_int32_t*) *pkt;
+	lenp = (uint32_t *) *pkt;
 	*pkt += sizeof(*lenp);
 	*lenp = htonl(len);
 
@@ -351,18 +341,15 @@
 }
 
 int
-xdr_string_decode(pkt, str, len_p)
-	char **pkt;
-	char *str;
-	int *len_p;		/* bufsize - 1 */
+xdr_string_decode(char **pkt, char *str, int *len_p)
 {
-	u_int32_t *lenp;
+	uint32_t *lenp;
 	char *datap;
 	int slen;	/* string length */
 	int plen;	/* padded length */
 
 	/* The data will be int aligned. */
-	lenp = (u_int32_t*) *pkt;
+	lenp = (uint32_t *) *pkt;
 	*pkt += sizeof(*lenp);
 	slen = ntohl(*lenp);
 	plen = (slen + 3) & ~3;
@@ -381,9 +368,7 @@
 
 
 int
-xdr_inaddr_encode(pkt, ia)
-	char **pkt;
-	struct in_addr ia;		/* network order */
+xdr_inaddr_encode(char **pkt, struct in_addr ia)
 {
 	struct xdr_inaddr *xi;
 	u_char *cp;
@@ -414,9 +399,7 @@
 }
 
 int
-xdr_inaddr_decode(pkt, ia)
-	char **pkt;
-	struct in_addr *ia;		/* network order */
+xdr_inaddr_decode(char **pkt, struct in_addr *ia)
 {
 	struct xdr_inaddr *xi;
 	u_char *cp;
Index: lib/libstand/ether.c
===================================================================
--- lib/libstand/ether.c
+++ lib/libstand/ether.c
@@ -54,12 +54,7 @@
 
 /* Caller must leave room for ethernet header in front!! */
 ssize_t
-sendether(d, pkt, len, dea, etype)
-	struct iodesc *d;
-	void *pkt;
-	size_t len;
-	u_char *dea;
-	int etype;
+sendether(struct iodesc *d, void *pkt, size_t len, uint8_t *dea, int etype)
 {
 	ssize_t n;
 	struct ether_header *eh;
@@ -86,32 +81,31 @@
 
 /*
  * Get a packet of any Ethernet type, with our address or
- * the broadcast address.  Save the Ether type in arg 5.
- * NOTE: Caller must leave room for the Ether header.
+ * the broadcast address.  Save the Ether type in etype.
+ * Unless there is an error, we pass the whole packet and the unencapsulated
+ * data.
  */
 ssize_t
-readether(d, pkt, len, tleft, etype)
-	struct iodesc *d;
-	void *pkt;
-	size_t len;
-	time_t tleft;
-	u_int16_t *etype;
+readether(struct iodesc *d, void **pkt, void **payload, time_t tleft,
+    uint16_t *etype)
 {
 	ssize_t n;
 	struct ether_header *eh;
+	void *ptr;
 
 #ifdef ETHER_DEBUG
  	if (debug)
 		printf("readether: called\n");
 #endif
 
-	eh = (struct ether_header *)pkt - 1;
-	len += sizeof(*eh);
-
-	n = netif_get(d, eh, len, tleft);
-	if (n == -1 || n < sizeof(*eh))
+	ptr = NULL;
+	n = netif_get(d, &ptr, tleft);
+	if (n == -1 || n < sizeof(*eh)) {
+		free(ptr);
 		return (-1);
+	}
 
+	eh = (struct ether_header *)((uintptr_t)ptr + 2);
 	/* Validate Ethernet address. */
 	if (bcmp(d->myea, eh->ether_dhost, 6) != 0 &&
 	    bcmp(bcea, eh->ether_dhost, 6) != 0) {
@@ -120,8 +114,12 @@
 			printf("readether: not ours (ea=%s)\n",
 			    ether_sprintf(eh->ether_dhost));
 #endif
+		free(ptr);
 		return (-1);
 	}
+
+	*pkt = ptr;
+	*payload = (void *)((uintptr_t)eh + sizeof(*eh));
 	*etype = ntohs(eh->ether_type);
 
 	n -= sizeof(*eh);
@@ -133,8 +131,7 @@
  */
 static char digits[] = "0123456789abcdef";
 char *
-ether_sprintf(ap)
-        u_char *ap;
+ether_sprintf(u_char *ap)
 {
 	int i;
 	static char etherbuf[18];
Index: lib/libstand/net.h
===================================================================
--- lib/libstand/net.h
+++ lib/libstand/net.h
@@ -107,16 +107,15 @@
 /* Link functions: */
 ssize_t sendether(struct iodesc *d, void *pkt, size_t len,
 			u_char *dea, int etype);
-ssize_t readether(struct iodesc *d, void *pkt, size_t len,
-			time_t tleft, u_int16_t *etype);
+ssize_t readether(struct iodesc *, void **, void **, time_t, uint16_t *);
 
 ssize_t	sendudp(struct iodesc *, void *, size_t);
-ssize_t	readudp(struct iodesc *, void *, size_t, time_t);
+ssize_t	readudp(struct iodesc *, void **, void **, time_t);
 ssize_t	sendrecv(struct iodesc *,
-		      ssize_t (*)(struct iodesc *, void *, size_t),
+			ssize_t (*)(struct iodesc *, void *, size_t),
 			void *, size_t,
-		        ssize_t (*)(struct iodesc *, void *, size_t, time_t),
-			void *, size_t);
+			ssize_t (*)(struct iodesc *, void **, void **, time_t),
+			void **, void **);
 
 /* bootp/DHCP */
 void	bootp(int, int);
Index: lib/libstand/net.c
===================================================================
--- lib/libstand/net.c
+++ lib/libstand/net.c
@@ -70,10 +70,10 @@
  */
 ssize_t
 sendrecv(struct iodesc *d,
-	ssize_t (*sproc)(struct iodesc *, void *, size_t),
-	void *sbuf, size_t ssize,
-	ssize_t (*rproc)(struct iodesc *, void *, size_t, time_t),
-	void *rbuf, size_t rsize)
+    ssize_t (*sproc)(struct iodesc *, void *, size_t),
+    void *sbuf, size_t ssize,
+    ssize_t (*rproc)(struct iodesc *, void **, void **, time_t),
+    void **pkt, void **payload)
 {
 	ssize_t cc;
 	time_t t, tmo, tlast;
@@ -116,7 +116,7 @@
 		}
 
 		/* Try to get a packet and process it. */
-		cc = (*rproc)(d, rbuf, rsize, tleft);
+		cc = (*rproc)(d, pkt, payload, tleft);
 		/* Return on data, EOF or real error. */
 		if (cc != -1 || errno != 0)
 			return (cc);
Index: lib/libstand/netif.h
===================================================================
--- lib/libstand/netif.h
+++ lib/libstand/netif.h
@@ -6,15 +6,13 @@
 #define __SYS_LIBNETBOOT_NETIF_H
 #include "iodesc.h"
 
-#define NENTS(x)	sizeof(x)/sizeof(x[0])
-
 struct netif_driver {
 	const	char *netif_bname;
 	int	(*netif_match)(struct netif *, void *);
 	int	(*netif_probe)(struct netif *, void *);
 	void	(*netif_init)(struct iodesc *, void *);
-	int	(*netif_get)(struct iodesc *, void *, size_t, time_t);
-	int	(*netif_put)(struct iodesc *, void *, size_t);
+	ssize_t	(*netif_get)(struct iodesc *, void **, time_t);
+	ssize_t	(*netif_put)(struct iodesc *, void *, size_t);
 	void	(*netif_end)(struct netif *);
 	struct	netif_dif *netif_ifs;
 	int	netif_nifs;
@@ -56,7 +54,7 @@
 int		netif_probe(struct netif *, void *);
 void		netif_attach(struct netif *, struct iodesc *, void *);
 void		netif_detach(struct netif *);
-ssize_t		netif_get(struct iodesc *, void *, size_t, time_t);
+ssize_t		netif_get(struct iodesc *, void **, time_t);
 ssize_t		netif_put(struct iodesc *, void *, size_t);
 
 int		netif_open(void *);
Index: lib/libstand/netif.c
===================================================================
--- lib/libstand/netif.c
+++ lib/libstand/netif.c
@@ -59,7 +59,7 @@
  */
 
 void
-netif_init()
+netif_init(void)
 {
 	struct netif_driver *drv;
 	int d, i;
@@ -76,13 +76,11 @@
 }
 
 int
-netif_match(nif, machdep_hint)
-	struct netif *nif;
-	void *machdep_hint;
+netif_match(struct netif *nif, void *machdep_hint)
 {
 	struct netif_driver *drv = nif->nif_driver;
 
-#if 0
+#if NETIF_DEBUG
 	if (netif_debug)
 		printf("%s%d: netif_match (%d)\n", drv->netif_bname,
 		    nif->nif_unit, nif->nif_sel);
@@ -91,8 +89,7 @@
 }
 
 struct netif *
-netif_select(machdep_hint)
-	void *machdep_hint;
+netif_select(void *machdep_hint)
 {
 	int d, u, unit_done, s;
 	struct netif_driver *drv;
@@ -162,9 +159,7 @@
 }
 
 int
-netif_probe(nif, machdep_hint)
-	struct netif *nif;
-	void *machdep_hint;
+netif_probe(struct netif *nif, void *machdep_hint)
 {
 	struct netif_driver *drv = nif->nif_driver;
 
@@ -176,10 +171,7 @@
 }
 
 void
-netif_attach(nif, desc, machdep_hint)
-	struct netif *nif;
-	struct iodesc *desc;
-	void *machdep_hint;
+netif_attach(struct netif *nif, struct iodesc *desc, void *machdep_hint)
 {
 	struct netif_driver *drv = nif->nif_driver;
 
@@ -199,8 +191,7 @@
 }
 
 void
-netif_detach(nif)
-	struct netif *nif;
+netif_detach(struct netif *nif)
 {
 	struct netif_driver *drv = nif->nif_driver;
 
@@ -217,11 +208,7 @@
 }
 
 ssize_t
-netif_get(desc, pkt, len, timo)
-	struct iodesc *desc;
-	void *pkt;
-	size_t len;
-	time_t timo;
+netif_get(struct iodesc *desc, void **pkt, time_t timo)
 {
 #ifdef NETIF_DEBUG
 	struct netif *nif = desc->io_netif;
@@ -238,20 +225,17 @@
 		panic("%s%d: no netif_get support\n", drv->netif_bname,
 		    nif->nif_unit);
 #endif
-	rv = drv->netif_get(desc, pkt, len, timo);
+	rv = drv->netif_get(desc, pkt, timo);
 #ifdef NETIF_DEBUG
 	if (netif_debug)
 		printf("%s%d: netif_get returning %d\n", drv->netif_bname,
 		    nif->nif_unit, (int)rv);
 #endif
-	return rv;
+	return (rv);
 }
 
 ssize_t
-netif_put(desc, pkt, len)
-	struct iodesc *desc;
-	void *pkt;
-	size_t len;
+netif_put(struct iodesc *desc, void *pkt, size_t len)
 {
 #ifdef NETIF_DEBUG
 	struct netif *nif = desc->io_netif;
@@ -274,12 +258,11 @@
 		printf("%s%d: netif_put returning %d\n", drv->netif_bname,
 		    nif->nif_unit, (int)rv);
 #endif
-	return rv;
+	return (rv);
 }
 
 struct iodesc *
-socktodesc(sock)
-	int sock;
+socktodesc(int sock)
 {
 	if (sock >= SOPEN_MAX) {
 		errno = EBADF;
@@ -289,8 +272,7 @@
 }
 
 int
-netif_open(machdep_hint)
-	void *machdep_hint;
+netif_open(void *machdep_hint)
 {
 	int fd;
 	struct iodesc *s;
@@ -313,23 +295,22 @@
 		printf("netboot: couldn't probe %s%d\n",
 		    nif->nif_driver->netif_bname, nif->nif_unit);
 		errno = EINVAL;
-		return(-1);
+		return (-1);
 	}
 	netif_attach(nif, s, machdep_hint);
 
-	return(fd);
+	return (fd);
 }
 
 int
-netif_close(sock)
-	int sock;
+netif_close(int sock)
 {
 	if (sock >= SOPEN_MAX) {
 		errno = EBADF;
-		return(-1);
+		return (-1);
 	}
 	netif_detach(sockets[sock].io_netif);
 	sockets[sock].io_netif = (struct netif *)0;
 
-	return(0);
+	return (0);
 }
Index: lib/libstand/nfs.c
===================================================================
--- lib/libstand/nfs.c
+++ lib/libstand/nfs.c
@@ -185,6 +185,7 @@
 int
 nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp)
 {
+	void *pkt = NULL;
 	int len;
 	struct args {
 		uint32_t len;
@@ -201,10 +202,6 @@
 		uint32_t h[RPC_HEADER_WORDS];
 		struct args d;
 	} sdata;
-	struct {
-		uint32_t h[RPC_HEADER_WORDS];
-		struct repl d;
-	} rdata;
 	size_t cc;
 
 #ifdef NFS_DEBUG
@@ -213,7 +210,6 @@
 #endif
 
 	args = &sdata.d;
-	repl = &rdata.d;
 
 	bzero(args, sizeof(*args));
 	len = strlen(path);
@@ -224,18 +220,25 @@
 	len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t));
 
 	cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT,
-	    args, len, repl, sizeof(*repl));
-	if (cc == -1)
+	    args, len, (void **)&repl, &pkt);
+	if (cc == -1) {
+		free(pkt);
 		/* errno was set by rpc_call */
 		return (errno);
-	if (cc < 2 * sizeof (uint32_t))
+	}
+	if (cc < 2 * sizeof (uint32_t)) {
+		free(pkt);
 		return (EBADRPC);
-	if (repl->errno != 0)
+	}
+	if (repl->errno != 0) {
+		free(pkt);
 		return (ntohl(repl->errno));
+	}
 	*fhlenp = ntohl(repl->fhsize);
 	bcopy(repl->fh, fhp, *fhlenp);
 
 	set_nfs_read_size();
+	free(pkt);
 	return (0);
 }
 
@@ -246,6 +249,7 @@
 int
 nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
 {
+	void *pkt = NULL;
 	int len, rlen, pos;
 	struct args {
 		uint32_t fhsize;
@@ -263,10 +267,6 @@
 		uint32_t h[RPC_HEADER_WORDS];
 		struct args d;
 	} sdata;
-	struct {
-		uint32_t h[RPC_HEADER_WORDS];
-		struct repl d;
-	} rdata;
 	ssize_t cc;
 
 #ifdef NFS_DEBUG
@@ -275,7 +275,6 @@
 #endif
 
 	args = &sdata.d;
-	repl = &rdata.d;
 
 	bzero(args, sizeof(*args));
 	args->fhsize = htonl(d->fhsize);
@@ -289,23 +288,30 @@
 	len = sizeof(uint32_t) + pos * sizeof(uint32_t) +
 	    roundup(len, sizeof(uint32_t));
 
-	rlen = sizeof(*repl);
-
 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP,
-	    args, len, repl, rlen);
-	if (cc == -1)
+	    args, len, (void **)&repl, &pkt);
+	if (cc == -1) {
+		free(pkt);
 		return (errno);		/* XXX - from rpc_call */
-	if (cc < 2 * sizeof(uint32_t))
+	}
+	if (cc < 2 * sizeof(uint32_t)) {
+		free(pkt);
 		return (EIO);
-	if (repl->errno != 0)
+	}
+	if (repl->errno != 0) {
+		free(pkt);
 		/* saerrno.h now matches NFS error numbers. */
 		return (ntohl(repl->errno));
+	}
 	newfd->fhsize = ntohl(repl->fhsize);
 	bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize);
 	pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
-	if (repl->fhplusattr[pos++] == 0)
+	if (repl->fhplusattr[pos++] == 0) {
+		free(pkt);
 		return (EIO);
+	}
 	bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa));
+	free(pkt);
 	return (0);
 }
 
@@ -316,6 +322,7 @@
 int
 nfs_readlink(struct nfs_iodesc *d, char *buf)
 {
+	void *pkt = NULL;
 	struct args {
 		uint32_t fhsize;
 		u_char fh[NFS_V3MAXFHSIZE];
@@ -331,11 +338,8 @@
 		uint32_t h[RPC_HEADER_WORDS];
 		struct args d;
 	} sdata;
-	struct {
-		uint32_t h[RPC_HEADER_WORDS];
-		struct repl d;
-	} rdata;
 	ssize_t cc;
+	int rc = 0;
 
 #ifdef NFS_DEBUG
 	if (debug)
@@ -343,32 +347,41 @@
 #endif
 
 	args = &sdata.d;
-	repl = &rdata.d;
 
 	bzero(args, sizeof(*args));
 	args->fhsize = htonl(d->fhsize);
 	bcopy(d->fh, args->fh, d->fhsize);
 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK,
 	    args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
-	    repl, sizeof(*repl));
+	    (void **)&repl, &pkt);
 	if (cc == -1)
 		return (errno);
 
-	if (cc < 2 * sizeof(uint32_t))
-		return (EIO);
+	if (cc < 2 * sizeof(uint32_t)) {
+		rc = EIO;
+		goto done;
+	}
 
-	if (repl->errno != 0)
-		return (ntohl(repl->errno));
+	if (repl->errno != 0) {
+		rc = ntohl(repl->errno);
+		goto done;
+	}
 
-	if (repl->ok == 0)
-		return (EIO);
+	if (repl->ok == 0) {
+		rc = EIO;
+		goto done;
+	}
 
 	repl->len = ntohl(repl->len);
-	if (repl->len > NFS_MAXPATHLEN)
-		return (ENAMETOOLONG);
+	if (repl->len > NFS_MAXPATHLEN) {
+		rc = ENAMETOOLONG;
+		goto done;
+	}
 
 	bcopy(repl->path, buf, repl->len);
 	buf[repl->len] = 0;
+done:
+	free(pkt);
 	return (0);
 }
 #endif
@@ -380,6 +393,7 @@
 ssize_t
 nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
 {
+	void *pkt = NULL;
 	struct args {
 		uint32_t fhsize;
 		uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3];
@@ -397,16 +411,11 @@
 		uint32_t h[RPC_HEADER_WORDS];
 		struct args d;
 	} sdata;
-	struct {
-		uint32_t h[RPC_HEADER_WORDS];
-		struct repl d;
-	} rdata;
 	size_t cc;
 	long x;
 	int hlen, rlen, pos;
 
 	args = &sdata.d;
-	repl = &rdata.d;
 
 	bzero(args, sizeof(*args));
 	args->fhsize = htonl(d->fhsize);
@@ -421,16 +430,19 @@
 
 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ,
 	    args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
-	    repl, sizeof(*repl));
-	if (cc == -1)
+	    (void **)&repl, &pkt);
+	if (cc == -1) {
 		/* errno was already set by rpc_call */
 		return (-1);
+	}
 	if (cc < hlen) {
 		errno = EBADRPC;
+		free(pkt);
 		return (-1);
 	}
 	if (repl->errno != 0) {
 		errno = ntohl(repl->errno);
+		free(pkt);
 		return (-1);
 	}
 	rlen = cc - hlen;
@@ -438,9 +450,11 @@
 	if (rlen < x) {
 		printf("nfsread: short packet, %d < %ld\n", rlen, x);
 		errno = EBADRPC;
+		free(pkt);
 		return (-1);
 	}
 	bcopy(repl->data, addr, x);
+	free(pkt);
 	return (x);
 }
 
@@ -481,17 +495,8 @@
 		return (ENXIO);
 	}
 
-	/*
-	 * This is silly - we should look at dv_type but that value is
-	 * arch dependant and we can't use it here.
-	 */
-#ifndef __i386__
-	if (strcmp(f->f_dev->dv_name, "net") != 0)
-		return (EINVAL);
-#else
-	if (strcmp(f->f_dev->dv_name, "pxe") != 0)
+	if (f->f_dev->dv_type != DEVT_NET)
 		return (EINVAL);
-#endif
 
 	if (!(desc = socktodesc(*(int *)(f->f_devdata))))
 		return (EINVAL);
@@ -660,9 +665,8 @@
 		printf("nfs_close: fp=0x%lx\n", (u_long)fp);
 #endif
 
-	if (fp)
-		free(fp);
-	f->f_fsdata = (void *)0;
+	free(fp);
+	f->f_fsdata = NULL;
 
 	return (0);
 }
@@ -773,11 +777,12 @@
 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
 	struct nfsv3_readdir_repl *repl;
 	struct nfsv3_readdir_entry *rent;
+	static void *pkt = NULL;
 	static char *buf;
 	static struct nfs_iodesc *pfp = NULL;
 	static uint64_t cookie = 0;
 	size_t cc;
-	int pos;
+	int pos, rc;
 
 	struct args {
 		uint32_t fhsize;
@@ -787,14 +792,12 @@
 		uint32_t h[RPC_HEADER_WORDS];
 		struct args d;
 	} sdata;
-	static struct {
-		uint32_t h[RPC_HEADER_WORDS];
-		u_char d[NFS_READDIRSIZE];
-	} rdata;
 
 	if (fp != pfp || fp->off != cookie) {
 		pfp = NULL;
 	refill:
+		free(pkt);
+		pkt = NULL;
 		args = &sdata.d;
 		bzero(args, sizeof(*args));
 
@@ -810,11 +813,16 @@
 		cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR,
 		    args, 6 * sizeof(uint32_t) +
 		    roundup(fp->fhsize, sizeof(uint32_t)),
-		    rdata.d, sizeof(rdata.d));
-		buf  = rdata.d;
+		    (void **)&buf, &pkt);
+		if (cc == -1) {
+			rc = errno;
+			goto err;
+		}
 		repl = (struct nfsv3_readdir_repl *)buf;
-		if (repl->errno != 0)
-			return (ntohl(repl->errno));
+		if (repl->errno != 0) {
+			rc = ntohl(repl->errno);
+			goto err;
+		}
 		pfp = fp;
 		cookie = fp->off;
 		fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) |
@@ -826,8 +834,8 @@
 	if (rent->follows == 0) {
 		/* fid0 is actually eof */
 		if (rent->fid0 != 0) {
-			cookie = 0;
-			return (ENOENT);
+			rc = ENOENT
+			goto err;
 		}
 		goto refill;
 	}
@@ -842,4 +850,11 @@
 	pos += 2;
 	buf = (u_char *)&rent->nameplus[pos];
 	return (0);
+
+err:
+	free(pkt);
+	pkt = NULL;
+	pfp = NULL;
+	cookie = 0;
+	return (rc);
 }
Index: lib/libstand/rarp.c
===================================================================
--- lib/libstand/rarp.c
+++ lib/libstand/rarp.c
@@ -54,17 +54,17 @@
 
 
 static ssize_t rarpsend(struct iodesc *, void *, size_t);
-static ssize_t rarprecv(struct iodesc *, void *, size_t, time_t);
+static ssize_t rarprecv(struct iodesc *, void **, void **, time_t);
 
 /*
  * Ethernet (Reverse) Address Resolution Protocol (see RFC 903, and 826).
  */
 int
-rarp_getipaddress(sock)
-	int sock;
+rarp_getipaddress(int sock)
 {
 	struct iodesc *d;
 	struct ether_arp *ap;
+	void *pkt;
 	struct {
 		u_char header[ETHER_SIZE];
 		struct {
@@ -72,13 +72,6 @@
 			u_char pad[18]; 	/* 60 - sizeof(arp) */
 		} data;
 	} wbuf;
-	struct {
-		u_char header[ETHER_SIZE];
-		struct {
-			struct ether_arp arp;
-			u_char pad[24]; 	/* extra space */
-		} data;
-	} rbuf;
 
 #ifdef RARP_DEBUG
  	if (debug)
@@ -102,21 +95,21 @@
 	ap->arp_op = htons(ARPOP_REVREQUEST);
 	bcopy(d->myea, ap->arp_sha, 6);
 	bcopy(d->myea, ap->arp_tha, 6);
+	pkt = NULL;
 
 	if (sendrecv(d,
 	    rarpsend, &wbuf.data, sizeof(wbuf.data),
-	    rarprecv, &rbuf.data, sizeof(rbuf.data)) < 0)
-	{
+	    rarprecv, &pkt, (void *)&ap) < 0) {
 		printf("No response for RARP request\n");
 		return (-1);
 	}
 
-	ap = &rbuf.data.arp;
 	bcopy(ap->arp_tpa, (char *)&myip, sizeof(myip));
 #if 0
 	/* XXX - Can NOT assume this is our root server! */
 	bcopy(ap->arp_spa, (char *)&rootip, sizeof(rootip));
 #endif
+	free(pkt);
 
 	/* Compute our "natural" netmask. */
 	if (IN_CLASSA(myip.s_addr))
@@ -134,10 +127,7 @@
  * Broadcast a RARP request (i.e. who knows who I am)
  */
 static ssize_t
-rarpsend(d, pkt, len)
-	struct iodesc *d;
-	void *pkt;
-	size_t len;
+rarpsend(struct iodesc *d, void *pkt, size_t len)
 {
 
 #ifdef RARP_DEBUG
@@ -153,28 +143,26 @@
  * else -1 (and errno == 0)
  */
 static ssize_t
-rarprecv(d, pkt, len, tleft)
-	struct iodesc *d;
-	void *pkt;
-	size_t len;
-	time_t tleft;
+rarprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft)
 {
 	ssize_t n;
 	struct ether_arp *ap;
-	u_int16_t etype;	/* host order */
+	void *ptr = NULL;
+	uint16_t etype;		/* host order */
 
 #ifdef RARP_DEBUG
  	if (debug)
 		printf("rarprecv: ");
 #endif
 
-	n = readether(d, pkt, len, tleft, &etype);
+	n = readether(d, ptr, (void **)&ap, tleft, &etype);
 	errno = 0;	/* XXX */
 	if (n == -1 || n < sizeof(struct ether_arp)) {
 #ifdef RARP_DEBUG
 		if (debug)
 			printf("bad len=%d\n", n);
 #endif
+		free(ptr);
 		return (-1);
 	}
 
@@ -183,10 +171,10 @@
 		if (debug)
 			printf("bad type=0x%x\n", etype);
 #endif
+		free(ptr);
 		return (-1);
 	}
 
-	ap = (struct ether_arp *)pkt;
 	if (ap->arp_hrd != htons(ARPHRD_ETHER) ||
 	    ap->arp_pro != htons(ETHERTYPE_IP) ||
 	    ap->arp_hln != sizeof(ap->arp_sha) ||
@@ -196,6 +184,7 @@
 		if (debug)
 			printf("bad hrd/pro/hln/pln\n");
 #endif
+		free(ptr);
 		return (-1);
 	}
 
@@ -204,6 +193,7 @@
 		if (debug)
 			printf("bad op=0x%x\n", ntohs(ap->arp_op));
 #endif
+		free(ptr);
 		return (-1);
 	}
 
@@ -213,6 +203,7 @@
 		if (debug)
 			printf("unwanted address\n");
 #endif
+		free(ptr);
 		return (-1);
 	}
 
@@ -221,5 +212,7 @@
  	if (debug)
 		printf("got it\n");
 #endif
+	*pkt = ptr;
+	*payload = ap;
 	return (n);
 }
Index: lib/libstand/rpc.h
===================================================================
--- lib/libstand/rpc.h
+++ lib/libstand/rpc.h
@@ -48,7 +48,7 @@
 
 /* RPC functions: */
 ssize_t	rpc_call(struct iodesc *, n_long, n_long, n_long,
-		     void *, size_t, void *, size_t);
+		     void *, size_t, void **, void **);
 void	rpc_fromaddr(void *, struct in_addr *, u_short *);
 int	rpc_pmap_getcache(struct in_addr, u_int, u_int);
 void	rpc_pmap_putcache(struct in_addr, u_int, u_int, int);
Index: lib/libstand/rpc.c
===================================================================
--- lib/libstand/rpc.c
+++ lib/libstand/rpc.c
@@ -97,7 +97,7 @@
 };
 
 /* Local forwards */
-static	ssize_t recvrpc(struct iodesc *, void *, size_t, time_t);
+static	ssize_t recvrpc(struct iodesc *, void **, void **, time_t);
 static	int rpc_getport(struct iodesc *, n_long, n_long);
 
 int rpc_xid;
@@ -109,14 +109,14 @@
  */
 ssize_t
 rpc_call(struct iodesc *d, n_long prog, n_long vers, n_long proc,
-	void *sdata, size_t slen, void *rdata, size_t rlen)
+	void *sdata, size_t slen, void **rdata, void **pkt)
 {
-	ssize_t cc;
+	ssize_t cc, rsize;
 	struct auth_info *auth;
 	struct rpc_call *call;
 	struct rpc_reply *reply;
 	char *send_head, *send_tail;
-	char *recv_head, *recv_tail;
+	void *ptr;
 	n_long x;
 	int port;	/* host order */
 
@@ -145,7 +145,6 @@
 	auth->authtype = htonl(RPCAUTH_NULL);
 	auth->authlen = 0;
 
-#if 1
 	/* Auth credentials: always auth unix (as root) */
 	send_head -= sizeof(struct auth_unix);
 	bzero(send_head, sizeof(struct auth_unix));
@@ -153,13 +152,6 @@
 	auth = (struct auth_info *)send_head;
 	auth->authtype = htonl(RPCAUTH_UNIX);
 	auth->authlen = htonl(sizeof(struct auth_unix));
-#else
-	/* Auth credentials: always auth_null (XXX OK?) */
-	send_head -= sizeof(*auth);
-	auth = send_head;
-	auth->authtype = htonl(RPCAUTH_NULL);
-	auth->authlen = 0;
-#endif
 
 	/* RPC call structure. */
 	send_head -= sizeof(*call);
@@ -172,34 +164,28 @@
 	call->rp_vers = htonl(vers);
 	call->rp_proc = htonl(proc);
 
-	/* Make room for the rpc_reply header. */
-	recv_head = rdata;
-	recv_tail = (char *)rdata + rlen;
-	recv_head -= sizeof(*reply);
-
+	ptr = NULL;
 	cc = sendrecv(d,
 	    sendudp, send_head, send_tail - send_head,
-	    recvrpc, recv_head, recv_tail - recv_head);
+	    recvrpc, &ptr, (void **)&reply);
 
 #ifdef RPC_DEBUG
 	if (debug)
-		printf("callrpc: cc=%ld rlen=%lu\n", (long)cc, (u_long)rlen);
+		printf("callrpc: cc=%zd\n", cc);
 #endif
 	if (cc == -1)
 		return (-1);
 
 	if (cc <= sizeof(*reply)) {
 		errno = EBADRPC;
+		free(ptr);
 		return (-1);
 	}
 
-	recv_tail = recv_head + cc;
-
 	/*
 	 * Check the RPC reply status.
 	 * The xid, dir, astatus were already checked.
 	 */
-	reply = (struct rpc_reply *)recv_head;
 	auth = &reply->rp_u.rpu_rok.rok_auth;
 	x = ntohl(auth->authlen);
 	if (x != 0) {
@@ -208,17 +194,21 @@
 			printf("callrpc: reply auth != NULL\n");
 #endif
 		errno = EBADRPC;
-		return(-1);
+		free(ptr);
+		return (-1);
 	}
 	x = ntohl(reply->rp_u.rpu_rok.rok_status);
 	if (x != 0) {
 		printf("callrpc: error = %ld\n", (long)x);
 		errno = EBADRPC;
-		return(-1);
+		free(ptr);
+		return (-1);
 	}
-	recv_head += sizeof(*reply);
 
-	return (ssize_t)(recv_tail - recv_head);
+	rsize = cc - sizeof(*reply);
+	*rdata = (void *)((uintptr_t)reply + sizeof(*reply));
+	*pkt = ptr;
+	return (rsize);
 }
 
 /*
@@ -227,8 +217,9 @@
  * Remaining checks are done by callrpc
  */
 static ssize_t
-recvrpc(struct iodesc *d, void *pkt, size_t len, time_t tleft)
+recvrpc(struct iodesc *d, void **pkt, void **payload, time_t tleft)
 {
+	void *ptr;
 	struct rpc_reply *reply;
 	ssize_t	n;
 	int	x;
@@ -236,14 +227,15 @@
 	errno = 0;
 #ifdef RPC_DEBUG
 	if (debug)
-		printf("recvrpc: called len=%lu\n", (u_long)len);
+		printf("recvrpc: called\n");
 #endif
 
-	n = readudp(d, pkt, len, tleft);
-	if (n <= (4 * 4))
-		return -1;
-
-	reply = (struct rpc_reply *)pkt;
+	ptr = NULL;
+	n = readudp(d, &ptr, (void **)&reply, tleft);
+	if (n <= (4 * 4)) {
+		free(ptr);
+		return (-1);
+	}
 
 	x = ntohl(reply->rp_xid);
 	if (x != rpc_xid) {
@@ -251,7 +243,8 @@
 		if (debug)
 			printf("recvrpc: rp_xid %d != xid %d\n", x, rpc_xid);
 #endif
-		return -1;
+		free(ptr);
+		return (-1);
 	}
 
 	x = ntohl(reply->rp_direction);
@@ -260,16 +253,20 @@
 		if (debug)
 			printf("recvrpc: rp_direction %d != REPLY\n", x);
 #endif
-		return -1;
+		free(ptr);
+		return (-1);
 	}
 
 	x = ntohl(reply->rp_astatus);
 	if (x != RPC_MSGACCEPTED) {
 		errno = ntohl(reply->rp_u.rpu_errno);
 		printf("recvrpc: reject, astat=%d, errno=%d\n", x, errno);
-		return -1;
+		free(ptr);
+		return (-1);
 	}
 
+	*pkt = ptr;
+	*payload = reply;
 	/* Return data count (thus indicating success) */
 	return (n);
 }
@@ -387,11 +384,7 @@
 		n_long	h[RPC_HEADER_WORDS];
 		struct args d;
 	} sdata;
-	struct {
-		n_long	h[RPC_HEADER_WORDS];
-		struct res d;
-		n_long  pad;
-	} rdata;
+	void *pkt;
 	ssize_t cc;
 	int port;
 
@@ -416,16 +409,18 @@
 	args->vers = htonl(vers);
 	args->proto = htonl(IPPROTO_UDP);
 	args->port = 0;
-	res = &rdata.d;
+	pkt = NULL;
 
 	cc = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT,
-		args, sizeof(*args), res, sizeof(*res));
+	    args, sizeof(*args), (void **)&res, &pkt);
 	if (cc < sizeof(*res)) {
 		printf("getport: %s", strerror(errno));
 		errno = EBADRPC;
+		free(pkt);
 		return (-1);
 	}
 	port = (int)ntohl(res->port);
+	free(pkt);
 
 	rpc_pmap_putcache(d->destip, prog, vers, port);
 
Index: lib/libstand/tftp.c
===================================================================
--- lib/libstand/tftp.c
+++ lib/libstand/tftp.c
@@ -73,8 +73,8 @@
 static ssize_t sendrecv_tftp(struct tftp_handle *h,
     ssize_t (*sproc)(struct iodesc *, void *, size_t),
     void *sbuf, size_t ssize,
-    ssize_t (*rproc)(struct tftp_handle *h, void *, ssize_t, time_t, unsigned short *),
-    void *rbuf, size_t rsize, unsigned short *rtype);
+    ssize_t (*rproc)(struct tftp_handle *h, void **, void **, time_t, unsigned short *),
+    void **, void **, unsigned short *rtype);
 
 struct fs_ops tftp_fsops = {
 	"tftp",
@@ -114,11 +114,8 @@
 	char           *path;	/* saved for re-requests */
 	unsigned int	tftp_blksize;
 	unsigned long	tftp_tsize;
-	struct {
-		u_char header[HEADER_SIZE];
-		struct tftphdr t;
-		u_char space[TFTP_MAX_BLKSIZE];
-	} __packed __aligned(4) lastdata;
+	void		*pkt;
+	struct tftphdr	*tftp_hdr;
 };
 
 #define	TFTP_MAX_ERRCODE EOPTNEG
@@ -181,20 +178,23 @@
 }
 
 static ssize_t
-recvtftp(struct tftp_handle *h, void *pkt, ssize_t len, time_t tleft,
+recvtftp(struct tftp_handle *h, void **pkt, void **payload, time_t tleft,
     unsigned short *rtype)
 {
 	struct iodesc *d = h->iodesc;
 	struct tftphdr *t;
+	void *ptr = NULL;
+	ssize_t len;
 
 	errno = 0;
 
-	len = readudp(d, pkt, len, tleft);
+	len = readudp(d, &ptr, (void **)&t, tleft);
 
-	if (len < 4)
+	if (len < 4) {
+		free(ptr);
 		return (-1);
+	}
 
-	t = (struct tftphdr *) pkt;
 	*rtype = ntohs(t->th_opcode);
 	switch (ntohs(t->th_opcode)) {
 	case DATA: {
@@ -204,6 +204,7 @@
 			/*
 			 * Expected block?
 			 */
+			free(ptr);
 			return (-1);
 		}
 		if (d->xid == 1) {
@@ -211,11 +212,13 @@
 			 * First data packet from new port.
 			 */
 			struct udphdr *uh;
-			uh = (struct udphdr *) pkt - 1;
+			uh = (struct udphdr *) t - 1;
 			d->destport = uh->uh_sport;
 		} /* else check uh_sport has not changed??? */
-		got = len - (t->th_data - (char *) t);
-		return got;
+		got = len - (t->th_data - (char *)t);
+		*pkt = ptr;
+		*payload = t;
+		return (got);
 	}
 	case ERROR:
 		if ((unsigned) ntohs(t->th_code) > TFTP_MAX_ERRCODE) {
@@ -227,6 +230,7 @@
 #endif
 			errno = tftperrors[ntohs(t->th_code)];
 		}
+		free(ptr);
 		return (-1);
 	case OACK: {
 		struct udphdr *uh;
@@ -237,6 +241,7 @@
 		 * Drop the pkt.
 		 */
 		if (d->xid != 1) {
+			free(ptr);
 			return (-1);
 		}
 
@@ -244,7 +249,7 @@
 		 * Remember which port this OACK came from, because we need
 		 * to send the ACK or errors back to it.
 		 */
-		uh = (struct udphdr *) pkt - 1;
+		uh = (struct udphdr *) t - 1;
 		d->destport = uh->uh_sport;
 		
 		/* Parse options ACK-ed by the server. */
@@ -252,14 +257,18 @@
 		if (tftp_parse_oack(h, t->th_u.tu_stuff, tftp_oack_len) != 0) {
 			tftp_senderr(h, EOPTNEG, "Malformed OACK");
 			errno = EIO;
+			free(ptr);
 			return (-1);
 		}
+		*pkt = ptr;
+		*payload = t;
 		return (0);
 	}
 	default:
 #ifdef TFTP_DEBUG
 		printf("tftp type %d not handled\n", ntohs(t->th_opcode));
 #endif
+		free(ptr);
 		return (-1);
 	}
 }
@@ -276,6 +285,7 @@
 	char           *wtail;
 	int             l;
 	ssize_t         res;
+	void *pkt;
 	struct tftphdr *t;
 	char *tftp_blksize = NULL;
 	int blksize_l;
@@ -314,8 +324,6 @@
 	bcopy("0", wtail, 2);
 	wtail += 2;
 
-	t = &h->lastdata.t;
-
 	/* h->iodesc->myport = htons(--tftpport); */
 	h->iodesc->myport = htons(tftpport + (getsecs() & 0x3ff));
 	h->iodesc->destport = htons(IPPORT_TFTP);
@@ -325,8 +333,17 @@
 	h->islastblock = 0;
 	h->validsize = 0;
 
+	pkt = NULL;
 	res = sendrecv_tftp(h, &sendudp, &wbuf.t, wtail - (char *) &wbuf.t,
-		       &recvtftp, t, sizeof(*t) + h->tftp_blksize, &rtype);
+		       &recvtftp, &pkt, (void **)&t, &rtype);
+	if (res == -1) {
+		free(pkt);
+		return (errno);
+	}
+
+	free(h->pkt);
+	h->pkt = pkt;
+	h->tftp_hdr = t;
 
 	if (rtype == OACK)
 		return (tftp_getnextblock(h));
@@ -362,6 +379,7 @@
 	} __packed __aligned(4) wbuf;
 	char           *wtail;
 	int             res;
+	void *pkt;
 	struct tftphdr *t;
 	unsigned short rtype = 0;
 	wbuf.t.th_opcode = htons((u_short) ACK);
@@ -369,16 +387,20 @@
 	wbuf.t.th_block = htons((u_short) h->currblock);
 	wtail += 2;
 
-	t = &h->lastdata.t;
-
 	h->iodesc->xid = h->currblock + 1;	/* expected block */
 
+	pkt = NULL;
 	res = sendrecv_tftp(h, &sendudp, &wbuf.t, wtail - (char *) &wbuf.t,
-		       &recvtftp, t, sizeof(*t) + h->tftp_blksize, &rtype);
+		       &recvtftp, &pkt, (void **)&t, &rtype);
 
-	if (res == -1)		/* 0 is OK! */
+	if (res == -1) {		/* 0 is OK! */
+		free(pkt);
 		return (errno);
+	}
 
+	free(h->pkt);
+	h->pkt = pkt;
+	h->tftp_hdr = t;
 	h->currblock++;
 	h->validsize = res;
 	if (res < h->tftp_blksize)
@@ -405,14 +427,8 @@
 	if (netproto != NET_TFTP)
 		return (EINVAL);
 
-	if (strcmp(f->f_dev->dv_name, "net") != 0) {
-#ifdef __i386__
-		if (strcmp(f->f_dev->dv_name, "pxe") != 0)
-			return (EINVAL);
-#else
+	if (f->f_dev->dv_type != DEVT_NET)
 		return (EINVAL);
-#endif
-	}
 
 	if (is_open)
 		return (EBUSY);
@@ -507,7 +523,7 @@
 				return (EINVAL);
 			}
 			count = (size < inbuffer ? size : inbuffer);
-			bcopy(tftpfile->lastdata.t.th_data + offinblock,
+			bcopy(tftpfile->tftp_hdr->th_data + offinblock,
 			    addr, count);
 
 			addr = (char *)addr + count;
@@ -540,6 +556,7 @@
 
 	if (tftpfile) {
 		free(tftpfile->path);
+		free(tftpfile->pkt);
 		free(tftpfile);
 	}
 	is_open = 0;
@@ -591,8 +608,9 @@
 sendrecv_tftp(struct tftp_handle *h,
     ssize_t (*sproc)(struct iodesc *, void *, size_t),
     void *sbuf, size_t ssize,
-    ssize_t (*rproc)(struct tftp_handle *, void *, ssize_t, time_t, unsigned short *),
-    void *rbuf, size_t rsize, unsigned short *rtype)
+    ssize_t (*rproc)(struct tftp_handle *, void **, void **, time_t,
+    unsigned short *),
+    void **pkt, void **payload, unsigned short *rtype)
 {
 	struct iodesc *d = h->iodesc;
 	ssize_t cc;
@@ -624,7 +642,7 @@
 
 recvnext:
 		/* Try to get a packet and process it. */
-		cc = (*rproc)(h, rbuf, rsize, tleft, rtype);
+		cc = (*rproc)(h, pkt, payload, tleft, rtype);
 		/* Return on data, EOF or real error. */
 		if (cc != -1 || errno != 0)
 			return (cc);
Index: lib/libstand/udp.c
===================================================================
--- lib/libstand/udp.c
+++ lib/libstand/udp.c
@@ -59,10 +59,7 @@
 
 /* Caller must leave room for ethernet, ip and udp headers in front!! */
 ssize_t
-sendudp(d, pkt, len)
-	struct iodesc *d;
-	void *pkt;
-	size_t len;
+sendudp(struct iodesc *d, void *pkt, size_t len)
 {
 	ssize_t cc;
 	struct ip *ip;
@@ -131,32 +128,29 @@
 
 /*
  * Receive a UDP packet and validate it is for us.
- * Caller leaves room for the headers (Ether, IP, UDP)
  */
 ssize_t
-readudp(d, pkt, len, tleft)
-	struct iodesc *d;
-	void *pkt;
-	size_t len;
-	time_t tleft;
+readudp(struct iodesc *d, void **pkt, void **payload, time_t tleft)
 {
 	ssize_t n;
 	size_t hlen;
 	struct ip *ip;
 	struct udphdr *uh;
-	u_int16_t etype;	/* host order */
+	uint16_t etype;		/* host order */
+	void *ptr;
 
 #ifdef NET_DEBUG
 	if (debug)
 		printf("readudp: called\n");
 #endif
 
-	uh = (struct udphdr *)pkt - 1;
-	ip = (struct ip *)uh - 1;
-
-	n = readether(d, ip, len + sizeof(*ip) + sizeof(*uh), tleft, &etype);
-	if (n == -1 || n < sizeof(*ip) + sizeof(*uh))
-		return -1;
+	ip = NULL;
+	ptr = NULL;
+	n = readether(d, &ptr, (void **)&ip, tleft, &etype);
+	if (n == -1 || n < sizeof(*ip) + sizeof(*uh)) {
+		free(ptr);
+		return (-1);
+	}
 
 	/* Ethernet address checks now in readether() */
 
@@ -167,7 +161,8 @@
 			/* Send ARP reply */
 			arp_reply(d, ah);
 		}
-		return -1;
+		free(ptr);
+		return (-1);
 	}
 
 	if (etype != ETHERTYPE_IP) {
@@ -175,7 +170,8 @@
 		if (debug)
 			printf("readudp: not IP. ether_type=%x\n", etype);
 #endif
-		return -1;
+		free(ptr);
+		return (-1);
 	}
 
 	/* Check ip header */
@@ -185,7 +181,8 @@
 		if (debug)
 			printf("readudp: IP version or not UDP. ip_v=%d ip_p=%d\n", ip->ip_v, ip->ip_p);
 #endif
-		return -1;
+		free(ptr);
+		return (-1);
 	}
 
 	hlen = ip->ip_hl << 2;
@@ -195,7 +192,8 @@
 		if (debug)
 			printf("readudp: short hdr or bad cksum.\n");
 #endif
-		return -1;
+		free(ptr);
+		return (-1);
 	}
 	if (n < ntohs(ip->ip_len)) {
 #ifdef NET_DEBUG
@@ -203,7 +201,8 @@
 			printf("readudp: bad length %d < %d.\n",
 			       (int)n, ntohs(ip->ip_len));
 #endif
-		return -1;
+		free(ptr);
+		return (-1);
 	}
 	if (d->myip.s_addr && ip->ip_dst.s_addr != d->myip.s_addr) {
 #ifdef NET_DEBUG
@@ -212,12 +211,14 @@
 			printf("%s\n", inet_ntoa(ip->ip_dst));
 		}
 #endif
-		return -1;
+		free(ptr);
+		return (-1);
 	}
 
+	uh = (struct udphdr *)((uintptr_t)ip + sizeof (*ip));
 	/* If there were ip options, make them go away */
 	if (hlen != sizeof(*ip)) {
-		bcopy(((u_char *)ip) + hlen, uh, len - hlen);
+		bcopy(((u_char *)ip) + hlen, uh, uh->uh_ulen - hlen);
 		ip->ip_len = htons(sizeof(*ip));
 		n -= hlen - sizeof(*ip);
 	}
@@ -227,7 +228,8 @@
 			printf("readudp: bad dport %d != %d\n",
 				d->myport, ntohs(uh->uh_dport));
 #endif
-		return -1;
+		free(ptr);
+		return (-1);
 	}
 
 #ifndef UDP_NO_CKSUM
@@ -238,7 +240,8 @@
 		n = ntohs(uh->uh_ulen) + sizeof(*ip);
 		if (n > RECV_SIZE - ETHER_SIZE) {
 			printf("readudp: huge packet, udp len %d\n", (int)n);
-			return -1;
+			free(ptr);
+			return (-1);
 		}
 
 		/* Check checksum (must save and restore ip header) */
@@ -251,8 +254,8 @@
 			if (debug)
 				printf("readudp: bad cksum\n");
 #endif
-			*ip = tip;
-			return -1;
+			free(ptr);
+			return (-1);
 		}
 		*ip = tip;
 	}
@@ -263,10 +266,13 @@
 			printf("readudp: bad udp len %d < %d\n",
 				ntohs(uh->uh_ulen), (int)sizeof(*uh));
 #endif
-		return -1;
+		free(ptr);
+		return (-1);
 	}
 
 	n = (n > (ntohs(uh->uh_ulen) - sizeof(*uh))) ? 
 	    ntohs(uh->uh_ulen) - sizeof(*uh) : n;
+	*pkt = ptr;
+	*payload = (void *)((uintptr_t)uh + sizeof(*uh));
 	return (n);
 }
Index: sys/boot/common/dev_net.c
===================================================================
--- sys/boot/common/dev_net.c
+++ sys/boot/common/dev_net.c
@@ -58,6 +58,7 @@
 #include <netinet/in_systm.h>
 
 #include <stand.h>
+#include <stddef.h>
 #include <string.h>
 #include <net.h>
 #include <netif.h>
@@ -79,7 +80,7 @@
 static int	net_open(struct open_file *, ...);
 static int	net_close(struct open_file *);
 static void	net_cleanup(void);
-static int	net_strategy();
+static int	net_strategy(void *, int, daddr_t, size_t, char *, size_t *);
 static int	net_print(int);
 
 static int net_getparams(int sock);
@@ -216,7 +217,8 @@
 }
 
 static int
-net_strategy()
+net_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf,
+    size_t *rsize)
 {
 
 	return (EIO);
@@ -246,6 +248,8 @@
 {
 	char buf[MAXHOSTNAMELEN];
 	n_long rootaddr, smask;
+	struct iodesc *d = socktodesc(sock);
+	extern struct in_addr servip;
 
 #ifdef	SUPPORT_BOOTP
 	/*
@@ -254,8 +258,26 @@
 	 * be initialized.  If any remain uninitialized, we will
 	 * use RARP and RPC/bootparam (the Sun way) to get them.
 	 */
-	if (try_bootp)
-		bootp(sock, BOOTP_NONE);
+	if (try_bootp) {
+		int rc = -1;
+		if (bootp_response != NULL) {
+			rc = dhcp_try_rfc1048(bootp_response->bp_vend,
+			    bootp_response_size -
+			    offsetof(struct bootp, bp_vend));
+
+			if (servip.s_addr == 0)
+				servip = bootp_response->bp_siaddr;
+			if (rootip.s_addr == 0)
+				rootip = bootp_response->bp_siaddr;
+			if (gateip.s_addr == 0)
+				gateip = bootp_response->bp_giaddr;
+			if (myip.s_addr == 0)
+				myip = bootp_response->bp_yiaddr;
+			d->myip = myip;
+		}
+		if (rc < 0)
+			bootp(sock, BOOTP_NONE);
+	}
 	if (myip.s_addr != 0)
 		goto exit;
 #ifdef	NETIF_DEBUG
Index: sys/boot/efi/libefi/efinet.c
===================================================================
--- sys/boot/efi/libefi/efinet.c
+++ sys/boot/efi/libefi/efinet.c
@@ -36,19 +36,17 @@
 #include <net.h>
 #include <netif.h>
 
-#include <dev_net.c>
-
 #include <efi.h>
 #include <efilib.h>
 
 static EFI_GUID sn_guid = EFI_SIMPLE_NETWORK_PROTOCOL;
 
 static void efinet_end(struct netif *);
-static int efinet_get(struct iodesc *, void *, size_t, time_t);
+static ssize_t efinet_get(struct iodesc *, void **, time_t);
 static void efinet_init(struct iodesc *, void *);
 static int efinet_match(struct netif *, void *);
 static int efinet_probe(struct netif *, void *);
-static int efinet_put(struct iodesc *, void *, size_t);
+static ssize_t efinet_put(struct iodesc *, void *, size_t);
 
 struct netif_driver efinetif = {   
 	.netif_bname = "efinet",
@@ -113,7 +111,7 @@
 	return (0);
 }
 
-static int
+static ssize_t
 efinet_put(struct iodesc *desc, void *pkt, size_t len)
 {
 	struct netif *nif = desc->io_netif;
@@ -125,14 +123,14 @@
 	if (net == NULL)
 		return (-1);
 
-	status = net->Transmit(net, 0, len, pkt, 0, 0, 0);
+	status = net->Transmit(net, 0, len, pkt, NULL, NULL, NULL);
 	if (status != EFI_SUCCESS)
 		return (-1);
 
 	/* Wait for the buffer to be transmitted */
 	do {
 		buf = NULL;	/* XXX Is this needed? */
-		status = net->GetStatus(net, 0, &buf);
+		status = net->GetStatus(net, NULL, &buf);
 		/*
 		 * XXX EFI1.1 and the E1000 card returns a different 
 		 * address than we gave.  Sigh.
@@ -143,41 +141,42 @@
 	return ((status == EFI_SUCCESS) ? len : -1);
 }
 
-static int
-efinet_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout)
+static ssize_t
+efinet_get(struct iodesc *desc, void **pkt, time_t timeout)
 {
 	struct netif *nif = desc->io_netif;
 	EFI_SIMPLE_NETWORK *net;
 	EFI_STATUS status;
 	UINTN bufsz;
 	time_t t;
-	char buf[2048];
+	char *buf, *ptr;
+	ssize_t ret = -1;
 
 	net = nif->nif_devdata;
 	if (net == NULL)
-		return (0);
+		return (ret);
+
+	bufsz = roundup2(net->Mode->MaxPacketSize, 64) + 256;
+	buf = malloc(bufsz + 2);
+	if (buf == NULL)
+		return (ret);
+	ptr = buf + 2;
 
-	t = time(0);
-	while ((time(0) - t) < timeout) {
-		bufsz = sizeof(buf);
-		status = net->Receive(net, 0, &bufsz, buf, 0, 0, 0);
+	t = getsecs();
+	while ((getsecs() - t) < timeout) {
+		status = net->Receive(net, 0, &bufsz, ptr, NULL, NULL, NULL);
 		if (status == EFI_SUCCESS) {
-			/*
-			 * XXX EFI1.1 and the E1000 card trash our
-			 * workspace if we do not do this silly copy.
-			 * Either they are not respecting the len
-			 * value or do not like the alignment.
-			 */
-			if (bufsz > len)
-				bufsz = len;
-			bcopy(buf, pkt, bufsz);
-			return (bufsz);
+			*pkt = buf;
+			ret = (ssize_t)bufsz;
+			break;
 		}
 		if (status != EFI_NOT_READY)
-			return (0);
+			break;
 	}
 
-	return (0);
+	if (ret == -1)
+		free(buf);
+	return (ret);
 }
 
 static void
@@ -205,8 +204,8 @@
 	if (net->Mode->State == EfiSimpleNetworkStopped) {
 		status = net->Start(net);
 		if (status != EFI_SUCCESS) {
-			printf("net%d: cannot start interface (status=%ld)\n",
-			    nif->nif_unit, (long)status);
+			printf("net%d: cannot start interface (status=%lu)\n",
+			    nif->nif_unit, EFI_ERROR_CODE(status));
 			return;
 		}
 	}
@@ -214,8 +213,8 @@
 	if (net->Mode->State != EfiSimpleNetworkInitialized) {
 		status = net->Initialize(net, 0, 0);
 		if (status != EFI_SUCCESS) {
-			printf("net%d: cannot init. interface (status=%ld)\n",
-			    nif->nif_unit, (long)status);
+			printf("net%d: cannot init. interface (status=%lu)\n",
+			    nif->nif_unit, EFI_ERROR_CODE(status));
 			return;
 		}
 	}
@@ -224,10 +223,10 @@
 		UINT32 mask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
 		    EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
 
-		status = net->ReceiveFilters(net, mask, 0, FALSE, 0, 0);
+		status = net->ReceiveFilters(net, mask, 0, FALSE, 0, NULL);
 		if (status != EFI_SUCCESS) {
-			printf("net%d: cannot set rx. filters (status=%ld)\n",
-			    nif->nif_unit, (long)status);
+			printf("net%d: cannot set rx. filters (status=%lu)\n",
+			    nif->nif_unit, EFI_ERROR_CODE(status));
 			return;
 		}
 	}
@@ -258,9 +257,9 @@
 	.dv_name = "net",
 	.dv_type = DEVT_NET,
 	.dv_init = efinet_dev_init,
-	.dv_strategy = net_strategy,
-	.dv_open = net_open,
-	.dv_close = net_close,
+	.dv_strategy = NULL,		/* Will be set in efinet_dev_init */
+	.dv_open = NULL,		/* Will be set in efinet_dev_init */
+	.dv_close = NULL,		/* Will be set in efinet_dev_init */
 	.dv_ioctl = noioctl,
 	.dv_print = efinet_dev_print,
 	.dv_cleanup = NULL
@@ -277,13 +276,14 @@
 	EFI_STATUS status;
 	UINTN sz;
 	int err, i, nifs;
+	extern struct devsw netdev;
 
 	sz = 0;
 	handles = NULL;
-	status = BS->LocateHandle(ByProtocol, &sn_guid, 0, &sz, 0);
+	status = BS->LocateHandle(ByProtocol, &sn_guid, NULL, &sz, NULL);
 	if (status == EFI_BUFFER_TOO_SMALL) {
 		handles = (EFI_HANDLE *)malloc(sz);
-		status = BS->LocateHandle(ByProtocol, &sn_guid, 0, &sz,
+		status = BS->LocateHandle(ByProtocol, &sn_guid, NULL, &sz,
 		    handles);
 		if (EFI_ERROR(status))
 			free(handles);
@@ -313,10 +313,11 @@
 		 * pull packets off the network leading to lost packets.
 		 */
 		status = BS->OpenProtocol(handles[i], &sn_guid, (void **)&net,
-		    IH, 0, EFI_OPEN_PROTOCOL_EXCLUSIVE);
+		    IH, NULL, EFI_OPEN_PROTOCOL_EXCLUSIVE);
 		if (status != EFI_SUCCESS) {
 			printf("Unable to open network interface %d for "
-			    "exclusive access: %d\n", i, EFI_ERROR(status));
+			    "exclusive access: %lu\n", i,
+			    EFI_ERROR_CODE(status));
 		}
 
 		handles2[nifs] = handles[i];
@@ -351,6 +352,11 @@
 		dif->dif_stats = &stats[i];
 		dif->dif_private = handles2[i];
 	}
+
+	efinet_dev.dv_open = netdev.dv_open;
+	efinet_dev.dv_close = netdev.dv_close;
+	efinet_dev.dv_strategy = netdev.dv_strategy;
+
 done:
 	free(handles2);
 	return (err);
Index: sys/boot/efi/libefi/time.c
===================================================================
--- sys/boot/efi/libefi/time.c
+++ sys/boot/efi/libefi/time.c
@@ -230,5 +230,5 @@
 time_t
 getsecs(void)
 {
-    return time(0);
+    return time(NULL);
 }
Index: sys/boot/efi/loader/Makefile
===================================================================
--- sys/boot/efi/loader/Makefile
+++ sys/boot/efi/loader/Makefile
@@ -9,6 +9,7 @@
 PROG=		loader.sym
 INTERNALPROG=
 WARNS?=		3
+LOADER_NET_SUPPORT?=	yes
 
 # architecture-specific loader code
 SRCS=	autoload.c \
@@ -35,6 +36,10 @@
 CWARNFLAGS.zfs.c+=	-Wno-missing-prototypes
 .endif
 
+.if defined(LOADER_NET_SUPPORT)
+CFLAGS+=	-I${.CURDIR}/../../../../lib/libstand
+.endif
+
 .if ${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} > 40201
 CWARNFLAGS.self_reloc.c+=	-Wno-error=maybe-uninitialized
 .endif
Index: sys/boot/i386/libi386/pxe.h
===================================================================
--- sys/boot/i386/libi386/pxe.h
+++ sys/boot/i386/libi386/pxe.h
@@ -349,7 +349,7 @@
 	 */
 #	define PXENV_UNDI_ISR_OUT_DONE		0
 #	define PXENV_UNDI_ISR_OUT_TRANSMIT	2
-#	define PXENV_UNDI_ISR_OUT_RECIEVE	3
+#	define PXENV_UNDI_ISR_OUT_RECEIVE	3
 #	define PXENV_UNDI_ISR_OUT_BUSY		4
 } PACKED t_PXENV_UNDI_ISR;
 
Index: sys/boot/i386/libi386/pxe.c
===================================================================
--- sys/boot/i386/libi386/pxe.c
+++ sys/boot/i386/libi386/pxe.c
@@ -30,11 +30,14 @@
 __FBSDID("$FreeBSD$");
 
 #include <stand.h>
+#include <stddef.h>
 #include <string.h>
 #include <stdarg.h>
+#include <sys/param.h>
 
 #include <netinet/in_systm.h>
 #include <netinet/in.h>
+#include <netinet/ip.h>
 #include <netinet/udp.h>
 
 #include <net.h>
@@ -53,17 +56,15 @@
  * the PXE BIOS, and the data buffer is used to receive data from the PXE BIOS.
  */
 #define	PXE_BUFFER_SIZE		0x2000
-#define	PXE_TFTP_BUFFER_SIZE	512
 static char	scratch_buffer[PXE_BUFFER_SIZE];
 static char	data_buffer[PXE_BUFFER_SIZE];
 
 static pxenv_t *pxenv_p = NULL;	/* PXENV+ */
 static pxe_t *pxe_p = NULL;		/* !PXE */
-static BOOTPLAYER bootplayer;	/* PXE Cached information. */
 
+#ifdef PXE_DEBUG
 static int	pxe_debug = 0;
-static int	pxe_sock = -1;
-static int	pxe_opens = 0;
+#endif
 
 void		pxe_enable(void *pxeinfo);
 static void	(*pxe_call)(int func);
@@ -71,25 +72,17 @@
 static void	bangpxe_call(int func);
 
 static int	pxe_init(void);
-static int	pxe_strategy(void *devdata, int flag, daddr_t dblk,
-			    size_t size, char *buf, size_t *rsize);
-static int	pxe_open(struct open_file *f, ...);
-static int	pxe_close(struct open_file *f);
 static int	pxe_print(int verbose);
 static void	pxe_cleanup(void);
-static void	pxe_setnfshandle(char *rootpath);
 
 static void	pxe_perror(int error);
 static int	pxe_netif_match(struct netif *nif, void *machdep_hint);
 static int	pxe_netif_probe(struct netif *nif, void *machdep_hint);
 static void	pxe_netif_init(struct iodesc *desc, void *machdep_hint);
-static int	pxe_netif_get(struct iodesc *desc, void *pkt, size_t len,
-			    time_t timeout);
-static int	pxe_netif_put(struct iodesc *desc, void *pkt, size_t len);
+static ssize_t	pxe_netif_get(struct iodesc *, void **, time_t);
+static ssize_t	pxe_netif_put(struct iodesc *desc, void *pkt, size_t len);
 static void	pxe_netif_end(struct netif *nif);
 
-int nfs_getrootfh(struct iodesc*, char*, uint32_t*, u_char*);
-
 extern struct netif_stats	pxe_st[];
 extern u_int16_t		__bangpxeseg;
 extern u_int16_t		__bangpxeoff;
@@ -97,25 +90,24 @@
 extern u_int16_t		__pxenvseg;
 extern u_int16_t		__pxenvoff;
 extern void			__pxenventry(void);
-extern struct in_addr		servip;
 
 struct netif_dif pxe_ifs[] = {
 /*	dif_unit        dif_nsel        dif_stats       dif_private     */
 	{0,             1,              &pxe_st[0],     0}
 };
 
-struct netif_stats pxe_st[NENTS(pxe_ifs)];
+struct netif_stats pxe_st[nitems(pxe_ifs)];
 
 struct netif_driver pxenetif = {
-	"pxenet",
-	pxe_netif_match,
-	pxe_netif_probe,
-	pxe_netif_init,
-	pxe_netif_get,
-	pxe_netif_put,
-	pxe_netif_end,
-	pxe_ifs,
-	NENTS(pxe_ifs)
+	.netif_bname = "pxenet",
+	.netif_match = pxe_netif_match,
+	.netif_probe = pxe_netif_probe,
+	.netif_init = pxe_netif_init,
+	.netif_get = pxe_netif_get,
+	.netif_put = pxe_netif_put,
+	.netif_end = pxe_netif_end,
+	.netif_ifs = pxe_ifs,
+	.netif_nifs = nitems(pxe_ifs)
 };
 
 struct netif_driver *netif_drivers[] = {
@@ -124,15 +116,15 @@
 };
 
 struct devsw pxedisk = {
-	"pxe",
-	DEVT_NET,
-	pxe_init,
-	pxe_strategy,
-	pxe_open,
-	pxe_close,
-	noioctl,
-	pxe_print,
-	pxe_cleanup
+	.dv_name = "net",
+	.dv_type = DEVT_NET,
+	.dv_init = pxe_init,
+	.dv_strategy = NULL,	/* Will be set in pxe_init */
+	.dv_open = NULL,	/* Will be set in pxe_init */
+	.dv_close = NULL,	/* Will be set in pxe_init */
+	.dv_ioctl = noioctl,
+	.dv_print = pxe_print,
+	.dv_cleanup = pxe_cleanup
 };
 
 /*
@@ -160,6 +152,7 @@
 	int counter;
 	uint8_t checksum;
 	uint8_t *checkptr;
+	extern struct devsw netdev;
 
 	if (pxenv_p == NULL)
 		return (0);
@@ -215,7 +208,11 @@
 			break;
 		}
 	}
-	
+
+	pxedisk.dv_open = netdev.dv_open;
+	pxedisk.dv_close = netdev.dv_close;
+	pxedisk.dv_strategy = netdev.dv_strategy;
+
 	printf("\nPXE version %d.%d, real mode entry point ",
 	    (uint8_t) (pxenv_p->Version >> 8),
 	    (uint8_t) (pxenv_p->Version & 0xFF));
@@ -236,192 +233,29 @@
 		pxe_p = NULL;
 		return (0);
 	}
-	bcopy(PTOV((gci_p->Buffer.segment << 4) + gci_p->Buffer.offset),
-	    &bootplayer, gci_p->BufferSize);
-	return (1);
-}
-
-
-static int
-pxe_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
-    char *buf, size_t *rsize)
-{
-	return (EIO);
-}
-
-static int
-pxe_open(struct open_file *f, ...)
-{
-	va_list args;
-	char *devname;		/* Device part of file name (or NULL). */
-	char temp[FNAME_SIZE];
-	int error = 0;
-	int i;
-
-	va_start(args, f);
-	devname = va_arg(args, char*);
-	va_end(args);
-
-	/* On first open, do netif open, mount, etc. */
-	if (pxe_opens == 0) {
-		/* Find network interface. */
-		if (pxe_sock < 0) {
-			pxe_sock = netif_open(devname);
-			if (pxe_sock < 0) {
-				printf("pxe_open: netif_open() failed\n");
-				return (ENXIO);
-			}
-			if (pxe_debug)
-				printf("pxe_open: netif_open() succeeded\n");
-
-			if (socktodesc(pxe_sock) == NULL) {
-				printf("pxe_open: bad socket %d\n", pxe_sock);
-				return (ENXIO);
-			}
-
-		}
-		if (rootip.s_addr == 0) {
-			/*
-			 * Try to extract the RFC1048 data from PXE.
-			 * If fail do a bootp/dhcp request to find out where our
-			 * NFS/TFTP server is. Even if we dont get back
-			 * the proper information, fall back to the server
-			 * which brought us to life and a default rootpath.
-			 */
-
-			if (dhcp_try_rfc1048(bootplayer.vendor.d, BOOTP_DHCPVEND) < 0) {
-				if (pxe_debug)
-					printf("pxe_open: no RFC1048 data in PXE Cache\n");
-				bootp(pxe_sock, BOOTP_PXE);
-			} else if (pxe_debug) {
-				printf("pxe_open: loaded RFC1048 data from PXE Cache\n");
-			}
-
-#ifdef LOADER_TFTP_SUPPORT
-			bootp(pxe_sock, BOOTP_PXE);
-#endif
-			if (rootip.s_addr == 0)
-				rootip.s_addr = bootplayer.sip;
-			if (gateip.s_addr == 0)
-				gateip.s_addr = bootplayer.gip;
-			if (myip.s_addr == 0)
-				myip.s_addr = bootplayer.yip;
-			if (servip.s_addr == 0)
-				servip = rootip;
-
-			netproto = NET_NFS;
-			if (tftpip.s_addr != 0) {
-				netproto = NET_TFTP;
-				rootip.s_addr = tftpip.s_addr;
-			}
-
-			if (netproto == NET_NFS && !rootpath[0])
-				strcpy(rootpath, PXENFSROOTPATH);
-
-			for (i = 0; rootpath[i] != '\0' && i < FNAME_SIZE; i++)
-				if (rootpath[i] == ':')
-					break;
-			if (i && i != FNAME_SIZE && rootpath[i] == ':') {
-				rootpath[i++] = '\0';
-				if (inet_addr(&rootpath[0]) != INADDR_NONE)
-					rootip.s_addr = inet_addr(&rootpath[0]);
-				bcopy(&rootpath[i], &temp[0], strlen(&rootpath[i]) + 1);
-				bcopy(&temp[0], &rootpath[0], strlen(&rootpath[i]) + 1);
-			}
-			setenv("boot.netif.ip", inet_ntoa(myip), 1);
-			setenv("boot.netif.netmask", intoa(netmask), 1);
-			setenv("boot.netif.gateway", inet_ntoa(gateip), 1);
-			setenv("boot.netif.server", inet_ntoa(rootip), 1);
-			if (bootplayer.Hardware == ETHER_TYPE) {
-				sprintf(temp, "%6D", bootplayer.CAddr, ":");
-				setenv("boot.netif.hwaddr", temp, 1);
-			}
-			if (intf_mtu != 0) {
-				char mtu[16];
-				snprintf(sizeof(mtu), mtu, "%u", intf_mtu);
-				setenv("boot.netif.mtu", mtu, 1);
-			}
-			printf("pxe_open: server addr: %s\n", inet_ntoa(rootip));
-			printf("pxe_open: server path: %s\n", rootpath);
-			printf("pxe_open: gateway ip:  %s\n", inet_ntoa(gateip));
-			printf("pxe_open: my ip:       %s\n", inet_ntoa(myip));
-			printf("pxe_open: netmask:     %s\n", intoa(netmask));
-			printf("pxe_open: servip:      %s\n", inet_ntoa(servip));
-
-			if (netproto == NET_TFTP) {
-				setenv("boot.tftproot.server", inet_ntoa(rootip), 1);
-				setenv("boot.tftproot.path", rootpath, 1);
-			} else if (netproto == NET_NFS) {
-				setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
-				setenv("boot.nfsroot.path", rootpath, 1);
-			}
-			setenv("dhcp.host-name", hostname, 1);
-
-			setenv("pxeboot.ip", inet_ntoa(myip), 1);
-			if (bootplayer.Hardware == ETHER_TYPE) {
-				sprintf(temp, "%6D", bootplayer.CAddr, ":");
-				setenv("pxeboot.hwaddr", temp, 1);
-			}
-		}
-	}
-	pxe_opens++;
-	f->f_devdata = &pxe_sock;
-	return (error);
-}
-
-static int
-pxe_close(struct open_file *f)
-{
-
-#ifdef	PXE_DEBUG
-	if (pxe_debug)
-		printf("pxe_close: opens=%d\n", pxe_opens);
-#endif
-
-	/* On last close, do netif close, etc. */
-	f->f_devdata = NULL;
-	/* Extra close call? */
-	if (pxe_opens <= 0)
-		return (0);
-	pxe_opens--;
-	/* Not last close? */
-	if (pxe_opens > 0)
-		return (0);
-
-	if (netproto == NET_NFS) {
-		/* get an NFS filehandle for our root filesystem */
-		pxe_setnfshandle(rootpath);
-	}
-
-	if (pxe_sock >= 0) {
-
-#ifdef PXE_DEBUG
-	if (pxe_debug)
-		printf("pxe_close: calling netif_close()\n");
-#endif
-	netif_close(pxe_sock);
-	pxe_sock = -1;
+	free(bootp_response);
+	if ((bootp_response = malloc(gci_p->BufferSize)) != NULL) {
+		bootp_response_size = gci_p->BufferSize;
+		bcopy(PTOV((gci_p->Buffer.segment << 4) + gci_p->Buffer.offset),
+		    bootp_response, bootp_response_size);
 	}
-	return (0);
+	return (1);
 }
 
 static int
 pxe_print(int verbose)
 {
-	char line[255];
 	if (pxe_call == NULL)
 		return (0);
 
 	printf("%s devices:", pxedisk.dv_name);
 	if (pager_output("\n") != 0)
 		return (1);
+	printf("    %s0:", pxedisk.dv_name);
 	if (verbose) {
-		snprintf(line, sizeof(line), "    pxe0:    %s:%s\n",
-		    inet_ntoa(rootip), rootpath);
-	} else {
-		snprintf(line, sizeof(line), "    pxe0:\n");
+		printf("    %s:%s", inet_ntoa(rootip), rootpath);
 	}
-	return (pager_output(line));
+	return (pager_output("\n"));
 }
 
 static void
@@ -460,66 +294,6 @@
 	return;
 }
 
-/*
- * Reach inside the libstand NFS code and dig out an NFS handle
- * for the root filesystem.
- */
-#define	NFS_V3MAXFHSIZE		64
-
-struct nfs_iodesc {
-	struct iodesc *iodesc;
-	off_t off;
-	uint32_t fhsize;
-	u_char fh[NFS_V3MAXFHSIZE];
-	/* structure truncated */
-};
-extern struct nfs_iodesc nfs_root_node;
-extern int rpc_port;
-
-static void
-pxe_rpcmountcall()
-{
-	struct iodesc *d;
-	int error;
-
-	if (!(d = socktodesc(pxe_sock)))
-		return;
-	d->myport = htons(--rpc_port);
-	d->destip = rootip;
-	if ((error = nfs_getrootfh(d, rootpath, &nfs_root_node.fhsize,
-		nfs_root_node.fh)) != 0) {
-		printf("NFS MOUNT RPC error: %d\n", error);
-		nfs_root_node.fhsize = 0;
-	}
-	nfs_root_node.iodesc = d;
-}
-
-static void
-pxe_setnfshandle(char *rootpath)
-{
-	int i;
-	u_char *fh;
-	char buf[2 * NFS_V3MAXFHSIZE + 3], *cp;
-
-	/*
-	 * If NFS files were never opened, we need to do mount call
-	 * ourselves. Use nfs_root_node.iodesc as flag indicating
-	 * previous NFS usage.
-	 */
-	if (nfs_root_node.iodesc == NULL)
-		pxe_rpcmountcall();
-
-	fh = &nfs_root_node.fh[0];
-	buf[0] = 'X';
-	cp = &buf[1];
-	for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2)
-		sprintf(cp, "%02x", fh[i]);
-	sprintf(cp, "X");
-	setenv("boot.nfsroot.nfshandle", buf, 1);
-	sprintf(buf, "%d", nfs_root_node.fhsize);
-	setenv("boot.nfsroot.nfshandlelen", buf, 1);
-}
-
 void
 pxenv_call(int func)
 {
@@ -570,121 +344,196 @@
 static int
 pxe_netif_match(struct netif *nif, void *machdep_hint)
 {
-	return 1;
+	return (1);
 }
 
 static int
 pxe_netif_probe(struct netif *nif, void *machdep_hint)
 {
-	t_PXENV_UDP_OPEN *udpopen_p = (t_PXENV_UDP_OPEN *)scratch_buffer;
-
 	if (pxe_call == NULL)
-		return -1;
-
-	bzero(udpopen_p, sizeof(*udpopen_p));
-	udpopen_p->src_ip = bootplayer.yip;
-	pxe_call(PXENV_UDP_OPEN);
+		return (-1);
 
-	if (udpopen_p->status != 0) {
-		printf("pxe_netif_probe: failed %x\n", udpopen_p->status);
-		return -1;
-	}
-	return 0;
+	return (0);
 }
 
 static void
 pxe_netif_end(struct netif *nif)
 {
-	t_PXENV_UDP_CLOSE *udpclose_p = (t_PXENV_UDP_CLOSE *)scratch_buffer;
-	bzero(udpclose_p, sizeof(*udpclose_p));
+	t_PXENV_UNDI_CLOSE *undi_close_p;
 
-	pxe_call(PXENV_UDP_CLOSE);
-	if (udpclose_p->status != 0)
-		printf("pxe_end failed %x\n", udpclose_p->status);
+	undi_close_p = (t_PXENV_UNDI_CLOSE *)scratch_buffer;
+	bzero(undi_close_p, sizeof(*undi_close_p));
+	pxe_call(PXENV_UNDI_CLOSE);
+	if (undi_close_p->Status != 0)
+		printf("undi close failed: %x\n", undi_close_p->Status);
 }
 
 static void
 pxe_netif_init(struct iodesc *desc, void *machdep_hint)
 {
-	int i;
-	for (i = 0; i < 6; ++i)
-		desc->myea[i] = bootplayer.CAddr[i];
-	desc->xid = bootplayer.ident;
-}
+	t_PXENV_UNDI_GET_INFORMATION *undi_info_p;
+	t_PXENV_UNDI_OPEN *undi_open_p;
+	uint8_t *mac;
+	int i, len;
+
+	undi_info_p = (t_PXENV_UNDI_GET_INFORMATION *)scratch_buffer;
+	bzero(undi_info_p, sizeof(*undi_info_p));
+	pxe_call(PXENV_UNDI_GET_INFORMATION);
+	if (undi_info_p->Status != 0) {
+		printf("undi get info failed: %x\n", undi_info_p->Status);
+		return;
+	}
 
-static int
-pxe_netif_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout)
-{
-	return len;
-}
+	/* Make sure the CurrentNodeAddress is valid. */
+	for (i = 0; i < undi_info_p->HwAddrLen; ++i) {
+		if (undi_info_p->CurrentNodeAddress[i] != 0)
+			break;
+	}
+	if (i < undi_info_p->HwAddrLen) {
+		for (i = 0; i < undi_info_p->HwAddrLen; ++i) {
+			if (undi_info_p->CurrentNodeAddress[i] != 0xff)
+				break;
+		}
+	}
+	if (i < undi_info_p->HwAddrLen)
+		mac = undi_info_p->CurrentNodeAddress;
+	else
+		mac = undi_info_p->PermNodeAddress;
 
-static int
-pxe_netif_put(struct iodesc *desc, void *pkt, size_t len)
-{
-	return len;
+	len = min(sizeof (desc->myea), undi_info_p->HwAddrLen);
+	for (i = 0; i < len; ++i)
+		desc->myea[i] = mac[i];
+
+	if (bootp_response != NULL)
+		desc->xid = bootp_response->bp_xid;
+	else
+		desc->xid = 0;
+
+	undi_open_p = (t_PXENV_UNDI_OPEN *)scratch_buffer;
+	bzero(undi_open_p, sizeof(*undi_open_p));
+	undi_open_p->PktFilter = FLTR_DIRECTED | FLTR_BRDCST;
+	pxe_call(PXENV_UNDI_OPEN);
+	if (undi_open_p->Status != 0)
+		printf("undi open failed: %x\n", undi_open_p->Status);
 }
 
-ssize_t
-sendudp(struct iodesc *h, void *pkt, size_t len)
+static int
+pxe_netif_receive(void **pkt)
 {
-	t_PXENV_UDP_WRITE *udpwrite_p = (t_PXENV_UDP_WRITE *)scratch_buffer;
-	bzero(udpwrite_p, sizeof(*udpwrite_p));
+	t_PXENV_UNDI_ISR *isr = (t_PXENV_UNDI_ISR *)scratch_buffer;
+	char *buf, *ptr, *frame;
+	size_t size, rsize;
+
+	bzero(isr, sizeof(*isr));
+	isr->FuncFlag = PXENV_UNDI_ISR_IN_START;
+	pxe_call(PXENV_UNDI_ISR);
+	if (isr->Status != 0)
+		return (-1);
+
+	bzero(isr, sizeof(*isr));
+	isr->FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
+	pxe_call(PXENV_UNDI_ISR);
+	if (isr->Status != 0)
+		return (-1);
+
+	while (isr->FuncFlag == PXENV_UNDI_ISR_OUT_TRANSMIT) {
+		/*
+		 * Wait till transmit is done.
+		 */
+		bzero(isr, sizeof(*isr));
+		isr->FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
+		pxe_call(PXENV_UNDI_ISR);
+		if (isr->Status != 0 ||
+		    isr->FuncFlag == PXENV_UNDI_ISR_OUT_DONE)
+			return (-1);
+	}
+
+	while (isr->FuncFlag != PXENV_UNDI_ISR_OUT_RECEIVE) {
+		if (isr->Status != 0 ||
+		    isr->FuncFlag == PXENV_UNDI_ISR_OUT_DONE) {
+			return (-1);
+		}
+		bzero(isr, sizeof(*isr));
+		isr->FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
+		pxe_call(PXENV_UNDI_ISR);
+	}
+
+	size = isr->FrameLength;
+	buf = malloc(size + 2);
+	if (buf == NULL)
+		return (-1);
+	ptr = buf + 2;
+	rsize = 0;
+
+	while (rsize < size) {
+		frame = (char *)((uintptr_t)isr->Frame.segment << 4);
+		frame += isr->Frame.offset;
+		bcopy(PTOV(frame), ptr, isr->BufferLength);
+		ptr += isr->BufferLength;
+		rsize += isr->BufferLength;
+
+		bzero(isr, sizeof(*isr));
+		isr->FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
+		pxe_call(PXENV_UNDI_ISR);
+		if (isr->Status != 0) {
+			free(buf);
+			return (-1);
+		}
 
-	udpwrite_p->ip             = h->destip.s_addr;
-	udpwrite_p->dst_port       = h->destport;
-	udpwrite_p->src_port       = h->myport;
-	udpwrite_p->buffer_size    = len;
-	udpwrite_p->buffer.segment = VTOPSEG(pkt);
-	udpwrite_p->buffer.offset  = VTOPOFF(pkt);
+		/* Did we got another update? */
+		if (isr->FuncFlag == PXENV_UNDI_ISR_OUT_RECEIVE)
+			continue;
+		break;
+	}
 
-	if (netmask == 0 || SAMENET(myip, h->destip, netmask))
-		udpwrite_p->gw = 0;
-	else
-		udpwrite_p->gw = gateip.s_addr;
+	*pkt = buf;
+	return (rsize);
+}
 
-	pxe_call(PXENV_UDP_WRITE);
+static ssize_t
+pxe_netif_get(struct iodesc *desc, void **pkt, time_t timeout)
+{
+	time_t t;
+	void *ptr;
+	int ret = -1;
 
-#if 0
-	/* XXX - I dont know why we need this. */
-	delay(1000);
-#endif
-	if (udpwrite_p->status != 0) {
-		/* XXX: This happens a lot. It shouldn't. */
-		if (udpwrite_p->status != 1)
-			printf("sendudp failed %x\n", udpwrite_p->status);
-		return -1;
+	t = getsecs();
+	while ((getsecs() - t) < timeout) {
+		ret = pxe_netif_receive(&ptr);
+		if (ret != -1) {
+			*pkt = ptr;
+			break;
+		}
 	}
-	return len;
+	return (ret);
 }
 
-ssize_t
-readudp(struct iodesc *h, void *pkt, size_t len, time_t timeout)
+static ssize_t
+pxe_netif_put(struct iodesc *desc, void *pkt, size_t len)
 {
-	t_PXENV_UDP_READ *udpread_p = (t_PXENV_UDP_READ *)scratch_buffer;
-	struct udphdr *uh = NULL;
+	t_PXENV_UNDI_TRANSMIT *trans_p;
+	t_PXENV_UNDI_TBD *tbd_p;
+	char *data;
 
-	uh = (struct udphdr *) pkt - 1;
-	bzero(udpread_p, sizeof(*udpread_p));
+	trans_p = (t_PXENV_UNDI_TRANSMIT *)scratch_buffer;
+	bzero(trans_p, sizeof(*trans_p));
+	tbd_p = (t_PXENV_UNDI_TBD *)(scratch_buffer + sizeof(*trans_p));
+	bzero(tbd_p, sizeof(*tbd_p));
 
-	udpread_p->dest_ip        = h->myip.s_addr;
-	udpread_p->d_port         = h->myport;
-	udpread_p->buffer_size    = len;
-	udpread_p->buffer.segment = VTOPSEG(data_buffer);
-	udpread_p->buffer.offset  = VTOPOFF(data_buffer);
+	data = scratch_buffer + sizeof(*trans_p) + sizeof(*tbd_p);
 
-	pxe_call(PXENV_UDP_READ);
+	trans_p->TBD.segment = VTOPSEG(tbd_p);
+	trans_p->TBD.offset  = VTOPOFF(tbd_p);
 
-#if 0
-	/* XXX - I dont know why we need this. */
-	delay(1000);
-#endif
-	if (udpread_p->status != 0) {
-		/* XXX: This happens a lot. It shouldn't. */
-		if (udpread_p->status != 1)
-			printf("readudp failed %x\n", udpread_p->status);
-		return -1;
-	}
-	bcopy(data_buffer, pkt, udpread_p->buffer_size);
-	uh->uh_sport = udpread_p->s_port;
-	return udpread_p->buffer_size;
+	tbd_p->ImmedLength = len;
+	tbd_p->Xmit.segment = VTOPSEG(data);
+	tbd_p->Xmit.offset  = VTOPOFF(data);
+	bcopy(pkt, data, len);
+
+	pxe_call(PXENV_UNDI_TRANSMIT);
+	if (trans_p->Status != 0) {
+		return (-1);
+	}
+
+	return (len);
 }
Index: sys/boot/i386/loader/Makefile
===================================================================
--- sys/boot/i386/loader/Makefile
+++ sys/boot/i386/loader/Makefile
@@ -9,6 +9,7 @@
 INTERNALPROG=
 NEWVERSWHAT?=	"bootstrap loader" x86
 VERSION_FILE=	${.CURDIR}/../loader/version
+LOADER_NET_SUPPORT?=	yes
 
 # architecture-specific loader code
 SRCS=		main.c conf.c vers.c
@@ -25,6 +26,10 @@
 LIBZFSBOOT=	${.OBJDIR}/../../zfs/libzfsboot.a
 .endif
 
+.if defined(LOADER_NET_SUPPORT)
+CFLAGS+=	-I${.CURDIR}/../../../../lib/libstand
+.endif
+
 # Enable PXE TFTP or NFS support, not both.
 .if defined(LOADER_TFTP_SUPPORT)
 CFLAGS+=	-DLOADER_TFTP_SUPPORT
Index: sys/boot/ofw/libofw/ofw_net.c
===================================================================
--- sys/boot/ofw/libofw/ofw_net.c
+++ sys/boot/ofw/libofw/ofw_net.c
@@ -46,8 +46,8 @@
 static int	ofwn_probe(struct netif *, void *);
 static int	ofwn_match(struct netif *, void *);
 static void	ofwn_init(struct iodesc *, void *);
-static int	ofwn_get(struct iodesc *, void *, size_t, time_t);
-static int	ofwn_put(struct iodesc *, void *, size_t);
+static ssize_t	ofwn_get(struct iodesc *, void **, time_t);
+static ssize_t	ofwn_put(struct iodesc *, void *, size_t);
 static void	ofwn_end(struct netif *);
 
 extern struct netif_stats	ofwn_stats[];
@@ -57,7 +57,7 @@
 	{	0,		1,		&ofwn_stats[0],	0,	},
 };
 
-struct netif_stats ofwn_stats[NENTS(ofwn_ifs)];
+struct netif_stats ofwn_stats[nitems(ofwn_ifs)];
 
 struct netif_driver ofwnet = {
 	"net",			/* netif_bname */
@@ -68,7 +68,7 @@
 	ofwn_put,		/* netif_put */
 	ofwn_end,		/* netif_end */
 	ofwn_ifs,		/* netif_ifs */
-	NENTS(ofwn_ifs)		/* netif_nifs */
+	nitems(ofwn_ifs)		/* netif_nifs */
 };
 
 static ihandle_t	netinstance;
@@ -87,7 +87,7 @@
 	return 0;
 }
 
-static int
+static ssize_t
 ofwn_put(struct iodesc *desc, void *pkt, size_t len)
 {
 	size_t			sendlen;
@@ -124,20 +124,32 @@
 	return rv;
 }
 
-static int
-ofwn_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout)
+static ssize_t
+ofwn_get(struct iodesc *desc, void **pkt, time_t timeout)
 {
 	time_t	t;
-	int	length;
+	ssize_t	length;
+	size_t	len;
+	char	*buf, *ptr;
 
 #if defined(NETIF_DEBUG)
-	printf("netif_get: pkt=%p, maxlen=%d, timeout=%d\n", pkt, len,
-	    timeout);
+	printf("netif_get: pkt=%p, timeout=%d\n", pkt, timeout);
 #endif
 
+	/*
+	 * We should read the "max-frame-size" int property instead,
+	 * but at this time the iodesc does not have mtu, so we will take
+	 * a small shortcut here.
+	 */
+	len = 1500 + 64;
+	buf = malloc(len + 2);
+	if (buf == NULL)
+		return (-1);
+	ptr = buf + 2;
+
 	t = getsecs();
 	do {
-		length = OF_read(netinstance, pkt, len);
+		length = OF_read(netinstance, ptr, len);
 	} while ((length == -2 || length == 0) &&
 		(getsecs() - t < timeout));
 
@@ -145,12 +157,14 @@
 	printf("netif_get: received length=%d (%x)\n", length, length);
 #endif
 
-	if (length < 12)
-		return -1;
+	if (length < 12) {
+		free(buf);
+		return (-1);
+	}
 
 #if defined(NETIF_VERBOSE_DEBUG)
 	{
-		char *ch = pkt;
+		char *ch = ptr;
 		int i;
 
 		for(i = 0; i < 96; i += 4) {
@@ -163,7 +177,7 @@
 
 #if defined(NETIF_DEBUG)
 	{
-		struct ether_header *eh = pkt;
+		struct ether_header *eh = ptr;
 
 		printf("dst: %s ", ether_sprintf(eh->ether_dhost));
 		printf("src: %s ", ether_sprintf(eh->ether_shost));
@@ -171,7 +185,8 @@
 	}
 #endif
 
-	return length;
+	*pkt = buf;
+	return (length);
 }
 
 extern char *strchr();
Index: sys/boot/uboot/lib/net.c
===================================================================
--- sys/boot/uboot/lib/net.c
+++ sys/boot/uboot/lib/net.c
@@ -50,8 +50,8 @@
 static int	net_probe(struct netif *, void *);
 static int	net_match(struct netif *, void *);
 static void	net_init(struct iodesc *, void *);
-static int	net_get(struct iodesc *, void *, size_t, time_t);
-static int	net_put(struct iodesc *, void *, size_t);
+static ssize_t	net_get(struct iodesc *, void **, time_t);
+static ssize_t	net_put(struct iodesc *, void *, size_t);
 static void	net_end(struct netif *);
 
 extern struct netif_stats net_stats[];
@@ -61,7 +61,7 @@
 	{	0,		1,		&net_stats[0],	0,	},
 };
 
-struct netif_stats net_stats[NENTS(net_ifs)];
+struct netif_stats net_stats[nitems(net_ifs)];
 
 struct netif_driver uboot_net = {
 	"uboot_eth",		/* netif_bname */
@@ -72,7 +72,7 @@
 	net_put,		/* netif_put */
 	net_end,		/* netif_end */
 	net_ifs,		/* netif_ifs */
-	NENTS(net_ifs)		/* netif_nifs */
+	nitems(net_ifs)		/* netif_nifs */
 };
 
 struct uboot_softc {
@@ -232,7 +232,7 @@
 	return (0);
 }
 
-static int
+static ssize_t
 net_put(struct iodesc *desc, void *pkt, size_t len)
 {
 	struct netif *nif = desc->io_netif;
@@ -271,18 +271,21 @@
 	return (rv);
 }
 
-static int
-net_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout)
+static ssize_t
+net_get(struct iodesc *desc, void **pkt, time_t timeout)
 {
 	struct netif *nif = desc->io_netif;
 	struct uboot_softc *sc = nif->nif_devdata;
 	time_t t;
 	int err, rlen;
+	size_t len;
+	char *buf;
 
 #if defined(NETIF_DEBUG)
-	printf("net_get: pkt %p, len %d, timeout %d\n", pkt, len, timeout);
+	printf("net_get: pkt %p, timeout %d\n", pkt, timeout);
 #endif
 	t = getsecs();
+	len = sizeof(sc->sc_rxbuf);
 	do {
 		err = ub_dev_recv(sc->sc_handle, sc->sc_rxbuf, len, &rlen);
 
@@ -299,13 +302,12 @@
 #endif
 
 	if (rlen > 0) {
-		memcpy(pkt, sc->sc_rxbuf, MIN(len, rlen));
-		if (rlen != len) {
-#if defined(NETIF_DEBUG)
-			printf("net_get: len %x, rlen %x\n", len, rlen);
-#endif
-		}
-		return (rlen);
+		buf = malloc(rlen + 2);
+		if (buf == NULL)
+			return (-1);
+		memcpy(buf + 2, sc->sc_rxbuf, rlen);
+		*pkt = buf;
+		return ((ssize_t)rlen);
 	}
 
 	return (-1);