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