diff --git a/stand/efi/loader/loader_efi.h b/stand/efi/loader/loader_efi.h index e53e165d5ffc..8f16c06f6f90 100644 --- a/stand/efi/loader/loader_efi.h +++ b/stand/efi/loader/loader_efi.h @@ -62,6 +62,7 @@ void efi_copy_finish_nop(void); bool maybe_download_ramdisk(int argc, CHAR16 **argv); int download_md_image(const char *url); void maybe_download_initmd(void); +int boot_nic_unit(int *unitp); #if defined(__amd64__) || defined(__i386__) /* Need this to setup page tables */ diff --git a/stand/efi/loader/main.c b/stand/efi/loader/main.c index fa4647101d62..f04018041c94 100644 --- a/stand/efi/loader/main.c +++ b/stand/efi/loader/main.c @@ -1294,6 +1294,50 @@ is_efi_netboot(void) return (efi_devpath_get_mac(devpath, mac)); } +/* + * Find the net unit that booted us, so DHCP-triggered downloads (eg the + * initmd) go out the same NIC, not just whichever one enumerated first. + * Mirrors find_currdev()'s boot-device resolution, but net-only and usable + * before find_currdev() runs. + */ +int +boot_nic_unit(int *unitp) +{ + struct devsw *dev; + EFI_DEVICE_PATH *devpath, *copy; + EFI_HANDLE h; + uint64_t extra; + + if (efi_handle_lookup(boot_img->DeviceHandle, &dev, unitp, &extra) == 0 && + (dev == &efinet_dev || dev == &efihttp_dev)) + return (0); + + copy = NULL; + devpath = efi_lookup_image_devpath(IH); + while (devpath != NULL) { + h = efi_devpath_handle(devpath); + if (h == NULL) + break; + + free(copy); + copy = NULL; + + if (efi_handle_lookup(h, &dev, unitp, &extra) == 0 && + (dev == &efinet_dev || dev == &efihttp_dev)) { + free(copy); + return (0); + } + + devpath = efi_lookup_devpath(h); + if (devpath != NULL) { + copy = efi_devpath_trim(devpath); + devpath = copy; + } + } + free(copy); + return (ENOENT); +} + EFI_STATUS main(int argc, CHAR16 *argv[]) { diff --git a/stand/efi/loader/memdisk.c b/stand/efi/loader/memdisk.c index 8990f9393e85..02bd40c71ef2 100644 --- a/stand/efi/loader/memdisk.c +++ b/stand/efi/loader/memdisk.c @@ -228,16 +228,20 @@ maybe_download_initmd(void) const char *url; int error; - if (efi_find_handle(&efinet_dev, 0) == NULL) - return; - memset(&dev, 0, sizeof(dev)); dev.d_dev = &efinet_dev; - dev.d_unit = 0; + if (boot_nic_unit(&dev.d_unit) != 0) { + printf("Could not identify boot NIC, defaulting to net0\n"); + dev.d_unit = 0; + } + + if (efi_find_handle(&efinet_dev, dev.d_unit) == NULL) + return; + error = net_configure(&dev); if (error != 0) { - printf("Could not configure net0 for initmd: %s\n", - strerror(error)); + printf("Could not configure net%d for initmd: %s\n", + dev.d_unit, strerror(error)); return; }