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