xref: /dflybsd-src/stand/boot/pc32/libi386/pxe.c (revision 479ab7f0492f2a51b48e8537e4f1dc686fc6014b)
1*479ab7f0SSascha Wildner /*-
2*479ab7f0SSascha Wildner  * Copyright (c) 2000 Alfred Perlstein <alfred@freebsd.org>
3*479ab7f0SSascha Wildner  * Copyright (c) 2000 Paul Saab <ps@freebsd.org>
4*479ab7f0SSascha Wildner  * Copyright (c) 2000 John Baldwin <jhb@freebsd.org>
5*479ab7f0SSascha Wildner  * All rights reserved.
6*479ab7f0SSascha Wildner  *
7*479ab7f0SSascha Wildner  * Redistribution and use in source and binary forms, with or without
8*479ab7f0SSascha Wildner  * modification, are permitted provided that the following conditions
9*479ab7f0SSascha Wildner  * are met:
10*479ab7f0SSascha Wildner  * 1. Redistributions of source code must retain the above copyright
11*479ab7f0SSascha Wildner  *    notice, this list of conditions and the following disclaimer.
12*479ab7f0SSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
13*479ab7f0SSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
14*479ab7f0SSascha Wildner  *    documentation and/or other materials provided with the distribution.
15*479ab7f0SSascha Wildner  *
16*479ab7f0SSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17*479ab7f0SSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*479ab7f0SSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*479ab7f0SSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20*479ab7f0SSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*479ab7f0SSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*479ab7f0SSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*479ab7f0SSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*479ab7f0SSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*479ab7f0SSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*479ab7f0SSascha Wildner  * SUCH DAMAGE.
27*479ab7f0SSascha Wildner  *
28*479ab7f0SSascha Wildner  * $FreeBSD: src/sys/boot/i386/libi386/pxe.c,v 1.20 2003/08/25 23:28:31 obrien Exp $
29*479ab7f0SSascha Wildner  */
30*479ab7f0SSascha Wildner 
31*479ab7f0SSascha Wildner #include <sys/param.h>
32*479ab7f0SSascha Wildner #include <stand.h>
33*479ab7f0SSascha Wildner #include <string.h>
34*479ab7f0SSascha Wildner #include <stdarg.h>
35*479ab7f0SSascha Wildner 
36*479ab7f0SSascha Wildner #include <netinet/in_systm.h>
37*479ab7f0SSascha Wildner #include <netinet/in.h>
38*479ab7f0SSascha Wildner #include <netinet/udp.h>
39*479ab7f0SSascha Wildner #include <netinet/ip.h>
40*479ab7f0SSascha Wildner 
41*479ab7f0SSascha Wildner #include <net.h>
42*479ab7f0SSascha Wildner #include <netif.h>
43*479ab7f0SSascha Wildner #include <nfsv2.h>
44*479ab7f0SSascha Wildner #include <iodesc.h>
45*479ab7f0SSascha Wildner 
46*479ab7f0SSascha Wildner #include <bootp.h>
47*479ab7f0SSascha Wildner #include <bootstrap.h>
48*479ab7f0SSascha Wildner #include "btxv86.h"
49*479ab7f0SSascha Wildner #include "pxe.h"
50*479ab7f0SSascha Wildner 
51*479ab7f0SSascha Wildner /*
52*479ab7f0SSascha Wildner  * Allocate the PXE buffers statically instead of sticking grimy fingers into
53*479ab7f0SSascha Wildner  * BTX's private data area.  The scratch buffer is used to send information to
54*479ab7f0SSascha Wildner  * the PXE BIOS, and the data buffer is used to receive data from the PXE BIOS.
55*479ab7f0SSascha Wildner  */
56*479ab7f0SSascha Wildner #define	PXE_BUFFER_SIZE		0x2000
57*479ab7f0SSascha Wildner #define	PXE_TFTP_BUFFER_SIZE	512
58*479ab7f0SSascha Wildner static char	scratch_buffer[PXE_BUFFER_SIZE];
59*479ab7f0SSascha Wildner static char	data_buffer[PXE_BUFFER_SIZE];
60*479ab7f0SSascha Wildner 
61*479ab7f0SSascha Wildner static pxenv_t	*pxenv_p = NULL;        /* PXENV+ */
62*479ab7f0SSascha Wildner static pxe_t	*pxe_p   = NULL;	/* !PXE */
63*479ab7f0SSascha Wildner static BOOTPLAYER	bootplayer;	/* PXE Cached information. */
64*479ab7f0SSascha Wildner 
65*479ab7f0SSascha Wildner static int 	pxe_debug = 0;
66*479ab7f0SSascha Wildner static int	pxe_sock = -1;
67*479ab7f0SSascha Wildner static int	pxe_opens = 0;
68*479ab7f0SSascha Wildner static int	bugged_bios_pxe = 0;
69*479ab7f0SSascha Wildner 
70*479ab7f0SSascha Wildner void		pxe_enable(void *pxeinfo);
71*479ab7f0SSascha Wildner static void	(*pxe_call)(int func);
72*479ab7f0SSascha Wildner static void	pxenv_call(int func);
73*479ab7f0SSascha Wildner static void	bangpxe_call(int func);
74*479ab7f0SSascha Wildner 
75*479ab7f0SSascha Wildner static int	pxe_init(void);
76*479ab7f0SSascha Wildner static int	pxe_strategy(void *devdata, int flag, daddr_t dblk,
77*479ab7f0SSascha Wildner 			     size_t size, char *buf, size_t *rsize);
78*479ab7f0SSascha Wildner static int	pxe_open(struct open_file *f, ...);
79*479ab7f0SSascha Wildner static int	pxe_close(struct open_file *f);
80*479ab7f0SSascha Wildner static void	pxe_print(int verbose);
81*479ab7f0SSascha Wildner static void	pxe_cleanup(void);
82*479ab7f0SSascha Wildner static void	pxe_setnfshandle(char *rootpath);
83*479ab7f0SSascha Wildner 
84*479ab7f0SSascha Wildner static void	pxe_perror(int error);
85*479ab7f0SSascha Wildner static int	pxe_netif_match(struct netif *nif, void *machdep_hint);
86*479ab7f0SSascha Wildner static int	pxe_netif_probe(struct netif *nif, void *machdep_hint);
87*479ab7f0SSascha Wildner static void	pxe_netif_init(struct iodesc *desc, void *machdep_hint);
88*479ab7f0SSascha Wildner static int	pxe_netif_get(struct iodesc *desc, void *pkt, size_t len,
89*479ab7f0SSascha Wildner 			      time_t timeout);
90*479ab7f0SSascha Wildner static int	pxe_netif_put(struct iodesc *desc, void *pkt, size_t len);
91*479ab7f0SSascha Wildner static void	pxe_netif_end(struct netif *nif);
92*479ab7f0SSascha Wildner 
93*479ab7f0SSascha Wildner extern struct netif_stats	pxe_st[];
94*479ab7f0SSascha Wildner extern u_int16_t		__bangpxeseg;
95*479ab7f0SSascha Wildner extern u_int16_t		__bangpxeoff;
96*479ab7f0SSascha Wildner extern void			__bangpxeentry(void);
97*479ab7f0SSascha Wildner extern u_int16_t		__pxenvseg;
98*479ab7f0SSascha Wildner extern u_int16_t		__pxenvoff;
99*479ab7f0SSascha Wildner extern void			__pxenventry(void);
100*479ab7f0SSascha Wildner 
101*479ab7f0SSascha Wildner struct netif_dif pxe_ifs[] = {
102*479ab7f0SSascha Wildner /*      dif_unit        dif_nsel        dif_stats       dif_private     */
103*479ab7f0SSascha Wildner 	{0,             1,              &pxe_st[0],     0}
104*479ab7f0SSascha Wildner };
105*479ab7f0SSascha Wildner 
106*479ab7f0SSascha Wildner struct netif_stats pxe_st[NENTS(pxe_ifs)];
107*479ab7f0SSascha Wildner 
108*479ab7f0SSascha Wildner struct netif_driver pxenetif = {
109*479ab7f0SSascha Wildner 	"pxenet",
110*479ab7f0SSascha Wildner 	pxe_netif_match,
111*479ab7f0SSascha Wildner 	pxe_netif_probe,
112*479ab7f0SSascha Wildner 	pxe_netif_init,
113*479ab7f0SSascha Wildner 	pxe_netif_get,
114*479ab7f0SSascha Wildner 	pxe_netif_put,
115*479ab7f0SSascha Wildner 	pxe_netif_end,
116*479ab7f0SSascha Wildner 	pxe_ifs,
117*479ab7f0SSascha Wildner 	NENTS(pxe_ifs)
118*479ab7f0SSascha Wildner };
119*479ab7f0SSascha Wildner 
120*479ab7f0SSascha Wildner struct netif_driver *netif_drivers[] = {
121*479ab7f0SSascha Wildner 	&pxenetif,
122*479ab7f0SSascha Wildner 	NULL
123*479ab7f0SSascha Wildner };
124*479ab7f0SSascha Wildner 
125*479ab7f0SSascha Wildner struct devsw pxedisk = {
126*479ab7f0SSascha Wildner 	"pxe",
127*479ab7f0SSascha Wildner 	DEVT_NET,
128*479ab7f0SSascha Wildner 	pxe_init,
129*479ab7f0SSascha Wildner 	pxe_strategy,
130*479ab7f0SSascha Wildner 	pxe_open,
131*479ab7f0SSascha Wildner 	pxe_close,
132*479ab7f0SSascha Wildner 	noioctl,
133*479ab7f0SSascha Wildner 	pxe_print,
134*479ab7f0SSascha Wildner 	pxe_cleanup
135*479ab7f0SSascha Wildner };
136*479ab7f0SSascha Wildner 
137*479ab7f0SSascha Wildner /*
138*479ab7f0SSascha Wildner  * This function is called by the loader to enable PXE support if we
139*479ab7f0SSascha Wildner  * are booted by PXE.  The passed in pointer is a pointer to the
140*479ab7f0SSascha Wildner  * PXENV+ structure.
141*479ab7f0SSascha Wildner  */
142*479ab7f0SSascha Wildner void
pxe_enable(void * pxeinfo)143*479ab7f0SSascha Wildner pxe_enable(void *pxeinfo)
144*479ab7f0SSascha Wildner {
145*479ab7f0SSascha Wildner 	pxenv_p  = (pxenv_t *)pxeinfo;
146*479ab7f0SSascha Wildner 	pxe_p    = (pxe_t *)PTOV(pxenv_p->PXEPtr.segment * 16 +
147*479ab7f0SSascha Wildner 				 pxenv_p->PXEPtr.offset);
148*479ab7f0SSascha Wildner 	pxe_call = NULL;
149*479ab7f0SSascha Wildner }
150*479ab7f0SSascha Wildner 
151*479ab7f0SSascha Wildner /*
152*479ab7f0SSascha Wildner  * return true if pxe structures are found/initialized,
153*479ab7f0SSascha Wildner  * also figures out our IP information via the pxe cached info struct
154*479ab7f0SSascha Wildner  */
155*479ab7f0SSascha Wildner static int
pxe_init(void)156*479ab7f0SSascha Wildner pxe_init(void)
157*479ab7f0SSascha Wildner {
158*479ab7f0SSascha Wildner 	t_PXENV_GET_CACHED_INFO	*gci_p;
159*479ab7f0SSascha Wildner 	int	counter;
160*479ab7f0SSascha Wildner 	uint8_t checksum;
161*479ab7f0SSascha Wildner 	uint8_t *checkptr;
162*479ab7f0SSascha Wildner 
163*479ab7f0SSascha Wildner 	if(pxenv_p == NULL)
164*479ab7f0SSascha Wildner 		return (0);
165*479ab7f0SSascha Wildner 
166*479ab7f0SSascha Wildner 	/*  look for "PXENV+" */
167*479ab7f0SSascha Wildner 	if (bcmp((void *)pxenv_p->Signature, S_SIZE("PXENV+"))) {
168*479ab7f0SSascha Wildner 		pxenv_p = NULL;
169*479ab7f0SSascha Wildner 		return (0);
170*479ab7f0SSascha Wildner 	}
171*479ab7f0SSascha Wildner 
172*479ab7f0SSascha Wildner 	/* make sure the size is something we can handle */
173*479ab7f0SSascha Wildner 	if (pxenv_p->Length > sizeof(*pxenv_p)) {
174*479ab7f0SSascha Wildner 	  	printf("PXENV+ structure too large, ignoring\n");
175*479ab7f0SSascha Wildner 		pxenv_p = NULL;
176*479ab7f0SSascha Wildner 		return (0);
177*479ab7f0SSascha Wildner 	}
178*479ab7f0SSascha Wildner 
179*479ab7f0SSascha Wildner 	/*
180*479ab7f0SSascha Wildner 	 * do byte checksum:
181*479ab7f0SSascha Wildner 	 * add up each byte in the structure, the total should be 0
182*479ab7f0SSascha Wildner 	 */
183*479ab7f0SSascha Wildner 	checksum = 0;
184*479ab7f0SSascha Wildner 	checkptr = (uint8_t *) pxenv_p;
185*479ab7f0SSascha Wildner 	for (counter = 0; counter < pxenv_p->Length; counter++)
186*479ab7f0SSascha Wildner 		checksum += *checkptr++;
187*479ab7f0SSascha Wildner 	if (checksum != 0) {
188*479ab7f0SSascha Wildner 		printf("PXENV+ structure failed checksum, ignoring\n");
189*479ab7f0SSascha Wildner 		pxenv_p = NULL;
190*479ab7f0SSascha Wildner 		return (0);
191*479ab7f0SSascha Wildner 	}
192*479ab7f0SSascha Wildner 
193*479ab7f0SSascha Wildner 
194*479ab7f0SSascha Wildner 	/*
195*479ab7f0SSascha Wildner 	 * PXENV+ passed, so use that if !PXE is not available or
196*479ab7f0SSascha Wildner 	 * the checksum fails.
197*479ab7f0SSascha Wildner 	 */
198*479ab7f0SSascha Wildner 	pxe_call = pxenv_call;
199*479ab7f0SSascha Wildner 	if (pxenv_p->Version >= 0x0200) {
200*479ab7f0SSascha Wildner 		for (;;) {
201*479ab7f0SSascha Wildner 			if (bcmp((void *)pxe_p->Signature, S_SIZE("!PXE"))) {
202*479ab7f0SSascha Wildner 				pxe_p = NULL;
203*479ab7f0SSascha Wildner 				break;
204*479ab7f0SSascha Wildner 			}
205*479ab7f0SSascha Wildner 			checksum = 0;
206*479ab7f0SSascha Wildner 			checkptr = (uint8_t *)pxe_p;
207*479ab7f0SSascha Wildner 			for (counter = 0; counter < pxe_p->StructLength;
208*479ab7f0SSascha Wildner 			     counter++)
209*479ab7f0SSascha Wildner 				checksum += *checkptr++;
210*479ab7f0SSascha Wildner 			if (checksum != 0) {
211*479ab7f0SSascha Wildner 				pxe_p = NULL;
212*479ab7f0SSascha Wildner 				break;
213*479ab7f0SSascha Wildner 			}
214*479ab7f0SSascha Wildner 			pxe_call = bangpxe_call;
215*479ab7f0SSascha Wildner 			break;
216*479ab7f0SSascha Wildner 		}
217*479ab7f0SSascha Wildner 	}
218*479ab7f0SSascha Wildner 
219*479ab7f0SSascha Wildner 	printf("\nPXE version %d.%d, real mode entry point ",
220*479ab7f0SSascha Wildner 	       (uint8_t) (pxenv_p->Version >> 8),
221*479ab7f0SSascha Wildner 	       (uint8_t) (pxenv_p->Version & 0xFF));
222*479ab7f0SSascha Wildner 	if (pxe_call == bangpxe_call)
223*479ab7f0SSascha Wildner 		printf("@%04x:%04x\n",
224*479ab7f0SSascha Wildner 		       pxe_p->EntryPointSP.segment,
225*479ab7f0SSascha Wildner 		       pxe_p->EntryPointSP.offset);
226*479ab7f0SSascha Wildner 	else
227*479ab7f0SSascha Wildner 		printf("@%04x:%04x\n",
228*479ab7f0SSascha Wildner 		       pxenv_p->RMEntry.segment, pxenv_p->RMEntry.offset);
229*479ab7f0SSascha Wildner 
230*479ab7f0SSascha Wildner 	gci_p = (t_PXENV_GET_CACHED_INFO *) scratch_buffer;
231*479ab7f0SSascha Wildner 	bzero(gci_p, sizeof(*gci_p));
232*479ab7f0SSascha Wildner 	gci_p->PacketType =  PXENV_PACKET_TYPE_BINL_REPLY;
233*479ab7f0SSascha Wildner 	pxe_call(PXENV_GET_CACHED_INFO);
234*479ab7f0SSascha Wildner 	if (gci_p->Status != 0) {
235*479ab7f0SSascha Wildner 		pxe_perror(gci_p->Status);
236*479ab7f0SSascha Wildner 		pxe_p = NULL;
237*479ab7f0SSascha Wildner 		return (0);
238*479ab7f0SSascha Wildner 	}
239*479ab7f0SSascha Wildner 	bcopy(PTOV((gci_p->Buffer.segment << 4) + gci_p->Buffer.offset),
240*479ab7f0SSascha Wildner 	      &bootplayer, gci_p->BufferSize);
241*479ab7f0SSascha Wildner 	return (1);
242*479ab7f0SSascha Wildner }
243*479ab7f0SSascha Wildner 
244*479ab7f0SSascha Wildner 
245*479ab7f0SSascha Wildner static int
pxe_strategy(void * devdata,int flag,daddr_t dblk,size_t size,char * buf,size_t * rsize)246*479ab7f0SSascha Wildner pxe_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
247*479ab7f0SSascha Wildner 		char *buf, size_t *rsize)
248*479ab7f0SSascha Wildner {
249*479ab7f0SSascha Wildner 	return (EIO);
250*479ab7f0SSascha Wildner }
251*479ab7f0SSascha Wildner 
252*479ab7f0SSascha Wildner static int
pxe_open(struct open_file * f,...)253*479ab7f0SSascha Wildner pxe_open(struct open_file *f, ...)
254*479ab7f0SSascha Wildner {
255*479ab7f0SSascha Wildner     va_list args;
256*479ab7f0SSascha Wildner     char *devname;		/* Device part of file name (or NULL). */
257*479ab7f0SSascha Wildner     char temp[FNAME_SIZE];
258*479ab7f0SSascha Wildner     int error = 0;
259*479ab7f0SSascha Wildner     int i;
260*479ab7f0SSascha Wildner 
261*479ab7f0SSascha Wildner     va_start(args, f);
262*479ab7f0SSascha Wildner     devname = va_arg(args, char*);
263*479ab7f0SSascha Wildner     va_end(args);
264*479ab7f0SSascha Wildner 
265*479ab7f0SSascha Wildner     /* On first open, do netif open, mount, etc. */
266*479ab7f0SSascha Wildner     if (pxe_opens == 0) {
267*479ab7f0SSascha Wildner 	/* Find network interface. */
268*479ab7f0SSascha Wildner 	if (pxe_sock < 0) {
269*479ab7f0SSascha Wildner 	    pxe_sock = netif_open(devname);
270*479ab7f0SSascha Wildner 	    if (pxe_sock < 0) {
271*479ab7f0SSascha Wildner 		printf("pxe_open: netif_open() failed\n");
272*479ab7f0SSascha Wildner 		return (ENXIO);
273*479ab7f0SSascha Wildner 	    }
274*479ab7f0SSascha Wildner 	    if (pxe_debug)
275*479ab7f0SSascha Wildner 		printf("pxe_open: netif_open() succeeded\n");
276*479ab7f0SSascha Wildner 	}
277*479ab7f0SSascha Wildner 	if (rootip.s_addr == 0) {
278*479ab7f0SSascha Wildner 		/*
279*479ab7f0SSascha Wildner 		 * Do a bootp/dhcp request to find out where our
280*479ab7f0SSascha Wildner 		 * NFS/TFTP server is.  Even if we dont get back
281*479ab7f0SSascha Wildner 		 * the proper information, fall back to the server
282*479ab7f0SSascha Wildner 		 * which brought us to life and a default rootpath.
283*479ab7f0SSascha Wildner 		 */
284*479ab7f0SSascha Wildner 		bootp(pxe_sock, BOOTP_PXE);
285*479ab7f0SSascha Wildner 		if (rootip.s_addr == 0)
286*479ab7f0SSascha Wildner 			rootip.s_addr = bootplayer.sip;
287*479ab7f0SSascha Wildner 		if (!rootpath[1])
288*479ab7f0SSascha Wildner 			strcpy(rootpath, PXENFSROOTPATH);
289*479ab7f0SSascha Wildner 
290*479ab7f0SSascha Wildner 		for (i = 0; i < FNAME_SIZE && rootpath[i] != '\0'; i++) {
291*479ab7f0SSascha Wildner 			if (rootpath[i] == ':')
292*479ab7f0SSascha Wildner 				break;
293*479ab7f0SSascha Wildner 		}
294*479ab7f0SSascha Wildner 		if (i && i != FNAME_SIZE && rootpath[i] == ':') {
295*479ab7f0SSascha Wildner 			rootpath[i++] = '\0';
296*479ab7f0SSascha Wildner 			if (inet_addr(&rootpath[0]) != INADDR_NONE)
297*479ab7f0SSascha Wildner 				rootip.s_addr = inet_addr(&rootpath[0]);
298*479ab7f0SSascha Wildner 			bcopy(&rootpath[i], &temp[0], strlen(&rootpath[i])+1);
299*479ab7f0SSascha Wildner 			bcopy(&temp[0], &rootpath[0], strlen(&rootpath[i])+1);
300*479ab7f0SSascha Wildner 		}
301*479ab7f0SSascha Wildner 		printf("pxe_open: ip address : %s\n", inet_ntoa(myip));
302*479ab7f0SSascha Wildner 		printf("pxe_open: ip netmask : %s\n", intoa(netmask));
303*479ab7f0SSascha Wildner 		printf("pxe_open: nfs root mount: %s:%s\n", inet_ntoa(rootip), rootpath);
304*479ab7f0SSascha Wildner 		printf("pxe_open: gateway ip:  %s\n", inet_ntoa(gateip));
305*479ab7f0SSascha Wildner 
306*479ab7f0SSascha Wildner 		setenv("boot.netif.ip", inet_ntoa(myip), 1);
307*479ab7f0SSascha Wildner 		setenv("boot.netif.netmask", intoa(netmask), 1);
308*479ab7f0SSascha Wildner 		setenv("boot.netif.gateway", inet_ntoa(gateip), 1);
309*479ab7f0SSascha Wildner 		if (bootplayer.Hardware == ETHER_TYPE)
310*479ab7f0SSascha Wildner 			setenv("boot.netif.hwaddr", ether_sprintf(bootplayer.CAddr), 1);
311*479ab7f0SSascha Wildner 
312*479ab7f0SSascha Wildner 		setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
313*479ab7f0SSascha Wildner 		setenv("boot.nfsroot.path", rootpath, 1);
314*479ab7f0SSascha Wildner 
315*479ab7f0SSascha Wildner 		if (bootplayer.yip != INADDR_ANY &&
316*479ab7f0SSascha Wildner 		    bootplayer.yip != myip.s_addr) {
317*479ab7f0SSascha Wildner 			printf("Warning: PXE negotiated a different IP "
318*479ab7f0SSascha Wildner 			       "in the preloader\n");
319*479ab7f0SSascha Wildner 			bugged_bios_pxe = 1;
320*479ab7f0SSascha Wildner 		}
321*479ab7f0SSascha Wildner 	}
322*479ab7f0SSascha Wildner     }
323*479ab7f0SSascha Wildner     pxe_opens++;
324*479ab7f0SSascha Wildner     devreplace(f, &pxe_sock);
325*479ab7f0SSascha Wildner 
326*479ab7f0SSascha Wildner     return (error);
327*479ab7f0SSascha Wildner }
328*479ab7f0SSascha Wildner 
329*479ab7f0SSascha Wildner static int
pxe_close(struct open_file * f)330*479ab7f0SSascha Wildner pxe_close(struct open_file *f)
331*479ab7f0SSascha Wildner {
332*479ab7f0SSascha Wildner 
333*479ab7f0SSascha Wildner #ifdef	PXE_DEBUG
334*479ab7f0SSascha Wildner     if (pxe_debug)
335*479ab7f0SSascha Wildner 	printf("pxe_close: opens=%d\n", pxe_opens);
336*479ab7f0SSascha Wildner #endif
337*479ab7f0SSascha Wildner 
338*479ab7f0SSascha Wildner     /* On last close, do netif close, etc. */
339*479ab7f0SSascha Wildner     f->f_devdata = NULL;
340*479ab7f0SSascha Wildner     /* Extra close call? */
341*479ab7f0SSascha Wildner     if (pxe_opens <= 0)
342*479ab7f0SSascha Wildner 	return (0);
343*479ab7f0SSascha Wildner     pxe_opens--;
344*479ab7f0SSascha Wildner     /* Not last close? */
345*479ab7f0SSascha Wildner     if (pxe_opens > 0)
346*479ab7f0SSascha Wildner 	return(0);
347*479ab7f0SSascha Wildner 
348*479ab7f0SSascha Wildner     /* get an NFS filehandle for our root filesystem */
349*479ab7f0SSascha Wildner     pxe_setnfshandle(rootpath);
350*479ab7f0SSascha Wildner 
351*479ab7f0SSascha Wildner     if (pxe_sock >= 0) {
352*479ab7f0SSascha Wildner 
353*479ab7f0SSascha Wildner #ifdef PXE_DEBUG
354*479ab7f0SSascha Wildner 	if (pxe_debug)
355*479ab7f0SSascha Wildner 	    printf("pxe_close: calling netif_close()\n");
356*479ab7f0SSascha Wildner #endif
357*479ab7f0SSascha Wildner 	netif_close(pxe_sock);
358*479ab7f0SSascha Wildner 	pxe_sock = -1;
359*479ab7f0SSascha Wildner     }
360*479ab7f0SSascha Wildner     return (0);
361*479ab7f0SSascha Wildner }
362*479ab7f0SSascha Wildner 
363*479ab7f0SSascha Wildner static void
pxe_print(int verbose)364*479ab7f0SSascha Wildner pxe_print(int verbose)
365*479ab7f0SSascha Wildner {
366*479ab7f0SSascha Wildner 	if (pxe_call != NULL) {
367*479ab7f0SSascha Wildner 		if (*bootplayer.Sname == '\0') {
368*479ab7f0SSascha Wildner 			printf("      "IP_STR":%s\n",
369*479ab7f0SSascha Wildner 			       IP_ARGS(htonl(bootplayer.sip)),
370*479ab7f0SSascha Wildner 			       bootplayer.bootfile);
371*479ab7f0SSascha Wildner 		} else {
372*479ab7f0SSascha Wildner 			printf("      %s:%s\n", bootplayer.Sname,
373*479ab7f0SSascha Wildner 			       bootplayer.bootfile);
374*479ab7f0SSascha Wildner 		}
375*479ab7f0SSascha Wildner 	}
376*479ab7f0SSascha Wildner 
377*479ab7f0SSascha Wildner 	return;
378*479ab7f0SSascha Wildner }
379*479ab7f0SSascha Wildner 
380*479ab7f0SSascha Wildner static void
pxe_cleanup(void)381*479ab7f0SSascha Wildner pxe_cleanup(void)
382*479ab7f0SSascha Wildner {
383*479ab7f0SSascha Wildner #ifdef PXE_DEBUG
384*479ab7f0SSascha Wildner 	t_PXENV_UNLOAD_STACK *unload_stack_p =
385*479ab7f0SSascha Wildner 	    (t_PXENV_UNLOAD_STACK *)scratch_buffer;
386*479ab7f0SSascha Wildner 	t_PXENV_UNDI_SHUTDOWN *undi_shutdown_p =
387*479ab7f0SSascha Wildner 	    (t_PXENV_UNDI_SHUTDOWN *)scratch_buffer;
388*479ab7f0SSascha Wildner #endif
389*479ab7f0SSascha Wildner 
390*479ab7f0SSascha Wildner 	if (pxe_call == NULL)
391*479ab7f0SSascha Wildner 		return;
392*479ab7f0SSascha Wildner 
393*479ab7f0SSascha Wildner 	pxe_call(PXENV_UNDI_SHUTDOWN);
394*479ab7f0SSascha Wildner 
395*479ab7f0SSascha Wildner #ifdef PXE_DEBUG
396*479ab7f0SSascha Wildner 	if (pxe_debug && undi_shutdown_p->Status != 0)
397*479ab7f0SSascha Wildner 		printf("pxe_cleanup: UNDI_SHUTDOWN failed %x\n",
398*479ab7f0SSascha Wildner 		       undi_shutdown_p->Status);
399*479ab7f0SSascha Wildner #endif
400*479ab7f0SSascha Wildner 
401*479ab7f0SSascha Wildner 	pxe_call(PXENV_UNLOAD_STACK);
402*479ab7f0SSascha Wildner 
403*479ab7f0SSascha Wildner #ifdef PXE_DEBUG
404*479ab7f0SSascha Wildner 	if (pxe_debug && unload_stack_p->Status != 0)
405*479ab7f0SSascha Wildner 		printf("pxe_cleanup: UNLOAD_STACK failed %x\n",
406*479ab7f0SSascha Wildner 		    unload_stack_p->Status);
407*479ab7f0SSascha Wildner #endif
408*479ab7f0SSascha Wildner }
409*479ab7f0SSascha Wildner 
410*479ab7f0SSascha Wildner void
pxe_perror(int err)411*479ab7f0SSascha Wildner pxe_perror(int err)
412*479ab7f0SSascha Wildner {
413*479ab7f0SSascha Wildner 	return;
414*479ab7f0SSascha Wildner }
415*479ab7f0SSascha Wildner 
416*479ab7f0SSascha Wildner /* To prevent LTO warnings. Must match stand/lib/nfs.c struct. */
417*479ab7f0SSascha Wildner struct nfsv2_fattrs {
418*479ab7f0SSascha Wildner 	n_long	fa_type;
419*479ab7f0SSascha Wildner 	n_long	fa_mode;
420*479ab7f0SSascha Wildner 	n_long	fa_nlink;
421*479ab7f0SSascha Wildner 	n_long	fa_uid;
422*479ab7f0SSascha Wildner 	n_long	fa_gid;
423*479ab7f0SSascha Wildner 	n_long	fa_size;
424*479ab7f0SSascha Wildner 	n_long	fa_blocksize;
425*479ab7f0SSascha Wildner 	n_long	fa_rdev;
426*479ab7f0SSascha Wildner 	n_long	fa_blocks;
427*479ab7f0SSascha Wildner 	n_long	fa_fsid;
428*479ab7f0SSascha Wildner 	n_long	fa_fileid;
429*479ab7f0SSascha Wildner 	struct nfsv2_time fa_atime;
430*479ab7f0SSascha Wildner 	struct nfsv2_time fa_mtime;
431*479ab7f0SSascha Wildner 	struct nfsv2_time fa_ctime;
432*479ab7f0SSascha Wildner };
433*479ab7f0SSascha Wildner 
434*479ab7f0SSascha Wildner /*
435*479ab7f0SSascha Wildner  * Reach inside the libstand NFS code and dig out an NFS handle
436*479ab7f0SSascha Wildner  * for the root filesystem.  If there is no nfs handle but a NFS root
437*479ab7f0SSascha Wildner  * path was dynamically requested (not just as a default), then try
438*479ab7f0SSascha Wildner  * to get the handle.  This occurs if we are compiled for TFTP operation
439*479ab7f0SSascha Wildner  * but still want to pass an NFS root to the kernel.
440*479ab7f0SSascha Wildner  */
441*479ab7f0SSascha Wildner struct nfs_iodesc {
442*479ab7f0SSascha Wildner 	struct	iodesc	*iodesc;
443*479ab7f0SSascha Wildner 	off_t	off;
444*479ab7f0SSascha Wildner 	u_char	fh[NFS_FHSIZE];
445*479ab7f0SSascha Wildner 	/* structure truncated here */
446*479ab7f0SSascha Wildner 	struct nfsv2_fattrs unused;	/* unused */
447*479ab7f0SSascha Wildner };
448*479ab7f0SSascha Wildner extern struct	nfs_iodesc nfs_root_node;
449*479ab7f0SSascha Wildner 
450*479ab7f0SSascha Wildner static void
pxe_setnfshandle(char * rootpath)451*479ab7f0SSascha Wildner pxe_setnfshandle(char *rootpath)
452*479ab7f0SSascha Wildner {
453*479ab7f0SSascha Wildner 	int	i;
454*479ab7f0SSascha Wildner 	u_char	*fh;
455*479ab7f0SSascha Wildner 	char	buf[2 * NFS_FHSIZE + 3], *cp;
456*479ab7f0SSascha Wildner 
457*479ab7f0SSascha Wildner 	fh = &nfs_root_node.fh[0];
458*479ab7f0SSascha Wildner 
459*479ab7f0SSascha Wildner 	/*
460*479ab7f0SSascha Wildner 	 * If no file handle exists but a root path was dynamically
461*479ab7f0SSascha Wildner 	 * requested, try to get a good handle.
462*479ab7f0SSascha Wildner 	 */
463*479ab7f0SSascha Wildner 	for (i = 0; i < NFS_FHSIZE; ++i) {
464*479ab7f0SSascha Wildner 		if (fh[i])
465*479ab7f0SSascha Wildner 			break;
466*479ab7f0SSascha Wildner 	}
467*479ab7f0SSascha Wildner 	if (i != NFS_FHSIZE) {
468*479ab7f0SSascha Wildner 		buf[0] = 'X';
469*479ab7f0SSascha Wildner 		cp = &buf[1];
470*479ab7f0SSascha Wildner 		for (i = 0; i < NFS_FHSIZE; i++, cp += 2)
471*479ab7f0SSascha Wildner 			sprintf(cp, "%02x", fh[i]);
472*479ab7f0SSascha Wildner 		sprintf(cp, "X");
473*479ab7f0SSascha Wildner 		setenv("boot.nfsroot.nfshandle", buf, 1);
474*479ab7f0SSascha Wildner 	}
475*479ab7f0SSascha Wildner }
476*479ab7f0SSascha Wildner 
477*479ab7f0SSascha Wildner void
pxenv_call(int func)478*479ab7f0SSascha Wildner pxenv_call(int func)
479*479ab7f0SSascha Wildner {
480*479ab7f0SSascha Wildner #ifdef PXE_DEBUG
481*479ab7f0SSascha Wildner 	if (pxe_debug)
482*479ab7f0SSascha Wildner 		printf("pxenv_call %x\n", func);
483*479ab7f0SSascha Wildner #endif
484*479ab7f0SSascha Wildner 
485*479ab7f0SSascha Wildner 	bzero(&v86, sizeof(v86));
486*479ab7f0SSascha Wildner 	bzero(data_buffer, sizeof(data_buffer));
487*479ab7f0SSascha Wildner 
488*479ab7f0SSascha Wildner 	__pxenvseg = pxenv_p->RMEntry.segment;
489*479ab7f0SSascha Wildner 	__pxenvoff = pxenv_p->RMEntry.offset;
490*479ab7f0SSascha Wildner 
491*479ab7f0SSascha Wildner 	v86.ctl  = V86_ADDR | V86_CALLF | V86_FLAGS;
492*479ab7f0SSascha Wildner 	v86.es   = VTOPSEG(scratch_buffer);
493*479ab7f0SSascha Wildner 	v86.edi  = VTOPOFF(scratch_buffer);
494*479ab7f0SSascha Wildner 	v86.addr = (VTOPSEG(__pxenventry) << 16) | VTOPOFF(__pxenventry);
495*479ab7f0SSascha Wildner 	v86.ebx  = func;
496*479ab7f0SSascha Wildner 	v86int();
497*479ab7f0SSascha Wildner 	v86.ctl  = V86_FLAGS;
498*479ab7f0SSascha Wildner }
499*479ab7f0SSascha Wildner 
500*479ab7f0SSascha Wildner void
bangpxe_call(int func)501*479ab7f0SSascha Wildner bangpxe_call(int func)
502*479ab7f0SSascha Wildner {
503*479ab7f0SSascha Wildner #ifdef PXE_DEBUG
504*479ab7f0SSascha Wildner 	if (pxe_debug)
505*479ab7f0SSascha Wildner 		printf("bangpxe_call %x\n", func);
506*479ab7f0SSascha Wildner #endif
507*479ab7f0SSascha Wildner 
508*479ab7f0SSascha Wildner 	bzero(&v86, sizeof(v86));
509*479ab7f0SSascha Wildner 	bzero(data_buffer, sizeof(data_buffer));
510*479ab7f0SSascha Wildner 
511*479ab7f0SSascha Wildner 	__bangpxeseg = pxe_p->EntryPointSP.segment;
512*479ab7f0SSascha Wildner 	__bangpxeoff = pxe_p->EntryPointSP.offset;
513*479ab7f0SSascha Wildner 
514*479ab7f0SSascha Wildner 	v86.ctl  = V86_ADDR | V86_CALLF | V86_FLAGS;
515*479ab7f0SSascha Wildner 	v86.edx  = VTOPSEG(scratch_buffer);
516*479ab7f0SSascha Wildner 	v86.eax  = VTOPOFF(scratch_buffer);
517*479ab7f0SSascha Wildner 	v86.addr = (VTOPSEG(__bangpxeentry) << 16) | VTOPOFF(__bangpxeentry);
518*479ab7f0SSascha Wildner 	v86.ebx  = func;
519*479ab7f0SSascha Wildner 	v86int();
520*479ab7f0SSascha Wildner 	v86.ctl  = V86_FLAGS;
521*479ab7f0SSascha Wildner }
522*479ab7f0SSascha Wildner 
523*479ab7f0SSascha Wildner 
524*479ab7f0SSascha Wildner time_t
getsecs(void)525*479ab7f0SSascha Wildner getsecs(void)
526*479ab7f0SSascha Wildner {
527*479ab7f0SSascha Wildner 	time_t n = 0;
528*479ab7f0SSascha Wildner 	time(&n);
529*479ab7f0SSascha Wildner 	return n;
530*479ab7f0SSascha Wildner }
531*479ab7f0SSascha Wildner 
532*479ab7f0SSascha Wildner static int
pxe_netif_match(struct netif * nif,void * machdep_hint)533*479ab7f0SSascha Wildner pxe_netif_match(struct netif *nif, void *machdep_hint)
534*479ab7f0SSascha Wildner {
535*479ab7f0SSascha Wildner 	return 1;
536*479ab7f0SSascha Wildner }
537*479ab7f0SSascha Wildner 
538*479ab7f0SSascha Wildner 
539*479ab7f0SSascha Wildner static int
pxe_netif_probe(struct netif * nif,void * machdep_hint)540*479ab7f0SSascha Wildner pxe_netif_probe(struct netif *nif, void *machdep_hint)
541*479ab7f0SSascha Wildner {
542*479ab7f0SSascha Wildner 	t_PXENV_UDP_OPEN *udpopen_p = (t_PXENV_UDP_OPEN *)scratch_buffer;
543*479ab7f0SSascha Wildner 
544*479ab7f0SSascha Wildner 	if (pxe_call == NULL)
545*479ab7f0SSascha Wildner 		return -1;
546*479ab7f0SSascha Wildner 
547*479ab7f0SSascha Wildner 	bzero(udpopen_p, sizeof(*udpopen_p));
548*479ab7f0SSascha Wildner 	udpopen_p->src_ip = bootplayer.yip;
549*479ab7f0SSascha Wildner 	pxe_call(PXENV_UDP_OPEN);
550*479ab7f0SSascha Wildner 
551*479ab7f0SSascha Wildner 	if (udpopen_p->status != 0) {
552*479ab7f0SSascha Wildner 		printf("pxe_netif_probe: failed %x\n", udpopen_p->status);
553*479ab7f0SSascha Wildner 		return -1;
554*479ab7f0SSascha Wildner 	}
555*479ab7f0SSascha Wildner 	return 0;
556*479ab7f0SSascha Wildner }
557*479ab7f0SSascha Wildner 
558*479ab7f0SSascha Wildner static void
pxe_netif_end(struct netif * nif)559*479ab7f0SSascha Wildner pxe_netif_end(struct netif *nif)
560*479ab7f0SSascha Wildner {
561*479ab7f0SSascha Wildner 	t_PXENV_UDP_CLOSE *udpclose_p = (t_PXENV_UDP_CLOSE *)scratch_buffer;
562*479ab7f0SSascha Wildner 	bzero(udpclose_p, sizeof(*udpclose_p));
563*479ab7f0SSascha Wildner 
564*479ab7f0SSascha Wildner 	pxe_call(PXENV_UDP_CLOSE);
565*479ab7f0SSascha Wildner 	if (udpclose_p->status != 0)
566*479ab7f0SSascha Wildner 		printf("pxe_end failed %x\n", udpclose_p->status);
567*479ab7f0SSascha Wildner }
568*479ab7f0SSascha Wildner 
569*479ab7f0SSascha Wildner static void
pxe_netif_init(struct iodesc * desc,void * machdep_hint)570*479ab7f0SSascha Wildner pxe_netif_init(struct iodesc *desc, void *machdep_hint)
571*479ab7f0SSascha Wildner {
572*479ab7f0SSascha Wildner 	int i;
573*479ab7f0SSascha Wildner 	for (i = 0; i < 6; ++i)
574*479ab7f0SSascha Wildner 		desc->myea[i] = bootplayer.CAddr[i];
575*479ab7f0SSascha Wildner 	desc->xid = bootplayer.ident;
576*479ab7f0SSascha Wildner }
577*479ab7f0SSascha Wildner 
578*479ab7f0SSascha Wildner static int
pxe_netif_get(struct iodesc * desc,void * pkt,size_t len,time_t timeout)579*479ab7f0SSascha Wildner pxe_netif_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout)
580*479ab7f0SSascha Wildner {
581*479ab7f0SSascha Wildner 	return len;
582*479ab7f0SSascha Wildner }
583*479ab7f0SSascha Wildner 
584*479ab7f0SSascha Wildner static int
pxe_netif_put(struct iodesc * desc,void * pkt,size_t len)585*479ab7f0SSascha Wildner pxe_netif_put(struct iodesc *desc, void *pkt, size_t len)
586*479ab7f0SSascha Wildner {
587*479ab7f0SSascha Wildner 	return len;
588*479ab7f0SSascha Wildner }
589*479ab7f0SSascha Wildner 
590*479ab7f0SSascha Wildner ssize_t
sendudp(struct iodesc * h,void * pkt,size_t len)591*479ab7f0SSascha Wildner sendudp(struct iodesc *h, void *pkt, size_t len)
592*479ab7f0SSascha Wildner {
593*479ab7f0SSascha Wildner 	t_PXENV_UDP_WRITE *udpwrite_p = (t_PXENV_UDP_WRITE *)scratch_buffer;
594*479ab7f0SSascha Wildner 	bzero(udpwrite_p, sizeof(*udpwrite_p));
595*479ab7f0SSascha Wildner 
596*479ab7f0SSascha Wildner 	udpwrite_p->ip             = h->destip.s_addr;
597*479ab7f0SSascha Wildner 	udpwrite_p->dst_port       = h->destport;
598*479ab7f0SSascha Wildner 	udpwrite_p->src_port       = h->myport;
599*479ab7f0SSascha Wildner 	udpwrite_p->buffer_size    = len;
600*479ab7f0SSascha Wildner 	udpwrite_p->buffer.segment = VTOPSEG(pkt);
601*479ab7f0SSascha Wildner 	udpwrite_p->buffer.offset  = VTOPOFF(pkt);
602*479ab7f0SSascha Wildner 
603*479ab7f0SSascha Wildner 	if (netmask == 0 || SAMENET(myip, h->destip, netmask))
604*479ab7f0SSascha Wildner 		udpwrite_p->gw = 0;
605*479ab7f0SSascha Wildner 	else
606*479ab7f0SSascha Wildner 		udpwrite_p->gw = gateip.s_addr;
607*479ab7f0SSascha Wildner 
608*479ab7f0SSascha Wildner 	pxe_call(PXENV_UDP_WRITE);
609*479ab7f0SSascha Wildner 
610*479ab7f0SSascha Wildner #if 0
611*479ab7f0SSascha Wildner 	/* XXX - I dont know why we need this. */
612*479ab7f0SSascha Wildner 	delay(1000);
613*479ab7f0SSascha Wildner #endif
614*479ab7f0SSascha Wildner 	if (udpwrite_p->status != 0) {
615*479ab7f0SSascha Wildner 		/* XXX: This happens a lot.  It shouldn't. */
616*479ab7f0SSascha Wildner 		if (udpwrite_p->status != 1)
617*479ab7f0SSascha Wildner 			printf("sendudp failed %x\n", udpwrite_p->status);
618*479ab7f0SSascha Wildner 		return -1;
619*479ab7f0SSascha Wildner 	}
620*479ab7f0SSascha Wildner 	return len;
621*479ab7f0SSascha Wildner }
622*479ab7f0SSascha Wildner 
623*479ab7f0SSascha Wildner ssize_t
readudp(struct iodesc * h,void * pkt,size_t len,time_t timeout)624*479ab7f0SSascha Wildner readudp(struct iodesc *h, void *pkt, size_t len, time_t timeout)
625*479ab7f0SSascha Wildner {
626*479ab7f0SSascha Wildner 	t_PXENV_UDP_READ *udpread_p = (t_PXENV_UDP_READ *)scratch_buffer;
627*479ab7f0SSascha Wildner 	struct udphdr *uh;
628*479ab7f0SSascha Wildner 	struct ip *ip;
629*479ab7f0SSascha Wildner 
630*479ab7f0SSascha Wildner 	uh = (struct udphdr *) pkt - 1;
631*479ab7f0SSascha Wildner 	ip = (struct ip *)uh - 1;
632*479ab7f0SSascha Wildner again:
633*479ab7f0SSascha Wildner 	bzero(udpread_p, sizeof(*udpread_p));
634*479ab7f0SSascha Wildner 
635*479ab7f0SSascha Wildner 	/*
636*479ab7f0SSascha Wildner 	 * Bugged BIOSes (e.g. Gigabyte H97N-WIFI) can wind up asking for
637*479ab7f0SSascha Wildner 	 * a different IP than we negotiated, then using that IP instead
638*479ab7f0SSascha Wildner 	 * of the one we specified in the udpopen().
639*479ab7f0SSascha Wildner 	 */
640*479ab7f0SSascha Wildner 	if (bugged_bios_pxe)
641*479ab7f0SSascha Wildner 		udpread_p->dest_ip = INADDR_ANY;
642*479ab7f0SSascha Wildner 	else
643*479ab7f0SSascha Wildner 		udpread_p->dest_ip = h->myip.s_addr;
644*479ab7f0SSascha Wildner 	udpread_p->d_port         = h->myport;
645*479ab7f0SSascha Wildner 	udpread_p->buffer_size    = len;
646*479ab7f0SSascha Wildner 	udpread_p->buffer.segment = VTOPSEG(data_buffer);
647*479ab7f0SSascha Wildner 	udpread_p->buffer.offset  = VTOPOFF(data_buffer);
648*479ab7f0SSascha Wildner 
649*479ab7f0SSascha Wildner 	pxe_call(PXENV_UDP_READ);
650*479ab7f0SSascha Wildner 
651*479ab7f0SSascha Wildner 	if (udpread_p->status != 0) {
652*479ab7f0SSascha Wildner 		/* XXX: This happens a lot.  It shouldn't. */
653*479ab7f0SSascha Wildner 		if (udpread_p->status != 1)
654*479ab7f0SSascha Wildner 			printf("readudp failed %x\n", udpread_p->status);
655*479ab7f0SSascha Wildner 		return -1;
656*479ab7f0SSascha Wildner 	}
657*479ab7f0SSascha Wildner 
658*479ab7f0SSascha Wildner 	/*
659*479ab7f0SSascha Wildner 	 * If the BIOS is bugged in this manner we were forced to allow
660*479ab7f0SSascha Wildner 	 * any address in dest_ip and have to filter the packets ourselves.
661*479ab7f0SSascha Wildner 	 * The bugged BIOS used the wrong IP in the udpwrite (it used the
662*479ab7f0SSascha Wildner 	 * previously negotiated bootplayer.yip IP).  So make sure the IP
663*479ab7f0SSascha Wildner 	 * is either that one or the one we negotiated and specified in the
664*479ab7f0SSascha Wildner 	 * udpopen ourselves.
665*479ab7f0SSascha Wildner 	 */
666*479ab7f0SSascha Wildner 	if (bugged_bios_pxe) {
667*479ab7f0SSascha Wildner 		if (udpread_p->dest_ip != h->myip.s_addr &&
668*479ab7f0SSascha Wildner 		    udpread_p->dest_ip != bootplayer.yip &&
669*479ab7f0SSascha Wildner 		    udpread_p->dest_ip != INADDR_ANY) {
670*479ab7f0SSascha Wildner 			goto again;
671*479ab7f0SSascha Wildner 		}
672*479ab7f0SSascha Wildner 	}
673*479ab7f0SSascha Wildner 
674*479ab7f0SSascha Wildner 	bcopy(data_buffer, pkt, udpread_p->buffer_size);
675*479ab7f0SSascha Wildner 	uh->uh_sport = udpread_p->s_port;
676*479ab7f0SSascha Wildner 	ip->ip_src.s_addr = udpread_p->src_ip;
677*479ab7f0SSascha Wildner 	return udpread_p->buffer_size;
678*479ab7f0SSascha Wildner }
679