1*98d16a59Schristos /* $NetBSD: pxe.c,v 1.18 2013/10/20 19:47:28 christos Exp $ */
28bb2be29Sthorpej
38bb2be29Sthorpej /*
48bb2be29Sthorpej * Copyright 2001 Wasabi Systems, Inc.
58bb2be29Sthorpej * All rights reserved.
68bb2be29Sthorpej *
78bb2be29Sthorpej * Written by Jason R. Thorpe for Wasabi Systems, Inc.
88bb2be29Sthorpej *
98bb2be29Sthorpej * Redistribution and use in source and binary forms, with or without
108bb2be29Sthorpej * modification, are permitted provided that the following conditions
118bb2be29Sthorpej * are met:
128bb2be29Sthorpej * 1. Redistributions of source code must retain the above copyright
138bb2be29Sthorpej * notice, this list of conditions and the following disclaimer.
148bb2be29Sthorpej * 2. Redistributions in binary form must reproduce the above copyright
158bb2be29Sthorpej * notice, this list of conditions and the following disclaimer in the
168bb2be29Sthorpej * documentation and/or other materials provided with the distribution.
178bb2be29Sthorpej * 3. All advertising materials mentioning features or use of this software
188bb2be29Sthorpej * must display the following acknowledgement:
198bb2be29Sthorpej * This product includes software developed for the NetBSD Project by
208bb2be29Sthorpej * Wasabi Systems, Inc.
218bb2be29Sthorpej * 4. The name of Wasabi Systems, Inc. may not be used to endorse
228bb2be29Sthorpej * or promote products derived from this software without specific prior
238bb2be29Sthorpej * written permission.
248bb2be29Sthorpej *
258bb2be29Sthorpej * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
268bb2be29Sthorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
278bb2be29Sthorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
288bb2be29Sthorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
298bb2be29Sthorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
308bb2be29Sthorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
318bb2be29Sthorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
328bb2be29Sthorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
338bb2be29Sthorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
348bb2be29Sthorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
358bb2be29Sthorpej * POSSIBILITY OF SUCH DAMAGE.
368bb2be29Sthorpej */
378bb2be29Sthorpej
388bb2be29Sthorpej /*
398bb2be29Sthorpej * Copyright (c) 2000 Alfred Perlstein <alfred@freebsd.org>
408bb2be29Sthorpej * All rights reserved.
418bb2be29Sthorpej * Copyright (c) 2000 Paul Saab <ps@freebsd.org>
428bb2be29Sthorpej * All rights reserved.
438bb2be29Sthorpej * Copyright (c) 2000 John Baldwin <jhb@freebsd.org>
448bb2be29Sthorpej * All rights reserved.
458bb2be29Sthorpej *
468bb2be29Sthorpej * Redistribution and use in source and binary forms, with or without
478bb2be29Sthorpej * modification, are permitted provided that the following conditions
488bb2be29Sthorpej * are met:
498bb2be29Sthorpej * 1. Redistributions of source code must retain the above copyright
508bb2be29Sthorpej * notice, this list of conditions and the following disclaimer.
518bb2be29Sthorpej * 2. Redistributions in binary form must reproduce the above copyright
528bb2be29Sthorpej * notice, this list of conditions and the following disclaimer in the
538bb2be29Sthorpej * documentation and/or other materials provided with the distribution.
548bb2be29Sthorpej *
558bb2be29Sthorpej * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
568bb2be29Sthorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
578bb2be29Sthorpej * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
588bb2be29Sthorpej * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
598bb2be29Sthorpej * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
608bb2be29Sthorpej * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
618bb2be29Sthorpej * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
628bb2be29Sthorpej * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
638bb2be29Sthorpej * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
648bb2be29Sthorpej * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
658bb2be29Sthorpej * SUCH DAMAGE.
668bb2be29Sthorpej */
678bb2be29Sthorpej
688bb2be29Sthorpej /*
698bb2be29Sthorpej * Support for the Intel Preboot Execution Environment (PXE).
708bb2be29Sthorpej *
718bb2be29Sthorpej * PXE provides a UDP implementation as well as a UNDI network device
728bb2be29Sthorpej * driver. UNDI is much more complicated to use than PXE UDP, so we
738bb2be29Sthorpej * use PXE UDP as a cheap and easy way to get PXE support.
748bb2be29Sthorpej */
758bb2be29Sthorpej
768bb2be29Sthorpej #include <sys/param.h>
778bb2be29Sthorpej #include <sys/socket.h>
788bb2be29Sthorpej
798bb2be29Sthorpej #ifdef _STANDALONE
808bb2be29Sthorpej #include <lib/libkern/libkern.h>
818bb2be29Sthorpej #else
828bb2be29Sthorpej #include <string.h>
838bb2be29Sthorpej #endif
848bb2be29Sthorpej
858bb2be29Sthorpej #include <netinet/in.h>
868bb2be29Sthorpej #include <netinet/in_systm.h>
878bb2be29Sthorpej #include <netinet/ip.h>
888bb2be29Sthorpej #include <netinet/ip_var.h>
898bb2be29Sthorpej #include <netinet/udp.h>
908bb2be29Sthorpej #include <netinet/udp_var.h>
918bb2be29Sthorpej
928bb2be29Sthorpej #include <net/if_ether.h>
938bb2be29Sthorpej
948bb2be29Sthorpej #include <lib/libsa/stand.h>
958bb2be29Sthorpej #include <lib/libsa/net.h>
968bb2be29Sthorpej #include <lib/libsa/bootp.h>
978bb2be29Sthorpej
988bb2be29Sthorpej #include <libi386.h>
998bb2be29Sthorpej #include <bootinfo.h>
1008bb2be29Sthorpej
1018bb2be29Sthorpej #include "pxeboot.h"
1028bb2be29Sthorpej #include "pxe.h"
103542ccfb0Sdrochner #include "pxe_netif.h"
1048bb2be29Sthorpej
10568da4482Sperry void (*pxe_call)(uint16_t);
1068bb2be29Sthorpej
10768da4482Sperry void pxecall_bangpxe(uint16_t); /* pxe_call.S */
10868da4482Sperry void pxecall_pxenv(uint16_t); /* pxe_call.S */
1098bb2be29Sthorpej
110*98d16a59Schristos extern char pxe_command_buf[256];
1118bb2be29Sthorpej
1128bb2be29Sthorpej BOOTPLAYER bootplayer;
1138bb2be29Sthorpej
114542ccfb0Sdrochner static struct btinfo_netif bi_netif;
115542ccfb0Sdrochner
1168bb2be29Sthorpej /*****************************************************************************
1178bb2be29Sthorpej * This section is a replacement for libsa/udp.c
1188bb2be29Sthorpej *****************************************************************************/
1198bb2be29Sthorpej
1208bb2be29Sthorpej /* Caller must leave room for ethernet, ip, and udp headers in front!! */
1218bb2be29Sthorpej ssize_t
sendudp(struct iodesc * d,void * pkt,size_t len)1228bb2be29Sthorpej sendudp(struct iodesc *d, void *pkt, size_t len)
1238bb2be29Sthorpej {
1248bb2be29Sthorpej t_PXENV_UDP_WRITE *uw = (void *) pxe_command_buf;
1258bb2be29Sthorpej
1268bb2be29Sthorpej uw->status = 0;
1278bb2be29Sthorpej
1288bb2be29Sthorpej uw->ip = d->destip.s_addr;
1298bb2be29Sthorpej uw->gw = gateip.s_addr;
1308bb2be29Sthorpej uw->src_port = d->myport;
1318bb2be29Sthorpej uw->dst_port = d->destport;
1328bb2be29Sthorpej uw->buffer_size = len;
1338bb2be29Sthorpej uw->buffer.segment = VTOPSEG(pkt);
1348bb2be29Sthorpej uw->buffer.offset = VTOPOFF(pkt);
1358bb2be29Sthorpej
1368bb2be29Sthorpej pxe_call(PXENV_UDP_WRITE);
1378bb2be29Sthorpej
1388bb2be29Sthorpej if (uw->status != PXENV_STATUS_SUCCESS) {
1398bb2be29Sthorpej /* XXX This happens a lot; it shouldn't. */
1408bb2be29Sthorpej if (uw->status != PXENV_STATUS_FAILURE)
1418bb2be29Sthorpej printf("sendudp: PXENV_UDP_WRITE failed: 0x%x\n",
1428bb2be29Sthorpej uw->status);
1438bb2be29Sthorpej return (-1);
1448bb2be29Sthorpej }
1458bb2be29Sthorpej
1468bb2be29Sthorpej return (len);
1478bb2be29Sthorpej }
1488bb2be29Sthorpej
1498bb2be29Sthorpej /*
1508bb2be29Sthorpej * Receive a UDP packet and validate it for us.
1518bb2be29Sthorpej * Caller leaves room for the headers (Ether, IP, UDP).
1528bb2be29Sthorpej */
1538bb2be29Sthorpej ssize_t
readudp(struct iodesc * d,void * pkt,size_t len,saseconds_t tleft)15469cf32a7Stsutsui readudp(struct iodesc *d, void *pkt, size_t len, saseconds_t tleft)
1558bb2be29Sthorpej {
1568bb2be29Sthorpej t_PXENV_UDP_READ *ur = (void *) pxe_command_buf;
1578bb2be29Sthorpej struct udphdr *uh;
1588bb2be29Sthorpej struct ip *ip;
1598bb2be29Sthorpej
1608bb2be29Sthorpej uh = (struct udphdr *)pkt - 1;
1618bb2be29Sthorpej ip = (struct ip *)uh - 1;
1628bb2be29Sthorpej
163461a86f9Schristos (void)memset(ur, 0, sizeof(*ur));
1648bb2be29Sthorpej
1658bb2be29Sthorpej ur->dest_ip = d->myip.s_addr;
1668bb2be29Sthorpej ur->d_port = d->myport;
1678bb2be29Sthorpej ur->buffer_size = len;
1688bb2be29Sthorpej ur->buffer.segment = VTOPSEG(pkt);
1698bb2be29Sthorpej ur->buffer.offset = VTOPOFF(pkt);
1708bb2be29Sthorpej
1718bb2be29Sthorpej /* XXX Timeout unused. */
1728bb2be29Sthorpej
1738bb2be29Sthorpej pxe_call(PXENV_UDP_READ);
1748bb2be29Sthorpej
1758bb2be29Sthorpej if (ur->status != PXENV_STATUS_SUCCESS) {
1768bb2be29Sthorpej /* XXX This happens a lot; it shouldn't. */
1778bb2be29Sthorpej if (ur->status != PXENV_STATUS_FAILURE)
1788bb2be29Sthorpej printf("readudp: PXENV_UDP_READ_failed: 0x%0x\n",
1798bb2be29Sthorpej ur->status);
1808bb2be29Sthorpej return (-1);
1818bb2be29Sthorpej }
1828bb2be29Sthorpej
1838bb2be29Sthorpej ip->ip_src.s_addr = ur->src_ip;
1848bb2be29Sthorpej uh->uh_sport = ur->s_port;
1858bb2be29Sthorpej uh->uh_dport = d->myport;
1868bb2be29Sthorpej
187dd15fa81Sdrochner return (ur->buffer_size);
1888bb2be29Sthorpej }
1898bb2be29Sthorpej
190542ccfb0Sdrochner /*
191542ccfb0Sdrochner * netif layer:
192542ccfb0Sdrochner * open, close, shutdown: called from dev_net.c
193542ccfb0Sdrochner * socktodesc: called by network protocol modules
194542ccfb0Sdrochner *
195542ccfb0Sdrochner * We only allow one open socket.
196542ccfb0Sdrochner */
1978bb2be29Sthorpej
198542ccfb0Sdrochner static int pxe_inited;
199542ccfb0Sdrochner static struct iodesc desc;
2008bb2be29Sthorpej
2018bb2be29Sthorpej int
pxe_netif_open(void)202df7f595eScegger pxe_netif_open(void)
2038bb2be29Sthorpej {
2048bb2be29Sthorpej t_PXENV_UDP_OPEN *uo = (void *) pxe_command_buf;
2058bb2be29Sthorpej
206542ccfb0Sdrochner if (!pxe_inited) {
207542ccfb0Sdrochner if (pxe_init() != 0)
208542ccfb0Sdrochner return (-1);
209542ccfb0Sdrochner pxe_inited = 1;
210542ccfb0Sdrochner }
211542ccfb0Sdrochner BI_ADD(&bi_netif, BTINFO_NETIF, sizeof(bi_netif));
2128bb2be29Sthorpej
213461a86f9Schristos (void)memset(uo, 0, sizeof(*uo));
2148bb2be29Sthorpej
2158bb2be29Sthorpej uo->src_ip = bootplayer.yip;
2168bb2be29Sthorpej
2178bb2be29Sthorpej pxe_call(PXENV_UDP_OPEN);
2188bb2be29Sthorpej
2198bb2be29Sthorpej if (uo->status != PXENV_STATUS_SUCCESS) {
2208bb2be29Sthorpej printf("pxe_netif_probe: PXENV_UDP_OPEN failed: 0x%x\n",
2218bb2be29Sthorpej uo->status);
222542ccfb0Sdrochner return (-1);
2238bb2be29Sthorpej }
2248bb2be29Sthorpej
225e2cb8590Scegger memcpy(desc.myea, bootplayer.CAddr, ETHER_ADDR_LEN);
2268bb2be29Sthorpej
2278bb2be29Sthorpej /*
2288bb2be29Sthorpej * Since the PXE BIOS has already done DHCP, make sure we
2298bb2be29Sthorpej * don't reuse any of its transaction IDs.
2308bb2be29Sthorpej */
231542ccfb0Sdrochner desc.xid = bootplayer.ident;
2328bb2be29Sthorpej
233542ccfb0Sdrochner return (0);
2348bb2be29Sthorpej }
2358bb2be29Sthorpej
2368bb2be29Sthorpej void
pxe_netif_close(int sock)237454af1c0Sdsl pxe_netif_close(int sock)
2388bb2be29Sthorpej {
2398bb2be29Sthorpej t_PXENV_UDP_CLOSE *uc = (void *) pxe_command_buf;
2408bb2be29Sthorpej
241542ccfb0Sdrochner #ifdef NETIF_DEBUG
242542ccfb0Sdrochner if (sock != 0)
243542ccfb0Sdrochner printf("pxe_netif_close: sock=%d\n", sock);
244542ccfb0Sdrochner #endif
245542ccfb0Sdrochner
2468bb2be29Sthorpej uc->status = 0;
2478bb2be29Sthorpej
2488bb2be29Sthorpej pxe_call(PXENV_UDP_CLOSE);
2498bb2be29Sthorpej
2508bb2be29Sthorpej if (uc->status != PXENV_STATUS_SUCCESS)
2518bb2be29Sthorpej printf("pxe_netif_end: PXENV_UDP_CLOSE failed: 0x%x\n",
2528bb2be29Sthorpej uc->status);
253542ccfb0Sdrochner }
254542ccfb0Sdrochner
255542ccfb0Sdrochner struct iodesc *
socktodesc(int sock)256454af1c0Sdsl socktodesc(int sock)
257542ccfb0Sdrochner {
258542ccfb0Sdrochner
259542ccfb0Sdrochner #ifdef NETIF_DEBUG
260542ccfb0Sdrochner if (sock != 0)
261542ccfb0Sdrochner return (0);
262542ccfb0Sdrochner else
263542ccfb0Sdrochner #endif
264542ccfb0Sdrochner return (&desc);
265542ccfb0Sdrochner }
266542ccfb0Sdrochner
2678bb2be29Sthorpej /*****************************************************************************
2688bb2be29Sthorpej * PXE initialization and support routines
2698bb2be29Sthorpej *****************************************************************************/
2708bb2be29Sthorpej
27168da4482Sperry uint16_t pxe_command_buf_seg;
27268da4482Sperry uint16_t pxe_command_buf_off;
2738bb2be29Sthorpej
27468da4482Sperry extern uint16_t bangpxe_off, bangpxe_seg;
27568da4482Sperry extern uint16_t pxenv_off, pxenv_seg;
2768bb2be29Sthorpej
2778bb2be29Sthorpej static struct btinfo_netif bi_netif;
2788bb2be29Sthorpej
2798bb2be29Sthorpej int
pxe_init(void)2808bb2be29Sthorpej pxe_init(void)
2818bb2be29Sthorpej {
2828bb2be29Sthorpej t_PXENV_GET_CACHED_INFO *gci = (void *) pxe_command_buf;
2838bb2be29Sthorpej t_PXENV_UNDI_GET_NIC_TYPE *gnt = (void *) pxe_command_buf;
2848bb2be29Sthorpej pxenv_t *pxenv;
2858bb2be29Sthorpej pxe_t *pxe;
2868bb2be29Sthorpej char *cp;
2878bb2be29Sthorpej int i;
28868da4482Sperry uint8_t cksum, *ucp;
2898bb2be29Sthorpej
2908bb2be29Sthorpej /*
2918bb2be29Sthorpej * Checking for the presence of PXE is a machine-dependent
2928bb2be29Sthorpej * operation. On the IA-32, this can be done two ways:
2938bb2be29Sthorpej *
2948bb2be29Sthorpej * Int 0x1a function 0x5650
2958bb2be29Sthorpej *
2968bb2be29Sthorpej * Scan memory for the !PXE or PXENV+ signatures
2978bb2be29Sthorpej *
2988bb2be29Sthorpej * We do the latter, since the Int method returns a pointer
2998bb2be29Sthorpej * to a deprecated structure (PXENV+).
3008bb2be29Sthorpej */
3018bb2be29Sthorpej
3028bb2be29Sthorpej pxenv = NULL;
3038bb2be29Sthorpej pxe = NULL;
3048bb2be29Sthorpej
305e42f3e30Skanaoka for (cp = (char *)0xa0000; cp > (char *)0x10000; cp -= 2) {
3068bb2be29Sthorpej if (pxenv == NULL) {
3078bb2be29Sthorpej pxenv = (pxenv_t *)cp;
3088ff1e4e4Stron if (MEMSTRCMP(pxenv->Signature, "PXENV+"))
3098bb2be29Sthorpej pxenv = NULL;
3108bb2be29Sthorpej else {
31168da4482Sperry for (i = 0, ucp = (uint8_t *)cp, cksum = 0;
3128bb2be29Sthorpej i < pxenv->Length; i++)
3138bb2be29Sthorpej cksum += ucp[i];
3148bb2be29Sthorpej if (cksum != 0) {
3158bb2be29Sthorpej printf("pxe_init: bad cksum (0x%x) "
3168bb2be29Sthorpej "for PXENV+ at 0x%lx\n", cksum,
3178bb2be29Sthorpej (u_long) cp);
3188bb2be29Sthorpej pxenv = NULL;
3198bb2be29Sthorpej }
3208bb2be29Sthorpej }
3218bb2be29Sthorpej }
3228bb2be29Sthorpej
3238bb2be29Sthorpej if (pxe == NULL) {
3248bb2be29Sthorpej pxe = (pxe_t *)cp;
3258ff1e4e4Stron if (MEMSTRCMP(pxe->Signature, "!PXE"))
3268bb2be29Sthorpej pxe = NULL;
3278bb2be29Sthorpej else {
32868da4482Sperry for (i = 0, ucp = (uint8_t *)cp, cksum = 0;
3298bb2be29Sthorpej i < pxe->StructLength; i++)
3308bb2be29Sthorpej cksum += ucp[i];
3318bb2be29Sthorpej if (cksum != 0) {
3328bb2be29Sthorpej printf("pxe_init: bad cksum (0x%x) "
3338bb2be29Sthorpej "for !PXE at 0x%lx\n", cksum,
3348bb2be29Sthorpej (u_long) cp);
3358bb2be29Sthorpej pxe = NULL;
3368bb2be29Sthorpej }
3378bb2be29Sthorpej }
3388bb2be29Sthorpej }
3398bb2be29Sthorpej
3408bb2be29Sthorpej if (pxe != NULL && pxenv != NULL)
3418bb2be29Sthorpej break;
3428bb2be29Sthorpej }
3438bb2be29Sthorpej
3448bb2be29Sthorpej if (pxe == NULL && pxenv == NULL) {
3458bb2be29Sthorpej printf("pxe_init: No PXE BIOS found.\n");
3468bb2be29Sthorpej return (1);
3478bb2be29Sthorpej }
3488bb2be29Sthorpej
3498bb2be29Sthorpej if (pxenv != NULL) {
3508bb2be29Sthorpej printf("PXE BIOS Version %d.%d\n",
3518bb2be29Sthorpej (pxenv->Version >> 8) & 0xff, pxenv->Version & 0xff);
3528bb2be29Sthorpej if (pxenv->Version >= 0x0201 && pxe != NULL) {
3538bb2be29Sthorpej /* 2.1 or greater -- don't use PXENV+ */
3548bb2be29Sthorpej pxenv = NULL;
3558bb2be29Sthorpej }
3568bb2be29Sthorpej }
3578bb2be29Sthorpej
3588bb2be29Sthorpej if (pxe != NULL) {
3598bb2be29Sthorpej pxe_call = pxecall_bangpxe;
3608bb2be29Sthorpej bangpxe_off = pxe->EntryPointSP.offset;
3618bb2be29Sthorpej bangpxe_seg = pxe->EntryPointSP.segment;
3628bb2be29Sthorpej } else {
3638bb2be29Sthorpej pxe_call = pxecall_pxenv;
3648bb2be29Sthorpej pxenv_off = pxenv->RMEntry.offset;
3658bb2be29Sthorpej pxenv_seg = pxenv->RMEntry.segment;
3668bb2be29Sthorpej }
3678bb2be29Sthorpej
3688bb2be29Sthorpej /*
3698bb2be29Sthorpej * Pre-compute the segment/offset of the pxe_command_buf
3708bb2be29Sthorpej * to make things nicer in the low-level calling glue.
3718bb2be29Sthorpej */
3728bb2be29Sthorpej pxe_command_buf_seg = VTOPSEG(pxe_command_buf);
3738bb2be29Sthorpej pxe_command_buf_off = VTOPOFF(pxe_command_buf);
3748bb2be29Sthorpej
3758bb2be29Sthorpej /*
3768bb2be29Sthorpej * Get the cached info from the server's Discovery reply packet.
3778bb2be29Sthorpej */
378461a86f9Schristos (void)memset(gci, 0, sizeof(*gci));
3798bb2be29Sthorpej gci->PacketType = PXENV_PACKET_TYPE_BINL_REPLY;
3808bb2be29Sthorpej pxe_call(PXENV_GET_CACHED_INFO);
3818bb2be29Sthorpej if (gci->Status != PXENV_STATUS_SUCCESS) {
3828bb2be29Sthorpej printf("pxe_init: PXENV_GET_CACHED_INFO failed: 0x%x\n",
3838bb2be29Sthorpej gci->Status);
3848bb2be29Sthorpej return (1);
3858bb2be29Sthorpej }
3868bb2be29Sthorpej pvbcopy((void *)((gci->Buffer.segment << 4) + gci->Buffer.offset),
3878bb2be29Sthorpej &bootplayer, gci->BufferSize);
3888bb2be29Sthorpej
3898bb2be29Sthorpej /*
3908bb2be29Sthorpej * Get network interface information.
3918bb2be29Sthorpej */
392461a86f9Schristos (void)memset(gnt, 0, sizeof(*gnt));
3938bb2be29Sthorpej pxe_call(PXENV_UNDI_GET_NIC_TYPE);
3948bb2be29Sthorpej
3958bb2be29Sthorpej if (gnt->Status != PXENV_STATUS_SUCCESS) {
3968bb2be29Sthorpej printf("pxe_init: PXENV_UNDI_GET_NIC_TYPE failed: 0x%x\n",
3978bb2be29Sthorpej gnt->Status);
3988bb2be29Sthorpej return (0);
3998bb2be29Sthorpej }
4008bb2be29Sthorpej
4018bb2be29Sthorpej switch (gnt->NicType) {
4028bb2be29Sthorpej case PCI_NIC:
4038bb2be29Sthorpej case CardBus_NIC:
4048bb2be29Sthorpej strncpy(bi_netif.ifname, "pxe", sizeof(bi_netif.ifname));
4058bb2be29Sthorpej bi_netif.bus = BI_BUS_PCI;
4068bb2be29Sthorpej bi_netif.addr.tag = gnt->info.pci.BusDevFunc;
4078bb2be29Sthorpej
4088bb2be29Sthorpej printf("Using %s device at bus %d device %d function %d\n",
4098bb2be29Sthorpej gnt->NicType == PCI_NIC ? "PCI" : "CardBus",
4108bb2be29Sthorpej (gnt->info.pci.BusDevFunc >> 8) & 0xff,
4118bb2be29Sthorpej (gnt->info.pci.BusDevFunc >> 3) & 0x1f,
4128bb2be29Sthorpej gnt->info.pci.BusDevFunc & 0x7);
4138bb2be29Sthorpej break;
4148bb2be29Sthorpej
4158bb2be29Sthorpej case PnP_NIC:
4168bb2be29Sthorpej /* XXX Make bootinfo work with this. */
4178bb2be29Sthorpej printf("Using PnP device at 0x%x\n", gnt->info.pnp.CardSelNum);
4188bb2be29Sthorpej }
4198bb2be29Sthorpej
420542ccfb0Sdrochner printf("Ethernet address %s\n", ether_sprintf(bootplayer.CAddr));
421542ccfb0Sdrochner
4228bb2be29Sthorpej return (0);
4238bb2be29Sthorpej }
4248bb2be29Sthorpej
4258bb2be29Sthorpej void
pxe_fini(void)4268bb2be29Sthorpej pxe_fini(void)
4278bb2be29Sthorpej {
4288bb2be29Sthorpej t_PXENV_UNDI_SHUTDOWN *shutdown = (void *) pxe_command_buf;
4298bb2be29Sthorpej
4308bb2be29Sthorpej if (pxe_call == NULL)
4318bb2be29Sthorpej return;
4328bb2be29Sthorpej
4338bb2be29Sthorpej pxe_call(PXENV_UNDI_SHUTDOWN);
4348bb2be29Sthorpej
4358bb2be29Sthorpej if (shutdown->Status != PXENV_STATUS_SUCCESS)
4368bb2be29Sthorpej printf("pxe_fini: PXENV_UNDI_SHUTDOWN failed: 0x%x\n",
4378bb2be29Sthorpej shutdown->Status);
4388bb2be29Sthorpej }
439