1119482Sobrien/*-
258713Sjhb * Copyright (c) 2000 Alfred Perlstein <alfred@freebsd.org>
358713Sjhb * Copyright (c) 2000 Paul Saab <ps@freebsd.org>
458713Sjhb * Copyright (c) 2000 John Baldwin <jhb@freebsd.org>
558713Sjhb * All rights reserved.
658713Sjhb *
758713Sjhb * Redistribution and use in source and binary forms, with or without
858713Sjhb * modification, are permitted provided that the following conditions
958713Sjhb * are met:
1058713Sjhb * 1. Redistributions of source code must retain the above copyright
1158713Sjhb *    notice, this list of conditions and the following disclaimer.
1258713Sjhb * 2. Redistributions in binary form must reproduce the above copyright
1358713Sjhb *    notice, this list of conditions and the following disclaimer in the
1458713Sjhb *    documentation and/or other materials provided with the distribution.
1558713Sjhb *
1658713Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1758713Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1858713Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1958713Sjhb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2058713Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2158713Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2258713Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2358713Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2458713Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2558713Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2658713Sjhb * SUCH DAMAGE.
2758713Sjhb */
2858713Sjhb
29119482Sobrien#include <sys/cdefs.h>
30119482Sobrien__FBSDID("$FreeBSD$");
31119482Sobrien
3258713Sjhb#include <stand.h>
3359768Sps#include <string.h>
3459768Sps#include <stdarg.h>
3558713Sjhb
3659087Sps#include <netinet/in_systm.h>
3759087Sps#include <netinet/in.h>
3859087Sps#include <netinet/udp.h>
3959087Sps
4059087Sps#include <net.h>
4159087Sps#include <netif.h>
4265498Smsmith#include <nfsv2.h>
4365498Smsmith#include <iodesc.h>
4459087Sps
4564527Sps#include <bootp.h>
4658713Sjhb#include <bootstrap.h>
4758713Sjhb#include "btxv86.h"
4858993Sps#include "pxe.h"
4958713Sjhb
5058713Sjhb/*
5158713Sjhb * Allocate the PXE buffers statically instead of sticking grimy fingers into
5258713Sjhb * BTX's private data area.  The scratch buffer is used to send information to
5358713Sjhb * the PXE BIOS, and the data buffer is used to receive data from the PXE BIOS.
5458713Sjhb */
5558993Sps#define	PXE_BUFFER_SIZE		0x2000
5658993Sps#define	PXE_TFTP_BUFFER_SIZE	512
5758993Spsstatic char	scratch_buffer[PXE_BUFFER_SIZE];
5858993Spsstatic char	data_buffer[PXE_BUFFER_SIZE];
5958713Sjhb
6059390Spsstatic pxenv_t	*pxenv_p = NULL;        /* PXENV+ */
6159390Spsstatic pxe_t	*pxe_p   = NULL;	/* !PXE */
6259087Spsstatic BOOTPLAYER	bootplayer;	/* PXE Cached information. */
6358713Sjhb
6464187Sjhbstatic int 	pxe_debug = 0;
6559087Spsstatic int	pxe_sock = -1;
6659087Spsstatic int	pxe_opens = 0;
6759087Sps
6858713Sjhbvoid		pxe_enable(void *pxeinfo);
6959644Spsstatic void	(*pxe_call)(int func);
7059644Spsstatic void	pxenv_call(int func);
7159644Spsstatic void	bangpxe_call(int func);
7259087Sps
7358713Sjhbstatic int	pxe_init(void);
7459087Spsstatic int	pxe_strategy(void *devdata, int flag, daddr_t dblk,
7564187Sjhb			     size_t size, char *buf, size_t *rsize);
7658713Sjhbstatic int	pxe_open(struct open_file *f, ...);
7758713Sjhbstatic int	pxe_close(struct open_file *f);
7858713Sjhbstatic void	pxe_print(int verbose);
7959390Spsstatic void	pxe_cleanup(void);
8065498Smsmithstatic void	pxe_setnfshandle(char *rootpath);
8158713Sjhb
8258713Sjhbstatic void	pxe_perror(int error);
8359087Spsstatic int	pxe_netif_match(struct netif *nif, void *machdep_hint);
8459087Spsstatic int	pxe_netif_probe(struct netif *nif, void *machdep_hint);
8559087Spsstatic void	pxe_netif_init(struct iodesc *desc, void *machdep_hint);
8659087Spsstatic int	pxe_netif_get(struct iodesc *desc, void *pkt, size_t len,
8759087Sps			      time_t timeout);
8859087Spsstatic int	pxe_netif_put(struct iodesc *desc, void *pkt, size_t len);
8959087Spsstatic void	pxe_netif_end(struct netif *nif);
9058713Sjhb
9159087Spsextern struct netif_stats	pxe_st[];
9259644Spsextern u_int16_t		__bangpxeseg;
9359644Spsextern u_int16_t		__bangpxeoff;
9459644Spsextern void			__bangpxeentry(void);
9559644Spsextern u_int16_t		__pxenvseg;
9659644Spsextern u_int16_t		__pxenvoff;
9759644Spsextern void			__pxenventry(void);
9858713Sjhb
9959087Spsstruct netif_dif pxe_ifs[] = {
10059087Sps/*      dif_unit        dif_nsel        dif_stats       dif_private     */
10159087Sps	{0,             1,              &pxe_st[0],     0}
10259087Sps};
10358713Sjhb
10459087Spsstruct netif_stats pxe_st[NENTS(pxe_ifs)];
10559087Sps
10659087Spsstruct netif_driver pxenetif = {
10759087Sps	"pxenet",
10859087Sps	pxe_netif_match,
10959087Sps	pxe_netif_probe,
11059087Sps	pxe_netif_init,
11159087Sps	pxe_netif_get,
11259087Sps	pxe_netif_put,
11359087Sps	pxe_netif_end,
11459087Sps	pxe_ifs,
11559087Sps	NENTS(pxe_ifs)
11659087Sps};
11759087Sps
11859087Spsstruct netif_driver *netif_drivers[] = {
11959087Sps	&pxenetif,
12059087Sps	NULL
12159087Sps};
12259087Sps
12358713Sjhbstruct devsw pxedisk = {
12458713Sjhb	"pxe",
12558713Sjhb	DEVT_NET,
12658713Sjhb	pxe_init,
12758713Sjhb	pxe_strategy,
12858713Sjhb	pxe_open,
12958713Sjhb	pxe_close,
13058713Sjhb	noioctl,
13159408Sps	pxe_print,
13259408Sps	pxe_cleanup
13358713Sjhb};
13458713Sjhb
13558713Sjhb/*
13658713Sjhb * This function is called by the loader to enable PXE support if we
13758713Sjhb * are booted by PXE.  The passed in pointer is a pointer to the
13858713Sjhb * PXENV+ structure.
13958713Sjhb */
14058713Sjhbvoid
14158713Sjhbpxe_enable(void *pxeinfo)
14258713Sjhb{
14359644Sps	pxenv_p  = (pxenv_t *)pxeinfo;
14459644Sps	pxe_p    = (pxe_t *)PTOV(pxenv_p->PXEPtr.segment * 16 +
14559644Sps				 pxenv_p->PXEPtr.offset);
14659644Sps	pxe_call = NULL;
14758713Sjhb}
14858713Sjhb
14958713Sjhb/*
15058713Sjhb * return true if pxe structures are found/initialized,
15158713Sjhb * also figures out our IP information via the pxe cached info struct
15258713Sjhb */
15358713Sjhbstatic int
15458713Sjhbpxe_init(void)
15558713Sjhb{
15658713Sjhb	t_PXENV_GET_CACHED_INFO	*gci_p;
15758713Sjhb	int	counter;
15858713Sjhb	uint8_t checksum;
15958713Sjhb	uint8_t *checkptr;
16058713Sjhb
16158713Sjhb	if(pxenv_p == NULL)
16258713Sjhb		return (0);
16358713Sjhb
16458713Sjhb	/*  look for "PXENV+" */
16559456Sps	if (bcmp((void *)pxenv_p->Signature, S_SIZE("PXENV+"))) {
16659456Sps		pxenv_p = NULL;
16758713Sjhb		return (0);
16859456Sps	}
16958713Sjhb
17058713Sjhb	/* make sure the size is something we can handle */
17158713Sjhb	if (pxenv_p->Length > sizeof(*pxenv_p)) {
17258713Sjhb	  	printf("PXENV+ structure too large, ignoring\n");
17358713Sjhb		pxenv_p = NULL;
17458713Sjhb		return (0);
17558713Sjhb	}
17658713Sjhb
17758713Sjhb	/*
17858713Sjhb	 * do byte checksum:
17958713Sjhb	 * add up each byte in the structure, the total should be 0
18058713Sjhb	 */
18158713Sjhb	checksum = 0;
18258713Sjhb	checkptr = (uint8_t *) pxenv_p;
18358713Sjhb	for (counter = 0; counter < pxenv_p->Length; counter++)
18458713Sjhb		checksum += *checkptr++;
18558713Sjhb	if (checksum != 0) {
18658713Sjhb		printf("PXENV+ structure failed checksum, ignoring\n");
18758713Sjhb		pxenv_p = NULL;
18858713Sjhb		return (0);
18958713Sjhb	}
19059390Sps
19159644Sps
19259644Sps	/*
19359644Sps	 * PXENV+ passed, so use that if !PXE is not available or
19459644Sps	 * the checksum fails.
19559644Sps	 */
19659644Sps	pxe_call = pxenv_call;
19759644Sps	if (pxenv_p->Version >= 0x0200) {
19859644Sps		for (;;) {
19959644Sps			if (bcmp((void *)pxe_p->Signature, S_SIZE("!PXE"))) {
20059644Sps				pxe_p = NULL;
20159644Sps				break;
20259644Sps			}
20359644Sps			checksum = 0;
20459644Sps			checkptr = (uint8_t *)pxe_p;
20559644Sps			for (counter = 0; counter < pxe_p->StructLength;
20659644Sps			     counter++)
20759644Sps				checksum += *checkptr++;
20859644Sps			if (checksum != 0) {
20959644Sps				pxe_p = NULL;
21059644Sps				break;
21159644Sps			}
21259644Sps			pxe_call = bangpxe_call;
21359644Sps			break;
21459644Sps		}
21559390Sps	}
21659644Sps
21759644Sps	printf("\nPXE version %d.%d, real mode entry point ",
21859644Sps	       (uint8_t) (pxenv_p->Version >> 8),
21959644Sps	       (uint8_t) (pxenv_p->Version & 0xFF));
22059644Sps	if (pxe_call == bangpxe_call)
22159644Sps		printf("@%04x:%04x\n",
22259644Sps		       pxe_p->EntryPointSP.segment,
22359644Sps		       pxe_p->EntryPointSP.offset);
22459644Sps	else
22559644Sps		printf("@%04x:%04x\n",
22659644Sps		       pxenv_p->RMEntry.segment, pxenv_p->RMEntry.offset);
22759390Sps
22858713Sjhb	gci_p = (t_PXENV_GET_CACHED_INFO *) scratch_buffer;
22958713Sjhb	bzero(gci_p, sizeof(*gci_p));
23058713Sjhb	gci_p->PacketType =  PXENV_PACKET_TYPE_BINL_REPLY;
23158713Sjhb	pxe_call(PXENV_GET_CACHED_INFO);
23258713Sjhb	if (gci_p->Status != 0) {
23358713Sjhb		pxe_perror(gci_p->Status);
23459455Sps		pxe_p = NULL;
23558713Sjhb		return (0);
23658713Sjhb	}
23759087Sps	bcopy(PTOV((gci_p->Buffer.segment << 4) + gci_p->Buffer.offset),
23859087Sps	      &bootplayer, gci_p->BufferSize);
23958713Sjhb	return (1);
24058713Sjhb}
24158713Sjhb
24259087Sps
24359087Spsstatic int
24459087Spspxe_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
24564187Sjhb		char *buf, size_t *rsize)
24658713Sjhb{
24759087Sps	return (EIO);
24858713Sjhb}
24958713Sjhb
25059087Spsstatic int
25159087Spspxe_open(struct open_file *f, ...)
25258713Sjhb{
25359087Sps    va_list args;
25459087Sps    char *devname;		/* Device part of file name (or NULL). */
25559686Sps    char temp[FNAME_SIZE];
25659087Sps    int error = 0;
25759686Sps    int i;
25859686Sps
25959087Sps    va_start(args, f);
26059087Sps    devname = va_arg(args, char*);
26159087Sps    va_end(args);
26259087Sps
26359087Sps    /* On first open, do netif open, mount, etc. */
26459087Sps    if (pxe_opens == 0) {
26559087Sps	/* Find network interface. */
26659087Sps	if (pxe_sock < 0) {
26759087Sps	    pxe_sock = netif_open(devname);
26859087Sps	    if (pxe_sock < 0) {
26959087Sps		printf("pxe_open: netif_open() failed\n");
27059087Sps		return (ENXIO);
27159087Sps	    }
27264187Sjhb	    if (pxe_debug)
27359087Sps		printf("pxe_open: netif_open() succeeded\n");
27459087Sps	}
27559686Sps	if (rootip.s_addr == 0) {
27659686Sps		/*
27759686Sps		 * Do a bootp/dhcp request to find out where our
27859686Sps		 * NFS/TFTP server is.  Even if we dont get back
27959686Sps		 * the proper information, fall back to the server
28059686Sps		 * which brought us to life and a default rootpath.
28159686Sps		 */
28264527Sps		bootp(pxe_sock, BOOTP_PXE);
28359768Sps		if (rootip.s_addr == 0)
28459686Sps			rootip.s_addr = bootplayer.sip;
285197082Semaste		if (!rootpath[0])
28659686Sps			strcpy(rootpath, PXENFSROOTPATH);
28759686Sps
288116451Siedowse		for (i = 0; rootpath[i] != '\0' && i < FNAME_SIZE; i++)
28968362Sps			if (rootpath[i] == ':')
29059686Sps				break;
291116451Siedowse		if (i && i != FNAME_SIZE && rootpath[i] == ':') {
29268362Sps			rootpath[i++] = '\0';
29368362Sps			if (inet_addr(&rootpath[0]) != INADDR_NONE)
29468362Sps				rootip.s_addr = inet_addr(&rootpath[0]);
29559686Sps			bcopy(&rootpath[i], &temp[0], strlen(&rootpath[i])+1);
29659686Sps			bcopy(&temp[0], &rootpath[0], strlen(&rootpath[i])+1);
29759686Sps		}
29859686Sps		printf("pxe_open: server addr: %s\n", inet_ntoa(rootip));
29959686Sps		printf("pxe_open: server path: %s\n", rootpath);
30059686Sps		printf("pxe_open: gateway ip:  %s\n", inet_ntoa(gateip));
30164522Sps
30265498Smsmith		setenv("boot.netif.ip", inet_ntoa(myip), 1);
30365498Smsmith		setenv("boot.netif.netmask", intoa(netmask), 1);
30465498Smsmith		setenv("boot.netif.gateway", inet_ntoa(gateip), 1);
30565498Smsmith		if (bootplayer.Hardware == ETHER_TYPE) {
30665498Smsmith		    sprintf(temp, "%6D", bootplayer.CAddr, ":");
30765498Smsmith		    setenv("boot.netif.hwaddr", temp, 1);
30865498Smsmith		}
30965498Smsmith		setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
31065498Smsmith		setenv("boot.nfsroot.path", rootpath, 1);
311145209Swollman		setenv("dhcp.host-name", hostname, 1);
31259686Sps	}
31359087Sps    }
31459087Sps    pxe_opens++;
31559087Sps    f->f_devdata = &pxe_sock;
31659087Sps    return (error);
31758713Sjhb}
31858713Sjhb
31959087Spsstatic int
32059087Spspxe_close(struct open_file *f)
32158713Sjhb{
32258713Sjhb
32359087Sps#ifdef	PXE_DEBUG
32464187Sjhb    if (pxe_debug)
32559087Sps	printf("pxe_close: opens=%d\n", pxe_opens);
32659087Sps#endif
32758713Sjhb
32859087Sps    /* On last close, do netif close, etc. */
32959087Sps    f->f_devdata = NULL;
33059087Sps    /* Extra close call? */
33159087Sps    if (pxe_opens <= 0)
33259087Sps	return (0);
33359087Sps    pxe_opens--;
33459087Sps    /* Not last close? */
33559087Sps    if (pxe_opens > 0)
33659087Sps	return(0);
33759686Sps
338172591Sps#ifdef LOADER_NFS_SUPPORT
33965498Smsmith    /* get an NFS filehandle for our root filesystem */
34065498Smsmith    pxe_setnfshandle(rootpath);
341172591Sps#endif
34265498Smsmith
34359087Sps    if (pxe_sock >= 0) {
34465498Smsmith
34559087Sps#ifdef PXE_DEBUG
34664187Sjhb	if (pxe_debug)
34759087Sps	    printf("pxe_close: calling netif_close()\n");
34859087Sps#endif
34959087Sps	netif_close(pxe_sock);
35059087Sps	pxe_sock = -1;
35159087Sps    }
35259087Sps    return (0);
35359087Sps}
35458713Sjhb
35559087Spsstatic void
35659087Spspxe_print(int verbose)
35759087Sps{
35859644Sps	if (pxe_call != NULL) {
35959087Sps		if (*bootplayer.Sname == '\0') {
36059087Sps			printf("      "IP_STR":%s\n",
36159087Sps			       IP_ARGS(htonl(bootplayer.sip)),
36259087Sps			       bootplayer.bootfile);
36359087Sps		} else {
36459087Sps			printf("      %s:%s\n", bootplayer.Sname,
36559087Sps			       bootplayer.bootfile);
36659087Sps		}
36759087Sps	}
36858713Sjhb
36959087Sps	return;
37058713Sjhb}
37158713Sjhb
37259390Spsstatic void
37359390Spspxe_cleanup(void)
37459390Sps{
37564187Sjhb#ifdef PXE_DEBUG
37659390Sps	t_PXENV_UNLOAD_STACK *unload_stack_p =
37759390Sps	    (t_PXENV_UNLOAD_STACK *)scratch_buffer;
37859390Sps	t_PXENV_UNDI_SHUTDOWN *undi_shutdown_p =
37959390Sps	    (t_PXENV_UNDI_SHUTDOWN *)scratch_buffer;
38064187Sjhb#endif
38159087Sps
38259644Sps	if (pxe_call == NULL)
38359455Sps		return;
38459455Sps
38559408Sps	pxe_call(PXENV_UNDI_SHUTDOWN);
38659855Sps
38759855Sps#ifdef PXE_DEBUG
38864187Sjhb	if (pxe_debug && undi_shutdown_p->Status != 0)
38959644Sps		printf("pxe_cleanup: UNDI_SHUTDOWN failed %x\n",
39059855Sps		       undi_shutdown_p->Status);
39159855Sps#endif
39259408Sps
39359390Sps	pxe_call(PXENV_UNLOAD_STACK);
39459855Sps
39559855Sps#ifdef PXE_DEBUG
39664187Sjhb	if (pxe_debug && unload_stack_p->Status != 0)
39759644Sps		printf("pxe_cleanup: UNLOAD_STACK failed %x\n",
39859408Sps		    unload_stack_p->Status);
39959855Sps#endif
40059390Sps}
40159390Sps
40258713Sjhbvoid
40358713Sjhbpxe_perror(int err)
40458713Sjhb{
40558713Sjhb	return;
40658713Sjhb}
40758713Sjhb
408231035Ssbruno#ifdef LOADER_NFS_SUPPORT
40965498Smsmith/*
41065498Smsmith * Reach inside the libstand NFS code and dig out an NFS handle
41165498Smsmith * for the root filesystem.
41265498Smsmith */
413212126Srmacklem#ifdef OLD_NFSV2
41465498Smsmithstruct nfs_iodesc {
41565498Smsmith	struct	iodesc	*iodesc;
41665498Smsmith	off_t	off;
41765498Smsmith	u_char	fh[NFS_FHSIZE];
41865498Smsmith	/* structure truncated here */
41965498Smsmith};
42065498Smsmithextern struct	nfs_iodesc nfs_root_node;
421143476Skanextern int      rpc_port;
42265498Smsmith
42365498Smsmithstatic void
424143476Skanpxe_rpcmountcall()
425143476Skan{
426143476Skan	struct	iodesc *d;
427143476Skan	int     error;
428143476Skan
429143476Skan	if (!(d = socktodesc(pxe_sock)))
430143476Skan		return;
431143476Skan        d->myport = htons(--rpc_port);
432143476Skan        d->destip = rootip;
433143476Skan	if ((error = nfs_getrootfh(d, rootpath, nfs_root_node.fh)) != 0)
434143476Skan		printf("NFS MOUNT RPC error: %d\n", error);
435143476Skan	nfs_root_node.iodesc = d;
436143476Skan}
437143476Skan
438143476Skanstatic void
43965498Smsmithpxe_setnfshandle(char *rootpath)
44065498Smsmith{
44165498Smsmith	int	i;
44265498Smsmith	u_char	*fh;
44365498Smsmith	char	buf[2 * NFS_FHSIZE + 3], *cp;
44465498Smsmith
445143476Skan	/*
446143476Skan	 * If NFS files were never opened, we need to do mount call
447143476Skan	 * ourselves. Use nfs_root_node.iodesc as flag indicating
448143476Skan	 * previous NFS usage.
449143476Skan	 */
450143476Skan	if (nfs_root_node.iodesc == NULL)
451143476Skan		pxe_rpcmountcall();
452143476Skan
45365498Smsmith	fh = &nfs_root_node.fh[0];
45465498Smsmith	buf[0] = 'X';
45565498Smsmith	cp = &buf[1];
45665498Smsmith	for (i = 0; i < NFS_FHSIZE; i++, cp += 2)
45765498Smsmith		sprintf(cp, "%02x", fh[i]);
45865498Smsmith	sprintf(cp, "X");
45965498Smsmith	setenv("boot.nfsroot.nfshandle", buf, 1);
46065498Smsmith}
461212126Srmacklem#else	/* !OLD_NFSV2 */
46265498Smsmith
463212126Srmacklem#define	NFS_V3MAXFHSIZE		64
464212126Srmacklem
465212126Srmacklemstruct nfs_iodesc {
466212126Srmacklem	struct iodesc *iodesc;
467212126Srmacklem	off_t off;
468212126Srmacklem	uint32_t fhsize;
469212126Srmacklem	u_char fh[NFS_V3MAXFHSIZE];
470212126Srmacklem	/* structure truncated */
471212126Srmacklem};
472212126Srmacklemextern struct nfs_iodesc nfs_root_node;
473212126Srmacklemextern int rpc_port;
474212126Srmacklem
475212126Srmacklemstatic void
476212126Srmacklempxe_rpcmountcall()
477212126Srmacklem{
478212126Srmacklem	struct iodesc *d;
479212126Srmacklem	int error;
480212126Srmacklem
481212126Srmacklem	if (!(d = socktodesc(pxe_sock)))
482212126Srmacklem		return;
483212126Srmacklem        d->myport = htons(--rpc_port);
484212126Srmacklem        d->destip = rootip;
485212126Srmacklem	if ((error = nfs_getrootfh(d, rootpath, &nfs_root_node.fhsize,
486212126Srmacklem	    nfs_root_node.fh)) != 0) {
487212126Srmacklem		printf("NFS MOUNT RPC error: %d\n", error);
488212126Srmacklem		nfs_root_node.fhsize = 0;
489212126Srmacklem	}
490212126Srmacklem	nfs_root_node.iodesc = d;
491212126Srmacklem}
492212126Srmacklem
493212126Srmacklemstatic void
494212126Srmacklempxe_setnfshandle(char *rootpath)
495212126Srmacklem{
496212126Srmacklem	int i;
497212126Srmacklem	u_char *fh;
498212126Srmacklem	char buf[2 * NFS_V3MAXFHSIZE + 3], *cp;
499212126Srmacklem
500212126Srmacklem	/*
501212126Srmacklem	 * If NFS files were never opened, we need to do mount call
502212126Srmacklem	 * ourselves. Use nfs_root_node.iodesc as flag indicating
503212126Srmacklem	 * previous NFS usage.
504212126Srmacklem	 */
505212126Srmacklem	if (nfs_root_node.iodesc == NULL)
506212126Srmacklem		pxe_rpcmountcall();
507212126Srmacklem
508212126Srmacklem	fh = &nfs_root_node.fh[0];
509212126Srmacklem	buf[0] = 'X';
510212126Srmacklem	cp = &buf[1];
511212126Srmacklem	for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2)
512212126Srmacklem		sprintf(cp, "%02x", fh[i]);
513212126Srmacklem	sprintf(cp, "X");
514212126Srmacklem	setenv("boot.nfsroot.nfshandle", buf, 1);
515212126Srmacklem	sprintf(buf, "%d", nfs_root_node.fhsize);
516212126Srmacklem	setenv("boot.nfsroot.nfshandlelen", buf, 1);
517212126Srmacklem}
518212126Srmacklem#endif	/* OLD_NFSV2 */
519231035Ssbruno#endif /* LOADER_NFS_SUPPORT */
520212126Srmacklem
52158713Sjhbvoid
52259644Spspxenv_call(int func)
52358713Sjhb{
52459644Sps#ifdef PXE_DEBUG
52564187Sjhb	if (pxe_debug)
52659644Sps		printf("pxenv_call %x\n", func);
52759644Sps#endif
52859644Sps
52958713Sjhb	bzero(&v86, sizeof(v86));
53058713Sjhb	bzero(data_buffer, sizeof(data_buffer));
53159390Sps
53259644Sps	__pxenvseg = pxenv_p->RMEntry.segment;
53359644Sps	__pxenvoff = pxenv_p->RMEntry.offset;
53459390Sps
53559390Sps	v86.ctl  = V86_ADDR | V86_CALLF | V86_FLAGS;
53659644Sps	v86.es   = VTOPSEG(scratch_buffer);
53759644Sps	v86.edi  = VTOPOFF(scratch_buffer);
53859644Sps	v86.addr = (VTOPSEG(__pxenventry) << 16) | VTOPOFF(__pxenventry);
53959644Sps	v86.ebx  = func;
54059644Sps	v86int();
54159644Sps	v86.ctl  = V86_FLAGS;
54259644Sps}
54359644Sps
54459644Spsvoid
54559644Spsbangpxe_call(int func)
54659644Sps{
54759644Sps#ifdef PXE_DEBUG
54864187Sjhb	if (pxe_debug)
54959644Sps		printf("bangpxe_call %x\n", func);
55059644Sps#endif
55159644Sps
55259644Sps	bzero(&v86, sizeof(v86));
55359644Sps	bzero(data_buffer, sizeof(data_buffer));
55459644Sps
55559644Sps	__bangpxeseg = pxe_p->EntryPointSP.segment;
55659644Sps	__bangpxeoff = pxe_p->EntryPointSP.offset;
55759644Sps
55859644Sps	v86.ctl  = V86_ADDR | V86_CALLF | V86_FLAGS;
55959390Sps	v86.edx  = VTOPSEG(scratch_buffer);
56059390Sps	v86.eax  = VTOPOFF(scratch_buffer);
56159644Sps	v86.addr = (VTOPSEG(__bangpxeentry) << 16) | VTOPOFF(__bangpxeentry);
56259390Sps	v86.ebx  = func;
56358713Sjhb	v86int();
56459390Sps	v86.ctl  = V86_FLAGS;
56558713Sjhb}
56658713Sjhb
56759087Sps
56859087Spstime_t
56959087Spsgetsecs()
57058713Sjhb{
57159087Sps	time_t n = 0;
57259087Sps	time(&n);
57359087Sps	return n;
57458713Sjhb}
57558713Sjhb
57658713Sjhbstatic int
57759087Spspxe_netif_match(struct netif *nif, void *machdep_hint)
57858713Sjhb{
57959087Sps	return 1;
58058713Sjhb}
58158713Sjhb
58259087Sps
58358713Sjhbstatic int
58459087Spspxe_netif_probe(struct netif *nif, void *machdep_hint)
58558713Sjhb{
58659087Sps	t_PXENV_UDP_OPEN *udpopen_p = (t_PXENV_UDP_OPEN *)scratch_buffer;
58759456Sps
58859644Sps	if (pxe_call == NULL)
58959456Sps		return -1;
59059456Sps
59159087Sps	bzero(udpopen_p, sizeof(*udpopen_p));
59259087Sps	udpopen_p->src_ip = bootplayer.yip;
59359087Sps	pxe_call(PXENV_UDP_OPEN);
59458713Sjhb
59559390Sps	if (udpopen_p->status != 0) {
59659087Sps		printf("pxe_netif_probe: failed %x\n", udpopen_p->status);
59759390Sps		return -1;
59859390Sps	}
59959087Sps	return 0;
60058713Sjhb}
60158713Sjhb
60259087Spsstatic void
60359087Spspxe_netif_end(struct netif *nif)
60458713Sjhb{
60559087Sps	t_PXENV_UDP_CLOSE *udpclose_p = (t_PXENV_UDP_CLOSE *)scratch_buffer;
60659087Sps	bzero(udpclose_p, sizeof(*udpclose_p));
60758713Sjhb
60859087Sps	pxe_call(PXENV_UDP_CLOSE);
60959087Sps	if (udpclose_p->status != 0)
61059087Sps		printf("pxe_end failed %x\n", udpclose_p->status);
61158713Sjhb}
61258713Sjhb
61359087Spsstatic void
61459087Spspxe_netif_init(struct iodesc *desc, void *machdep_hint)
61558713Sjhb{
61659686Sps	int i;
61759686Sps	for (i = 0; i < 6; ++i)
61859686Sps		desc->myea[i] = bootplayer.CAddr[i];
61959686Sps	desc->xid = bootplayer.ident;
62058713Sjhb}
62158713Sjhb
62258713Sjhbstatic int
62359087Spspxe_netif_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout)
62458713Sjhb{
62559087Sps	return len;
62658713Sjhb}
62758713Sjhb
62858713Sjhbstatic int
62959087Spspxe_netif_put(struct iodesc *desc, void *pkt, size_t len)
63058713Sjhb{
63159087Sps	return len;
63258713Sjhb}
63358713Sjhb
63459087Spsssize_t
63559087Spssendudp(struct iodesc *h, void *pkt, size_t len)
63658713Sjhb{
63759087Sps	t_PXENV_UDP_WRITE *udpwrite_p = (t_PXENV_UDP_WRITE *)scratch_buffer;
63859087Sps	bzero(udpwrite_p, sizeof(*udpwrite_p));
63959087Sps
64059686Sps	udpwrite_p->ip             = h->destip.s_addr;
64159087Sps	udpwrite_p->dst_port       = h->destport;
64259087Sps	udpwrite_p->src_port       = h->myport;
64359087Sps	udpwrite_p->buffer_size    = len;
64459087Sps	udpwrite_p->buffer.segment = VTOPSEG(pkt);
64559087Sps	udpwrite_p->buffer.offset  = VTOPOFF(pkt);
64658713Sjhb
64774265Sps	if (netmask == 0 || SAMENET(myip, h->destip, netmask))
64874265Sps		udpwrite_p->gw = 0;
64974265Sps	else
65074265Sps		udpwrite_p->gw = gateip.s_addr;
65174265Sps
65259087Sps	pxe_call(PXENV_UDP_WRITE);
65358713Sjhb
65459390Sps#if 0
65559087Sps	/* XXX - I dont know why we need this. */
65659087Sps	delay(1000);
65759390Sps#endif
65859390Sps	if (udpwrite_p->status != 0) {
65959673Sps		/* XXX: This happens a lot.  It shouldn't. */
66059673Sps		if (udpwrite_p->status != 1)
66159673Sps			printf("sendudp failed %x\n", udpwrite_p->status);
66259390Sps		return -1;
66359390Sps	}
66459087Sps	return len;
66558713Sjhb}
66658713Sjhb
66759087Spsssize_t
66859087Spsreadudp(struct iodesc *h, void *pkt, size_t len, time_t timeout)
66958713Sjhb{
67059087Sps	t_PXENV_UDP_READ *udpread_p = (t_PXENV_UDP_READ *)scratch_buffer;
67159087Sps	struct udphdr *uh = NULL;
67259087Sps
67359087Sps	uh = (struct udphdr *) pkt - 1;
67459087Sps	bzero(udpread_p, sizeof(*udpread_p));
67559087Sps
67659686Sps	udpread_p->dest_ip        = h->myip.s_addr;
67759087Sps	udpread_p->d_port         = h->myport;
67859087Sps	udpread_p->buffer_size    = len;
67959087Sps	udpread_p->buffer.segment = VTOPSEG(data_buffer);
68059087Sps	udpread_p->buffer.offset  = VTOPOFF(data_buffer);
68158713Sjhb
68259087Sps	pxe_call(PXENV_UDP_READ);
68358713Sjhb
68459390Sps#if 0
68559087Sps	/* XXX - I dont know why we need this. */
68659087Sps	delay(1000);
68759390Sps#endif
68859390Sps	if (udpread_p->status != 0) {
68959390Sps		/* XXX: This happens a lot.  It shouldn't. */
69059390Sps		if (udpread_p->status != 1)
69159390Sps			printf("readudp failed %x\n", udpread_p->status);
69259390Sps		return -1;
69359390Sps	}
69459087Sps	bcopy(data_buffer, pkt, udpread_p->buffer_size);
69559087Sps	uh->uh_sport = udpread_p->s_port;
69659087Sps	return udpread_p->buffer_size;
69758713Sjhb}
698