1119482Sobrien/*- 258713Sjhb * Copyright (c) 2000 Alfred Perlstein <alfred@freebsd.org> 358713Sjhb * Copyright (c) 2000 Paul Saab <ps@freebsd.org> 458713Sjhb * Copyright (c) 2000 John Baldwin <jhb@freebsd.org> 558713Sjhb * All rights reserved. 658713Sjhb * 758713Sjhb * Redistribution and use in source and binary forms, with or without 858713Sjhb * modification, are permitted provided that the following conditions 958713Sjhb * are met: 1058713Sjhb * 1. Redistributions of source code must retain the above copyright 1158713Sjhb * notice, this list of conditions and the following disclaimer. 1258713Sjhb * 2. Redistributions in binary form must reproduce the above copyright 1358713Sjhb * notice, this list of conditions and the following disclaimer in the 1458713Sjhb * documentation and/or other materials provided with the distribution. 1558713Sjhb * 1658713Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1758713Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1858713Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1958713Sjhb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2058713Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2158713Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2258713Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2358713Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2458713Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2558713Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2658713Sjhb * SUCH DAMAGE. 2758713Sjhb */ 2858713Sjhb 29119482Sobrien#include <sys/cdefs.h> 30119482Sobrien__FBSDID("$FreeBSD$"); 31119482Sobrien 3258713Sjhb#include <stand.h> 3359768Sps#include <string.h> 3459768Sps#include <stdarg.h> 3558713Sjhb 3659087Sps#include <netinet/in_systm.h> 3759087Sps#include <netinet/in.h> 3859087Sps#include <netinet/udp.h> 3959087Sps 4059087Sps#include <net.h> 4159087Sps#include <netif.h> 4265498Smsmith#include <nfsv2.h> 4365498Smsmith#include <iodesc.h> 4459087Sps 4564527Sps#include <bootp.h> 4658713Sjhb#include <bootstrap.h> 4758713Sjhb#include "btxv86.h" 4858993Sps#include "pxe.h" 4958713Sjhb 5058713Sjhb/* 5158713Sjhb * Allocate the PXE buffers statically instead of sticking grimy fingers into 5258713Sjhb * BTX's private data area. The scratch buffer is used to send information to 5358713Sjhb * the PXE BIOS, and the data buffer is used to receive data from the PXE BIOS. 5458713Sjhb */ 5558993Sps#define PXE_BUFFER_SIZE 0x2000 5658993Sps#define PXE_TFTP_BUFFER_SIZE 512 5758993Spsstatic char scratch_buffer[PXE_BUFFER_SIZE]; 5858993Spsstatic char data_buffer[PXE_BUFFER_SIZE]; 5958713Sjhb 6059390Spsstatic pxenv_t *pxenv_p = NULL; /* PXENV+ */ 6159390Spsstatic pxe_t *pxe_p = NULL; /* !PXE */ 6259087Spsstatic BOOTPLAYER bootplayer; /* PXE Cached information. */ 6358713Sjhb 6464187Sjhbstatic int pxe_debug = 0; 6559087Spsstatic int pxe_sock = -1; 6659087Spsstatic int pxe_opens = 0; 6759087Sps 6858713Sjhbvoid pxe_enable(void *pxeinfo); 6959644Spsstatic void (*pxe_call)(int func); 7059644Spsstatic void pxenv_call(int func); 7159644Spsstatic void bangpxe_call(int func); 7259087Sps 7358713Sjhbstatic int pxe_init(void); 7459087Spsstatic int pxe_strategy(void *devdata, int flag, daddr_t dblk, 7564187Sjhb size_t size, char *buf, size_t *rsize); 7658713Sjhbstatic int pxe_open(struct open_file *f, ...); 7758713Sjhbstatic int pxe_close(struct open_file *f); 7858713Sjhbstatic void pxe_print(int verbose); 7959390Spsstatic void pxe_cleanup(void); 8065498Smsmithstatic void pxe_setnfshandle(char *rootpath); 8158713Sjhb 8258713Sjhbstatic void pxe_perror(int error); 8359087Spsstatic int pxe_netif_match(struct netif *nif, void *machdep_hint); 8459087Spsstatic int pxe_netif_probe(struct netif *nif, void *machdep_hint); 8559087Spsstatic void pxe_netif_init(struct iodesc *desc, void *machdep_hint); 8659087Spsstatic int pxe_netif_get(struct iodesc *desc, void *pkt, size_t len, 8759087Sps time_t timeout); 8859087Spsstatic int pxe_netif_put(struct iodesc *desc, void *pkt, size_t len); 8959087Spsstatic void pxe_netif_end(struct netif *nif); 9058713Sjhb 9159087Spsextern struct netif_stats pxe_st[]; 9259644Spsextern u_int16_t __bangpxeseg; 9359644Spsextern u_int16_t __bangpxeoff; 9459644Spsextern void __bangpxeentry(void); 9559644Spsextern u_int16_t __pxenvseg; 9659644Spsextern u_int16_t __pxenvoff; 9759644Spsextern void __pxenventry(void); 9858713Sjhb 9959087Spsstruct netif_dif pxe_ifs[] = { 10059087Sps/* dif_unit dif_nsel dif_stats dif_private */ 10159087Sps {0, 1, &pxe_st[0], 0} 10259087Sps}; 10358713Sjhb 10459087Spsstruct netif_stats pxe_st[NENTS(pxe_ifs)]; 10559087Sps 10659087Spsstruct netif_driver pxenetif = { 10759087Sps "pxenet", 10859087Sps pxe_netif_match, 10959087Sps pxe_netif_probe, 11059087Sps pxe_netif_init, 11159087Sps pxe_netif_get, 11259087Sps pxe_netif_put, 11359087Sps pxe_netif_end, 11459087Sps pxe_ifs, 11559087Sps NENTS(pxe_ifs) 11659087Sps}; 11759087Sps 11859087Spsstruct netif_driver *netif_drivers[] = { 11959087Sps &pxenetif, 12059087Sps NULL 12159087Sps}; 12259087Sps 12358713Sjhbstruct devsw pxedisk = { 12458713Sjhb "pxe", 12558713Sjhb DEVT_NET, 12658713Sjhb pxe_init, 12758713Sjhb pxe_strategy, 12858713Sjhb pxe_open, 12958713Sjhb pxe_close, 13058713Sjhb noioctl, 13159408Sps pxe_print, 13259408Sps pxe_cleanup 13358713Sjhb}; 13458713Sjhb 13558713Sjhb/* 13658713Sjhb * This function is called by the loader to enable PXE support if we 13758713Sjhb * are booted by PXE. The passed in pointer is a pointer to the 13858713Sjhb * PXENV+ structure. 13958713Sjhb */ 14058713Sjhbvoid 14158713Sjhbpxe_enable(void *pxeinfo) 14258713Sjhb{ 14359644Sps pxenv_p = (pxenv_t *)pxeinfo; 14459644Sps pxe_p = (pxe_t *)PTOV(pxenv_p->PXEPtr.segment * 16 + 14559644Sps pxenv_p->PXEPtr.offset); 14659644Sps pxe_call = NULL; 14758713Sjhb} 14858713Sjhb 14958713Sjhb/* 15058713Sjhb * return true if pxe structures are found/initialized, 15158713Sjhb * also figures out our IP information via the pxe cached info struct 15258713Sjhb */ 15358713Sjhbstatic int 15458713Sjhbpxe_init(void) 15558713Sjhb{ 15658713Sjhb t_PXENV_GET_CACHED_INFO *gci_p; 15758713Sjhb int counter; 15858713Sjhb uint8_t checksum; 15958713Sjhb uint8_t *checkptr; 16058713Sjhb 16158713Sjhb if(pxenv_p == NULL) 16258713Sjhb return (0); 16358713Sjhb 16458713Sjhb /* look for "PXENV+" */ 16559456Sps if (bcmp((void *)pxenv_p->Signature, S_SIZE("PXENV+"))) { 16659456Sps pxenv_p = NULL; 16758713Sjhb return (0); 16859456Sps } 16958713Sjhb 17058713Sjhb /* make sure the size is something we can handle */ 17158713Sjhb if (pxenv_p->Length > sizeof(*pxenv_p)) { 17258713Sjhb printf("PXENV+ structure too large, ignoring\n"); 17358713Sjhb pxenv_p = NULL; 17458713Sjhb return (0); 17558713Sjhb } 17658713Sjhb 17758713Sjhb /* 17858713Sjhb * do byte checksum: 17958713Sjhb * add up each byte in the structure, the total should be 0 18058713Sjhb */ 18158713Sjhb checksum = 0; 18258713Sjhb checkptr = (uint8_t *) pxenv_p; 18358713Sjhb for (counter = 0; counter < pxenv_p->Length; counter++) 18458713Sjhb checksum += *checkptr++; 18558713Sjhb if (checksum != 0) { 18658713Sjhb printf("PXENV+ structure failed checksum, ignoring\n"); 18758713Sjhb pxenv_p = NULL; 18858713Sjhb return (0); 18958713Sjhb } 19059390Sps 19159644Sps 19259644Sps /* 19359644Sps * PXENV+ passed, so use that if !PXE is not available or 19459644Sps * the checksum fails. 19559644Sps */ 19659644Sps pxe_call = pxenv_call; 19759644Sps if (pxenv_p->Version >= 0x0200) { 19859644Sps for (;;) { 19959644Sps if (bcmp((void *)pxe_p->Signature, S_SIZE("!PXE"))) { 20059644Sps pxe_p = NULL; 20159644Sps break; 20259644Sps } 20359644Sps checksum = 0; 20459644Sps checkptr = (uint8_t *)pxe_p; 20559644Sps for (counter = 0; counter < pxe_p->StructLength; 20659644Sps counter++) 20759644Sps checksum += *checkptr++; 20859644Sps if (checksum != 0) { 20959644Sps pxe_p = NULL; 21059644Sps break; 21159644Sps } 21259644Sps pxe_call = bangpxe_call; 21359644Sps break; 21459644Sps } 21559390Sps } 21659644Sps 21759644Sps printf("\nPXE version %d.%d, real mode entry point ", 21859644Sps (uint8_t) (pxenv_p->Version >> 8), 21959644Sps (uint8_t) (pxenv_p->Version & 0xFF)); 22059644Sps if (pxe_call == bangpxe_call) 22159644Sps printf("@%04x:%04x\n", 22259644Sps pxe_p->EntryPointSP.segment, 22359644Sps pxe_p->EntryPointSP.offset); 22459644Sps else 22559644Sps printf("@%04x:%04x\n", 22659644Sps pxenv_p->RMEntry.segment, pxenv_p->RMEntry.offset); 22759390Sps 22858713Sjhb gci_p = (t_PXENV_GET_CACHED_INFO *) scratch_buffer; 22958713Sjhb bzero(gci_p, sizeof(*gci_p)); 23058713Sjhb gci_p->PacketType = PXENV_PACKET_TYPE_BINL_REPLY; 23158713Sjhb pxe_call(PXENV_GET_CACHED_INFO); 23258713Sjhb if (gci_p->Status != 0) { 23358713Sjhb pxe_perror(gci_p->Status); 23459455Sps pxe_p = NULL; 23558713Sjhb return (0); 23658713Sjhb } 23759087Sps bcopy(PTOV((gci_p->Buffer.segment << 4) + gci_p->Buffer.offset), 23859087Sps &bootplayer, gci_p->BufferSize); 23958713Sjhb return (1); 24058713Sjhb} 24158713Sjhb 24259087Sps 24359087Spsstatic int 24459087Spspxe_strategy(void *devdata, int flag, daddr_t dblk, size_t size, 24564187Sjhb char *buf, size_t *rsize) 24658713Sjhb{ 24759087Sps return (EIO); 24858713Sjhb} 24958713Sjhb 25059087Spsstatic int 25159087Spspxe_open(struct open_file *f, ...) 25258713Sjhb{ 25359087Sps va_list args; 25459087Sps char *devname; /* Device part of file name (or NULL). */ 25559686Sps char temp[FNAME_SIZE]; 25659087Sps int error = 0; 25759686Sps int i; 25859686Sps 25959087Sps va_start(args, f); 26059087Sps devname = va_arg(args, char*); 26159087Sps va_end(args); 26259087Sps 26359087Sps /* On first open, do netif open, mount, etc. */ 26459087Sps if (pxe_opens == 0) { 26559087Sps /* Find network interface. */ 26659087Sps if (pxe_sock < 0) { 26759087Sps pxe_sock = netif_open(devname); 26859087Sps if (pxe_sock < 0) { 26959087Sps printf("pxe_open: netif_open() failed\n"); 27059087Sps return (ENXIO); 27159087Sps } 27264187Sjhb if (pxe_debug) 27359087Sps printf("pxe_open: netif_open() succeeded\n"); 27459087Sps } 27559686Sps if (rootip.s_addr == 0) { 27659686Sps /* 27759686Sps * Do a bootp/dhcp request to find out where our 27859686Sps * NFS/TFTP server is. Even if we dont get back 27959686Sps * the proper information, fall back to the server 28059686Sps * which brought us to life and a default rootpath. 28159686Sps */ 28264527Sps bootp(pxe_sock, BOOTP_PXE); 28359768Sps if (rootip.s_addr == 0) 28459686Sps rootip.s_addr = bootplayer.sip; 285197082Semaste if (!rootpath[0]) 28659686Sps strcpy(rootpath, PXENFSROOTPATH); 28759686Sps 288116451Siedowse for (i = 0; rootpath[i] != '\0' && i < FNAME_SIZE; i++) 28968362Sps if (rootpath[i] == ':') 29059686Sps break; 291116451Siedowse if (i && i != FNAME_SIZE && rootpath[i] == ':') { 29268362Sps rootpath[i++] = '\0'; 29368362Sps if (inet_addr(&rootpath[0]) != INADDR_NONE) 29468362Sps rootip.s_addr = inet_addr(&rootpath[0]); 29559686Sps bcopy(&rootpath[i], &temp[0], strlen(&rootpath[i])+1); 29659686Sps bcopy(&temp[0], &rootpath[0], strlen(&rootpath[i])+1); 29759686Sps } 29859686Sps printf("pxe_open: server addr: %s\n", inet_ntoa(rootip)); 29959686Sps printf("pxe_open: server path: %s\n", rootpath); 30059686Sps printf("pxe_open: gateway ip: %s\n", inet_ntoa(gateip)); 30164522Sps 30265498Smsmith setenv("boot.netif.ip", inet_ntoa(myip), 1); 30365498Smsmith setenv("boot.netif.netmask", intoa(netmask), 1); 30465498Smsmith setenv("boot.netif.gateway", inet_ntoa(gateip), 1); 30565498Smsmith if (bootplayer.Hardware == ETHER_TYPE) { 30665498Smsmith sprintf(temp, "%6D", bootplayer.CAddr, ":"); 30765498Smsmith setenv("boot.netif.hwaddr", temp, 1); 30865498Smsmith } 30965498Smsmith setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); 31065498Smsmith setenv("boot.nfsroot.path", rootpath, 1); 311145209Swollman setenv("dhcp.host-name", hostname, 1); 31259686Sps } 31359087Sps } 31459087Sps pxe_opens++; 31559087Sps f->f_devdata = &pxe_sock; 31659087Sps return (error); 31758713Sjhb} 31858713Sjhb 31959087Spsstatic int 32059087Spspxe_close(struct open_file *f) 32158713Sjhb{ 32258713Sjhb 32359087Sps#ifdef PXE_DEBUG 32464187Sjhb if (pxe_debug) 32559087Sps printf("pxe_close: opens=%d\n", pxe_opens); 32659087Sps#endif 32758713Sjhb 32859087Sps /* On last close, do netif close, etc. */ 32959087Sps f->f_devdata = NULL; 33059087Sps /* Extra close call? */ 33159087Sps if (pxe_opens <= 0) 33259087Sps return (0); 33359087Sps pxe_opens--; 33459087Sps /* Not last close? */ 33559087Sps if (pxe_opens > 0) 33659087Sps return(0); 33759686Sps 338172591Sps#ifdef LOADER_NFS_SUPPORT 33965498Smsmith /* get an NFS filehandle for our root filesystem */ 34065498Smsmith pxe_setnfshandle(rootpath); 341172591Sps#endif 34265498Smsmith 34359087Sps if (pxe_sock >= 0) { 34465498Smsmith 34559087Sps#ifdef PXE_DEBUG 34664187Sjhb if (pxe_debug) 34759087Sps printf("pxe_close: calling netif_close()\n"); 34859087Sps#endif 34959087Sps netif_close(pxe_sock); 35059087Sps pxe_sock = -1; 35159087Sps } 35259087Sps return (0); 35359087Sps} 35458713Sjhb 35559087Spsstatic void 35659087Spspxe_print(int verbose) 35759087Sps{ 35859644Sps if (pxe_call != NULL) { 35959087Sps if (*bootplayer.Sname == '\0') { 36059087Sps printf(" "IP_STR":%s\n", 36159087Sps IP_ARGS(htonl(bootplayer.sip)), 36259087Sps bootplayer.bootfile); 36359087Sps } else { 36459087Sps printf(" %s:%s\n", bootplayer.Sname, 36559087Sps bootplayer.bootfile); 36659087Sps } 36759087Sps } 36858713Sjhb 36959087Sps return; 37058713Sjhb} 37158713Sjhb 37259390Spsstatic void 37359390Spspxe_cleanup(void) 37459390Sps{ 37564187Sjhb#ifdef PXE_DEBUG 37659390Sps t_PXENV_UNLOAD_STACK *unload_stack_p = 37759390Sps (t_PXENV_UNLOAD_STACK *)scratch_buffer; 37859390Sps t_PXENV_UNDI_SHUTDOWN *undi_shutdown_p = 37959390Sps (t_PXENV_UNDI_SHUTDOWN *)scratch_buffer; 38064187Sjhb#endif 38159087Sps 38259644Sps if (pxe_call == NULL) 38359455Sps return; 38459455Sps 38559408Sps pxe_call(PXENV_UNDI_SHUTDOWN); 38659855Sps 38759855Sps#ifdef PXE_DEBUG 38864187Sjhb if (pxe_debug && undi_shutdown_p->Status != 0) 38959644Sps printf("pxe_cleanup: UNDI_SHUTDOWN failed %x\n", 39059855Sps undi_shutdown_p->Status); 39159855Sps#endif 39259408Sps 39359390Sps pxe_call(PXENV_UNLOAD_STACK); 39459855Sps 39559855Sps#ifdef PXE_DEBUG 39664187Sjhb if (pxe_debug && unload_stack_p->Status != 0) 39759644Sps printf("pxe_cleanup: UNLOAD_STACK failed %x\n", 39859408Sps unload_stack_p->Status); 39959855Sps#endif 40059390Sps} 40159390Sps 40258713Sjhbvoid 40358713Sjhbpxe_perror(int err) 40458713Sjhb{ 40558713Sjhb return; 40658713Sjhb} 40758713Sjhb 408231035Ssbruno#ifdef LOADER_NFS_SUPPORT 40965498Smsmith/* 41065498Smsmith * Reach inside the libstand NFS code and dig out an NFS handle 41165498Smsmith * for the root filesystem. 41265498Smsmith */ 413212126Srmacklem#ifdef OLD_NFSV2 41465498Smsmithstruct nfs_iodesc { 41565498Smsmith struct iodesc *iodesc; 41665498Smsmith off_t off; 41765498Smsmith u_char fh[NFS_FHSIZE]; 41865498Smsmith /* structure truncated here */ 41965498Smsmith}; 42065498Smsmithextern struct nfs_iodesc nfs_root_node; 421143476Skanextern int rpc_port; 42265498Smsmith 42365498Smsmithstatic void 424143476Skanpxe_rpcmountcall() 425143476Skan{ 426143476Skan struct iodesc *d; 427143476Skan int error; 428143476Skan 429143476Skan if (!(d = socktodesc(pxe_sock))) 430143476Skan return; 431143476Skan d->myport = htons(--rpc_port); 432143476Skan d->destip = rootip; 433143476Skan if ((error = nfs_getrootfh(d, rootpath, nfs_root_node.fh)) != 0) 434143476Skan printf("NFS MOUNT RPC error: %d\n", error); 435143476Skan nfs_root_node.iodesc = d; 436143476Skan} 437143476Skan 438143476Skanstatic void 43965498Smsmithpxe_setnfshandle(char *rootpath) 44065498Smsmith{ 44165498Smsmith int i; 44265498Smsmith u_char *fh; 44365498Smsmith char buf[2 * NFS_FHSIZE + 3], *cp; 44465498Smsmith 445143476Skan /* 446143476Skan * If NFS files were never opened, we need to do mount call 447143476Skan * ourselves. Use nfs_root_node.iodesc as flag indicating 448143476Skan * previous NFS usage. 449143476Skan */ 450143476Skan if (nfs_root_node.iodesc == NULL) 451143476Skan pxe_rpcmountcall(); 452143476Skan 45365498Smsmith fh = &nfs_root_node.fh[0]; 45465498Smsmith buf[0] = 'X'; 45565498Smsmith cp = &buf[1]; 45665498Smsmith for (i = 0; i < NFS_FHSIZE; i++, cp += 2) 45765498Smsmith sprintf(cp, "%02x", fh[i]); 45865498Smsmith sprintf(cp, "X"); 45965498Smsmith setenv("boot.nfsroot.nfshandle", buf, 1); 46065498Smsmith} 461212126Srmacklem#else /* !OLD_NFSV2 */ 46265498Smsmith 463212126Srmacklem#define NFS_V3MAXFHSIZE 64 464212126Srmacklem 465212126Srmacklemstruct nfs_iodesc { 466212126Srmacklem struct iodesc *iodesc; 467212126Srmacklem off_t off; 468212126Srmacklem uint32_t fhsize; 469212126Srmacklem u_char fh[NFS_V3MAXFHSIZE]; 470212126Srmacklem /* structure truncated */ 471212126Srmacklem}; 472212126Srmacklemextern struct nfs_iodesc nfs_root_node; 473212126Srmacklemextern int rpc_port; 474212126Srmacklem 475212126Srmacklemstatic void 476212126Srmacklempxe_rpcmountcall() 477212126Srmacklem{ 478212126Srmacklem struct iodesc *d; 479212126Srmacklem int error; 480212126Srmacklem 481212126Srmacklem if (!(d = socktodesc(pxe_sock))) 482212126Srmacklem return; 483212126Srmacklem d->myport = htons(--rpc_port); 484212126Srmacklem d->destip = rootip; 485212126Srmacklem if ((error = nfs_getrootfh(d, rootpath, &nfs_root_node.fhsize, 486212126Srmacklem nfs_root_node.fh)) != 0) { 487212126Srmacklem printf("NFS MOUNT RPC error: %d\n", error); 488212126Srmacklem nfs_root_node.fhsize = 0; 489212126Srmacklem } 490212126Srmacklem nfs_root_node.iodesc = d; 491212126Srmacklem} 492212126Srmacklem 493212126Srmacklemstatic void 494212126Srmacklempxe_setnfshandle(char *rootpath) 495212126Srmacklem{ 496212126Srmacklem int i; 497212126Srmacklem u_char *fh; 498212126Srmacklem char buf[2 * NFS_V3MAXFHSIZE + 3], *cp; 499212126Srmacklem 500212126Srmacklem /* 501212126Srmacklem * If NFS files were never opened, we need to do mount call 502212126Srmacklem * ourselves. Use nfs_root_node.iodesc as flag indicating 503212126Srmacklem * previous NFS usage. 504212126Srmacklem */ 505212126Srmacklem if (nfs_root_node.iodesc == NULL) 506212126Srmacklem pxe_rpcmountcall(); 507212126Srmacklem 508212126Srmacklem fh = &nfs_root_node.fh[0]; 509212126Srmacklem buf[0] = 'X'; 510212126Srmacklem cp = &buf[1]; 511212126Srmacklem for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2) 512212126Srmacklem sprintf(cp, "%02x", fh[i]); 513212126Srmacklem sprintf(cp, "X"); 514212126Srmacklem setenv("boot.nfsroot.nfshandle", buf, 1); 515212126Srmacklem sprintf(buf, "%d", nfs_root_node.fhsize); 516212126Srmacklem setenv("boot.nfsroot.nfshandlelen", buf, 1); 517212126Srmacklem} 518212126Srmacklem#endif /* OLD_NFSV2 */ 519231035Ssbruno#endif /* LOADER_NFS_SUPPORT */ 520212126Srmacklem 52158713Sjhbvoid 52259644Spspxenv_call(int func) 52358713Sjhb{ 52459644Sps#ifdef PXE_DEBUG 52564187Sjhb if (pxe_debug) 52659644Sps printf("pxenv_call %x\n", func); 52759644Sps#endif 52859644Sps 52958713Sjhb bzero(&v86, sizeof(v86)); 53058713Sjhb bzero(data_buffer, sizeof(data_buffer)); 53159390Sps 53259644Sps __pxenvseg = pxenv_p->RMEntry.segment; 53359644Sps __pxenvoff = pxenv_p->RMEntry.offset; 53459390Sps 53559390Sps v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; 53659644Sps v86.es = VTOPSEG(scratch_buffer); 53759644Sps v86.edi = VTOPOFF(scratch_buffer); 53859644Sps v86.addr = (VTOPSEG(__pxenventry) << 16) | VTOPOFF(__pxenventry); 53959644Sps v86.ebx = func; 54059644Sps v86int(); 54159644Sps v86.ctl = V86_FLAGS; 54259644Sps} 54359644Sps 54459644Spsvoid 54559644Spsbangpxe_call(int func) 54659644Sps{ 54759644Sps#ifdef PXE_DEBUG 54864187Sjhb if (pxe_debug) 54959644Sps printf("bangpxe_call %x\n", func); 55059644Sps#endif 55159644Sps 55259644Sps bzero(&v86, sizeof(v86)); 55359644Sps bzero(data_buffer, sizeof(data_buffer)); 55459644Sps 55559644Sps __bangpxeseg = pxe_p->EntryPointSP.segment; 55659644Sps __bangpxeoff = pxe_p->EntryPointSP.offset; 55759644Sps 55859644Sps v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; 55959390Sps v86.edx = VTOPSEG(scratch_buffer); 56059390Sps v86.eax = VTOPOFF(scratch_buffer); 56159644Sps v86.addr = (VTOPSEG(__bangpxeentry) << 16) | VTOPOFF(__bangpxeentry); 56259390Sps v86.ebx = func; 56358713Sjhb v86int(); 56459390Sps v86.ctl = V86_FLAGS; 56558713Sjhb} 56658713Sjhb 56759087Sps 56859087Spstime_t 56959087Spsgetsecs() 57058713Sjhb{ 57159087Sps time_t n = 0; 57259087Sps time(&n); 57359087Sps return n; 57458713Sjhb} 57558713Sjhb 57658713Sjhbstatic int 57759087Spspxe_netif_match(struct netif *nif, void *machdep_hint) 57858713Sjhb{ 57959087Sps return 1; 58058713Sjhb} 58158713Sjhb 58259087Sps 58358713Sjhbstatic int 58459087Spspxe_netif_probe(struct netif *nif, void *machdep_hint) 58558713Sjhb{ 58659087Sps t_PXENV_UDP_OPEN *udpopen_p = (t_PXENV_UDP_OPEN *)scratch_buffer; 58759456Sps 58859644Sps if (pxe_call == NULL) 58959456Sps return -1; 59059456Sps 59159087Sps bzero(udpopen_p, sizeof(*udpopen_p)); 59259087Sps udpopen_p->src_ip = bootplayer.yip; 59359087Sps pxe_call(PXENV_UDP_OPEN); 59458713Sjhb 59559390Sps if (udpopen_p->status != 0) { 59659087Sps printf("pxe_netif_probe: failed %x\n", udpopen_p->status); 59759390Sps return -1; 59859390Sps } 59959087Sps return 0; 60058713Sjhb} 60158713Sjhb 60259087Spsstatic void 60359087Spspxe_netif_end(struct netif *nif) 60458713Sjhb{ 60559087Sps t_PXENV_UDP_CLOSE *udpclose_p = (t_PXENV_UDP_CLOSE *)scratch_buffer; 60659087Sps bzero(udpclose_p, sizeof(*udpclose_p)); 60758713Sjhb 60859087Sps pxe_call(PXENV_UDP_CLOSE); 60959087Sps if (udpclose_p->status != 0) 61059087Sps printf("pxe_end failed %x\n", udpclose_p->status); 61158713Sjhb} 61258713Sjhb 61359087Spsstatic void 61459087Spspxe_netif_init(struct iodesc *desc, void *machdep_hint) 61558713Sjhb{ 61659686Sps int i; 61759686Sps for (i = 0; i < 6; ++i) 61859686Sps desc->myea[i] = bootplayer.CAddr[i]; 61959686Sps desc->xid = bootplayer.ident; 62058713Sjhb} 62158713Sjhb 62258713Sjhbstatic int 62359087Spspxe_netif_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout) 62458713Sjhb{ 62559087Sps return len; 62658713Sjhb} 62758713Sjhb 62858713Sjhbstatic int 62959087Spspxe_netif_put(struct iodesc *desc, void *pkt, size_t len) 63058713Sjhb{ 63159087Sps return len; 63258713Sjhb} 63358713Sjhb 63459087Spsssize_t 63559087Spssendudp(struct iodesc *h, void *pkt, size_t len) 63658713Sjhb{ 63759087Sps t_PXENV_UDP_WRITE *udpwrite_p = (t_PXENV_UDP_WRITE *)scratch_buffer; 63859087Sps bzero(udpwrite_p, sizeof(*udpwrite_p)); 63959087Sps 64059686Sps udpwrite_p->ip = h->destip.s_addr; 64159087Sps udpwrite_p->dst_port = h->destport; 64259087Sps udpwrite_p->src_port = h->myport; 64359087Sps udpwrite_p->buffer_size = len; 64459087Sps udpwrite_p->buffer.segment = VTOPSEG(pkt); 64559087Sps udpwrite_p->buffer.offset = VTOPOFF(pkt); 64658713Sjhb 64774265Sps if (netmask == 0 || SAMENET(myip, h->destip, netmask)) 64874265Sps udpwrite_p->gw = 0; 64974265Sps else 65074265Sps udpwrite_p->gw = gateip.s_addr; 65174265Sps 65259087Sps pxe_call(PXENV_UDP_WRITE); 65358713Sjhb 65459390Sps#if 0 65559087Sps /* XXX - I dont know why we need this. */ 65659087Sps delay(1000); 65759390Sps#endif 65859390Sps if (udpwrite_p->status != 0) { 65959673Sps /* XXX: This happens a lot. It shouldn't. */ 66059673Sps if (udpwrite_p->status != 1) 66159673Sps printf("sendudp failed %x\n", udpwrite_p->status); 66259390Sps return -1; 66359390Sps } 66459087Sps return len; 66558713Sjhb} 66658713Sjhb 66759087Spsssize_t 66859087Spsreadudp(struct iodesc *h, void *pkt, size_t len, time_t timeout) 66958713Sjhb{ 67059087Sps t_PXENV_UDP_READ *udpread_p = (t_PXENV_UDP_READ *)scratch_buffer; 67159087Sps struct udphdr *uh = NULL; 67259087Sps 67359087Sps uh = (struct udphdr *) pkt - 1; 67459087Sps bzero(udpread_p, sizeof(*udpread_p)); 67559087Sps 67659686Sps udpread_p->dest_ip = h->myip.s_addr; 67759087Sps udpread_p->d_port = h->myport; 67859087Sps udpread_p->buffer_size = len; 67959087Sps udpread_p->buffer.segment = VTOPSEG(data_buffer); 68059087Sps udpread_p->buffer.offset = VTOPOFF(data_buffer); 68158713Sjhb 68259087Sps pxe_call(PXENV_UDP_READ); 68358713Sjhb 68459390Sps#if 0 68559087Sps /* XXX - I dont know why we need this. */ 68659087Sps delay(1000); 68759390Sps#endif 68859390Sps if (udpread_p->status != 0) { 68959390Sps /* XXX: This happens a lot. It shouldn't. */ 69059390Sps if (udpread_p->status != 1) 69159390Sps printf("readudp failed %x\n", udpread_p->status); 69259390Sps return -1; 69359390Sps } 69459087Sps bcopy(data_buffer, pkt, udpread_p->buffer_size); 69559087Sps uh->uh_sport = udpread_p->s_port; 69659087Sps return udpread_p->buffer_size; 69758713Sjhb} 698