pxe.c revision 145209
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: head/sys/boot/i386/libi386/pxe.c 145209 2005-04-17 21:38:22Z wollman $");
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;
28559768Sps		if (!rootpath[1])
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
33865498Smsmith    /* get an NFS filehandle for our root filesystem */
33965498Smsmith    pxe_setnfshandle(rootpath);
34065498Smsmith
34159087Sps    if (pxe_sock >= 0) {
34265498Smsmith
34359087Sps#ifdef PXE_DEBUG
34464187Sjhb	if (pxe_debug)
34559087Sps	    printf("pxe_close: calling netif_close()\n");
34659087Sps#endif
34759087Sps	netif_close(pxe_sock);
34859087Sps	pxe_sock = -1;
34959087Sps    }
35059087Sps    return (0);
35159087Sps}
35258713Sjhb
35359087Spsstatic void
35459087Spspxe_print(int verbose)
35559087Sps{
35659644Sps	if (pxe_call != NULL) {
35759087Sps		if (*bootplayer.Sname == '\0') {
35859087Sps			printf("      "IP_STR":%s\n",
35959087Sps			       IP_ARGS(htonl(bootplayer.sip)),
36059087Sps			       bootplayer.bootfile);
36159087Sps		} else {
36259087Sps			printf("      %s:%s\n", bootplayer.Sname,
36359087Sps			       bootplayer.bootfile);
36459087Sps		}
36559087Sps	}
36658713Sjhb
36759087Sps	return;
36858713Sjhb}
36958713Sjhb
37059390Spsstatic void
37159390Spspxe_cleanup(void)
37259390Sps{
37364187Sjhb#ifdef PXE_DEBUG
37459390Sps	t_PXENV_UNLOAD_STACK *unload_stack_p =
37559390Sps	    (t_PXENV_UNLOAD_STACK *)scratch_buffer;
37659390Sps	t_PXENV_UNDI_SHUTDOWN *undi_shutdown_p =
37759390Sps	    (t_PXENV_UNDI_SHUTDOWN *)scratch_buffer;
37864187Sjhb#endif
37959087Sps
38059644Sps	if (pxe_call == NULL)
38159455Sps		return;
38259455Sps
38359408Sps	pxe_call(PXENV_UNDI_SHUTDOWN);
38459855Sps
38559855Sps#ifdef PXE_DEBUG
38664187Sjhb	if (pxe_debug && undi_shutdown_p->Status != 0)
38759644Sps		printf("pxe_cleanup: UNDI_SHUTDOWN failed %x\n",
38859855Sps		       undi_shutdown_p->Status);
38959855Sps#endif
39059408Sps
39159390Sps	pxe_call(PXENV_UNLOAD_STACK);
39259855Sps
39359855Sps#ifdef PXE_DEBUG
39464187Sjhb	if (pxe_debug && unload_stack_p->Status != 0)
39559644Sps		printf("pxe_cleanup: UNLOAD_STACK failed %x\n",
39659408Sps		    unload_stack_p->Status);
39759855Sps#endif
39859390Sps}
39959390Sps
40058713Sjhbvoid
40158713Sjhbpxe_perror(int err)
40258713Sjhb{
40358713Sjhb	return;
40458713Sjhb}
40558713Sjhb
40665498Smsmith/*
40765498Smsmith * Reach inside the libstand NFS code and dig out an NFS handle
40865498Smsmith * for the root filesystem.
40965498Smsmith */
41065498Smsmithstruct nfs_iodesc {
41165498Smsmith	struct	iodesc	*iodesc;
41265498Smsmith	off_t	off;
41365498Smsmith	u_char	fh[NFS_FHSIZE];
41465498Smsmith	/* structure truncated here */
41565498Smsmith};
41665498Smsmithextern struct	nfs_iodesc nfs_root_node;
417143476Skanextern int      rpc_port;
41865498Smsmith
41965498Smsmithstatic void
420143476Skanpxe_rpcmountcall()
421143476Skan{
422143476Skan	struct	iodesc *d;
423143476Skan	int     error;
424143476Skan
425143476Skan	if (!(d = socktodesc(pxe_sock)))
426143476Skan		return;
427143476Skan        d->myport = htons(--rpc_port);
428143476Skan        d->destip = rootip;
429143476Skan	if ((error = nfs_getrootfh(d, rootpath, nfs_root_node.fh)) != 0)
430143476Skan		printf("NFS MOUNT RPC error: %d\n", error);
431143476Skan	nfs_root_node.iodesc = d;
432143476Skan}
433143476Skan
434143476Skanstatic void
43565498Smsmithpxe_setnfshandle(char *rootpath)
43665498Smsmith{
43765498Smsmith	int	i;
43865498Smsmith	u_char	*fh;
43965498Smsmith	char	buf[2 * NFS_FHSIZE + 3], *cp;
44065498Smsmith
441143476Skan	/*
442143476Skan	 * If NFS files were never opened, we need to do mount call
443143476Skan	 * ourselves. Use nfs_root_node.iodesc as flag indicating
444143476Skan	 * previous NFS usage.
445143476Skan	 */
446143476Skan	if (nfs_root_node.iodesc == NULL)
447143476Skan		pxe_rpcmountcall();
448143476Skan
44965498Smsmith	fh = &nfs_root_node.fh[0];
45065498Smsmith	buf[0] = 'X';
45165498Smsmith	cp = &buf[1];
45265498Smsmith	for (i = 0; i < NFS_FHSIZE; i++, cp += 2)
45365498Smsmith		sprintf(cp, "%02x", fh[i]);
45465498Smsmith	sprintf(cp, "X");
45565498Smsmith	setenv("boot.nfsroot.nfshandle", buf, 1);
45665498Smsmith}
45765498Smsmith
45858713Sjhbvoid
45959644Spspxenv_call(int func)
46058713Sjhb{
46159644Sps#ifdef PXE_DEBUG
46264187Sjhb	if (pxe_debug)
46359644Sps		printf("pxenv_call %x\n", func);
46459644Sps#endif
46559644Sps
46658713Sjhb	bzero(&v86, sizeof(v86));
46758713Sjhb	bzero(data_buffer, sizeof(data_buffer));
46859390Sps
46959644Sps	__pxenvseg = pxenv_p->RMEntry.segment;
47059644Sps	__pxenvoff = pxenv_p->RMEntry.offset;
47159390Sps
47259390Sps	v86.ctl  = V86_ADDR | V86_CALLF | V86_FLAGS;
47359644Sps	v86.es   = VTOPSEG(scratch_buffer);
47459644Sps	v86.edi  = VTOPOFF(scratch_buffer);
47559644Sps	v86.addr = (VTOPSEG(__pxenventry) << 16) | VTOPOFF(__pxenventry);
47659644Sps	v86.ebx  = func;
47759644Sps	v86int();
47859644Sps	v86.ctl  = V86_FLAGS;
47959644Sps}
48059644Sps
48159644Spsvoid
48259644Spsbangpxe_call(int func)
48359644Sps{
48459644Sps#ifdef PXE_DEBUG
48564187Sjhb	if (pxe_debug)
48659644Sps		printf("bangpxe_call %x\n", func);
48759644Sps#endif
48859644Sps
48959644Sps	bzero(&v86, sizeof(v86));
49059644Sps	bzero(data_buffer, sizeof(data_buffer));
49159644Sps
49259644Sps	__bangpxeseg = pxe_p->EntryPointSP.segment;
49359644Sps	__bangpxeoff = pxe_p->EntryPointSP.offset;
49459644Sps
49559644Sps	v86.ctl  = V86_ADDR | V86_CALLF | V86_FLAGS;
49659390Sps	v86.edx  = VTOPSEG(scratch_buffer);
49759390Sps	v86.eax  = VTOPOFF(scratch_buffer);
49859644Sps	v86.addr = (VTOPSEG(__bangpxeentry) << 16) | VTOPOFF(__bangpxeentry);
49959390Sps	v86.ebx  = func;
50058713Sjhb	v86int();
50159390Sps	v86.ctl  = V86_FLAGS;
50258713Sjhb}
50358713Sjhb
50459087Sps
50559087Spstime_t
50659087Spsgetsecs()
50758713Sjhb{
50859087Sps	time_t n = 0;
50959087Sps	time(&n);
51059087Sps	return n;
51158713Sjhb}
51258713Sjhb
51358713Sjhbstatic int
51459087Spspxe_netif_match(struct netif *nif, void *machdep_hint)
51558713Sjhb{
51659087Sps	return 1;
51758713Sjhb}
51858713Sjhb
51959087Sps
52058713Sjhbstatic int
52159087Spspxe_netif_probe(struct netif *nif, void *machdep_hint)
52258713Sjhb{
52359087Sps	t_PXENV_UDP_OPEN *udpopen_p = (t_PXENV_UDP_OPEN *)scratch_buffer;
52459456Sps
52559644Sps	if (pxe_call == NULL)
52659456Sps		return -1;
52759456Sps
52859087Sps	bzero(udpopen_p, sizeof(*udpopen_p));
52959087Sps	udpopen_p->src_ip = bootplayer.yip;
53059087Sps	pxe_call(PXENV_UDP_OPEN);
53158713Sjhb
53259390Sps	if (udpopen_p->status != 0) {
53359087Sps		printf("pxe_netif_probe: failed %x\n", udpopen_p->status);
53459390Sps		return -1;
53559390Sps	}
53659087Sps	return 0;
53758713Sjhb}
53858713Sjhb
53959087Spsstatic void
54059087Spspxe_netif_end(struct netif *nif)
54158713Sjhb{
54259087Sps	t_PXENV_UDP_CLOSE *udpclose_p = (t_PXENV_UDP_CLOSE *)scratch_buffer;
54359087Sps	bzero(udpclose_p, sizeof(*udpclose_p));
54458713Sjhb
54559087Sps	pxe_call(PXENV_UDP_CLOSE);
54659087Sps	if (udpclose_p->status != 0)
54759087Sps		printf("pxe_end failed %x\n", udpclose_p->status);
54858713Sjhb}
54958713Sjhb
55059087Spsstatic void
55159087Spspxe_netif_init(struct iodesc *desc, void *machdep_hint)
55258713Sjhb{
55359686Sps	int i;
55459686Sps	for (i = 0; i < 6; ++i)
55559686Sps		desc->myea[i] = bootplayer.CAddr[i];
55659686Sps	desc->xid = bootplayer.ident;
55758713Sjhb}
55858713Sjhb
55958713Sjhbstatic int
56059087Spspxe_netif_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout)
56158713Sjhb{
56259087Sps	return len;
56358713Sjhb}
56458713Sjhb
56558713Sjhbstatic int
56659087Spspxe_netif_put(struct iodesc *desc, void *pkt, size_t len)
56758713Sjhb{
56859087Sps	return len;
56958713Sjhb}
57058713Sjhb
57159087Spsssize_t
57259087Spssendudp(struct iodesc *h, void *pkt, size_t len)
57358713Sjhb{
57459087Sps	t_PXENV_UDP_WRITE *udpwrite_p = (t_PXENV_UDP_WRITE *)scratch_buffer;
57559087Sps	bzero(udpwrite_p, sizeof(*udpwrite_p));
57659087Sps
57759686Sps	udpwrite_p->ip             = h->destip.s_addr;
57859087Sps	udpwrite_p->dst_port       = h->destport;
57959087Sps	udpwrite_p->src_port       = h->myport;
58059087Sps	udpwrite_p->buffer_size    = len;
58159087Sps	udpwrite_p->buffer.segment = VTOPSEG(pkt);
58259087Sps	udpwrite_p->buffer.offset  = VTOPOFF(pkt);
58358713Sjhb
58474265Sps	if (netmask == 0 || SAMENET(myip, h->destip, netmask))
58574265Sps		udpwrite_p->gw = 0;
58674265Sps	else
58774265Sps		udpwrite_p->gw = gateip.s_addr;
58874265Sps
58959087Sps	pxe_call(PXENV_UDP_WRITE);
59058713Sjhb
59159390Sps#if 0
59259087Sps	/* XXX - I dont know why we need this. */
59359087Sps	delay(1000);
59459390Sps#endif
59559390Sps	if (udpwrite_p->status != 0) {
59659673Sps		/* XXX: This happens a lot.  It shouldn't. */
59759673Sps		if (udpwrite_p->status != 1)
59859673Sps			printf("sendudp failed %x\n", udpwrite_p->status);
59959390Sps		return -1;
60059390Sps	}
60159087Sps	return len;
60258713Sjhb}
60358713Sjhb
60459087Spsssize_t
60559087Spsreadudp(struct iodesc *h, void *pkt, size_t len, time_t timeout)
60658713Sjhb{
60759087Sps	t_PXENV_UDP_READ *udpread_p = (t_PXENV_UDP_READ *)scratch_buffer;
60859087Sps	struct udphdr *uh = NULL;
60959087Sps
61059087Sps	uh = (struct udphdr *) pkt - 1;
61159087Sps	bzero(udpread_p, sizeof(*udpread_p));
61259087Sps
61359686Sps	udpread_p->dest_ip        = h->myip.s_addr;
61459087Sps	udpread_p->d_port         = h->myport;
61559087Sps	udpread_p->buffer_size    = len;
61659087Sps	udpread_p->buffer.segment = VTOPSEG(data_buffer);
61759087Sps	udpread_p->buffer.offset  = VTOPOFF(data_buffer);
61858713Sjhb
61959087Sps	pxe_call(PXENV_UDP_READ);
62058713Sjhb
62159390Sps#if 0
62259087Sps	/* XXX - I dont know why we need this. */
62359087Sps	delay(1000);
62459390Sps#endif
62559390Sps	if (udpread_p->status != 0) {
62659390Sps		/* XXX: This happens a lot.  It shouldn't. */
62759390Sps		if (udpread_p->status != 1)
62859390Sps			printf("readudp failed %x\n", udpread_p->status);
62959390Sps		return -1;
63059390Sps	}
63159087Sps	bcopy(data_buffer, pkt, udpread_p->buffer_size);
63259087Sps	uh->uh_sport = udpread_p->s_port;
63359087Sps	return udpread_p->buffer_size;
63458713Sjhb}
635