1 /*- 2 * Copyright (c) 2001 Doug Rabson 3 * Copyright (c) 2002, 2006 Marcel Moolenaar 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/param.h> 29 #include <net/ethernet.h> 30 #include <netinet/in.h> 31 #include <netinet/in_systm.h> 32 33 #include <stand.h> 34 #include <net.h> 35 #include <netif.h> 36 #include <bootp.h> 37 38 #include <efi.h> 39 #include <efilib.h> 40 #include <Protocol/SimpleNetwork.h> 41 #include <Protocol/PxeBaseCode.h> 42 43 #include "dev_net.h" 44 45 static EFI_GUID sn_guid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID; 46 static EFI_GUID pxe_guid = EFI_PXE_BASE_CODE_PROTOCOL_GUID; 47 48 /* 49 * Snapshot of the UEFI PXE Base Code Protocol's cached DhcpAck taken 50 * at device enumeration time, before efinet_probe() opens the Simple 51 * Network Protocol with EFI_OPEN_PROTOCOL_EXCLUSIVE. The EXCLUSIVE 52 * open forces the firmware to disconnect any driver holding the SNP 53 * handle BY_DRIVER (including the UEFI PXE stack), which uninstalls 54 * the PXE Base Code Protocol from that handle. We capture the ACK 55 * here so it survives that disconnect. 56 * 57 * Per PXE 2.1, ProxyOffer's siaddr is the authoritative PXE boot 58 * server and overrides any siaddr in the primary DhcpAck. We splice 59 * it into dhcp_ack.Dhcpv4.BootpSiAddr at snapshot time, so downstream 60 * only sees one merged packet — no need to store ProxyOffer separately. 61 * 62 * Indexed by netif unit; allocated in efi_pxe_snapshot_all(). 63 */ 64 struct pxe_cache_entry { 65 bool valid; 66 EFI_PXE_BASE_CODE_PACKET dhcp_ack; 67 }; 68 69 static struct pxe_cache_entry *pxe_cache; 70 71 static void efinet_end(struct netif *); 72 static ssize_t efinet_get(struct iodesc *, void **, time_t); 73 static void efinet_init(struct iodesc *, void *); 74 static int efinet_match(struct netif *, void *); 75 static int efinet_probe(struct netif *, void *); 76 static ssize_t efinet_put(struct iodesc *, void *, size_t); 77 78 struct netif_driver efinetif = { 79 .netif_bname = "efinet", 80 .netif_match = efinet_match, 81 .netif_probe = efinet_probe, 82 .netif_init = efinet_init, 83 .netif_get = efinet_get, 84 .netif_put = efinet_put, 85 .netif_end = efinet_end, 86 .netif_ifs = NULL, 87 .netif_nifs = 0 88 }; 89 90 #ifdef EFINET_DEBUG 91 static void 92 dump_mode(EFI_SIMPLE_NETWORK_MODE *mode) 93 { 94 int i; 95 96 printf("State = %x\n", mode->State); 97 printf("HwAddressSize = %u\n", mode->HwAddressSize); 98 printf("MediaHeaderSize = %u\n", mode->MediaHeaderSize); 99 printf("MaxPacketSize = %u\n", mode->MaxPacketSize); 100 printf("NvRamSize = %u\n", mode->NvRamSize); 101 printf("NvRamAccessSize = %u\n", mode->NvRamAccessSize); 102 printf("ReceiveFilterMask = %x\n", mode->ReceiveFilterMask); 103 printf("ReceiveFilterSetting = %u\n", mode->ReceiveFilterSetting); 104 printf("MaxMCastFilterCount = %u\n", mode->MaxMCastFilterCount); 105 printf("MCastFilterCount = %u\n", mode->MCastFilterCount); 106 printf("MCastFilter = {"); 107 for (i = 0; i < mode->MCastFilterCount; i++) 108 printf(" %s", ether_sprintf(mode->MCastFilter[i].Addr)); 109 printf(" }\n"); 110 printf("CurrentAddress = %s\n", 111 ether_sprintf(mode->CurrentAddress.Addr)); 112 printf("BroadcastAddress = %s\n", 113 ether_sprintf(mode->BroadcastAddress.Addr)); 114 printf("PermanentAddress = %s\n", 115 ether_sprintf(mode->PermanentAddress.Addr)); 116 printf("IfType = %u\n", mode->IfType); 117 printf("MacAddressChangeable = %d\n", mode->MacAddressChangeable); 118 printf("MultipleTxSupported = %d\n", mode->MultipleTxSupported); 119 printf("MediaPresentSupported = %d\n", mode->MediaPresentSupported); 120 printf("MediaPresent = %d\n", mode->MediaPresent); 121 } 122 #endif 123 124 static int 125 efinet_match(struct netif *nif, void *machdep_hint) 126 { 127 struct devdesc *dev = machdep_hint; 128 129 if (dev->d_unit == nif->nif_unit) 130 return (1); 131 return(0); 132 } 133 134 static int 135 efinet_probe(struct netif *nif, void *machdep_hint) 136 { 137 EFI_SIMPLE_NETWORK *net; 138 EFI_HANDLE h; 139 EFI_STATUS status; 140 141 h = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private; 142 /* 143 * Open the network device in exclusive mode. Without this 144 * we will be racing with the UEFI network stack. It will 145 * pull packets off the network leading to lost packets. 146 */ 147 status = BS->OpenProtocol(h, &sn_guid, (void **)&net, 148 IH, NULL, EFI_OPEN_PROTOCOL_EXCLUSIVE); 149 if (status != EFI_SUCCESS) { 150 printf("Unable to open network interface %d for " 151 "exclusive access: %lu\n", nif->nif_unit, 152 DECODE_ERROR(status)); 153 return (efi_status_to_errno(status)); 154 } 155 156 return (0); 157 } 158 159 static ssize_t 160 efinet_put(struct iodesc *desc, void *pkt, size_t len) 161 { 162 struct netif *nif = desc->io_netif; 163 EFI_SIMPLE_NETWORK *net; 164 EFI_STATUS status; 165 void *buf; 166 167 net = nif->nif_devdata; 168 if (net == NULL) 169 return (-1); 170 171 status = net->Transmit(net, 0, len, pkt, NULL, NULL, NULL); 172 if (status != EFI_SUCCESS) 173 return (-1); 174 175 /* Wait for the buffer to be transmitted */ 176 do { 177 buf = NULL; /* XXX Is this needed? */ 178 status = net->GetStatus(net, NULL, &buf); 179 /* 180 * XXX EFI1.1 and the E1000 card returns a different 181 * address than we gave. Sigh. 182 */ 183 } while (status == EFI_SUCCESS && buf == NULL); 184 185 /* XXX How do we deal with status != EFI_SUCCESS now? */ 186 return ((status == EFI_SUCCESS) ? len : -1); 187 } 188 189 static ssize_t 190 efinet_get(struct iodesc *desc, void **pkt, time_t timeout) 191 { 192 struct netif *nif = desc->io_netif; 193 EFI_SIMPLE_NETWORK *net; 194 EFI_STATUS status; 195 UINTN bufsz; 196 time_t t; 197 char *buf, *ptr; 198 ssize_t ret = -1; 199 200 net = nif->nif_devdata; 201 if (net == NULL) 202 return (ret); 203 204 bufsz = net->Mode->MaxPacketSize + ETHER_HDR_LEN + ETHER_CRC_LEN; 205 buf = malloc(bufsz + ETHER_ALIGN); 206 if (buf == NULL) 207 return (ret); 208 ptr = buf + ETHER_ALIGN; 209 210 t = getsecs(); 211 while ((getsecs() - t) < timeout) { 212 status = net->Receive(net, NULL, &bufsz, ptr, NULL, NULL, NULL); 213 if (status == EFI_SUCCESS) { 214 *pkt = buf; 215 ret = (ssize_t)bufsz; 216 break; 217 } 218 if (status != EFI_NOT_READY) 219 break; 220 } 221 222 if (ret == -1) 223 free(buf); 224 return (ret); 225 } 226 227 /* 228 * Snapshot the UEFI PXE Base Code Protocol's cached DhcpAck for handle 229 * h (which must carry EFI_PXE_BASE_CODE_PROTOCOL) into pce, splicing 230 * ProxyOffer's siaddr into it if present (per PXE 2.1, ProxyOffer's 231 * siaddr is the authoritative boot server and overrides DhcpAck's). 232 * 233 * Silently leaves pce->valid = false if the protocol is absent, the 234 * PXE base code is not Started on this handle (i.e. it wasn't the 235 * interface used to network-boot), or no DhcpAck was received. 236 */ 237 static void 238 efi_pxe_snapshot(EFI_HANDLE h, struct pxe_cache_entry *pce) 239 { 240 EFI_PXE_BASE_CODE_PROTOCOL *pxe; 241 EFI_PXE_BASE_CODE_MODE *mode; 242 EFI_STATUS status; 243 244 status = BS->OpenProtocol(h, &pxe_guid, (void **)&pxe, 245 IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); 246 if (EFI_ERROR(status)) 247 return; 248 249 mode = pxe->Mode; 250 if (mode->Started && mode->DhcpAckReceived) { 251 memcpy(&pce->dhcp_ack, &mode->DhcpAck, sizeof(pce->dhcp_ack)); 252 253 if (mode->ProxyOfferReceived) { 254 uint32_t proxy_siaddr = 0; 255 256 memcpy(&proxy_siaddr, 257 mode->ProxyOffer.Dhcpv4.BootpSiAddr, 4); 258 if (proxy_siaddr != 0) 259 memcpy(pce->dhcp_ack.Dhcpv4.BootpSiAddr, 260 &proxy_siaddr, 4); 261 } 262 pce->valid = true; 263 } 264 265 BS->CloseProtocol(h, &pxe_guid, IH, NULL); 266 } 267 268 /* 269 * Walk a device path looking for the first MSG_MAC_ADDR_DP node and 270 * copy its 6-byte Ethernet MAC into out. Returns true on success, 271 * e.g. false if dp has no NIC node at all. 272 */ 273 bool 274 efi_devpath_get_mac(EFI_DEVICE_PATH *dp, uint8_t out[6]) 275 { 276 MAC_ADDR_DEVICE_PATH *mac; 277 278 if (dp == NULL) 279 return (false); 280 while (!IsDevicePathEnd(dp)) { 281 if (DevicePathType(dp) == MESSAGING_DEVICE_PATH && 282 DevicePathSubType(dp) == MSG_MAC_ADDR_DP) { 283 mac = (MAC_ADDR_DEVICE_PATH *)dp; 284 memcpy(out, &mac->MacAddress, 6); 285 return (true); 286 } 287 dp = NextDevicePathNode(dp); 288 } 289 return (false); 290 } 291 292 /* 293 * Populate the pxe_cache[] array for all nifs SNP units. Runs during 294 * efinet_dev_init() before any SNP is opened EXCLUSIVE, so the UEFI 295 * PXE driver is still bound and its Mode data is intact. 296 * 297 * Per the UEFI 2.x network-stack architecture, EFI_PXE_BASE_CODE_PROTOCOL 298 * lives on an upper-layer child handle whose device path extends the 299 * SNP's MAC-terminated path with Ipv4()/Ipv6() nodes. Enumerate all 300 * handles carrying PXE Base Code Protocol via LocateHandle() and match 301 * each back to an SNP unit by MAC address extracted from the handle's 302 * device path. This also transparently covers the legacy single-handle 303 * case where PXE Base Code is installed on the SNP handle itself: 304 * LocateHandle() returns that handle, whose device path ends in a MAC 305 * node that trivially matches the same SNP unit. 306 */ 307 static void 308 efi_pxe_snapshot_all(int nifs) 309 { 310 EFI_HANDLE *pxe_handles; 311 EFI_STATUS status; 312 UINTN sz; 313 int i, j, npxe; 314 315 sz = 0; 316 status = BS->LocateHandle(ByProtocol, &pxe_guid, NULL, &sz, NULL); 317 if (status != EFI_BUFFER_TOO_SMALL) 318 return; 319 pxe_handles = malloc(sz); 320 if (pxe_handles == NULL) 321 return; 322 status = BS->LocateHandle(ByProtocol, &pxe_guid, NULL, &sz, 323 pxe_handles); 324 if (EFI_ERROR(status)) { 325 free(pxe_handles); 326 return; 327 } 328 npxe = sz / sizeof(EFI_HANDLE); 329 330 /* 331 * PXE is present on this system; allocate the per-unit cache 332 * only now. Non-PXE UEFI boots pay nothing for this feature. 333 */ 334 pxe_cache = calloc(nifs, sizeof(struct pxe_cache_entry)); 335 if (pxe_cache == NULL) { 336 free(pxe_handles); 337 return; 338 } 339 340 for (i = 0; i < npxe; i++) { 341 EFI_DEVICE_PATH *dp; 342 uint8_t pxe_mac[6]; 343 344 dp = efi_lookup_devpath(pxe_handles[i]); 345 if (!efi_devpath_get_mac(dp, pxe_mac)) 346 continue; 347 348 for (j = 0; j < nifs; j++) { 349 EFI_DEVICE_PATH *snp_dp, *node; 350 MAC_ADDR_DEVICE_PATH *snp_mac; 351 352 if (pxe_cache[j].valid) 353 continue; 354 snp_dp = efi_lookup_devpath( 355 efinetif.netif_ifs[j].dif_private); 356 if ((node = efi_devpath_last_node(snp_dp)) == NULL) 357 continue; 358 snp_mac = (MAC_ADDR_DEVICE_PATH *)node; 359 if (memcmp(&snp_mac->MacAddress, pxe_mac, 6) != 0) 360 continue; 361 efi_pxe_snapshot(pxe_handles[i], &pxe_cache[j]); 362 break; 363 } 364 } 365 366 free(pxe_handles); 367 } 368 369 /* 370 * Publish the UEFI PXE Base Code snapshot to the shared bootp_response 371 * global so that the loader's DHCP client (stand/libsa/bootp.c) can 372 * pick it up and enter RFC 2131 INIT-REBOOT instead of running a full 373 * DISCOVER/OFFER/REQUEST/ACK cycle. Also seed servip from the 374 * ProxyOffer's siaddr, which is the authoritative PXE boot server on 375 * setups where the primary DHCP is not PXE-aware (its DhcpAck siaddr 376 * is zero). bootp()'s post-processing preserves this pre-set servip 377 * when the INIT-REBOOT ACK arrives with siaddr == 0. 378 */ 379 static void 380 efi_pxe_publish_cache(int unit) 381 { 382 const struct pxe_cache_entry *pce; 383 384 if (pxe_cache == NULL) 385 return; 386 pce = &pxe_cache[unit]; 387 if (!pce->valid) 388 return; 389 390 free(bootp_response); 391 bootp_response_size = 0; 392 bootp_response = malloc(sizeof(pce->dhcp_ack)); 393 if (bootp_response == NULL) 394 return; 395 memcpy(bootp_response, &pce->dhcp_ack, sizeof(pce->dhcp_ack)); 396 bootp_response_size = sizeof(pce->dhcp_ack); 397 398 DEBUG_PRINTF(1, ("%s: bootp_response=%p size=%zu\n", 399 __func__, bootp_response, bootp_response_size)); 400 } 401 402 /* 403 * Loader uses BOOTP/DHCP and also uses RARP as a fallback to populate 404 * network parameters and problems with DHCP servers can cause the loader 405 * to fail to populate them. Allow the device to ask about the basic 406 * network parameters and if present use them. 407 */ 408 static void 409 efi_env_net_params(struct iodesc *desc) 410 { 411 char *envstr; 412 in_addr_t ipaddr, mask, gwaddr, serveraddr; 413 n_long rootaddr; 414 415 if ((envstr = getenv("rootpath")) != NULL) 416 strlcpy(rootpath, envstr, sizeof(rootpath)); 417 418 /* 419 * Get network parameters. 420 */ 421 envstr = getenv("ipaddr"); 422 ipaddr = (envstr != NULL) ? inet_addr(envstr) : 0; 423 424 envstr = getenv("netmask"); 425 mask = (envstr != NULL) ? inet_addr(envstr) : 0; 426 427 envstr = getenv("gatewayip"); 428 gwaddr = (envstr != NULL) ? inet_addr(envstr) : 0; 429 430 envstr = getenv("serverip"); 431 serveraddr = (envstr != NULL) ? inet_addr(envstr) : 0; 432 433 /* No network params. */ 434 if (ipaddr == 0 && mask == 0 && gwaddr == 0 && serveraddr == 0) 435 return; 436 437 /* Partial network params. */ 438 if (ipaddr == 0 || mask == 0 || gwaddr == 0 || serveraddr == 0) { 439 printf("Incomplete network settings from U-Boot\n"); 440 return; 441 } 442 443 /* 444 * Set network parameters. 445 */ 446 myip.s_addr = ipaddr; 447 netmask = mask; 448 gateip.s_addr = gwaddr; 449 servip.s_addr = serveraddr; 450 451 /* 452 * There must be a rootpath. It may be ip:/path or it may be just the 453 * path in which case the ip needs to be serverip. 454 */ 455 #ifdef LOADER_NET_SUPPORT 456 rootaddr = net_parse_rootpath(); 457 if (rootaddr == INADDR_NONE) 458 rootaddr = serveraddr; 459 #else 460 rootaddr = serveraddr; 461 #endif 462 rootip.s_addr = rootaddr; 463 464 #ifdef EFINET_DEBUG 465 printf("%s: proto=%d\n", __func__, netproto); 466 printf("%s: ip=%s\n", __func__, inet_ntoa(myip)); 467 printf("%s: mask=%s\n", __func__, intoa(netmask)); 468 printf("%s: gateway=%s\n", __func__, inet_ntoa(gateip)); 469 printf("%s: server=%s\n", __func__, inet_ntoa(servip)); 470 #endif 471 472 desc->myip = myip; 473 } 474 475 static void 476 efinet_init(struct iodesc *desc, void *machdep_hint) 477 { 478 struct netif *nif = desc->io_netif; 479 EFI_SIMPLE_NETWORK *net; 480 EFI_HANDLE h; 481 EFI_STATUS status; 482 UINT32 mask; 483 484 /* Attempt to get netboot params from env */ 485 efi_env_net_params(desc); 486 487 if (nif->nif_driver->netif_ifs[nif->nif_unit].dif_unit < 0) { 488 printf("Invalid network interface %d\n", nif->nif_unit); 489 return; 490 } 491 492 h = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private; 493 if (rootip.s_addr == 0) 494 efi_pxe_publish_cache(nif->nif_unit); 495 status = OpenProtocolByHandle(h, &sn_guid, (void **)&nif->nif_devdata); 496 if (status != EFI_SUCCESS) { 497 printf("net%d: cannot fetch interface data (status=%lu)\n", 498 nif->nif_unit, DECODE_ERROR(status)); 499 return; 500 } 501 502 net = nif->nif_devdata; 503 if (net->Mode->State == EfiSimpleNetworkStopped) { 504 status = net->Start(net); 505 if (status != EFI_SUCCESS) { 506 printf("net%d: cannot start interface (status=%lu)\n", 507 nif->nif_unit, DECODE_ERROR(status)); 508 return; 509 } 510 } 511 512 if (net->Mode->State != EfiSimpleNetworkInitialized) { 513 status = net->Initialize(net, 0, 0); 514 if (status != EFI_SUCCESS) { 515 printf("net%d: cannot init. interface (status=%lu)\n", 516 nif->nif_unit, DECODE_ERROR(status)); 517 return; 518 } 519 } 520 521 mask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | 522 EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST; 523 524 status = net->ReceiveFilters(net, mask, 0, FALSE, 0, NULL); 525 if (status != EFI_SUCCESS) 526 printf("net%d: cannot set rx. filters (status=%lu)\n", 527 nif->nif_unit, DECODE_ERROR(status)); 528 529 #ifdef EFINET_DEBUG 530 dump_mode(net->Mode); 531 #endif 532 533 bcopy(net->Mode->CurrentAddress.Addr, desc->myea, 6); 534 } 535 536 static void 537 efinet_end(struct netif *nif) 538 { 539 EFI_SIMPLE_NETWORK *net = nif->nif_devdata; 540 EFI_HANDLE h; 541 542 if (net == NULL) 543 return; 544 545 net->Shutdown(net); 546 h = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private; 547 BS->CloseProtocol(h, &sn_guid, IH, NULL); 548 nif->nif_devdata = NULL; 549 } 550 551 static int efinet_dev_init(void); 552 static int efinet_dev_print(int); 553 554 struct devsw efinet_dev = { 555 .dv_name = "net", 556 .dv_type = DEVT_NET, 557 .dv_init = efinet_dev_init, 558 .dv_strategy = NULL, /* Will be set in efinet_dev_init */ 559 .dv_open = NULL, /* Will be set in efinet_dev_init */ 560 .dv_close = NULL, /* Will be set in efinet_dev_init */ 561 .dv_ioctl = noioctl, 562 .dv_print = efinet_dev_print, 563 .dv_cleanup = nullsys, 564 }; 565 566 static int 567 efinet_dev_init(void) 568 { 569 struct netif_dif *dif; 570 struct netif_stats *stats; 571 EFI_DEVICE_PATH *devpath, *node; 572 EFI_HANDLE *handles, *handles2; 573 EFI_STATUS status; 574 UINTN sz; 575 int err, i, nifs; 576 extern struct devsw netdev; 577 578 /* 579 * Advertise our DHCP Client-System Architecture (RFC 4578). Many 580 * x86_64 UEFI firmwares report themselves as "EFI BC" (0x0007) 581 * rather than "EFI x86-64" (0x0009); match that convention for 582 * best DHCP-server config compatibility. 583 */ 584 #if defined(__amd64__) 585 bootp_client_arch = 0x0007; /* EFI BC */ 586 #elif defined(__i386__) 587 bootp_client_arch = 0x0006; /* EFI IA32 */ 588 #elif defined(__aarch64__) 589 bootp_client_arch = 0x000b; /* EFI 64-bit ARM */ 590 #elif defined(__arm__) 591 bootp_client_arch = 0x000a; /* EFI 32-bit ARM */ 592 #elif defined(__riscv) 593 bootp_client_arch = 0x001b; /* EFI 64-bit RISC-V */ 594 #endif 595 596 sz = 0; 597 handles = NULL; 598 status = BS->LocateHandle(ByProtocol, &sn_guid, NULL, &sz, NULL); 599 if (status == EFI_BUFFER_TOO_SMALL) { 600 handles = (EFI_HANDLE *)malloc(sz); 601 if (handles == NULL) 602 return (ENOMEM); 603 status = BS->LocateHandle(ByProtocol, &sn_guid, NULL, &sz, 604 handles); 605 if (EFI_ERROR(status)) 606 free(handles); 607 } 608 if (EFI_ERROR(status)) 609 return (efi_status_to_errno(status)); 610 handles2 = (EFI_HANDLE *)malloc(sz); 611 if (handles2 == NULL) { 612 free(handles); 613 return (ENOMEM); 614 } 615 nifs = 0; 616 for (i = 0; i < sz / sizeof(EFI_HANDLE); i++) { 617 devpath = efi_lookup_devpath(handles[i]); 618 if (devpath == NULL) 619 continue; 620 if ((node = efi_devpath_last_node(devpath)) == NULL) 621 continue; 622 623 if (DevicePathType(node) != MESSAGING_DEVICE_PATH || 624 DevicePathSubType(node) != MSG_MAC_ADDR_DP) 625 continue; 626 627 handles2[nifs] = handles[i]; 628 nifs++; 629 } 630 free(handles); 631 if (nifs == 0) { 632 err = ENOENT; 633 goto done; 634 } 635 636 err = efi_register_handles(&efinet_dev, handles2, NULL, nifs); 637 if (err != 0) 638 goto done; 639 640 efinetif.netif_ifs = calloc(nifs, sizeof(struct netif_dif)); 641 stats = calloc(nifs, sizeof(struct netif_stats)); 642 if (efinetif.netif_ifs == NULL || stats == NULL) { 643 free(efinetif.netif_ifs); 644 free(stats); 645 efinetif.netif_ifs = NULL; 646 err = ENOMEM; 647 goto done; 648 } 649 efinetif.netif_nifs = nifs; 650 651 for (i = 0; i < nifs; i++) { 652 653 dif = &efinetif.netif_ifs[i]; 654 dif->dif_unit = i; 655 dif->dif_nsel = 1; 656 dif->dif_stats = &stats[i]; 657 dif->dif_private = handles2[i]; 658 } 659 660 /* 661 * Snapshot the PXE Base Code cache now, before any code path 662 * opens the SNP with EFI_OPEN_PROTOCOL_EXCLUSIVE (efinet_probe()). 663 * An EXCLUSIVE open causes the firmware to disconnect the UEFI 664 * PXE driver, which uninstalls the PXE Base Code Protocol and 665 * loses the cached DhcpAck/ProxyOffer packets. 666 */ 667 efi_pxe_snapshot_all(nifs); 668 669 #ifdef LOADER_NET_SUPPORT 670 efinet_dev.dv_cleanup = netdev.dv_cleanup; 671 efinet_dev.dv_open = netdev.dv_open; 672 efinet_dev.dv_close = netdev.dv_close; 673 efinet_dev.dv_strategy = netdev.dv_strategy; 674 #endif 675 676 done: 677 free(handles2); 678 return (err); 679 } 680 681 static int 682 efinet_dev_print(int verbose) 683 { 684 CHAR16 *text; 685 EFI_HANDLE h; 686 int unit, ret = 0; 687 688 printf("%s devices:", efinet_dev.dv_name); 689 if ((ret = pager_output("\n")) != 0) 690 return (ret); 691 692 for (unit = 0, h = efi_find_handle(&efinet_dev, 0); 693 h != NULL; h = efi_find_handle(&efinet_dev, ++unit)) { 694 printf(" %s%d:", efinet_dev.dv_name, unit); 695 if (verbose) { 696 text = efi_devpath_name(efi_lookup_devpath(h)); 697 if (text != NULL) { 698 printf(" %S", text); 699 efi_free_devpath_name(text); 700 } 701 } 702 if ((ret = pager_output("\n")) != 0) 703 break; 704 } 705 return (ret); 706 } 707