pxe.c revision 68362
158713Sjhb/*
258713Sjhb * Copyright (c) 2000 Alfred Perlstein <alfred@freebsd.org>
358713Sjhb * All rights reserved.
458713Sjhb * Copyright (c) 2000 Paul Saab <ps@freebsd.org>
558713Sjhb * All rights reserved.
658713Sjhb * Copyright (c) 2000 John Baldwin <jhb@freebsd.org>
758713Sjhb * All rights reserved.
858713Sjhb *
958713Sjhb * Redistribution and use in source and binary forms, with or without
1058713Sjhb * modification, are permitted provided that the following conditions
1158713Sjhb * are met:
1258713Sjhb * 1. Redistributions of source code must retain the above copyright
1358713Sjhb *    notice, this list of conditions and the following disclaimer.
1458713Sjhb * 2. Redistributions in binary form must reproduce the above copyright
1558713Sjhb *    notice, this list of conditions and the following disclaimer in the
1658713Sjhb *    documentation and/or other materials provided with the distribution.
1758713Sjhb *
1858713Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1958713Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2058713Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2158713Sjhb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2258713Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2358713Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2458713Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2558713Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2658713Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2758713Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2858713Sjhb * SUCH DAMAGE.
2958713Sjhb *
3058713Sjhb * $FreeBSD: head/sys/boot/i386/libi386/pxe.c 68362 2000-11-05 14:55:09Z ps $
3158713Sjhb */
3258713Sjhb
3358713Sjhb#include <stand.h>
3459768Sps#include <string.h>
3559768Sps#include <stdarg.h>
3658713Sjhb
3759087Sps#include <netinet/in_systm.h>
3859087Sps#include <netinet/in.h>
3959087Sps#include <netinet/udp.h>
4059087Sps
4159087Sps#include <net.h>
4259087Sps#include <netif.h>
4365498Smsmith#include <nfsv2.h>
4465498Smsmith#include <iodesc.h>
4559087Sps
4664527Sps#include <bootp.h>
4758713Sjhb#include <bootstrap.h>
4858713Sjhb#include "btxv86.h"
4958993Sps#include "pxe.h"
5058713Sjhb
5158713Sjhb/*
5258713Sjhb * Allocate the PXE buffers statically instead of sticking grimy fingers into
5358713Sjhb * BTX's private data area.  The scratch buffer is used to send information to
5458713Sjhb * the PXE BIOS, and the data buffer is used to receive data from the PXE BIOS.
5558713Sjhb */
5658993Sps#define	PXE_BUFFER_SIZE		0x2000
5758993Sps#define	PXE_TFTP_BUFFER_SIZE	512
5858993Spsstatic char	scratch_buffer[PXE_BUFFER_SIZE];
5958993Spsstatic char	data_buffer[PXE_BUFFER_SIZE];
6058713Sjhb
6159390Spsstatic pxenv_t	*pxenv_p = NULL;        /* PXENV+ */
6259390Spsstatic pxe_t	*pxe_p   = NULL;	/* !PXE */
6359087Spsstatic BOOTPLAYER	bootplayer;	/* PXE Cached information. */
6458713Sjhb
6564187Sjhbstatic int 	pxe_debug = 0;
6659087Spsstatic int	pxe_sock = -1;
6759087Spsstatic int	pxe_opens = 0;
6859087Sps
6958713Sjhbvoid		pxe_enable(void *pxeinfo);
7059644Spsstatic void	(*pxe_call)(int func);
7159644Spsstatic void	pxenv_call(int func);
7259644Spsstatic void	bangpxe_call(int func);
7359087Sps
7458713Sjhbstatic int	pxe_init(void);
7559087Spsstatic int	pxe_strategy(void *devdata, int flag, daddr_t dblk,
7664187Sjhb			     size_t size, char *buf, size_t *rsize);
7758713Sjhbstatic int	pxe_open(struct open_file *f, ...);
7858713Sjhbstatic int	pxe_close(struct open_file *f);
7958713Sjhbstatic void	pxe_print(int verbose);
8059390Spsstatic void	pxe_cleanup(void);
8165498Smsmithstatic void	pxe_setnfshandle(char *rootpath);
8258713Sjhb
8358713Sjhbstatic void	pxe_perror(int error);
8459087Spsstatic int	pxe_netif_match(struct netif *nif, void *machdep_hint);
8559087Spsstatic int	pxe_netif_probe(struct netif *nif, void *machdep_hint);
8659087Spsstatic void	pxe_netif_init(struct iodesc *desc, void *machdep_hint);
8759087Spsstatic int	pxe_netif_get(struct iodesc *desc, void *pkt, size_t len,
8859087Sps			      time_t timeout);
8959087Spsstatic int	pxe_netif_put(struct iodesc *desc, void *pkt, size_t len);
9059087Spsstatic void	pxe_netif_end(struct netif *nif);
9158713Sjhb
9259087Spsextern struct netif_stats	pxe_st[];
9359644Spsextern u_int16_t		__bangpxeseg;
9459644Spsextern u_int16_t		__bangpxeoff;
9559644Spsextern void			__bangpxeentry(void);
9659644Spsextern u_int16_t		__pxenvseg;
9759644Spsextern u_int16_t		__pxenvoff;
9859644Spsextern void			__pxenventry(void);
9958713Sjhb
10059087Spsstruct netif_dif pxe_ifs[] = {
10159087Sps/*      dif_unit        dif_nsel        dif_stats       dif_private     */
10259087Sps	{0,             1,              &pxe_st[0],     0}
10359087Sps};
10458713Sjhb
10559087Spsstruct netif_stats pxe_st[NENTS(pxe_ifs)];
10659087Sps
10759087Spsstruct netif_driver pxenetif = {
10859087Sps	"pxenet",
10959087Sps	pxe_netif_match,
11059087Sps	pxe_netif_probe,
11159087Sps	pxe_netif_init,
11259087Sps	pxe_netif_get,
11359087Sps	pxe_netif_put,
11459087Sps	pxe_netif_end,
11559087Sps	pxe_ifs,
11659087Sps	NENTS(pxe_ifs)
11759087Sps};
11859087Sps
11959087Spsstruct netif_driver *netif_drivers[] = {
12059087Sps	&pxenetif,
12159087Sps	NULL
12259087Sps};
12359087Sps
12458713Sjhbstruct devsw pxedisk = {
12558713Sjhb	"pxe",
12658713Sjhb	DEVT_NET,
12758713Sjhb	pxe_init,
12858713Sjhb	pxe_strategy,
12958713Sjhb	pxe_open,
13058713Sjhb	pxe_close,
13158713Sjhb	noioctl,
13259408Sps	pxe_print,
13359408Sps	pxe_cleanup
13458713Sjhb};
13558713Sjhb
13658713Sjhb/*
13758713Sjhb * This function is called by the loader to enable PXE support if we
13858713Sjhb * are booted by PXE.  The passed in pointer is a pointer to the
13958713Sjhb * PXENV+ structure.
14058713Sjhb */
14158713Sjhbvoid
14258713Sjhbpxe_enable(void *pxeinfo)
14358713Sjhb{
14459644Sps	pxenv_p  = (pxenv_t *)pxeinfo;
14559644Sps	pxe_p    = (pxe_t *)PTOV(pxenv_p->PXEPtr.segment * 16 +
14659644Sps				 pxenv_p->PXEPtr.offset);
14759644Sps	pxe_call = NULL;
14858713Sjhb}
14958713Sjhb
15058713Sjhb/*
15158713Sjhb * return true if pxe structures are found/initialized,
15258713Sjhb * also figures out our IP information via the pxe cached info struct
15358713Sjhb */
15458713Sjhbstatic int
15558713Sjhbpxe_init(void)
15658713Sjhb{
15758713Sjhb	t_PXENV_GET_CACHED_INFO	*gci_p;
15858713Sjhb	int	counter;
15958713Sjhb	uint8_t checksum;
16058713Sjhb	uint8_t *checkptr;
16158713Sjhb
16258713Sjhb	if(pxenv_p == NULL)
16358713Sjhb		return (0);
16458713Sjhb
16558713Sjhb	/*  look for "PXENV+" */
16659456Sps	if (bcmp((void *)pxenv_p->Signature, S_SIZE("PXENV+"))) {
16759456Sps		pxenv_p = NULL;
16858713Sjhb		return (0);
16959456Sps	}
17058713Sjhb
17158713Sjhb	/* make sure the size is something we can handle */
17258713Sjhb	if (pxenv_p->Length > sizeof(*pxenv_p)) {
17358713Sjhb	  	printf("PXENV+ structure too large, ignoring\n");
17458713Sjhb		pxenv_p = NULL;
17558713Sjhb		return (0);
17658713Sjhb	}
17758713Sjhb
17858713Sjhb	/*
17958713Sjhb	 * do byte checksum:
18058713Sjhb	 * add up each byte in the structure, the total should be 0
18158713Sjhb	 */
18258713Sjhb	checksum = 0;
18358713Sjhb	checkptr = (uint8_t *) pxenv_p;
18458713Sjhb	for (counter = 0; counter < pxenv_p->Length; counter++)
18558713Sjhb		checksum += *checkptr++;
18658713Sjhb	if (checksum != 0) {
18758713Sjhb		printf("PXENV+ structure failed checksum, ignoring\n");
18858713Sjhb		pxenv_p = NULL;
18958713Sjhb		return (0);
19058713Sjhb	}
19159390Sps
19259644Sps
19359644Sps	/*
19459644Sps	 * PXENV+ passed, so use that if !PXE is not available or
19559644Sps	 * the checksum fails.
19659644Sps	 */
19759644Sps	pxe_call = pxenv_call;
19859644Sps	if (pxenv_p->Version >= 0x0200) {
19959644Sps		for (;;) {
20059644Sps			if (bcmp((void *)pxe_p->Signature, S_SIZE("!PXE"))) {
20159644Sps				pxe_p = NULL;
20259644Sps				break;
20359644Sps			}
20459644Sps			checksum = 0;
20559644Sps			checkptr = (uint8_t *)pxe_p;
20659644Sps			for (counter = 0; counter < pxe_p->StructLength;
20759644Sps			     counter++)
20859644Sps				checksum += *checkptr++;
20959644Sps			if (checksum != 0) {
21059644Sps				pxe_p = NULL;
21159644Sps				break;
21259644Sps			}
21359644Sps			pxe_call = bangpxe_call;
21459644Sps			break;
21559644Sps		}
21659390Sps	}
21759644Sps
21859644Sps	printf("\nPXE version %d.%d, real mode entry point ",
21959644Sps	       (uint8_t) (pxenv_p->Version >> 8),
22059644Sps	       (uint8_t) (pxenv_p->Version & 0xFF));
22159644Sps	if (pxe_call == bangpxe_call)
22259644Sps		printf("@%04x:%04x\n",
22359644Sps		       pxe_p->EntryPointSP.segment,
22459644Sps		       pxe_p->EntryPointSP.offset);
22559644Sps	else
22659644Sps		printf("@%04x:%04x\n",
22759644Sps		       pxenv_p->RMEntry.segment, pxenv_p->RMEntry.offset);
22859390Sps
22958713Sjhb	gci_p = (t_PXENV_GET_CACHED_INFO *) scratch_buffer;
23058713Sjhb	bzero(gci_p, sizeof(*gci_p));
23158713Sjhb	gci_p->PacketType =  PXENV_PACKET_TYPE_BINL_REPLY;
23258713Sjhb	pxe_call(PXENV_GET_CACHED_INFO);
23358713Sjhb	if (gci_p->Status != 0) {
23458713Sjhb		pxe_perror(gci_p->Status);
23559455Sps		pxe_p = NULL;
23658713Sjhb		return (0);
23758713Sjhb	}
23859087Sps	bcopy(PTOV((gci_p->Buffer.segment << 4) + gci_p->Buffer.offset),
23959087Sps	      &bootplayer, gci_p->BufferSize);
24058713Sjhb	return (1);
24158713Sjhb}
24258713Sjhb
24359087Sps
24459087Spsstatic int
24559087Spspxe_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
24664187Sjhb		char *buf, size_t *rsize)
24758713Sjhb{
24859087Sps	return (EIO);
24958713Sjhb}
25058713Sjhb
25159087Spsstatic int
25259087Spspxe_open(struct open_file *f, ...)
25358713Sjhb{
25459087Sps    va_list args;
25559087Sps    char *devname;		/* Device part of file name (or NULL). */
25659686Sps    char temp[FNAME_SIZE];
25759087Sps    int error = 0;
25859686Sps    int i;
25959686Sps
26059087Sps    va_start(args, f);
26159087Sps    devname = va_arg(args, char*);
26259087Sps    va_end(args);
26359087Sps
26459087Sps    /* On first open, do netif open, mount, etc. */
26559087Sps    if (pxe_opens == 0) {
26659087Sps	/* Find network interface. */
26759087Sps	if (pxe_sock < 0) {
26859087Sps	    pxe_sock = netif_open(devname);
26959087Sps	    if (pxe_sock < 0) {
27059087Sps		printf("pxe_open: netif_open() failed\n");
27159087Sps		return (ENXIO);
27259087Sps	    }
27364187Sjhb	    if (pxe_debug)
27459087Sps		printf("pxe_open: netif_open() succeeded\n");
27559087Sps	}
27659686Sps	if (rootip.s_addr == 0) {
27759686Sps		/*
27859686Sps		 * Do a bootp/dhcp request to find out where our
27959686Sps		 * NFS/TFTP server is.  Even if we dont get back
28059686Sps		 * the proper information, fall back to the server
28159686Sps		 * which brought us to life and a default rootpath.
28259686Sps		 */
28364527Sps		bootp(pxe_sock, BOOTP_PXE);
28459768Sps		if (rootip.s_addr == 0)
28559686Sps			rootip.s_addr = bootplayer.sip;
28659768Sps		if (!rootpath[1])
28759686Sps			strcpy(rootpath, PXENFSROOTPATH);
28859686Sps
28968362Sps		for (i = 0; i < FNAME_SIZE; i++)
29068362Sps			if (rootpath[i] == ':')
29159686Sps				break;
29268362Sps		if (i && i != FNAME_SIZE) {
29368362Sps			rootpath[i++] = '\0';
29468362Sps			if (inet_addr(&rootpath[0]) != INADDR_NONE)
29568362Sps				rootip.s_addr = inet_addr(&rootpath[0]);
29659686Sps			bcopy(&rootpath[i], &temp[0], strlen(&rootpath[i])+1);
29759686Sps			bcopy(&temp[0], &rootpath[0], strlen(&rootpath[i])+1);
29859686Sps		}
29959686Sps		printf("pxe_open: server addr: %s\n", inet_ntoa(rootip));
30059686Sps		printf("pxe_open: server path: %s\n", rootpath);
30159686Sps		printf("pxe_open: gateway ip:  %s\n", inet_ntoa(gateip));
30264522Sps
30365498Smsmith		setenv("boot.netif.ip", inet_ntoa(myip), 1);
30465498Smsmith		setenv("boot.netif.netmask", intoa(netmask), 1);
30565498Smsmith		setenv("boot.netif.gateway", inet_ntoa(gateip), 1);
30665498Smsmith		if (bootplayer.Hardware == ETHER_TYPE) {
30765498Smsmith		    sprintf(temp, "%6D", bootplayer.CAddr, ":");
30865498Smsmith		    setenv("boot.netif.hwaddr", temp, 1);
30965498Smsmith		}
31065498Smsmith		setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
31165498Smsmith		setenv("boot.nfsroot.path", rootpath, 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;
41765498Smsmith
41865498Smsmithstatic void
41965498Smsmithpxe_setnfshandle(char *rootpath)
42065498Smsmith{
42165498Smsmith	int	i;
42265498Smsmith	u_char	*fh;
42365498Smsmith	char	buf[2 * NFS_FHSIZE + 3], *cp;
42465498Smsmith
42565498Smsmith	fh = &nfs_root_node.fh[0];
42665498Smsmith	buf[0] = 'X';
42765498Smsmith	cp = &buf[1];
42865498Smsmith	for (i = 0; i < NFS_FHSIZE; i++, cp += 2)
42965498Smsmith		sprintf(cp, "%02x", fh[i]);
43065498Smsmith	sprintf(cp, "X");
43165498Smsmith	setenv("boot.nfsroot.nfshandle", buf, 1);
43265498Smsmith}
43365498Smsmith
43458713Sjhbvoid
43559644Spspxenv_call(int func)
43658713Sjhb{
43759644Sps#ifdef PXE_DEBUG
43864187Sjhb	if (pxe_debug)
43959644Sps		printf("pxenv_call %x\n", func);
44059644Sps#endif
44159644Sps
44258713Sjhb	bzero(&v86, sizeof(v86));
44358713Sjhb	bzero(data_buffer, sizeof(data_buffer));
44459390Sps
44559644Sps	__pxenvseg = pxenv_p->RMEntry.segment;
44659644Sps	__pxenvoff = pxenv_p->RMEntry.offset;
44759390Sps
44859390Sps	v86.ctl  = V86_ADDR | V86_CALLF | V86_FLAGS;
44959644Sps	v86.es   = VTOPSEG(scratch_buffer);
45059644Sps	v86.edi  = VTOPOFF(scratch_buffer);
45159644Sps	v86.addr = (VTOPSEG(__pxenventry) << 16) | VTOPOFF(__pxenventry);
45259644Sps	v86.ebx  = func;
45359644Sps	v86int();
45459644Sps	v86.ctl  = V86_FLAGS;
45559644Sps}
45659644Sps
45759644Spsvoid
45859644Spsbangpxe_call(int func)
45959644Sps{
46059644Sps#ifdef PXE_DEBUG
46164187Sjhb	if (pxe_debug)
46259644Sps		printf("bangpxe_call %x\n", func);
46359644Sps#endif
46459644Sps
46559644Sps	bzero(&v86, sizeof(v86));
46659644Sps	bzero(data_buffer, sizeof(data_buffer));
46759644Sps
46859644Sps	__bangpxeseg = pxe_p->EntryPointSP.segment;
46959644Sps	__bangpxeoff = pxe_p->EntryPointSP.offset;
47059644Sps
47159644Sps	v86.ctl  = V86_ADDR | V86_CALLF | V86_FLAGS;
47259390Sps	v86.edx  = VTOPSEG(scratch_buffer);
47359390Sps	v86.eax  = VTOPOFF(scratch_buffer);
47459644Sps	v86.addr = (VTOPSEG(__bangpxeentry) << 16) | VTOPOFF(__bangpxeentry);
47559390Sps	v86.ebx  = func;
47658713Sjhb	v86int();
47759390Sps	v86.ctl  = V86_FLAGS;
47858713Sjhb}
47958713Sjhb
48059087Sps
48159087Spstime_t
48259087Spsgetsecs()
48358713Sjhb{
48459087Sps	time_t n = 0;
48559087Sps	time(&n);
48659087Sps	return n;
48758713Sjhb}
48858713Sjhb
48958713Sjhbstatic int
49059087Spspxe_netif_match(struct netif *nif, void *machdep_hint)
49158713Sjhb{
49259087Sps	return 1;
49358713Sjhb}
49458713Sjhb
49559087Sps
49658713Sjhbstatic int
49759087Spspxe_netif_probe(struct netif *nif, void *machdep_hint)
49858713Sjhb{
49959087Sps	t_PXENV_UDP_OPEN *udpopen_p = (t_PXENV_UDP_OPEN *)scratch_buffer;
50059456Sps
50159644Sps	if (pxe_call == NULL)
50259456Sps		return -1;
50359456Sps
50459087Sps	bzero(udpopen_p, sizeof(*udpopen_p));
50559087Sps	udpopen_p->src_ip = bootplayer.yip;
50659087Sps	pxe_call(PXENV_UDP_OPEN);
50758713Sjhb
50859390Sps	if (udpopen_p->status != 0) {
50959087Sps		printf("pxe_netif_probe: failed %x\n", udpopen_p->status);
51059390Sps		return -1;
51159390Sps	}
51259087Sps	return 0;
51358713Sjhb}
51458713Sjhb
51559087Spsstatic void
51659087Spspxe_netif_end(struct netif *nif)
51758713Sjhb{
51859087Sps	t_PXENV_UDP_CLOSE *udpclose_p = (t_PXENV_UDP_CLOSE *)scratch_buffer;
51959087Sps	bzero(udpclose_p, sizeof(*udpclose_p));
52058713Sjhb
52159087Sps	pxe_call(PXENV_UDP_CLOSE);
52259087Sps	if (udpclose_p->status != 0)
52359087Sps		printf("pxe_end failed %x\n", udpclose_p->status);
52458713Sjhb}
52558713Sjhb
52659087Spsstatic void
52759087Spspxe_netif_init(struct iodesc *desc, void *machdep_hint)
52858713Sjhb{
52959686Sps	int i;
53059686Sps	for (i = 0; i < 6; ++i)
53159686Sps		desc->myea[i] = bootplayer.CAddr[i];
53259686Sps	desc->xid = bootplayer.ident;
53358713Sjhb}
53458713Sjhb
53558713Sjhbstatic int
53659087Spspxe_netif_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout)
53758713Sjhb{
53859087Sps	return len;
53958713Sjhb}
54058713Sjhb
54158713Sjhbstatic int
54259087Spspxe_netif_put(struct iodesc *desc, void *pkt, size_t len)
54358713Sjhb{
54459087Sps	return len;
54558713Sjhb}
54658713Sjhb
54759087Spsssize_t
54859087Spssendudp(struct iodesc *h, void *pkt, size_t len)
54958713Sjhb{
55059087Sps	t_PXENV_UDP_WRITE *udpwrite_p = (t_PXENV_UDP_WRITE *)scratch_buffer;
55159087Sps	bzero(udpwrite_p, sizeof(*udpwrite_p));
55259087Sps
55359686Sps	udpwrite_p->ip             = h->destip.s_addr;
55459087Sps	udpwrite_p->dst_port       = h->destport;
55559087Sps	udpwrite_p->src_port       = h->myport;
55659686Sps	udpwrite_p->gw             = gateip.s_addr;
55759087Sps	udpwrite_p->buffer_size    = len;
55859087Sps	udpwrite_p->buffer.segment = VTOPSEG(pkt);
55959087Sps	udpwrite_p->buffer.offset  = VTOPOFF(pkt);
56058713Sjhb
56159087Sps	pxe_call(PXENV_UDP_WRITE);
56258713Sjhb
56359390Sps#if 0
56459087Sps	/* XXX - I dont know why we need this. */
56559087Sps	delay(1000);
56659390Sps#endif
56759390Sps	if (udpwrite_p->status != 0) {
56859673Sps		/* XXX: This happens a lot.  It shouldn't. */
56959673Sps		if (udpwrite_p->status != 1)
57059673Sps			printf("sendudp failed %x\n", udpwrite_p->status);
57159390Sps		return -1;
57259390Sps	}
57359087Sps	return len;
57458713Sjhb}
57558713Sjhb
57659087Spsssize_t
57759087Spsreadudp(struct iodesc *h, void *pkt, size_t len, time_t timeout)
57858713Sjhb{
57959087Sps	t_PXENV_UDP_READ *udpread_p = (t_PXENV_UDP_READ *)scratch_buffer;
58059087Sps	struct udphdr *uh = NULL;
58159087Sps
58259087Sps	uh = (struct udphdr *) pkt - 1;
58359087Sps	bzero(udpread_p, sizeof(*udpread_p));
58459087Sps
58559686Sps	udpread_p->dest_ip        = h->myip.s_addr;
58659087Sps	udpread_p->d_port         = h->myport;
58759087Sps	udpread_p->buffer_size    = len;
58859087Sps	udpread_p->buffer.segment = VTOPSEG(data_buffer);
58959087Sps	udpread_p->buffer.offset  = VTOPOFF(data_buffer);
59058713Sjhb
59159087Sps	pxe_call(PXENV_UDP_READ);
59258713Sjhb
59359390Sps#if 0
59459087Sps	/* XXX - I dont know why we need this. */
59559087Sps	delay(1000);
59659390Sps#endif
59759390Sps	if (udpread_p->status != 0) {
59859390Sps		/* XXX: This happens a lot.  It shouldn't. */
59959390Sps		if (udpread_p->status != 1)
60059390Sps			printf("readudp failed %x\n", udpread_p->status);
60159390Sps		return -1;
60259390Sps	}
60359087Sps	bcopy(data_buffer, pkt, udpread_p->buffer_size);
60459087Sps	uh->uh_sport = udpread_p->s_port;
60559087Sps	return udpread_p->buffer_size;
60658713Sjhb}
607