Annotation of sys/arch/i386/stand/libsa/pxe.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: pxe.c,v 1.5 2007/07/27 17:46:56 tom Exp $ */
! 2: /* $NetBSD: pxe.c,v 1.5 2003/03/11 18:29:00 drochner Exp $ */
! 3:
! 4: /*
! 5: * Copyright 2001 Wasabi Systems, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * Written by Jason R. Thorpe for Wasabi Systems, Inc.
! 9: *
! 10: * Redistribution and use in source and binary forms, with or without
! 11: * modification, are permitted provided that the following conditions
! 12: * are met:
! 13: * 1. Redistributions of source code must retain the above copyright
! 14: * notice, this list of conditions and the following disclaimer.
! 15: * 2. Redistributions in binary form must reproduce the above copyright
! 16: * notice, this list of conditions and the following disclaimer in the
! 17: * documentation and/or other materials provided with the distribution.
! 18: * 3. All advertising materials mentioning features or use of this software
! 19: * must display the following acknowledgement:
! 20: * This product includes software developed for the NetBSD Project by
! 21: * Wasabi Systems, Inc.
! 22: * 4. The name of Wasabi Systems, Inc. may not be used to endorse
! 23: * or promote products derived from this software without specific prior
! 24: * written permission.
! 25: *
! 26: * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
! 27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 28: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 29: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
! 30: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 31: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 32: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 33: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 34: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 35: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 36: * POSSIBILITY OF SUCH DAMAGE.
! 37: */
! 38:
! 39: /*
! 40: * Copyright (c) 2000 Alfred Perlstein <alfred@freebsd.org>
! 41: * All rights reserved.
! 42: * Copyright (c) 2000 Paul Saab <ps@freebsd.org>
! 43: * All rights reserved.
! 44: * Copyright (c) 2000 John Baldwin <jhb@freebsd.org>
! 45: * All rights reserved.
! 46: *
! 47: * Redistribution and use in source and binary forms, with or without
! 48: * modification, are permitted provided that the following conditions
! 49: * are met:
! 50: * 1. Redistributions of source code must retain the above copyright
! 51: * notice, this list of conditions and the following disclaimer.
! 52: * 2. Redistributions in binary form must reproduce the above copyright
! 53: * notice, this list of conditions and the following disclaimer in the
! 54: * documentation and/or other materials provided with the distribution.
! 55: *
! 56: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 57: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 58: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 59: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 60: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 61: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 62: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 63: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 64: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 65: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 66: * SUCH DAMAGE.
! 67: */
! 68:
! 69: /*
! 70: * Support for the Intel Preboot Execution Environment (PXE).
! 71: *
! 72: * PXE provides a UDP implementation as well as a UNDI network device
! 73: * driver. UNDI is much more complicated to use than PXE UDP, so we
! 74: * use PXE UDP as a cheap and easy way to get PXE support.
! 75: */
! 76:
! 77: #include <sys/param.h>
! 78: #include <sys/socket.h>
! 79:
! 80: #ifdef _STANDALONE
! 81: #include <lib/libkern/libkern.h>
! 82: #else
! 83: #include <string.h>
! 84: #endif
! 85:
! 86: #include <net/if.h>
! 87:
! 88: #include <netinet/in.h>
! 89: #include <netinet/if_ether.h>
! 90: #include <netinet/in_systm.h>
! 91: #include <netinet/ip.h>
! 92: #include <netinet/ip_var.h>
! 93: #include <netinet/udp.h>
! 94: #include <netinet/udp_var.h>
! 95:
! 96: #include <lib/libsa/stand.h>
! 97: #include <lib/libsa/net.h>
! 98: #include <lib/libsa/bootp.h>
! 99:
! 100: #include <stand/boot/bootarg.h>
! 101: #include <machine/biosvar.h>
! 102:
! 103: #include "pxeboot.h"
! 104: #include "pxe.h"
! 105: #include "pxe_netif.h"
! 106:
! 107: void (*pxe_call)(u_int16_t);
! 108:
! 109: void pxecall_bangpxe(u_int16_t); /* pxe_call.S */
! 110: void pxecall_pxenv(u_int16_t); /* pxe_call.S */
! 111:
! 112: char pxe_command_buf[256];
! 113:
! 114: BOOTPLAYER bootplayer;
! 115:
! 116: struct in_addr servip; /* for tftp */ /* XXX init this */
! 117:
! 118: extern char *bootmac; /* To pass to kernel */
! 119:
! 120: /* static struct btinfo_netif bi_netif; */
! 121:
! 122: /*****************************************************************************
! 123: * This section is a replacement for libsa/udp.c
! 124: *****************************************************************************/
! 125:
! 126: /* Caller must leave room for ethernet, ip, and udp headers in front!! */
! 127: ssize_t
! 128: pxesendudp(struct iodesc *d, void *pkt, size_t len)
! 129: {
! 130: t_PXENV_UDP_WRITE *uw = (void *) pxe_command_buf;
! 131:
! 132: uw->status = 0;
! 133:
! 134: uw->ip = d->destip.s_addr;
! 135: uw->gw = gateip.s_addr;
! 136: uw->src_port = d->myport;
! 137: uw->dst_port = d->destport;
! 138: uw->buffer_size = len;
! 139: uw->buffer.segment = VTOPSEG(pkt);
! 140: uw->buffer.offset = VTOPOFF(pkt);
! 141:
! 142: pxe_call(PXENV_UDP_WRITE);
! 143:
! 144: if (uw->status != PXENV_STATUS_SUCCESS) {
! 145: /* XXX This happens a lot; it shouldn't. */
! 146: if (uw->status != PXENV_STATUS_FAILURE)
! 147: printf("sendudp: PXENV_UDP_WRITE failed: 0x%x\n",
! 148: uw->status);
! 149: return -1;
! 150: }
! 151:
! 152: return len;
! 153: }
! 154:
! 155: /*
! 156: * Receive a UDP packet and validate it for us.
! 157: * Caller leaves room for the headers (Ether, IP, UDP).
! 158: */
! 159: ssize_t
! 160: pxereadudp(struct iodesc *d, void *pkt, size_t len, time_t tleft)
! 161: {
! 162: t_PXENV_UDP_READ *ur = (void *) pxe_command_buf;
! 163: struct udphdr *uh;
! 164: struct ip *ip;
! 165:
! 166: uh = (struct udphdr *)pkt - 1;
! 167: ip = (struct ip *)uh - 1;
! 168:
! 169: bzero(ur, sizeof(*ur));
! 170:
! 171: ur->dest_ip = d->myip.s_addr;
! 172: ur->d_port = d->myport;
! 173: ur->buffer_size = len;
! 174: ur->buffer.segment = VTOPSEG(pkt);
! 175: ur->buffer.offset = VTOPOFF(pkt);
! 176:
! 177: /* XXX Timeout unused. */
! 178:
! 179: pxe_call(PXENV_UDP_READ);
! 180:
! 181: if (ur->status != PXENV_STATUS_SUCCESS) {
! 182: /* XXX This happens a lot; it shouldn't. */
! 183: if (ur->status != PXENV_STATUS_FAILURE)
! 184: printf("readudp: PXENV_UDP_READ_failed: 0x%0x\n",
! 185: ur->status);
! 186: return -1;
! 187: }
! 188:
! 189: ip->ip_src.s_addr = ur->src_ip;
! 190: uh->uh_sport = ur->s_port;
! 191: uh->uh_dport = d->myport;
! 192:
! 193: return ur->buffer_size;
! 194: }
! 195:
! 196: /*
! 197: * netif layer:
! 198: * open, close, shutdown: called from dev_net.c
! 199: * socktodesc: called by network protocol modules
! 200: *
! 201: * We only allow one open socket.
! 202: */
! 203:
! 204: static int pxe_inited;
! 205: static struct iodesc desc;
! 206:
! 207: int
! 208: pxe_netif_open()
! 209: {
! 210: t_PXENV_UDP_OPEN *uo = (void *) pxe_command_buf;
! 211:
! 212: #ifdef NETIF_DEBUG
! 213: printf("pxe_netif_open()\n");
! 214: #endif
! 215: if (!pxe_inited) {
! 216: if (pxe_init(0) != 0)
! 217: return -1;
! 218: pxe_inited = 1;
! 219: }
! 220: /* BI_ADD(&bi_netif, BTINFO_NETIF, sizeof(bi_netif)); */
! 221:
! 222: bzero(uo, sizeof(*uo));
! 223:
! 224: uo->src_ip = bootplayer.yip;
! 225:
! 226: pxe_call(PXENV_UDP_OPEN);
! 227:
! 228: if (uo->status != PXENV_STATUS_SUCCESS) {
! 229: printf("\npxe_netif_open: PXENV_UDP_OPEN failed: 0x%x\n",
! 230: uo->status);
! 231: return -1;
! 232: }
! 233:
! 234: bcopy(bootplayer.CAddr, desc.myea, ETHER_ADDR_LEN);
! 235: bootmac = bootplayer.CAddr;
! 236:
! 237: /*
! 238: * Since the PXE BIOS has already done DHCP, make sure we
! 239: * don't reuse any of its transaction IDs.
! 240: */
! 241: desc.xid = bootplayer.ident;
! 242:
! 243: return 0;
! 244: }
! 245:
! 246: void
! 247: pxe_netif_close(sock)
! 248: int sock;
! 249: {
! 250: t_PXENV_UDP_CLOSE *uc = (void *) pxe_command_buf;
! 251:
! 252: #ifdef NETIF_DEBUG
! 253: if (sock != 0)
! 254: printf("pxe_netif_close: sock=%d\n", sock);
! 255: #endif
! 256:
! 257: uc->status = 0;
! 258:
! 259: pxe_call(PXENV_UDP_CLOSE);
! 260:
! 261: if (uc->status != PXENV_STATUS_SUCCESS)
! 262: printf("pxe_netif_end: PXENV_UDP_CLOSE failed: 0x%x\n",
! 263: uc->status);
! 264: }
! 265:
! 266: void
! 267: pxe_netif_shutdown()
! 268: {
! 269: #ifdef NETIF_DEBUG
! 270: printf("pxe_netif_shutdown()\n");
! 271: #endif
! 272:
! 273: pxe_shutdown();
! 274: }
! 275:
! 276: struct iodesc *
! 277: pxesocktodesc(sock)
! 278: int sock;
! 279: {
! 280:
! 281: #ifdef NETIF_DEBUG
! 282: if (sock != 0)
! 283: return 0;
! 284: else
! 285: #endif
! 286: return &desc;
! 287: }
! 288:
! 289: /*****************************************************************************
! 290: * PXE initialization and support routines
! 291: *****************************************************************************/
! 292:
! 293: u_int16_t pxe_command_buf_seg;
! 294: u_int16_t pxe_command_buf_off;
! 295:
! 296: extern u_int16_t bangpxe_off, bangpxe_seg;
! 297: extern u_int16_t pxenv_off, pxenv_seg;
! 298:
! 299: /* static struct btinfo_netif bi_netif; */
! 300:
! 301: void
! 302: pxeprobe(void)
! 303: {
! 304: if (!pxe_inited) {
! 305: if (pxe_init(1) == 0) {
! 306: pxe_inited = 1;
! 307: }
! 308: }
! 309: }
! 310:
! 311: int
! 312: pxe_init(int quiet)
! 313: {
! 314: t_PXENV_GET_CACHED_INFO *gci = (void *) pxe_command_buf;
! 315: pxenv_t *pxenv;
! 316: pxe_t *pxe;
! 317: char *cp;
! 318: int i;
! 319: u_int8_t cksum, *ucp;
! 320:
! 321: /*
! 322: * Checking for the presence of PXE is a machine-dependent
! 323: * operation. On the IA-32, this can be done two ways:
! 324: *
! 325: * Int 0x1a function 0x5650
! 326: *
! 327: * Scan memory for the !PXE or PXENV+ signatures
! 328: *
! 329: * We do the latter, since the Int method returns a pointer
! 330: * to a deprecated structure (PXENV+).
! 331: */
! 332:
! 333: pxenv = NULL;
! 334: pxe = NULL;
! 335:
! 336: for (cp = (char *)0xa0000; cp > (char *)0x10000; cp -= 2) {
! 337: if (pxenv == NULL) {
! 338: pxenv = (pxenv_t *)cp;
! 339: if (memcmp(pxenv->Signature, S_SIZE("PXENV+")) != 0)
! 340: pxenv = NULL;
! 341: else {
! 342: for (i = 0, ucp = (u_int8_t *)cp, cksum = 0;
! 343: i < pxenv->Length; i++)
! 344: cksum += ucp[i];
! 345: if (cksum != 0) {
! 346: printf("\npxe_init: bad cksum (0x%x) "
! 347: "for PXENV+ at 0x%lx\n", cksum,
! 348: (u_long) cp);
! 349: pxenv = NULL;
! 350: }
! 351: }
! 352: }
! 353:
! 354: if (pxe == NULL) {
! 355: pxe = (pxe_t *)cp;
! 356: if (memcmp(pxe->Signature, S_SIZE("!PXE")) != 0)
! 357: pxe = NULL;
! 358: else {
! 359: for (i = 0, ucp = (u_int8_t *)cp, cksum = 0;
! 360: i < pxe->StructLength; i++)
! 361: cksum += ucp[i];
! 362: if (cksum != 0) {
! 363: printf("pxe_init: bad cksum (0x%x) "
! 364: "for !PXE at 0x%lx\n", cksum,
! 365: (u_long) cp);
! 366: pxe = NULL;
! 367: }
! 368: }
! 369: }
! 370:
! 371: if (pxe != NULL && pxenv != NULL)
! 372: break;
! 373: }
! 374:
! 375: if (pxe == NULL && pxenv == NULL) {
! 376: if (!quiet) printf("pxe_init: No PXE BIOS found.\n");
! 377: return 1;
! 378: }
! 379:
! 380: if (pxenv == NULL) {
! 381: /* assert(pxe != NULL); */
! 382:
! 383: printf(quiet ? " pxe!" : "PXE present\n");
! 384: } else { /* pxenv != NULL */
! 385: int bang = 0;
! 386:
! 387: if (pxenv->Version >= 0x0201 && pxe != NULL) {
! 388: /* 2.1 or greater -- don't use PXENV+ */
! 389: bang = 1;
! 390: }
! 391:
! 392: if (quiet) {
! 393: printf(" pxe%c[%d.%d]",
! 394: (bang ? '!' : '+'),
! 395: (pxenv->Version >> 8) & 0xff,
! 396: pxenv->Version & 0xff);
! 397: } else {
! 398: printf("PXE BIOS Version %d.%d\n",
! 399: (pxenv->Version >> 8) & 0xff,
! 400: pxenv->Version & 0xff);
! 401: }
! 402:
! 403: if (bang) {
! 404: pxenv = NULL;
! 405: }
! 406: }
! 407:
! 408: if (pxenv == NULL) {
! 409: pxe_call = pxecall_bangpxe;
! 410: bangpxe_off = pxe->EntryPointSP.offset;
! 411: bangpxe_seg = pxe->EntryPointSP.segment;
! 412: } else {
! 413: pxe_call = pxecall_pxenv;
! 414: pxenv_off = pxenv->RMEntry.offset;
! 415: pxenv_seg = pxenv->RMEntry.segment;
! 416: }
! 417:
! 418: /*
! 419: * Pre-compute the segment/offset of the pxe_command_buf
! 420: * to make things nicer in the low-level calling glue.
! 421: */
! 422: pxe_command_buf_seg = VTOPSEG(pxe_command_buf);
! 423: pxe_command_buf_off = VTOPOFF(pxe_command_buf);
! 424:
! 425: /*
! 426: * Get the cached info from the server's Discovery reply packet.
! 427: */
! 428: bzero(gci, sizeof(*gci));
! 429: gci->PacketType = PXENV_PACKET_TYPE_CACHED_REPLY;
! 430: pxe_call(PXENV_GET_CACHED_INFO);
! 431:
! 432: if (gci->Status != PXENV_STATUS_SUCCESS) {
! 433: printf("\npxeinfo: PXENV_GET_CACHED_INFO failed: 0x%x\n",
! 434: gci->Status);
! 435: return 1;
! 436: }
! 437:
! 438: memcpy(&bootplayer,
! 439: SEGOFF2FLAT(gci->Buffer.segment, gci->Buffer.offset),
! 440: gci->BufferSize);
! 441:
! 442: bcopy(&bootplayer.yip, &myip.s_addr, sizeof(myip.s_addr));
! 443: bcopy(&bootplayer.sip, &servip.s_addr, sizeof(servip.s_addr));
! 444:
! 445: /* Compute our "natural" netmask. */
! 446: if (IN_CLASSA(myip.s_addr))
! 447: netmask = IN_CLASSA_NET;
! 448: else if (IN_CLASSB(myip.s_addr))
! 449: netmask = IN_CLASSB_NET;
! 450: else
! 451: netmask = IN_CLASSC_NET;
! 452:
! 453: return 0;
! 454: }
! 455:
! 456: void
! 457: pxeinfo(void)
! 458: {
! 459: u_int8_t *p;
! 460: #ifdef PXE_DEBUG
! 461: t_PXENV_UNDI_GET_NIC_TYPE *gnt = (void *) pxe_command_buf;
! 462: #endif
! 463:
! 464: printf(" mac %s", ether_sprintf(bootplayer.CAddr));
! 465: p = (u_int8_t *)&myip.s_addr;
! 466: printf(", ip %d.%d.%d.%d", p[0], p[1], p[2], p[3]);
! 467: p = (u_int8_t *)&servip.s_addr;
! 468: printf(", server %d.%d.%d.%d", p[0], p[1], p[2], p[3]);
! 469:
! 470: #ifdef PXE_DEBUG
! 471: /*
! 472: * Get network interface information.
! 473: */
! 474: bzero(gnt, sizeof(*gnt));
! 475: pxe_call(PXENV_UNDI_GET_NIC_TYPE);
! 476:
! 477: if (gnt->Status != PXENV_STATUS_SUCCESS) {
! 478: printf("\npxeinfo: PXENV_UNDI_GET_NIC_TYPE failed: 0x%x\n",
! 479: gnt->Status);
! 480: return;
! 481: }
! 482:
! 483: switch (gnt->NicType) {
! 484: case PCI_NIC:
! 485: case CardBus_NIC:
! 486: /* strncpy(bi_netif.ifname, "pxe", sizeof(bi_netif.ifname)); */
! 487: /* bi_netif.bus = BI_BUS_PCI; */
! 488: /* bi_netif.addr.tag = gnt->info.pci.BusDevFunc; */
! 489:
! 490: printf("\nPXE: Using %s device at bus %d device %d function %d\n",
! 491: gnt->NicType == PCI_NIC ? "PCI" : "CardBus",
! 492: (gnt->info.pci.BusDevFunc >> 8) & 0xff,
! 493: (gnt->info.pci.BusDevFunc >> 3) & 0x1f,
! 494: gnt->info.pci.BusDevFunc & 0x7);
! 495: break;
! 496:
! 497: case PnP_NIC:
! 498: /* XXX Make bootinfo work with this. */
! 499: printf("\nPXE: Using PnP device at 0x%x\n",
! 500: gnt->info.pnp.CardSelNum);
! 501: }
! 502: #endif
! 503: }
! 504:
! 505: void
! 506: pxe_shutdown(void)
! 507: {
! 508: int try;
! 509: t_PXENV_UNLOAD_STACK *unload = (void *) pxe_command_buf;
! 510: t_PXENV_UNDI_SHUTDOWN *shutdown = (void *) pxe_command_buf;
! 511: #ifdef PXE_DEBUG
! 512: t_PXENV_UDP_CLOSE *close = (void *) pxe_command_buf;
! 513: #endif
! 514:
! 515: if (pxe_call == NULL)
! 516: return;
! 517:
! 518: /* Close any open UDP connections. Ignore return value. */
! 519: pxe_call(PXENV_UDP_CLOSE);
! 520: #ifdef PXE_DEBUG
! 521: printf("pxe_shutdown: PXENV_UDP_CLOSE returned 0x%x\n", close->status);
! 522: #endif
! 523:
! 524: /* Sometimes PXENV_UNDI_SHUTDOWN doesn't work at first */
! 525: for (try = 3; try > 0; try--) {
! 526: pxe_call(PXENV_UNDI_SHUTDOWN);
! 527:
! 528: if (shutdown->Status == PXENV_STATUS_SUCCESS)
! 529: break;
! 530:
! 531: printf("pxe_shutdown: PXENV_UNDI_SHUTDOWN failed: 0x%x\n",
! 532: shutdown->Status);
! 533:
! 534: if (try != 1)
! 535: sleep(1);
! 536: }
! 537:
! 538: /* Have multiple attempts at PXENV_UNLOAD_STACK, too */
! 539: for (try = 3; try > 0; try--) {
! 540: pxe_call(PXENV_UNLOAD_STACK);
! 541:
! 542: if (unload->Status == PXENV_STATUS_SUCCESS)
! 543: break;
! 544:
! 545: printf("pxe_shutdown: PXENV_UNLOAD_STACK failed: 0x%x\n",
! 546: unload->Status);
! 547:
! 548: if (try != 1)
! 549: sleep(1);
! 550: }
! 551: }
CVSweb