Module Name:    src
Committed By:   nonaka
Date:           Wed Apr 11 10:32:10 UTC 2018

Modified Files:
        src/sys/arch/i386/stand/efiboot: Makefile.efiboot boot.c conf.c
            devopen.c devopen.h efiboot.c efiboot.h efidisk.c
Added Files:
        src/sys/arch/i386/stand/efiboot: dev_net.c efinet.c efinet.h efipxe.c

Log Message:
efiboot: Added network boot support.


To generate a diff of this commit:
cvs rdiff -u -r1.11 -r1.12 src/sys/arch/i386/stand/efiboot/Makefile.efiboot
cvs rdiff -u -r1.9 -r1.10 src/sys/arch/i386/stand/efiboot/boot.c
cvs rdiff -u -r1.1 -r1.2 src/sys/arch/i386/stand/efiboot/conf.c
cvs rdiff -u -r0 -r1.1 src/sys/arch/i386/stand/efiboot/dev_net.c \
    src/sys/arch/i386/stand/efiboot/efinet.c \
    src/sys/arch/i386/stand/efiboot/efinet.h \
    src/sys/arch/i386/stand/efiboot/efipxe.c
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/i386/stand/efiboot/devopen.c
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/i386/stand/efiboot/devopen.h
cvs rdiff -u -r1.6 -r1.7 src/sys/arch/i386/stand/efiboot/efiboot.c
cvs rdiff -u -r1.7 -r1.8 src/sys/arch/i386/stand/efiboot/efiboot.h
cvs rdiff -u -r1.5 -r1.6 src/sys/arch/i386/stand/efiboot/efidisk.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/i386/stand/efiboot/Makefile.efiboot
diff -u src/sys/arch/i386/stand/efiboot/Makefile.efiboot:1.11 src/sys/arch/i386/stand/efiboot/Makefile.efiboot:1.12
--- src/sys/arch/i386/stand/efiboot/Makefile.efiboot:1.11	Tue Mar 27 14:15:05 2018
+++ src/sys/arch/i386/stand/efiboot/Makefile.efiboot	Wed Apr 11 10:32:09 2018
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile.efiboot,v 1.11 2018/03/27 14:15:05 nonaka Exp $
+# $NetBSD: Makefile.efiboot,v 1.12 2018/04/11 10:32:09 nonaka Exp $
 
 S=		${.CURDIR}/../../../../..
 
@@ -8,12 +8,12 @@ NEWVERSWHAT?=	"EFI Boot"
 
 AFLAGS.start.S= ${${ACTIVE_CC} == "clang":?-no-integrated-as:}
 
-SOURCES?= start.S conf.c devopen.c efiboot.c self_reloc.c
-LIBI386SRCS= boot.c biosdisk.c bootinfo.c bootinfo_biosgeom.c
-LIBI386SRCS+= bootmenu.c diskbuf.c exec.c menuutils.c
-LIBI386SRCS+= panic.c parseutils.c pread.c
-LIBI386SRCS+= efichar.c eficons.c efidelay.c efidev.c efidisk.c efidisk_ll.c
-LIBI386SRCS+= efigetsecs.c efimemory.c
+SOURCES= start.S boot.c conf.c devopen.c dev_net.c self_reloc.c panic.c
+SOURCES+= efiboot.c efichar.c eficons.c efidelay.c efidev.c
+SOURCES+= efidisk.c efidisk_ll.c efigetsecs.c efimemory.c
+SOURCES+= efinet.c efipxe.c
+LIBI386SRCS= biosdisk.c bootinfo.c bootinfo_biosgeom.c bootmenu.c
+LIBI386SRCS+= diskbuf.c exec.c menuutils.c parseutils.c pread.c
 SRCS= ${SOURCES} ${EXTRA_SOURCES} ${LIBI386SRCS}
 
 PIE_CFLAGS=
@@ -57,10 +57,22 @@ CPPFLAGS+= -DSUPPORT_CD9660
 CPPFLAGS+= -D"devb2cdb(bno)=(bno)"
 CPPFLAGS+= -DSUPPORT_DOSFS
 CPPFLAGS+= -DSUPPORT_EXT2FS
+CPPFLAGS+= -DSUPPORT_BOOTP
+CPPFLAGS+= -DSUPPORT_DHCP
+CPPFLAGS+= -DSUPPORT_NFS
+#CPPFLAGS+= -DSUPPORT_TFTP
 CPPFLAGS+= -DPASS_BIOSGEOM
 CPPFLAGS+= -DBIOSDISK_DEFAULT_SECSIZE=2048	# for bootinfo_biosgeom.c
 CPPFLAGS+= -DLIBSA_ENABLE_LS_OP
 
+#CPPFLAGS+= -DARP_DEBUG
+#CPPFLAGS+= -DBOOTP_DEBUG
+#CPPFLAGS+= -DNET_DEBUG
+#CPPFLAGS+= -DNETIF_DEBUG
+#CPPFLAGS+= -DNFS_DEBUG
+#CPPFLAGS+= -DRARP_DEBUG
+#CPPFLAGS+= -DRPC_DEBUG
+
 EFIDIR= ${S}/external/bsd/gnu-efi/dist
 GNUEFIARCH?= ${MACHINE_CPU}
 CPPFLAGS+= -I${EFIDIR}/inc -I${EFIDIR}/inc/${GNUEFIARCH}
@@ -69,12 +81,12 @@ CPPFLAGS+= -I${EFIDIR}/inc/protocol
 SAMISCCPPFLAGS+= -DLIBSA_PRINTF_LONGLONG_SUPPORT
 SAMISCCPPFLAGS+= -DLIBSA_PRINTF_WIDTH_SUPPORT
 SAMISCCPPFLAGS+= -D"cdb2devb(bno)=(bno)"
-SAMISCMAKEFLAGS+= SA_USE_CREAD=yes      # Read compressed kernels
-SAMISCMAKEFLAGS+= SA_INCLUDE_NET=no     # Netboot via TFTP, NFS
 
 ### find out what to use for libsa
 SA_AS= library
 SAMISCMAKEFLAGS+="SA_USE_LOADFILE=yes"
+SAMISCMAKEFLAGS+="SA_USE_CREAD=yes"
+SAMISCMAKEFLAGS+="SA_INCLUDE_NET=yes"
 SAMISCMAKEFLAGS+="SA_ENABLE_LS_OP=yes"
 .include "${S}/lib/libsa/Makefile.inc"
 LIBSA= ${SALIB}

Index: src/sys/arch/i386/stand/efiboot/boot.c
diff -u src/sys/arch/i386/stand/efiboot/boot.c:1.9 src/sys/arch/i386/stand/efiboot/boot.c:1.10
--- src/sys/arch/i386/stand/efiboot/boot.c:1.9	Mon Apr  2 09:44:18 2018
+++ src/sys/arch/i386/stand/efiboot/boot.c	Wed Apr 11 10:32:09 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: boot.c,v 1.9 2018/04/02 09:44:18 nonaka Exp $	*/
+/*	$NetBSD: boot.c,v 1.10 2018/04/11 10:32:09 nonaka Exp $	*/
 
 /*-
  * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org>
@@ -182,6 +182,21 @@ parsebootfile(const char *fname, char **
 }
 
 static char *
+snprint_bootdev(char *buf, size_t bufsize, const char *devname, int unit,
+    int partition)
+{
+	static const char *no_partition_devs[] = { "esp", "net", "nfs", "tftp" };
+	int i;
+
+	for (i = 0; i < __arraycount(no_partition_devs); i++)
+		if (strcmp(devname, no_partition_devs[i]) == 0)
+			break;
+	snprintf(buf, bufsize, "%s%d%c", devname, unit,
+	    i < __arraycount(no_partition_devs) ? '\0' : 'a' + partition);
+	return buf;
+}
+
+static char *
 sprint_bootsel(const char *filename)
 {
 	char *fsname, *devname;
@@ -191,8 +206,8 @@ sprint_bootsel(const char *filename)
 
 	if (parsebootfile(filename, &fsname, &devname, &unit,
 			  &partition, &file) == 0) {
-		snprintf(buf, sizeof(buf), "%s%d%c:%s", devname, unit,
-		    'a' + partition, file);
+		snprintf(buf, sizeof(buf), "%s:%s", snprint_bootdev(buf,
+		    sizeof(buf), devname, unit, partition), file);
 		return buf;
 	}
 	return "(invalid)";
@@ -276,7 +291,9 @@ boot(void)
 
 	if (!(boot_params.bp_flags & X86_BP_FLAGS_NOBOOTCONF)) {
 #ifdef EFIBOOTCFG_FILENAME
-		int rv = parsebootconf(EFIBOOTCFG_FILENAME);
+		int rv = EINVAL;
+		if (efi_bootdp_type != BOOT_DEVICE_TYPE_NET)
+			rv = parsebootconf(EFIBOOTCFG_FILENAME);
 		if (rv)
 #endif
 		parsebootconf(BOOTCFG_FILENAME);
@@ -421,13 +438,15 @@ void
 command_dev(char *arg)
 {
 	static char savedevname[MAXDEVNAME + 1];
+	char buf[80];
 	char *fsname, *devname;
 	const char *file; /* dummy */
 
 	if (*arg == '\0') {
 		efi_disk_show();
-		printf("default %s%d%c\n", default_devname, default_unit,
-		       'a' + default_partition);
+		efi_net_show();
+		printf("default %s\n", snprint_bootdev(buf, sizeof(buf),
+		    default_devname, default_unit, default_partition));
 		return;
 	}
 

Index: src/sys/arch/i386/stand/efiboot/conf.c
diff -u src/sys/arch/i386/stand/efiboot/conf.c:1.1 src/sys/arch/i386/stand/efiboot/conf.c:1.2
--- src/sys/arch/i386/stand/efiboot/conf.c:1.1	Tue Jan 24 11:09:14 2017
+++ src/sys/arch/i386/stand/efiboot/conf.c	Wed Apr 11 10:32:09 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: conf.c,v 1.1 2017/01/24 11:09:14 nonaka Exp $	 */
+/*	$NetBSD: conf.c,v 1.2 2018/04/11 10:32:09 nonaka Exp $	 */
 
 /*
  * Copyright (c) 1997
@@ -43,15 +43,52 @@
 #ifdef SUPPORT_CD9660
 #include <lib/libsa/cd9660.h>
 #endif
+#if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP)
+#include <lib/libsa/net.h>
+#include <lib/libsa/dev_net.h>
+#ifdef SUPPORT_NFS
+#include <lib/libsa/nfs.h>
+#endif
+#ifdef SUPPORT_TFTP
+#include <lib/libsa/tftp.h>
+#endif
+#endif
 #include <biosdisk.h>
+#include "efinet.h"
 
 struct devsw devsw[] = {
 	{ "disk", biosdisk_strategy, biosdisk_open, biosdisk_close, biosdisk_ioctl },
+	{ "net", net_strategy, net_open, net_close, net_ioctl },
 };
 int ndevs = __arraycount(devsw);
 
+#if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP)
+struct netif_driver *netif_drivers[] = {
+	&efinetif,
+};
+int n_netif_drivers = __arraycount(netif_drivers);
+#endif
+
 struct fs_ops file_system[] = {
 #ifdef SUPPORT_CD9660
+	FS_OPS(null),
+#endif
+	FS_OPS(null), FS_OPS(null),
+	FS_OPS(null), FS_OPS(null),
+#ifdef SUPPORT_EXT2FS
+	FS_OPS(null),
+#endif
+#ifdef SUPPORT_MINIXFS3
+	FS_OPS(null),
+#endif
+#ifdef SUPPORT_DOSFS
+	FS_OPS(null),
+#endif
+};
+int nfsys = __arraycount(file_system);
+
+struct fs_ops file_system_disk[] = {
+#ifdef SUPPORT_CD9660
 	FS_OPS(cd9660),
 #endif
 	FS_OPS(ffsv1), FS_OPS(ffsv2),
@@ -66,4 +103,13 @@ struct fs_ops file_system[] = {
 	FS_OPS(dosfs),
 #endif
 };
-int nfsys = __arraycount(file_system);
+__CTASSERT(__arraycount(file_system) == __arraycount(file_system_disk));
+const int nfsys_disk = __arraycount(file_system_disk);
+
+struct fs_ops file_system_null = FS_OPS(null);
+#ifdef SUPPORT_NFS
+struct fs_ops file_system_nfs = FS_OPS(nfs);
+#endif
+#ifdef SUPPORT_TFTP
+struct fs_ops file_system_tftp = FS_OPS(tftp);
+#endif

Index: src/sys/arch/i386/stand/efiboot/devopen.c
diff -u src/sys/arch/i386/stand/efiboot/devopen.c:1.4 src/sys/arch/i386/stand/efiboot/devopen.c:1.5
--- src/sys/arch/i386/stand/efiboot/devopen.c:1.4	Mon Apr  2 09:44:18 2018
+++ src/sys/arch/i386/stand/efiboot/devopen.c	Wed Apr 11 10:32:09 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: devopen.c,v 1.4 2018/04/02 09:44:18 nonaka Exp $	 */
+/*	$NetBSD: devopen.c,v 1.5 2018/04/11 10:32:09 nonaka Exp $	 */
 
 /*-
  * Copyright (c) 2005 The NetBSD Foundation, Inc.
@@ -56,6 +56,8 @@
 
 #include "efiboot.h"
 
+#include <lib/libsa/dev_net.h>
+
 #include <biosdisk.h>
 #include "devopen.h"
 #include <bootinfo.h>
@@ -81,7 +83,14 @@ bios2dev(int biosdev, daddr_t sector, ch
 
 	*unit = biosdev & 0x7f;
 
-	if (biosdev >= 0x80 + get_harddrives()) {
+	if (efi_bootdp_type == BOOT_DEVICE_TYPE_NET) {
+		*devname = "net";
+		*unit = efi_net_get_booted_interface_unit();
+		if (*unit < 0)
+			*unit = 0;
+		*partition = 0;
+		return;
+	} else if (biosdev >= 0x80 + get_harddrives()) {
 		*devname = "cd";
 		*unit -= get_harddrives();
 	} else
@@ -99,16 +108,90 @@ extern bool kernel_loaded;
 int
 devopen(struct open_file *f, const char *fname, char **file)
 {
+#if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP)
+	static const char *net_devnames[] = {
+#if defined(SUPPORT_NFS)
+	    "nfs",
+#endif
+#if defined(SUPPORT_TFTP)
+	    "tftp",
+#endif
+	};
+#endif
+	struct devdesc desc;
+	struct devsw *dev;
 	char *fsname, *devname;
 	int unit, partition;
 	int biosdev;
-	int error;
+	int i, n, error;
 
 	error = parsebootfile(fname, &fsname, &devname, &unit, &partition,
 	    (const char **) file);
 	if (error)
 		return error;
 
+	memcpy(file_system, file_system_disk, sizeof(*file_system) * nfsys);
+	nfsys = nfsys_disk;
+
+#if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP)
+	for (i = 0; i < __arraycount(net_devnames); i++) {
+		if (strcmp(devname, net_devnames[i]) == 0) {
+			fsname = devname;
+			devname = "net";
+			break;
+		}
+	}
+#endif
+
+	for (i = 1; i < ndevs; i++) {
+		dev = &devsw[i];
+		if (strcmp(devname, DEV_NAME(dev)) == 0) {
+			if (strcmp(devname, "net") == 0) {
+				n = 0;
+#if defined(SUPPORT_NFS)
+				if (strcmp(fsname, "nfs") == 0) {
+					memcpy(&file_system[n++], &file_system_nfs,
+					    sizeof(file_system_nfs));
+				} else
+#endif
+#if defined(SUPPORT_TFTP)
+				if (strcmp(fsname, "tftp") == 0) {
+					memcpy(&file_system[n++], &file_system_tftp,
+					    sizeof(file_system_tftp));
+				} else
+#endif
+				{
+#if defined(SUPPORT_NFS)
+					memcpy(&file_system[n++], &file_system_nfs,
+					    sizeof(file_system_nfs));
+#endif
+#if defined(SUPPORT_TFTP)
+					memcpy(&file_system[n++], &file_system_tftp,
+					    sizeof(file_system_tftp));
+#endif
+				}
+				nfsys = n;
+
+				try_bootp = 1;
+			}
+
+			memset(&desc, 0, sizeof(desc));
+			strlcpy(desc.d_name, devname, sizeof(desc.d_name));
+			desc.d_unit = unit;
+
+			f->f_dev = dev;
+			if (!kernel_loaded) {
+				strncpy(bibp.bootpath, *file,
+				    sizeof(bibp.bootpath));
+				BI_ADD(&bibp, BTINFO_BOOTPATH, sizeof(bibp));
+			}
+			return DEV_OPEN(f->f_dev)(f, &desc);
+		}
+	}
+
+	/*
+	 * biosdisk
+	 */
 	if (strcmp(devname, "esp") == 0) {
 		bios2dev(boot_biosdev, boot_biossector, &devname, &unit,
 		    &partition);

Index: src/sys/arch/i386/stand/efiboot/devopen.h
diff -u src/sys/arch/i386/stand/efiboot/devopen.h:1.2 src/sys/arch/i386/stand/efiboot/devopen.h:1.3
--- src/sys/arch/i386/stand/efiboot/devopen.h:1.2	Mon Apr  2 09:44:18 2018
+++ src/sys/arch/i386/stand/efiboot/devopen.h	Wed Apr 11 10:32:09 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: devopen.h,v 1.2 2018/04/02 09:44:18 nonaka Exp $	*/
+/*	$NetBSD: devopen.h,v 1.3 2018/04/11 10:32:09 nonaka Exp $	*/
 
 /*-
  * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org>
@@ -28,7 +28,17 @@
 
 extern int boot_biosdev;
 extern daddr_t boot_biossector;
+extern const int nfsys_disk;
+extern struct fs_ops file_system_disk[];
+extern struct fs_ops file_system_nfs;
+extern struct fs_ops file_system_tftp;
+extern struct fs_ops file_system_null;
 
 #define	MAXDEVNAME	16
 
 void bios2dev(int, daddr_t, char **, int *, int *);
+
+struct devdesc {
+	char	d_name[MAXDEVNAME];
+	char	d_unit;
+};

Index: src/sys/arch/i386/stand/efiboot/efiboot.c
diff -u src/sys/arch/i386/stand/efiboot/efiboot.c:1.6 src/sys/arch/i386/stand/efiboot/efiboot.c:1.7
--- src/sys/arch/i386/stand/efiboot/efiboot.c:1.6	Tue Mar 27 14:15:05 2018
+++ src/sys/arch/i386/stand/efiboot/efiboot.c	Wed Apr 11 10:32:09 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: efiboot.c,v 1.6 2018/03/27 14:15:05 nonaka Exp $	*/
+/*	$NetBSD: efiboot.c,v 1.7 2018/04/11 10:32:09 nonaka Exp $	*/
 
 /*-
  * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org>
@@ -34,7 +34,7 @@
 
 EFI_HANDLE IH;
 EFI_DEVICE_PATH *efi_bootdp;
-int efi_bootdp_type = BIOSDISK_TYPE_HD;
+enum efi_boot_device_type efi_bootdp_type = BOOT_DEVICE_TYPE_HD;
 EFI_LOADED_IMAGE *efi_li;
 uintptr_t efi_main_sp;
 physaddr_t efi_loadaddr, efi_kernel_start;
@@ -79,12 +79,19 @@ efi_main(EFI_HANDLE imageHandle, EFI_SYS
 	for (dp = dp0; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp)) {
 		if (DevicePathType(dp) == MEDIA_DEVICE_PATH &&
 		    DevicePathSubType(dp) == MEDIA_CDROM_DP) {
-			efi_bootdp_type = BIOSDISK_TYPE_CD;
+			efi_bootdp_type = BOOT_DEVICE_TYPE_CD;
+			break;
+		}
+		if (DevicePathType(dp) == MESSAGING_DEVICE_PATH &&
+		    DevicePathSubType(dp) == MSG_MAC_ADDR_DP) {
+			efi_bootdp_type = BOOT_DEVICE_TYPE_NET;
 			break;
 		}
 	}
 
 	efi_disk_probe();
+	efi_pxe_probe();
+	efi_net_probe();
 
 	status = uefi_call_wrapper(BS->SetWatchdogTimer, 4, 0, 0, 0, NULL);
 	if (EFI_ERROR(status))

Index: src/sys/arch/i386/stand/efiboot/efiboot.h
diff -u src/sys/arch/i386/stand/efiboot/efiboot.h:1.7 src/sys/arch/i386/stand/efiboot/efiboot.h:1.8
--- src/sys/arch/i386/stand/efiboot/efiboot.h:1.7	Tue Mar 27 14:15:05 2018
+++ src/sys/arch/i386/stand/efiboot/efiboot.h	Wed Apr 11 10:32:09 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: efiboot.h,v 1.7 2018/03/27 14:15:05 nonaka Exp $	*/
+/*	$NetBSD: efiboot.h,v 1.8 2018/04/11 10:32:09 nonaka Exp $	*/
 
 /*-
  * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org>
@@ -46,7 +46,11 @@ void print_banner(void);
 /* efiboot.c */
 extern EFI_HANDLE IH;
 extern EFI_DEVICE_PATH *efi_bootdp;
-extern int efi_bootdp_type;
+extern enum efi_boot_device_type {
+	BOOT_DEVICE_TYPE_HD,
+	BOOT_DEVICE_TYPE_CD,
+	BOOT_DEVICE_TYPE_NET
+} efi_bootdp_type;
 extern EFI_LOADED_IMAGE *efi_li;
 extern uintptr_t efi_main_sp;
 extern physaddr_t efi_loadaddr, efi_kernel_start;
@@ -80,5 +84,15 @@ void efi_memory_show_map(bool);
 EFI_MEMORY_DESCRIPTOR *efi_memory_get_map(UINTN *, UINTN *, UINTN *, UINT32 *,
     bool);
 
+/* efinet.c */
+void efi_net_probe(void);
+void efi_net_show(void);
+int efi_net_get_booted_interface_unit(void);
+
+/* efipxe.c */
+void efi_pxe_probe(void);
+void efi_pxe_show(void);
+bool efi_pxe_match_booted_interface(const EFI_MAC_ADDRESS *, UINT32);
+
 /* panic.c */
 __dead VOID Panic(IN CHAR16 *, ...);

Index: src/sys/arch/i386/stand/efiboot/efidisk.c
diff -u src/sys/arch/i386/stand/efiboot/efidisk.c:1.5 src/sys/arch/i386/stand/efiboot/efidisk.c:1.6
--- src/sys/arch/i386/stand/efiboot/efidisk.c:1.5	Mon Apr  2 09:44:18 2018
+++ src/sys/arch/i386/stand/efiboot/efidisk.c	Wed Apr 11 10:32:09 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: efidisk.c,v 1.5 2018/04/02 09:44:18 nonaka Exp $	*/
+/*	$NetBSD: efidisk.c,v 1.6 2018/04/11 10:32:09 nonaka Exp $	*/
 
 /*-
  * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org>
@@ -107,7 +107,7 @@ next:
 
 	FreePool(handles);
 
-	if (efi_bootdp_type == BIOSDISK_TYPE_CD) {
+	if (efi_bootdp_type == BOOT_DEVICE_TYPE_CD) {
 		edi = TAILQ_FIRST(&efi_disklist);
 		if (edi != NULL && edi->bootdev) {
 			edi->type = BIOSDISK_TYPE_CD;

Added files:

Index: src/sys/arch/i386/stand/efiboot/dev_net.c
diff -u /dev/null src/sys/arch/i386/stand/efiboot/dev_net.c:1.1
--- /dev/null	Wed Apr 11 10:32:10 2018
+++ src/sys/arch/i386/stand/efiboot/dev_net.c	Wed Apr 11 10:32:09 2018
@@ -0,0 +1,3 @@
+/*	$NetBSD: dev_net.c,v 1.1 2018/04/11 10:32:09 nonaka Exp $	*/
+
+#include <lib/libsa/dev_net.c>
Index: src/sys/arch/i386/stand/efiboot/efinet.c
diff -u /dev/null src/sys/arch/i386/stand/efiboot/efinet.c:1.1
--- /dev/null	Wed Apr 11 10:32:10 2018
+++ src/sys/arch/i386/stand/efiboot/efinet.c	Wed Apr 11 10:32:09 2018
@@ -0,0 +1,480 @@
+/*	$NetBSD: efinet.c,v 1.1 2018/04/11 10:32:09 nonaka Exp $	*/
+
+/*-
+ * Copyright (c) 2001 Doug Rabson
+ * Copyright (c) 2002, 2006 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+__FBSDID("$FreeBSD: head/stand/efi/libefi/efinet.c 321621 2017-07-27 15:06:34Z andrew $");
+#endif
+
+#include "efiboot.h"
+
+#include <lib/libsa/net.h>
+#include <lib/libsa/netif.h>
+
+#include <bootinfo.h>
+#include "devopen.h"
+
+#ifndef ETHER_ALIGN
+#define ETHER_ALIGN	2
+#endif
+
+#define ETHER_EXT_LEN	(ETHER_HDR_LEN + ETHER_CRC_LEN + ETHER_ALIGN)
+
+#if defined(DEBUG) || defined(ARP_DEBUG) || defined(BOOTP_DEBUG) || \
+    defined(NET_DEBUG) || defined(NETIF_DEBUG) || defined(NFS_DEBUG) || \
+    defined(RARP_DEBUG) || defined(RPC_DEBUG)
+int debug = 1;
+#else
+int debug = 0;
+#endif
+
+extern bool kernel_loaded;
+
+struct efinetinfo {
+	EFI_SIMPLE_NETWORK *net;
+	bool bootdev;
+	size_t pktbufsz;
+	UINT8 *pktbuf;
+	struct {
+		int type;
+		u_int tag;
+	} bus;
+};
+static struct btinfo_netif bi_netif;
+
+static int	efinet_match(struct netif *, void *);
+static int	efinet_probe(struct netif *, void *);
+static void	efinet_init(struct iodesc *, void *);
+static int	efinet_get(struct iodesc *, void *, size_t, saseconds_t);
+static int	efinet_put(struct iodesc *, void *, size_t);
+static void	efinet_end(struct netif *);
+
+struct netif_driver efinetif = {
+	.netif_bname = "net",
+	.netif_match = efinet_match,
+	.netif_probe = efinet_probe,
+	.netif_init = efinet_init,
+	.netif_get = efinet_get,
+	.netif_put = efinet_put,
+	.netif_end = efinet_end,
+	.netif_ifs = NULL,
+	.netif_nifs = 0
+};
+
+#ifdef EFINET_DEBUG
+static void
+dump_mode(EFI_SIMPLE_NETWORK_MODE *mode)
+{
+	int i;
+
+	printf("State                 = %x\n", mode->State);
+	printf("HwAddressSize         = %u\n", mode->HwAddressSize);
+	printf("MediaHeaderSize       = %u\n", mode->MediaHeaderSize);
+	printf("MaxPacketSize         = %u\n", mode->MaxPacketSize);
+	printf("NvRamSize             = %u\n", mode->NvRamSize);
+	printf("NvRamAccessSize       = %u\n", mode->NvRamAccessSize);
+	printf("ReceiveFilterMask     = %x\n", mode->ReceiveFilterMask);
+	printf("ReceiveFilterSetting  = %u\n", mode->ReceiveFilterSetting);
+	printf("MaxMCastFilterCount   = %u\n", mode->MaxMCastFilterCount);
+	printf("MCastFilterCount      = %u\n", mode->MCastFilterCount);
+	printf("MCastFilter           = {");
+	for (i = 0; i < mode->MCastFilterCount; i++)
+		printf(" %s", ether_sprintf(mode->MCastFilter[i].Addr));
+	printf(" }\n");
+	printf("CurrentAddress        = %s\n",
+	    ether_sprintf(mode->CurrentAddress.Addr));
+	printf("BroadcastAddress      = %s\n",
+	    ether_sprintf(mode->BroadcastAddress.Addr));
+	printf("PermanentAddress      = %s\n",
+	    ether_sprintf(mode->PermanentAddress.Addr));
+	printf("IfType                = %u\n", mode->IfType);
+	printf("MacAddressChangeable  = %d\n", mode->MacAddressChangeable);
+	printf("MultipleTxSupported   = %d\n", mode->MultipleTxSupported);
+	printf("MediaPresentSupported = %d\n", mode->MediaPresentSupported);
+	printf("MediaPresent          = %d\n", mode->MediaPresent);
+}
+#endif
+
+static int
+efinet_match(struct netif *nif, void *machdep_hint)
+{
+	struct devdesc *dev = machdep_hint;
+
+	if (dev->d_unit != nif->nif_unit)
+		return 0;
+
+	return 1;
+}
+
+static int
+efinet_probe(struct netif *nif, void *machdep_hint)
+{
+
+	return 0;
+}
+
+static int
+efinet_put(struct iodesc *desc, void *pkt, size_t len)
+{
+	struct netif *nif = desc->io_netif;
+	struct efinetinfo *eni = nif->nif_devdata;
+	EFI_SIMPLE_NETWORK *net;
+	EFI_STATUS status;
+	void *buf;
+
+	if (eni == NULL)
+		return -1;
+	net = eni->net;
+
+	status = uefi_call_wrapper(net->Transmit, 7, net, 0, (UINTN)len, pkt, NULL,
+	    NULL, NULL);
+	if (EFI_ERROR(status))
+		return -1;
+
+	/* Wait for the buffer to be transmitted */
+	do {
+		buf = NULL;	/* XXX Is this needed? */
+		status = uefi_call_wrapper(net->GetStatus, 3, net, NULL, &buf);
+		/*
+		 * XXX EFI1.1 and the E1000 card returns a different
+		 * address than we gave.  Sigh.
+		 */
+	} while (!EFI_ERROR(status) && buf == NULL);
+
+	/* XXX How do we deal with status != EFI_SUCCESS now? */
+	return EFI_ERROR(status) ? -1 : len;
+}
+
+static int
+efinet_get(struct iodesc *desc, void *pkt, size_t len, saseconds_t timeout)
+{
+	struct netif *nif = desc->io_netif;
+	struct efinetinfo *eni = nif->nif_devdata;
+	EFI_SIMPLE_NETWORK *net;
+	EFI_STATUS status;
+	UINTN bufsz, rsz;
+	time_t t;
+	char *buf, *ptr;
+	int ret = -1;
+
+	if (eni == NULL)
+		return -1;
+	net = eni->net;
+
+	if (eni->pktbufsz < net->Mode->MaxPacketSize + ETHER_EXT_LEN) {
+		bufsz = net->Mode->MaxPacketSize + ETHER_EXT_LEN;
+		buf = alloc(bufsz);
+		if (buf == NULL)
+			return -1;
+		dealloc(eni->pktbuf, eni->pktbufsz);
+		eni->pktbufsz = bufsz;
+		eni->pktbuf = buf;
+	}
+	ptr = eni->pktbuf + ETHER_ALIGN;
+
+	t = getsecs();
+	while ((getsecs() - t) < timeout) {
+		rsz = eni->pktbufsz;
+		status = uefi_call_wrapper(net->Receive, 7, net, NULL, &rsz, ptr,
+		    NULL, NULL, NULL);
+		if (!EFI_ERROR(status)) {
+			rsz = min(rsz, len);
+			memcpy(pkt, ptr, rsz);
+			ret = (int)rsz;
+			break;
+		}
+		if (status != EFI_NOT_READY)
+			break;
+	}
+
+	return ret;
+}
+
+static void
+efinet_init(struct iodesc *desc, void *machdep_hint)
+{
+	struct netif *nif = desc->io_netif;
+	struct efinetinfo *eni;
+	EFI_SIMPLE_NETWORK *net;
+	EFI_STATUS status;
+	UINT32 mask;
+
+	if (nif->nif_driver->netif_ifs[nif->nif_unit].dif_unit < 0) {
+		printf("Invalid network interface %d\n", nif->nif_unit);
+		return;
+	}
+
+	eni = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private;
+	nif->nif_devdata = eni;
+	net = eni->net;
+	if (net->Mode->State == EfiSimpleNetworkStopped) {
+		status = uefi_call_wrapper(net->Start, 1, net);
+		if (EFI_ERROR(status)) {
+			printf("net%d: cannot start interface (status=%"
+			    PRIxMAX ")\n", nif->nif_unit, (uintmax_t)status);
+			return;
+		}
+	}
+
+	if (net->Mode->State != EfiSimpleNetworkInitialized) {
+		status = uefi_call_wrapper(net->Initialize, 3, net, 0, 0);
+		if (EFI_ERROR(status)) {
+			printf("net%d: cannot init. interface (status=%"
+			    PRIxMAX ")\n", nif->nif_unit, (uintmax_t)status);
+			return;
+		}
+	}
+
+	mask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
+	    EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
+
+	status = uefi_call_wrapper(net->ReceiveFilters, 6, net, mask, 0, FALSE,
+	    0, NULL);
+	if (EFI_ERROR(status)) {
+		printf("net%d: cannot set rx. filters (status=%" PRIxMAX ")\n",
+		    nif->nif_unit, (uintmax_t)status);
+		return;
+	}
+
+	if (!kernel_loaded) {
+		bi_netif.bus = eni->bus.type;
+		bi_netif.addr.tag = eni->bus.tag;
+		snprintf(bi_netif.ifname, sizeof(bi_netif.ifname), "net%d",
+		    nif->nif_unit);
+		BI_ADD(&bi_netif, BTINFO_NETIF, sizeof(bi_netif));
+	}
+
+#ifdef EFINET_DEBUG
+	dump_mode(net->Mode);
+#endif
+
+	memcpy(desc->myea, net->Mode->CurrentAddress.Addr, 6);
+	desc->xid = 1;
+}
+
+static void
+efinet_end(struct netif *nif)
+{
+	struct efinetinfo *eni = nif->nif_devdata;
+	EFI_SIMPLE_NETWORK *net;
+
+	if (eni == NULL)
+		return;
+	net = eni->net;
+
+	uefi_call_wrapper(net->Shutdown, 1, net);
+}
+
+static bool
+efi_net_pci_probe(struct efinetinfo *eni, EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *pdp)
+{
+	PCI_DEVICE_PATH *pci = (PCI_DEVICE_PATH *)dp;
+	int bus = -1;
+
+	if (pdp != NULL &&
+	    DevicePathType(pdp) == ACPI_DEVICE_PATH &&
+	    (DevicePathSubType(pdp) == ACPI_DP ||
+	     DevicePathSubType(pdp) == EXPANDED_ACPI_DP)) {
+		ACPI_HID_DEVICE_PATH *acpi = (ACPI_HID_DEVICE_PATH *)pdp;
+		/* PCI root bus */
+		if (acpi->HID == EISA_PNP_ID(0x0A08) ||
+		    acpi->HID == EISA_PNP_ID(0x0A03)) {
+			bus = acpi->UID;
+		}
+	}
+	if (bus < 0)
+		return false;
+
+	eni->bus.type = BI_BUS_PCI;
+	eni->bus.tag = (bus & 0xff) << 8;
+	eni->bus.tag |= (pci->Device & 0x1f) << 3;
+	eni->bus.tag |= pci->Function & 0x7;
+	return true;
+}
+
+void
+efi_net_probe(void)
+{
+	struct efinetinfo *enis;
+	struct netif_dif *dif;
+	struct netif_stats *stats;
+	EFI_DEVICE_PATH *dp0, *dp, *pdp;
+	EFI_SIMPLE_NETWORK *net;
+	EFI_HANDLE *handles;
+	EFI_STATUS status;
+	UINTN i, nhandles;
+	int nifs;
+	bool found;
+
+	status = LibLocateHandle(ByProtocol, &SimpleNetworkProtocol, NULL,
+	    &nhandles, &handles);
+	if (EFI_ERROR(status) || nhandles == 0)
+		return;
+
+	enis = alloc(nhandles * sizeof(*enis));
+	if (enis == NULL)
+		return;
+	memset(enis, 0, nhandles * sizeof(*enis));
+
+	nifs = 0;
+	for (i = 0; i < nhandles; i++) {
+		status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i],
+		    &DevicePathProtocol, (void **)&dp0);
+		if (EFI_ERROR(status))
+			continue;
+
+		found = false;
+		for (dp = dp0; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp)) {
+			if (DevicePathType(dp) == MESSAGING_DEVICE_PATH &&
+			    DevicePathSubType(dp) == MSG_MAC_ADDR_DP) {
+				found = true;
+				break;
+			}
+		}
+		if (!found)
+			continue;
+
+		status = uefi_call_wrapper(BS->OpenProtocol, 6, handles[i],
+		    &SimpleNetworkProtocol, (void **)&net, IH, NULL,
+		    EFI_OPEN_PROTOCOL_EXCLUSIVE);
+		if (EFI_ERROR(status)) {
+			printf("Unable to open network interface %" PRIuMAX
+			    " for exclusive access: %" PRIxMAX "\n",
+			    (uintmax_t)i, (uintmax_t)status);
+		}
+
+		found = false;
+		for (pdp = NULL, dp = dp0;
+		    !IsDevicePathEnd(dp);
+		    pdp = dp, dp = NextDevicePathNode(dp)) {
+			if (DevicePathType(dp) == HARDWARE_DEVICE_PATH) {
+				if (DevicePathSubType(dp) == HW_PCI_DP)
+					found = efi_net_pci_probe(&enis[nifs],
+					    dp, pdp);
+				break;
+			}
+		}
+		if (found) {
+			enis[nifs].net = net;
+			enis[nifs].bootdev = efi_pxe_match_booted_interface(
+			    &net->Mode->CurrentAddress, net->Mode->HwAddressSize);
+			enis[nifs].pktbufsz = net->Mode->MaxPacketSize +
+			    ETHER_EXT_LEN;
+			enis[nifs].pktbuf = alloc(enis[nifs].pktbufsz);
+			if (enis[nifs].pktbuf == NULL) {
+				while (i-- > 0) {
+					dealloc(enis[i].pktbuf, enis[i].pktbufsz);
+					if (i == 0)
+						break;
+				}
+				dealloc(enis, nhandles * sizeof(*enis));
+				FreePool(handles);
+				return;
+			}
+			nifs++;
+		}
+	}
+
+	FreePool(handles);
+
+	if (nifs == 0)
+		return;
+
+	efinetif.netif_ifs = alloc(nifs * sizeof(*dif));
+	stats = alloc(nifs * sizeof(*stats));
+	if (efinetif.netif_ifs == NULL || stats == NULL) {
+		if (efinetif.netif_ifs != NULL) {
+			dealloc(efinetif.netif_ifs, nifs * sizeof(*dif));
+			efinetif.netif_ifs = NULL;
+		}
+		if (stats != NULL)
+			dealloc(stats, nifs * sizeof(*stats));
+		for (i = 0; i < nifs; i++)
+			dealloc(enis[i].pktbuf, enis[i].pktbufsz);
+		dealloc(enis, nhandles * sizeof(*enis));
+		return;
+	}
+	memset(efinetif.netif_ifs, 0, nifs * sizeof(*dif));
+	memset(stats, 0, nifs * sizeof(*stats));
+	efinetif.netif_nifs = nifs;
+
+	for (i = 0; i < nifs; i++) {
+		dif = &efinetif.netif_ifs[i];
+		dif->dif_unit = i;
+		dif->dif_nsel = 1;
+		dif->dif_stats = &stats[i];
+		dif->dif_private = &enis[i];
+	}
+}
+
+void
+efi_net_show(void)
+{
+	const struct netif_dif *dif;
+	const struct efinetinfo *eni;
+	EFI_SIMPLE_NETWORK *net;
+	int i;
+
+	for (i = 0; i < efinetif.netif_nifs; i++) {
+		dif = &efinetif.netif_ifs[i];
+		eni = dif->dif_private;
+		net = eni->net;
+
+		printf("net net%d", dif->dif_unit);
+		if (net->Mode != NULL) {
+			for (UINT32 x = 0; x < net->Mode->HwAddressSize; x++) {
+				printf("%c%02x", x == 0 ? ' ' : ':',
+				    net->Mode->CurrentAddress.Addr[x]);
+			}
+		}
+		if (eni->bus.type == BI_BUS_PCI) {
+			printf(" pci%d,%d,%d", (eni->bus.tag >> 8) & 0xff,
+			    (eni->bus.tag >> 3) & 0x1f, eni->bus.tag & 0x7);
+		}
+		if (eni->bootdev)
+			printf(" pxeboot");
+		printf("\n");
+	}
+}
+
+int
+efi_net_get_booted_interface_unit(void)
+{
+	const struct netif_dif *dif;
+	const struct efinetinfo *eni;
+	int i;
+
+	for (i = 0; i < efinetif.netif_nifs; i++) {
+		dif = &efinetif.netif_ifs[i];
+		eni = dif->dif_private;
+		if (eni->bootdev)
+			return dif->dif_unit;
+	}
+	return -1;
+}
Index: src/sys/arch/i386/stand/efiboot/efinet.h
diff -u /dev/null src/sys/arch/i386/stand/efiboot/efinet.h:1.1
--- /dev/null	Wed Apr 11 10:32:10 2018
+++ src/sys/arch/i386/stand/efiboot/efinet.h	Wed Apr 11 10:32:09 2018
@@ -0,0 +1,29 @@
+/*	$NetBSD: efinet.h,v 1.1 2018/04/11 10:32:09 nonaka Exp $	*/
+
+/*-
+ * Copyright (c) 2018 Kimihiro Nonaka <non...@netbsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+extern struct netif_driver efinetif;
Index: src/sys/arch/i386/stand/efiboot/efipxe.c
diff -u /dev/null src/sys/arch/i386/stand/efiboot/efipxe.c:1.1
--- /dev/null	Wed Apr 11 10:32:10 2018
+++ src/sys/arch/i386/stand/efiboot/efipxe.c	Wed Apr 11 10:32:09 2018
@@ -0,0 +1,141 @@
+/*	$NetBSD: efipxe.c,v 1.1 2018/04/11 10:32:09 nonaka Exp $	*/
+/*	$OpenBSD: efipxe.c,v 1.3 2018/01/30 20:19:06 naddy Exp $	*/
+
+/*
+ * Copyright (c) 2017 Patrick Wildt <patr...@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/queue.h>
+
+#include "efiboot.h"
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <lib/libsa/bootp.h>	/* for VM_RFC1048 */
+
+
+struct efipxeinfo {
+	TAILQ_ENTRY(efipxeinfo)	list;
+
+	EFI_PXE_BASE_CODE	*pxe;
+	EFI_SIMPLE_NETWORK	*net;
+	EFI_MAC_ADDRESS		mac;
+	UINT32			addrsz;
+};
+TAILQ_HEAD(efipxeinfo_lh, efipxeinfo);
+static struct efipxeinfo_lh efi_pxelist;
+static int nefipxes;
+
+void
+efi_pxe_probe(void)
+{
+	struct efipxeinfo *epi;
+	EFI_PXE_BASE_CODE *pxe;
+	EFI_DEVICE_PATH *dp;
+	EFI_SIMPLE_NETWORK *net;
+	EFI_HANDLE *handles;
+	EFI_STATUS status;
+	UINTN nhandles;
+	int i, depth;
+	bool found;
+
+	TAILQ_INIT(&efi_pxelist);
+
+        status = LibLocateHandle(ByProtocol, &PxeBaseCodeProtocol, NULL,
+	    &nhandles, &handles);
+	if (EFI_ERROR(status))
+		return;
+
+	for (i = 0; i < nhandles; i++) {
+		status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i],
+		    &DevicePathProtocol, (void **)&dp);
+		if (EFI_ERROR(status))
+			continue;
+
+		depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH);
+		if (efi_device_path_ncmp(efi_bootdp, dp, depth))
+			continue;
+
+		status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i],
+		    &PxeBaseCodeProtocol, (void **)&pxe);
+		if (EFI_ERROR(status))
+			continue;
+
+		if (pxe->Mode == NULL ||
+		    (!pxe->Mode->DhcpAckReceived && !pxe->Mode->PxeReplyReceived))
+			continue;
+
+		status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i],
+		    &SimpleNetworkProtocol, (void **)&net);
+		if (EFI_ERROR(status))
+			continue;
+
+		if (net->Mode == NULL)
+			continue;
+
+		found = false;
+		TAILQ_FOREACH(epi, &efi_pxelist, list) {
+			if (net->Mode->HwAddressSize == epi->addrsz &&
+			    memcmp(net->Mode->CurrentAddress.Addr, epi->mac.Addr,
+			      net->Mode->HwAddressSize) == 0) {
+				found = true;
+				break;
+			}
+		}
+		if (found)
+			continue;
+
+		epi = alloc(sizeof(*epi));
+		if (epi == NULL)
+			continue;
+
+		memset(epi, 0, sizeof(*epi));
+		epi->pxe = pxe;
+		epi->net = net;
+		epi->addrsz = net->Mode->HwAddressSize;
+		memcpy(epi->mac.Addr, net->Mode->CurrentAddress.Addr, epi->addrsz);
+
+		TAILQ_INSERT_TAIL(&efi_pxelist, epi, list);
+		nefipxes++;
+	}
+}
+
+void
+efi_pxe_show(void)
+{
+	const struct efipxeinfo *epi;
+	UINT32 i, n;
+
+	n = 0;
+	TAILQ_FOREACH(epi, &efi_pxelist, list) {
+		printf("pxe pxe%d", n++);
+		for (i = 0; i < epi->addrsz; i++)
+			printf("%c%02x", i == 0 ? ' ' : ':', epi->mac.Addr[i]);
+		printf("\n");
+	}
+}
+
+bool
+efi_pxe_match_booted_interface(const EFI_MAC_ADDRESS *mac, UINT32 addrsz)
+{
+	const struct efipxeinfo *epi;
+
+	TAILQ_FOREACH(epi, &efi_pxelist, list) {
+		if (addrsz == epi->addrsz &&
+		    memcmp(mac->Addr, epi->mac.Addr, addrsz) == 0)
+			return true;
+	}
+	return false;
+}

Reply via email to