Deleted Added
full compact
pxe.c (313355) pxe.c (328889)
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
29#include <sys/cdefs.h>
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
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: stable/11/sys/boot/i386/libi386/pxe.c 313355 2017-02-06 22:03:07Z tsoome $");
30__FBSDID("$FreeBSD: stable/11/sys/boot/i386/libi386/pxe.c 328889 2018-02-05 17:01:18Z kevans $");
31
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
40#include <net.h>
41#include <netif.h>
42#include <nfsv2.h>
43#include <iodesc.h>
44
45#include <bootp.h>
46#include <bootstrap.h>
47#include "btxv86.h"
48#include "pxe.h"
49
50/*
51 * Allocate the PXE buffers statically instead of sticking grimy fingers into
52 * BTX's private data area. The scratch buffer is used to send information to
53 * the PXE BIOS, and the data buffer is used to receive data from the PXE BIOS.
54 */
55#define PXE_BUFFER_SIZE 0x2000
56#define PXE_TFTP_BUFFER_SIZE 512
57static char scratch_buffer[PXE_BUFFER_SIZE];
58static char data_buffer[PXE_BUFFER_SIZE];
59
60static pxenv_t *pxenv_p = NULL; /* PXENV+ */
61static pxe_t *pxe_p = NULL; /* !PXE */
62static BOOTPLAYER bootplayer; /* PXE Cached information. */
63
64static int pxe_debug = 0;
65static int pxe_sock = -1;
66static int pxe_opens = 0;
67
68void pxe_enable(void *pxeinfo);
69static void (*pxe_call)(int func);
70static void pxenv_call(int func);
71static void bangpxe_call(int func);
72
73static int pxe_init(void);
74static int pxe_strategy(void *devdata, int flag, daddr_t dblk,
75 size_t size, char *buf, size_t *rsize);
76static int pxe_open(struct open_file *f, ...);
77static int pxe_close(struct open_file *f);
31
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
40#include <net.h>
41#include <netif.h>
42#include <nfsv2.h>
43#include <iodesc.h>
44
45#include <bootp.h>
46#include <bootstrap.h>
47#include "btxv86.h"
48#include "pxe.h"
49
50/*
51 * Allocate the PXE buffers statically instead of sticking grimy fingers into
52 * BTX's private data area. The scratch buffer is used to send information to
53 * the PXE BIOS, and the data buffer is used to receive data from the PXE BIOS.
54 */
55#define PXE_BUFFER_SIZE 0x2000
56#define PXE_TFTP_BUFFER_SIZE 512
57static char scratch_buffer[PXE_BUFFER_SIZE];
58static char data_buffer[PXE_BUFFER_SIZE];
59
60static pxenv_t *pxenv_p = NULL; /* PXENV+ */
61static pxe_t *pxe_p = NULL; /* !PXE */
62static BOOTPLAYER bootplayer; /* PXE Cached information. */
63
64static int pxe_debug = 0;
65static int pxe_sock = -1;
66static int pxe_opens = 0;
67
68void pxe_enable(void *pxeinfo);
69static void (*pxe_call)(int func);
70static void pxenv_call(int func);
71static void bangpxe_call(int func);
72
73static int pxe_init(void);
74static int pxe_strategy(void *devdata, int flag, daddr_t dblk,
75 size_t size, char *buf, size_t *rsize);
76static int pxe_open(struct open_file *f, ...);
77static int pxe_close(struct open_file *f);
78static void pxe_print(int verbose);
78static int pxe_print(int verbose);
79static void pxe_cleanup(void);
80static void pxe_setnfshandle(char *rootpath);
81
82static void pxe_perror(int error);
83static int pxe_netif_match(struct netif *nif, void *machdep_hint);
84static int pxe_netif_probe(struct netif *nif, void *machdep_hint);
85static void pxe_netif_init(struct iodesc *desc, void *machdep_hint);
86static int pxe_netif_get(struct iodesc *desc, void *pkt, size_t len,
87 time_t timeout);
88static int pxe_netif_put(struct iodesc *desc, void *pkt, size_t len);
89static void pxe_netif_end(struct netif *nif);
90
91#ifdef OLD_NFSV2
92int nfs_getrootfh(struct iodesc*, char*, u_char*);
93#else
94int nfs_getrootfh(struct iodesc*, char*, uint32_t*, u_char*);
95#endif
96
97extern struct netif_stats pxe_st[];
98extern u_int16_t __bangpxeseg;
99extern u_int16_t __bangpxeoff;
100extern void __bangpxeentry(void);
101extern u_int16_t __pxenvseg;
102extern u_int16_t __pxenvoff;
103extern void __pxenventry(void);
104
105struct netif_dif pxe_ifs[] = {
106/* dif_unit dif_nsel dif_stats dif_private */
107 {0, 1, &pxe_st[0], 0}
108};
109
110struct netif_stats pxe_st[NENTS(pxe_ifs)];
111
112struct netif_driver pxenetif = {
113 "pxenet",
114 pxe_netif_match,
115 pxe_netif_probe,
116 pxe_netif_init,
117 pxe_netif_get,
118 pxe_netif_put,
119 pxe_netif_end,
120 pxe_ifs,
121 NENTS(pxe_ifs)
122};
123
124struct netif_driver *netif_drivers[] = {
125 &pxenetif,
126 NULL
127};
128
129struct devsw pxedisk = {
130 "pxe",
131 DEVT_NET,
132 pxe_init,
133 pxe_strategy,
134 pxe_open,
135 pxe_close,
136 noioctl,
137 pxe_print,
138 pxe_cleanup
139};
140
141/*
142 * This function is called by the loader to enable PXE support if we
143 * are booted by PXE. The passed in pointer is a pointer to the
144 * PXENV+ structure.
145 */
146void
147pxe_enable(void *pxeinfo)
148{
149 pxenv_p = (pxenv_t *)pxeinfo;
150 pxe_p = (pxe_t *)PTOV(pxenv_p->PXEPtr.segment * 16 +
151 pxenv_p->PXEPtr.offset);
152 pxe_call = NULL;
153}
154
155/*
156 * return true if pxe structures are found/initialized,
157 * also figures out our IP information via the pxe cached info struct
158 */
159static int
160pxe_init(void)
161{
162 t_PXENV_GET_CACHED_INFO *gci_p;
163 int counter;
164 uint8_t checksum;
165 uint8_t *checkptr;
166
167 if(pxenv_p == NULL)
168 return (0);
169
170 /* look for "PXENV+" */
171 if (bcmp((void *)pxenv_p->Signature, S_SIZE("PXENV+"))) {
172 pxenv_p = NULL;
173 return (0);
174 }
175
176 /* make sure the size is something we can handle */
177 if (pxenv_p->Length > sizeof(*pxenv_p)) {
178 printf("PXENV+ structure too large, ignoring\n");
179 pxenv_p = NULL;
180 return (0);
181 }
182
183 /*
184 * do byte checksum:
185 * add up each byte in the structure, the total should be 0
186 */
187 checksum = 0;
188 checkptr = (uint8_t *) pxenv_p;
189 for (counter = 0; counter < pxenv_p->Length; counter++)
190 checksum += *checkptr++;
191 if (checksum != 0) {
192 printf("PXENV+ structure failed checksum, ignoring\n");
193 pxenv_p = NULL;
194 return (0);
195 }
196
197
198 /*
199 * PXENV+ passed, so use that if !PXE is not available or
200 * the checksum fails.
201 */
202 pxe_call = pxenv_call;
203 if (pxenv_p->Version >= 0x0200) {
204 for (;;) {
205 if (bcmp((void *)pxe_p->Signature, S_SIZE("!PXE"))) {
206 pxe_p = NULL;
207 break;
208 }
209 checksum = 0;
210 checkptr = (uint8_t *)pxe_p;
211 for (counter = 0; counter < pxe_p->StructLength;
212 counter++)
213 checksum += *checkptr++;
214 if (checksum != 0) {
215 pxe_p = NULL;
216 break;
217 }
218 pxe_call = bangpxe_call;
219 break;
220 }
221 }
222
223 printf("\nPXE version %d.%d, real mode entry point ",
224 (uint8_t) (pxenv_p->Version >> 8),
225 (uint8_t) (pxenv_p->Version & 0xFF));
226 if (pxe_call == bangpxe_call)
227 printf("@%04x:%04x\n",
228 pxe_p->EntryPointSP.segment,
229 pxe_p->EntryPointSP.offset);
230 else
231 printf("@%04x:%04x\n",
232 pxenv_p->RMEntry.segment, pxenv_p->RMEntry.offset);
233
234 gci_p = (t_PXENV_GET_CACHED_INFO *) scratch_buffer;
235 bzero(gci_p, sizeof(*gci_p));
236 gci_p->PacketType = PXENV_PACKET_TYPE_BINL_REPLY;
237 pxe_call(PXENV_GET_CACHED_INFO);
238 if (gci_p->Status != 0) {
239 pxe_perror(gci_p->Status);
240 pxe_p = NULL;
241 return (0);
242 }
243 bcopy(PTOV((gci_p->Buffer.segment << 4) + gci_p->Buffer.offset),
244 &bootplayer, gci_p->BufferSize);
245 return (1);
246}
247
248
249static int
250pxe_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
251 char *buf, size_t *rsize)
252{
253 return (EIO);
254}
255
256static int
257pxe_open(struct open_file *f, ...)
258{
259 va_list args;
260 char *devname; /* Device part of file name (or NULL). */
261 char temp[FNAME_SIZE];
262 int error = 0;
263 int i;
264
265 va_start(args, f);
266 devname = va_arg(args, char*);
267 va_end(args);
268
269 /* On first open, do netif open, mount, etc. */
270 if (pxe_opens == 0) {
271 /* Find network interface. */
272 if (pxe_sock < 0) {
273 pxe_sock = netif_open(devname);
274 if (pxe_sock < 0) {
275 printf("pxe_open: netif_open() failed\n");
276 return (ENXIO);
277 }
278 if (pxe_debug)
279 printf("pxe_open: netif_open() succeeded\n");
280 }
281 if (rootip.s_addr == 0) {
282 /*
283 * Do a bootp/dhcp request to find out where our
284 * NFS/TFTP server is. Even if we dont get back
285 * the proper information, fall back to the server
286 * which brought us to life and a default rootpath.
287 */
288 bootp(pxe_sock, BOOTP_PXE);
289 if (rootip.s_addr == 0)
290 rootip.s_addr = bootplayer.sip;
291
292 netproto = NET_NFS;
293 if (tftpip.s_addr != 0) {
294 netproto = NET_TFTP;
295 rootip.s_addr = tftpip.s_addr;
296 }
297
298 if (netproto == NET_NFS && !rootpath[0])
299 strcpy(rootpath, PXENFSROOTPATH);
300
301 for (i = 0; rootpath[i] != '\0' && i < FNAME_SIZE; i++)
302 if (rootpath[i] == ':')
303 break;
304 if (i && i != FNAME_SIZE && rootpath[i] == ':') {
305 rootpath[i++] = '\0';
306 if (inet_addr(&rootpath[0]) != INADDR_NONE)
307 rootip.s_addr = inet_addr(&rootpath[0]);
308 bcopy(&rootpath[i], &temp[0], strlen(&rootpath[i])+1);
309 bcopy(&temp[0], &rootpath[0], strlen(&rootpath[i])+1);
310 }
311 setenv("boot.netif.ip", inet_ntoa(myip), 1);
312 setenv("boot.netif.netmask", intoa(netmask), 1);
313 setenv("boot.netif.gateway", inet_ntoa(gateip), 1);
314 setenv("boot.netif.server", inet_ntoa(rootip), 1);
315 if (bootplayer.Hardware == ETHER_TYPE) {
316 sprintf(temp, "%6D", bootplayer.CAddr, ":");
317 setenv("boot.netif.hwaddr", temp, 1);
318 }
319 if (intf_mtu != 0) {
320 char mtu[16];
321 sprintf(mtu, "%u", intf_mtu);
322 setenv("boot.netif.mtu", mtu, 1);
323 }
324 printf("pxe_open: server addr: %s\n", inet_ntoa(rootip));
325 printf("pxe_open: server path: %s\n", rootpath);
326 printf("pxe_open: gateway ip: %s\n", inet_ntoa(gateip));
327
328 if (netproto == NET_TFTP) {
329 setenv("boot.tftproot.server", inet_ntoa(rootip), 1);
330 setenv("boot.tftproot.path", rootpath, 1);
331 } else if (netproto == NET_NFS) {
332 setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
333 setenv("boot.nfsroot.path", rootpath, 1);
334 }
335 setenv("dhcp.host-name", hostname, 1);
336
337 setenv("pxeboot.ip", inet_ntoa(myip), 1);
338 if (bootplayer.Hardware == ETHER_TYPE) {
339 sprintf(temp, "%6D", bootplayer.CAddr, ":");
340 setenv("pxeboot.hwaddr", temp, 1);
341 }
342 }
343 }
344 pxe_opens++;
345 f->f_devdata = &pxe_sock;
346 return (error);
347}
348
349static int
350pxe_close(struct open_file *f)
351{
352
353#ifdef PXE_DEBUG
354 if (pxe_debug)
355 printf("pxe_close: opens=%d\n", pxe_opens);
356#endif
357
358 /* On last close, do netif close, etc. */
359 f->f_devdata = NULL;
360 /* Extra close call? */
361 if (pxe_opens <= 0)
362 return (0);
363 pxe_opens--;
364 /* Not last close? */
365 if (pxe_opens > 0)
366 return(0);
367
368 if (netproto == NET_NFS) {
369 /* get an NFS filehandle for our root filesystem */
370 pxe_setnfshandle(rootpath);
371 }
372
373 if (pxe_sock >= 0) {
374
375#ifdef PXE_DEBUG
376 if (pxe_debug)
377 printf("pxe_close: calling netif_close()\n");
378#endif
379 netif_close(pxe_sock);
380 pxe_sock = -1;
381 }
382 return (0);
383}
384
79static void pxe_cleanup(void);
80static void pxe_setnfshandle(char *rootpath);
81
82static void pxe_perror(int error);
83static int pxe_netif_match(struct netif *nif, void *machdep_hint);
84static int pxe_netif_probe(struct netif *nif, void *machdep_hint);
85static void pxe_netif_init(struct iodesc *desc, void *machdep_hint);
86static int pxe_netif_get(struct iodesc *desc, void *pkt, size_t len,
87 time_t timeout);
88static int pxe_netif_put(struct iodesc *desc, void *pkt, size_t len);
89static void pxe_netif_end(struct netif *nif);
90
91#ifdef OLD_NFSV2
92int nfs_getrootfh(struct iodesc*, char*, u_char*);
93#else
94int nfs_getrootfh(struct iodesc*, char*, uint32_t*, u_char*);
95#endif
96
97extern struct netif_stats pxe_st[];
98extern u_int16_t __bangpxeseg;
99extern u_int16_t __bangpxeoff;
100extern void __bangpxeentry(void);
101extern u_int16_t __pxenvseg;
102extern u_int16_t __pxenvoff;
103extern void __pxenventry(void);
104
105struct netif_dif pxe_ifs[] = {
106/* dif_unit dif_nsel dif_stats dif_private */
107 {0, 1, &pxe_st[0], 0}
108};
109
110struct netif_stats pxe_st[NENTS(pxe_ifs)];
111
112struct netif_driver pxenetif = {
113 "pxenet",
114 pxe_netif_match,
115 pxe_netif_probe,
116 pxe_netif_init,
117 pxe_netif_get,
118 pxe_netif_put,
119 pxe_netif_end,
120 pxe_ifs,
121 NENTS(pxe_ifs)
122};
123
124struct netif_driver *netif_drivers[] = {
125 &pxenetif,
126 NULL
127};
128
129struct devsw pxedisk = {
130 "pxe",
131 DEVT_NET,
132 pxe_init,
133 pxe_strategy,
134 pxe_open,
135 pxe_close,
136 noioctl,
137 pxe_print,
138 pxe_cleanup
139};
140
141/*
142 * This function is called by the loader to enable PXE support if we
143 * are booted by PXE. The passed in pointer is a pointer to the
144 * PXENV+ structure.
145 */
146void
147pxe_enable(void *pxeinfo)
148{
149 pxenv_p = (pxenv_t *)pxeinfo;
150 pxe_p = (pxe_t *)PTOV(pxenv_p->PXEPtr.segment * 16 +
151 pxenv_p->PXEPtr.offset);
152 pxe_call = NULL;
153}
154
155/*
156 * return true if pxe structures are found/initialized,
157 * also figures out our IP information via the pxe cached info struct
158 */
159static int
160pxe_init(void)
161{
162 t_PXENV_GET_CACHED_INFO *gci_p;
163 int counter;
164 uint8_t checksum;
165 uint8_t *checkptr;
166
167 if(pxenv_p == NULL)
168 return (0);
169
170 /* look for "PXENV+" */
171 if (bcmp((void *)pxenv_p->Signature, S_SIZE("PXENV+"))) {
172 pxenv_p = NULL;
173 return (0);
174 }
175
176 /* make sure the size is something we can handle */
177 if (pxenv_p->Length > sizeof(*pxenv_p)) {
178 printf("PXENV+ structure too large, ignoring\n");
179 pxenv_p = NULL;
180 return (0);
181 }
182
183 /*
184 * do byte checksum:
185 * add up each byte in the structure, the total should be 0
186 */
187 checksum = 0;
188 checkptr = (uint8_t *) pxenv_p;
189 for (counter = 0; counter < pxenv_p->Length; counter++)
190 checksum += *checkptr++;
191 if (checksum != 0) {
192 printf("PXENV+ structure failed checksum, ignoring\n");
193 pxenv_p = NULL;
194 return (0);
195 }
196
197
198 /*
199 * PXENV+ passed, so use that if !PXE is not available or
200 * the checksum fails.
201 */
202 pxe_call = pxenv_call;
203 if (pxenv_p->Version >= 0x0200) {
204 for (;;) {
205 if (bcmp((void *)pxe_p->Signature, S_SIZE("!PXE"))) {
206 pxe_p = NULL;
207 break;
208 }
209 checksum = 0;
210 checkptr = (uint8_t *)pxe_p;
211 for (counter = 0; counter < pxe_p->StructLength;
212 counter++)
213 checksum += *checkptr++;
214 if (checksum != 0) {
215 pxe_p = NULL;
216 break;
217 }
218 pxe_call = bangpxe_call;
219 break;
220 }
221 }
222
223 printf("\nPXE version %d.%d, real mode entry point ",
224 (uint8_t) (pxenv_p->Version >> 8),
225 (uint8_t) (pxenv_p->Version & 0xFF));
226 if (pxe_call == bangpxe_call)
227 printf("@%04x:%04x\n",
228 pxe_p->EntryPointSP.segment,
229 pxe_p->EntryPointSP.offset);
230 else
231 printf("@%04x:%04x\n",
232 pxenv_p->RMEntry.segment, pxenv_p->RMEntry.offset);
233
234 gci_p = (t_PXENV_GET_CACHED_INFO *) scratch_buffer;
235 bzero(gci_p, sizeof(*gci_p));
236 gci_p->PacketType = PXENV_PACKET_TYPE_BINL_REPLY;
237 pxe_call(PXENV_GET_CACHED_INFO);
238 if (gci_p->Status != 0) {
239 pxe_perror(gci_p->Status);
240 pxe_p = NULL;
241 return (0);
242 }
243 bcopy(PTOV((gci_p->Buffer.segment << 4) + gci_p->Buffer.offset),
244 &bootplayer, gci_p->BufferSize);
245 return (1);
246}
247
248
249static int
250pxe_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
251 char *buf, size_t *rsize)
252{
253 return (EIO);
254}
255
256static int
257pxe_open(struct open_file *f, ...)
258{
259 va_list args;
260 char *devname; /* Device part of file name (or NULL). */
261 char temp[FNAME_SIZE];
262 int error = 0;
263 int i;
264
265 va_start(args, f);
266 devname = va_arg(args, char*);
267 va_end(args);
268
269 /* On first open, do netif open, mount, etc. */
270 if (pxe_opens == 0) {
271 /* Find network interface. */
272 if (pxe_sock < 0) {
273 pxe_sock = netif_open(devname);
274 if (pxe_sock < 0) {
275 printf("pxe_open: netif_open() failed\n");
276 return (ENXIO);
277 }
278 if (pxe_debug)
279 printf("pxe_open: netif_open() succeeded\n");
280 }
281 if (rootip.s_addr == 0) {
282 /*
283 * Do a bootp/dhcp request to find out where our
284 * NFS/TFTP server is. Even if we dont get back
285 * the proper information, fall back to the server
286 * which brought us to life and a default rootpath.
287 */
288 bootp(pxe_sock, BOOTP_PXE);
289 if (rootip.s_addr == 0)
290 rootip.s_addr = bootplayer.sip;
291
292 netproto = NET_NFS;
293 if (tftpip.s_addr != 0) {
294 netproto = NET_TFTP;
295 rootip.s_addr = tftpip.s_addr;
296 }
297
298 if (netproto == NET_NFS && !rootpath[0])
299 strcpy(rootpath, PXENFSROOTPATH);
300
301 for (i = 0; rootpath[i] != '\0' && i < FNAME_SIZE; i++)
302 if (rootpath[i] == ':')
303 break;
304 if (i && i != FNAME_SIZE && rootpath[i] == ':') {
305 rootpath[i++] = '\0';
306 if (inet_addr(&rootpath[0]) != INADDR_NONE)
307 rootip.s_addr = inet_addr(&rootpath[0]);
308 bcopy(&rootpath[i], &temp[0], strlen(&rootpath[i])+1);
309 bcopy(&temp[0], &rootpath[0], strlen(&rootpath[i])+1);
310 }
311 setenv("boot.netif.ip", inet_ntoa(myip), 1);
312 setenv("boot.netif.netmask", intoa(netmask), 1);
313 setenv("boot.netif.gateway", inet_ntoa(gateip), 1);
314 setenv("boot.netif.server", inet_ntoa(rootip), 1);
315 if (bootplayer.Hardware == ETHER_TYPE) {
316 sprintf(temp, "%6D", bootplayer.CAddr, ":");
317 setenv("boot.netif.hwaddr", temp, 1);
318 }
319 if (intf_mtu != 0) {
320 char mtu[16];
321 sprintf(mtu, "%u", intf_mtu);
322 setenv("boot.netif.mtu", mtu, 1);
323 }
324 printf("pxe_open: server addr: %s\n", inet_ntoa(rootip));
325 printf("pxe_open: server path: %s\n", rootpath);
326 printf("pxe_open: gateway ip: %s\n", inet_ntoa(gateip));
327
328 if (netproto == NET_TFTP) {
329 setenv("boot.tftproot.server", inet_ntoa(rootip), 1);
330 setenv("boot.tftproot.path", rootpath, 1);
331 } else if (netproto == NET_NFS) {
332 setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
333 setenv("boot.nfsroot.path", rootpath, 1);
334 }
335 setenv("dhcp.host-name", hostname, 1);
336
337 setenv("pxeboot.ip", inet_ntoa(myip), 1);
338 if (bootplayer.Hardware == ETHER_TYPE) {
339 sprintf(temp, "%6D", bootplayer.CAddr, ":");
340 setenv("pxeboot.hwaddr", temp, 1);
341 }
342 }
343 }
344 pxe_opens++;
345 f->f_devdata = &pxe_sock;
346 return (error);
347}
348
349static int
350pxe_close(struct open_file *f)
351{
352
353#ifdef PXE_DEBUG
354 if (pxe_debug)
355 printf("pxe_close: opens=%d\n", pxe_opens);
356#endif
357
358 /* On last close, do netif close, etc. */
359 f->f_devdata = NULL;
360 /* Extra close call? */
361 if (pxe_opens <= 0)
362 return (0);
363 pxe_opens--;
364 /* Not last close? */
365 if (pxe_opens > 0)
366 return(0);
367
368 if (netproto == NET_NFS) {
369 /* get an NFS filehandle for our root filesystem */
370 pxe_setnfshandle(rootpath);
371 }
372
373 if (pxe_sock >= 0) {
374
375#ifdef PXE_DEBUG
376 if (pxe_debug)
377 printf("pxe_close: calling netif_close()\n");
378#endif
379 netif_close(pxe_sock);
380 pxe_sock = -1;
381 }
382 return (0);
383}
384
385static void
385static int
386pxe_print(int verbose)
387{
386pxe_print(int verbose)
387{
388
388 char line[255];
389 if (pxe_call == NULL)
389 if (pxe_call == NULL)
390 return;
390 return (0);
391
391
392 printf(" pxe0: %s:%s\n", inet_ntoa(rootip), rootpath);
392 printf("%s devices:", pxedisk.dv_name);
393 if (pager_output("\n") != 0)
394 return (1);
395 if (verbose) {
396 snprintf(line, sizeof(line), " pxe0: %s:%s\n",
397 inet_ntoa(rootip), rootpath);
398 } else {
399 snprintf(line, sizeof(line), " pxe0:\n");
400 }
401 return (pager_output(line));
393}
394
395static void
396pxe_cleanup(void)
397{
398#ifdef PXE_DEBUG
399 t_PXENV_UNLOAD_STACK *unload_stack_p =
400 (t_PXENV_UNLOAD_STACK *)scratch_buffer;
401 t_PXENV_UNDI_SHUTDOWN *undi_shutdown_p =
402 (t_PXENV_UNDI_SHUTDOWN *)scratch_buffer;
403#endif
404
405 if (pxe_call == NULL)
406 return;
407
408 pxe_call(PXENV_UNDI_SHUTDOWN);
409
410#ifdef PXE_DEBUG
411 if (pxe_debug && undi_shutdown_p->Status != 0)
412 printf("pxe_cleanup: UNDI_SHUTDOWN failed %x\n",
413 undi_shutdown_p->Status);
414#endif
415
416 pxe_call(PXENV_UNLOAD_STACK);
417
418#ifdef PXE_DEBUG
419 if (pxe_debug && unload_stack_p->Status != 0)
420 printf("pxe_cleanup: UNLOAD_STACK failed %x\n",
421 unload_stack_p->Status);
422#endif
423}
424
425void
426pxe_perror(int err)
427{
428 return;
429}
430
431/*
432 * Reach inside the libstand NFS code and dig out an NFS handle
433 * for the root filesystem.
434 */
435#ifdef OLD_NFSV2
436struct nfs_iodesc {
437 struct iodesc *iodesc;
438 off_t off;
439 u_char fh[NFS_FHSIZE];
440 /* structure truncated here */
441};
442extern struct nfs_iodesc nfs_root_node;
443extern int rpc_port;
444
445static void
446pxe_rpcmountcall()
447{
448 struct iodesc *d;
449 int error;
450
451 if (!(d = socktodesc(pxe_sock)))
452 return;
453 d->myport = htons(--rpc_port);
454 d->destip = rootip;
455 if ((error = nfs_getrootfh(d, rootpath, nfs_root_node.fh)) != 0)
456 printf("NFS MOUNT RPC error: %d\n", error);
457 nfs_root_node.iodesc = d;
458}
459
460static void
461pxe_setnfshandle(char *rootpath)
462{
463 int i;
464 u_char *fh;
465 char buf[2 * NFS_FHSIZE + 3], *cp;
466
467 /*
468 * If NFS files were never opened, we need to do mount call
469 * ourselves. Use nfs_root_node.iodesc as flag indicating
470 * previous NFS usage.
471 */
472 if (nfs_root_node.iodesc == NULL)
473 pxe_rpcmountcall();
474
475 fh = &nfs_root_node.fh[0];
476 buf[0] = 'X';
477 cp = &buf[1];
478 for (i = 0; i < NFS_FHSIZE; i++, cp += 2)
479 sprintf(cp, "%02x", fh[i]);
480 sprintf(cp, "X");
481 setenv("boot.nfsroot.nfshandle", buf, 1);
482}
483#else /* !OLD_NFSV2 */
484
485#define NFS_V3MAXFHSIZE 64
486
487struct nfs_iodesc {
488 struct iodesc *iodesc;
489 off_t off;
490 uint32_t fhsize;
491 u_char fh[NFS_V3MAXFHSIZE];
492 /* structure truncated */
493};
494extern struct nfs_iodesc nfs_root_node;
495extern int rpc_port;
496
497static void
498pxe_rpcmountcall()
499{
500 struct iodesc *d;
501 int error;
502
503 if (!(d = socktodesc(pxe_sock)))
504 return;
505 d->myport = htons(--rpc_port);
506 d->destip = rootip;
507 if ((error = nfs_getrootfh(d, rootpath, &nfs_root_node.fhsize,
508 nfs_root_node.fh)) != 0) {
509 printf("NFS MOUNT RPC error: %d\n", error);
510 nfs_root_node.fhsize = 0;
511 }
512 nfs_root_node.iodesc = d;
513}
514
515static void
516pxe_setnfshandle(char *rootpath)
517{
518 int i;
519 u_char *fh;
520 char buf[2 * NFS_V3MAXFHSIZE + 3], *cp;
521
522 /*
523 * If NFS files were never opened, we need to do mount call
524 * ourselves. Use nfs_root_node.iodesc as flag indicating
525 * previous NFS usage.
526 */
527 if (nfs_root_node.iodesc == NULL)
528 pxe_rpcmountcall();
529
530 fh = &nfs_root_node.fh[0];
531 buf[0] = 'X';
532 cp = &buf[1];
533 for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2)
534 sprintf(cp, "%02x", fh[i]);
535 sprintf(cp, "X");
536 setenv("boot.nfsroot.nfshandle", buf, 1);
537 sprintf(buf, "%d", nfs_root_node.fhsize);
538 setenv("boot.nfsroot.nfshandlelen", buf, 1);
539}
540#endif /* OLD_NFSV2 */
541
542void
543pxenv_call(int func)
544{
545#ifdef PXE_DEBUG
546 if (pxe_debug)
547 printf("pxenv_call %x\n", func);
548#endif
549
550 bzero(&v86, sizeof(v86));
551 bzero(data_buffer, sizeof(data_buffer));
552
553 __pxenvseg = pxenv_p->RMEntry.segment;
554 __pxenvoff = pxenv_p->RMEntry.offset;
555
556 v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
557 v86.es = VTOPSEG(scratch_buffer);
558 v86.edi = VTOPOFF(scratch_buffer);
559 v86.addr = (VTOPSEG(__pxenventry) << 16) | VTOPOFF(__pxenventry);
560 v86.ebx = func;
561 v86int();
562 v86.ctl = V86_FLAGS;
563}
564
565void
566bangpxe_call(int func)
567{
568#ifdef PXE_DEBUG
569 if (pxe_debug)
570 printf("bangpxe_call %x\n", func);
571#endif
572
573 bzero(&v86, sizeof(v86));
574 bzero(data_buffer, sizeof(data_buffer));
575
576 __bangpxeseg = pxe_p->EntryPointSP.segment;
577 __bangpxeoff = pxe_p->EntryPointSP.offset;
578
579 v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
580 v86.edx = VTOPSEG(scratch_buffer);
581 v86.eax = VTOPOFF(scratch_buffer);
582 v86.addr = (VTOPSEG(__bangpxeentry) << 16) | VTOPOFF(__bangpxeentry);
583 v86.ebx = func;
584 v86int();
585 v86.ctl = V86_FLAGS;
586}
587
588
589time_t
590getsecs()
591{
592 time_t n = 0;
593 time(&n);
594 return n;
595}
596
597static int
598pxe_netif_match(struct netif *nif, void *machdep_hint)
599{
600 return 1;
601}
602
603
604static int
605pxe_netif_probe(struct netif *nif, void *machdep_hint)
606{
607 t_PXENV_UDP_OPEN *udpopen_p = (t_PXENV_UDP_OPEN *)scratch_buffer;
608
609 if (pxe_call == NULL)
610 return -1;
611
612 bzero(udpopen_p, sizeof(*udpopen_p));
613 udpopen_p->src_ip = bootplayer.yip;
614 pxe_call(PXENV_UDP_OPEN);
615
616 if (udpopen_p->status != 0) {
617 printf("pxe_netif_probe: failed %x\n", udpopen_p->status);
618 return -1;
619 }
620 return 0;
621}
622
623static void
624pxe_netif_end(struct netif *nif)
625{
626 t_PXENV_UDP_CLOSE *udpclose_p = (t_PXENV_UDP_CLOSE *)scratch_buffer;
627 bzero(udpclose_p, sizeof(*udpclose_p));
628
629 pxe_call(PXENV_UDP_CLOSE);
630 if (udpclose_p->status != 0)
631 printf("pxe_end failed %x\n", udpclose_p->status);
632}
633
634static void
635pxe_netif_init(struct iodesc *desc, void *machdep_hint)
636{
637 int i;
638 for (i = 0; i < 6; ++i)
639 desc->myea[i] = bootplayer.CAddr[i];
640 desc->xid = bootplayer.ident;
641}
642
643static int
644pxe_netif_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout)
645{
646 return len;
647}
648
649static int
650pxe_netif_put(struct iodesc *desc, void *pkt, size_t len)
651{
652 return len;
653}
654
655ssize_t
656sendudp(struct iodesc *h, void *pkt, size_t len)
657{
658 t_PXENV_UDP_WRITE *udpwrite_p = (t_PXENV_UDP_WRITE *)scratch_buffer;
659 bzero(udpwrite_p, sizeof(*udpwrite_p));
660
661 udpwrite_p->ip = h->destip.s_addr;
662 udpwrite_p->dst_port = h->destport;
663 udpwrite_p->src_port = h->myport;
664 udpwrite_p->buffer_size = len;
665 udpwrite_p->buffer.segment = VTOPSEG(pkt);
666 udpwrite_p->buffer.offset = VTOPOFF(pkt);
667
668 if (netmask == 0 || SAMENET(myip, h->destip, netmask))
669 udpwrite_p->gw = 0;
670 else
671 udpwrite_p->gw = gateip.s_addr;
672
673 pxe_call(PXENV_UDP_WRITE);
674
675#if 0
676 /* XXX - I dont know why we need this. */
677 delay(1000);
678#endif
679 if (udpwrite_p->status != 0) {
680 /* XXX: This happens a lot. It shouldn't. */
681 if (udpwrite_p->status != 1)
682 printf("sendudp failed %x\n", udpwrite_p->status);
683 return -1;
684 }
685 return len;
686}
687
688ssize_t
689readudp(struct iodesc *h, void *pkt, size_t len, time_t timeout)
690{
691 t_PXENV_UDP_READ *udpread_p = (t_PXENV_UDP_READ *)scratch_buffer;
692 struct udphdr *uh = NULL;
693
694 uh = (struct udphdr *) pkt - 1;
695 bzero(udpread_p, sizeof(*udpread_p));
696
697 udpread_p->dest_ip = h->myip.s_addr;
698 udpread_p->d_port = h->myport;
699 udpread_p->buffer_size = len;
700 udpread_p->buffer.segment = VTOPSEG(data_buffer);
701 udpread_p->buffer.offset = VTOPOFF(data_buffer);
702
703 pxe_call(PXENV_UDP_READ);
704
705#if 0
706 /* XXX - I dont know why we need this. */
707 delay(1000);
708#endif
709 if (udpread_p->status != 0) {
710 /* XXX: This happens a lot. It shouldn't. */
711 if (udpread_p->status != 1)
712 printf("readudp failed %x\n", udpread_p->status);
713 return -1;
714 }
715 bcopy(data_buffer, pkt, udpread_p->buffer_size);
716 uh->uh_sport = udpread_p->s_port;
717 return udpread_p->buffer_size;
718}
402}
403
404static void
405pxe_cleanup(void)
406{
407#ifdef PXE_DEBUG
408 t_PXENV_UNLOAD_STACK *unload_stack_p =
409 (t_PXENV_UNLOAD_STACK *)scratch_buffer;
410 t_PXENV_UNDI_SHUTDOWN *undi_shutdown_p =
411 (t_PXENV_UNDI_SHUTDOWN *)scratch_buffer;
412#endif
413
414 if (pxe_call == NULL)
415 return;
416
417 pxe_call(PXENV_UNDI_SHUTDOWN);
418
419#ifdef PXE_DEBUG
420 if (pxe_debug && undi_shutdown_p->Status != 0)
421 printf("pxe_cleanup: UNDI_SHUTDOWN failed %x\n",
422 undi_shutdown_p->Status);
423#endif
424
425 pxe_call(PXENV_UNLOAD_STACK);
426
427#ifdef PXE_DEBUG
428 if (pxe_debug && unload_stack_p->Status != 0)
429 printf("pxe_cleanup: UNLOAD_STACK failed %x\n",
430 unload_stack_p->Status);
431#endif
432}
433
434void
435pxe_perror(int err)
436{
437 return;
438}
439
440/*
441 * Reach inside the libstand NFS code and dig out an NFS handle
442 * for the root filesystem.
443 */
444#ifdef OLD_NFSV2
445struct nfs_iodesc {
446 struct iodesc *iodesc;
447 off_t off;
448 u_char fh[NFS_FHSIZE];
449 /* structure truncated here */
450};
451extern struct nfs_iodesc nfs_root_node;
452extern int rpc_port;
453
454static void
455pxe_rpcmountcall()
456{
457 struct iodesc *d;
458 int error;
459
460 if (!(d = socktodesc(pxe_sock)))
461 return;
462 d->myport = htons(--rpc_port);
463 d->destip = rootip;
464 if ((error = nfs_getrootfh(d, rootpath, nfs_root_node.fh)) != 0)
465 printf("NFS MOUNT RPC error: %d\n", error);
466 nfs_root_node.iodesc = d;
467}
468
469static void
470pxe_setnfshandle(char *rootpath)
471{
472 int i;
473 u_char *fh;
474 char buf[2 * NFS_FHSIZE + 3], *cp;
475
476 /*
477 * If NFS files were never opened, we need to do mount call
478 * ourselves. Use nfs_root_node.iodesc as flag indicating
479 * previous NFS usage.
480 */
481 if (nfs_root_node.iodesc == NULL)
482 pxe_rpcmountcall();
483
484 fh = &nfs_root_node.fh[0];
485 buf[0] = 'X';
486 cp = &buf[1];
487 for (i = 0; i < NFS_FHSIZE; i++, cp += 2)
488 sprintf(cp, "%02x", fh[i]);
489 sprintf(cp, "X");
490 setenv("boot.nfsroot.nfshandle", buf, 1);
491}
492#else /* !OLD_NFSV2 */
493
494#define NFS_V3MAXFHSIZE 64
495
496struct nfs_iodesc {
497 struct iodesc *iodesc;
498 off_t off;
499 uint32_t fhsize;
500 u_char fh[NFS_V3MAXFHSIZE];
501 /* structure truncated */
502};
503extern struct nfs_iodesc nfs_root_node;
504extern int rpc_port;
505
506static void
507pxe_rpcmountcall()
508{
509 struct iodesc *d;
510 int error;
511
512 if (!(d = socktodesc(pxe_sock)))
513 return;
514 d->myport = htons(--rpc_port);
515 d->destip = rootip;
516 if ((error = nfs_getrootfh(d, rootpath, &nfs_root_node.fhsize,
517 nfs_root_node.fh)) != 0) {
518 printf("NFS MOUNT RPC error: %d\n", error);
519 nfs_root_node.fhsize = 0;
520 }
521 nfs_root_node.iodesc = d;
522}
523
524static void
525pxe_setnfshandle(char *rootpath)
526{
527 int i;
528 u_char *fh;
529 char buf[2 * NFS_V3MAXFHSIZE + 3], *cp;
530
531 /*
532 * If NFS files were never opened, we need to do mount call
533 * ourselves. Use nfs_root_node.iodesc as flag indicating
534 * previous NFS usage.
535 */
536 if (nfs_root_node.iodesc == NULL)
537 pxe_rpcmountcall();
538
539 fh = &nfs_root_node.fh[0];
540 buf[0] = 'X';
541 cp = &buf[1];
542 for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2)
543 sprintf(cp, "%02x", fh[i]);
544 sprintf(cp, "X");
545 setenv("boot.nfsroot.nfshandle", buf, 1);
546 sprintf(buf, "%d", nfs_root_node.fhsize);
547 setenv("boot.nfsroot.nfshandlelen", buf, 1);
548}
549#endif /* OLD_NFSV2 */
550
551void
552pxenv_call(int func)
553{
554#ifdef PXE_DEBUG
555 if (pxe_debug)
556 printf("pxenv_call %x\n", func);
557#endif
558
559 bzero(&v86, sizeof(v86));
560 bzero(data_buffer, sizeof(data_buffer));
561
562 __pxenvseg = pxenv_p->RMEntry.segment;
563 __pxenvoff = pxenv_p->RMEntry.offset;
564
565 v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
566 v86.es = VTOPSEG(scratch_buffer);
567 v86.edi = VTOPOFF(scratch_buffer);
568 v86.addr = (VTOPSEG(__pxenventry) << 16) | VTOPOFF(__pxenventry);
569 v86.ebx = func;
570 v86int();
571 v86.ctl = V86_FLAGS;
572}
573
574void
575bangpxe_call(int func)
576{
577#ifdef PXE_DEBUG
578 if (pxe_debug)
579 printf("bangpxe_call %x\n", func);
580#endif
581
582 bzero(&v86, sizeof(v86));
583 bzero(data_buffer, sizeof(data_buffer));
584
585 __bangpxeseg = pxe_p->EntryPointSP.segment;
586 __bangpxeoff = pxe_p->EntryPointSP.offset;
587
588 v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
589 v86.edx = VTOPSEG(scratch_buffer);
590 v86.eax = VTOPOFF(scratch_buffer);
591 v86.addr = (VTOPSEG(__bangpxeentry) << 16) | VTOPOFF(__bangpxeentry);
592 v86.ebx = func;
593 v86int();
594 v86.ctl = V86_FLAGS;
595}
596
597
598time_t
599getsecs()
600{
601 time_t n = 0;
602 time(&n);
603 return n;
604}
605
606static int
607pxe_netif_match(struct netif *nif, void *machdep_hint)
608{
609 return 1;
610}
611
612
613static int
614pxe_netif_probe(struct netif *nif, void *machdep_hint)
615{
616 t_PXENV_UDP_OPEN *udpopen_p = (t_PXENV_UDP_OPEN *)scratch_buffer;
617
618 if (pxe_call == NULL)
619 return -1;
620
621 bzero(udpopen_p, sizeof(*udpopen_p));
622 udpopen_p->src_ip = bootplayer.yip;
623 pxe_call(PXENV_UDP_OPEN);
624
625 if (udpopen_p->status != 0) {
626 printf("pxe_netif_probe: failed %x\n", udpopen_p->status);
627 return -1;
628 }
629 return 0;
630}
631
632static void
633pxe_netif_end(struct netif *nif)
634{
635 t_PXENV_UDP_CLOSE *udpclose_p = (t_PXENV_UDP_CLOSE *)scratch_buffer;
636 bzero(udpclose_p, sizeof(*udpclose_p));
637
638 pxe_call(PXENV_UDP_CLOSE);
639 if (udpclose_p->status != 0)
640 printf("pxe_end failed %x\n", udpclose_p->status);
641}
642
643static void
644pxe_netif_init(struct iodesc *desc, void *machdep_hint)
645{
646 int i;
647 for (i = 0; i < 6; ++i)
648 desc->myea[i] = bootplayer.CAddr[i];
649 desc->xid = bootplayer.ident;
650}
651
652static int
653pxe_netif_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout)
654{
655 return len;
656}
657
658static int
659pxe_netif_put(struct iodesc *desc, void *pkt, size_t len)
660{
661 return len;
662}
663
664ssize_t
665sendudp(struct iodesc *h, void *pkt, size_t len)
666{
667 t_PXENV_UDP_WRITE *udpwrite_p = (t_PXENV_UDP_WRITE *)scratch_buffer;
668 bzero(udpwrite_p, sizeof(*udpwrite_p));
669
670 udpwrite_p->ip = h->destip.s_addr;
671 udpwrite_p->dst_port = h->destport;
672 udpwrite_p->src_port = h->myport;
673 udpwrite_p->buffer_size = len;
674 udpwrite_p->buffer.segment = VTOPSEG(pkt);
675 udpwrite_p->buffer.offset = VTOPOFF(pkt);
676
677 if (netmask == 0 || SAMENET(myip, h->destip, netmask))
678 udpwrite_p->gw = 0;
679 else
680 udpwrite_p->gw = gateip.s_addr;
681
682 pxe_call(PXENV_UDP_WRITE);
683
684#if 0
685 /* XXX - I dont know why we need this. */
686 delay(1000);
687#endif
688 if (udpwrite_p->status != 0) {
689 /* XXX: This happens a lot. It shouldn't. */
690 if (udpwrite_p->status != 1)
691 printf("sendudp failed %x\n", udpwrite_p->status);
692 return -1;
693 }
694 return len;
695}
696
697ssize_t
698readudp(struct iodesc *h, void *pkt, size_t len, time_t timeout)
699{
700 t_PXENV_UDP_READ *udpread_p = (t_PXENV_UDP_READ *)scratch_buffer;
701 struct udphdr *uh = NULL;
702
703 uh = (struct udphdr *) pkt - 1;
704 bzero(udpread_p, sizeof(*udpread_p));
705
706 udpread_p->dest_ip = h->myip.s_addr;
707 udpread_p->d_port = h->myport;
708 udpread_p->buffer_size = len;
709 udpread_p->buffer.segment = VTOPSEG(data_buffer);
710 udpread_p->buffer.offset = VTOPOFF(data_buffer);
711
712 pxe_call(PXENV_UDP_READ);
713
714#if 0
715 /* XXX - I dont know why we need this. */
716 delay(1000);
717#endif
718 if (udpread_p->status != 0) {
719 /* XXX: This happens a lot. It shouldn't. */
720 if (udpread_p->status != 1)
721 printf("readudp failed %x\n", udpread_p->status);
722 return -1;
723 }
724 bcopy(data_buffer, pkt, udpread_p->buffer_size);
725 uh->uh_sport = udpread_p->s_port;
726 return udpread_p->buffer_size;
727}