xref: /netbsd-src/sys/stand/efiboot/efinet.c (revision 71d224f4ab9b1138f061928df297156f39c5052c)
1*71d224f4Srin /*	$NetBSD: efinet.c,v 1.9 2024/01/01 13:38:57 rin Exp $	*/
213f5d069Sjmcneill 
313f5d069Sjmcneill /*-
413f5d069Sjmcneill  * Copyright (c) 2001 Doug Rabson
513f5d069Sjmcneill  * Copyright (c) 2002, 2006 Marcel Moolenaar
613f5d069Sjmcneill  * All rights reserved.
713f5d069Sjmcneill  *
813f5d069Sjmcneill  * Redistribution and use in source and binary forms, with or without
913f5d069Sjmcneill  * modification, are permitted provided that the following conditions
1013f5d069Sjmcneill  * are met:
1113f5d069Sjmcneill  * 1. Redistributions of source code must retain the above copyright
1213f5d069Sjmcneill  *    notice, this list of conditions and the following disclaimer.
1313f5d069Sjmcneill  * 2. Redistributions in binary form must reproduce the above copyright
1413f5d069Sjmcneill  *    notice, this list of conditions and the following disclaimer in the
1513f5d069Sjmcneill  *    documentation and/or other materials provided with the distribution.
1613f5d069Sjmcneill  *
1713f5d069Sjmcneill  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1813f5d069Sjmcneill  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1913f5d069Sjmcneill  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2013f5d069Sjmcneill  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2113f5d069Sjmcneill  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2213f5d069Sjmcneill  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2313f5d069Sjmcneill  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2413f5d069Sjmcneill  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2513f5d069Sjmcneill  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2613f5d069Sjmcneill  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2713f5d069Sjmcneill  * SUCH DAMAGE.
2813f5d069Sjmcneill  */
2913f5d069Sjmcneill 
3013f5d069Sjmcneill #include <sys/cdefs.h>
3196816df7Sjmcneill #include <sys/param.h>
3213f5d069Sjmcneill 
3313f5d069Sjmcneill #include "efiboot.h"
3413f5d069Sjmcneill 
3513f5d069Sjmcneill #include <lib/libsa/net.h>
3613f5d069Sjmcneill #include <lib/libsa/netif.h>
3713f5d069Sjmcneill #include <lib/libsa/dev_net.h>
3813f5d069Sjmcneill 
3913f5d069Sjmcneill #include "devopen.h"
4013f5d069Sjmcneill 
4113f5d069Sjmcneill #define ETHER_EXT_LEN	(ETHER_HDR_LEN + ETHER_CRC_LEN + ETHER_ALIGN)
4213f5d069Sjmcneill 
4313f5d069Sjmcneill #if defined(DEBUG) || defined(ARP_DEBUG) || defined(BOOTP_DEBUG) || \
4413f5d069Sjmcneill     defined(NET_DEBUG) || defined(NETIF_DEBUG) || defined(NFS_DEBUG) || \
4513f5d069Sjmcneill     defined(RARP_DEBUG) || defined(RPC_DEBUG)
4613f5d069Sjmcneill int debug = 1;
4713f5d069Sjmcneill #else
4813f5d069Sjmcneill int debug = 0;
4913f5d069Sjmcneill #endif
5013f5d069Sjmcneill 
5113f5d069Sjmcneill extern bool kernel_loaded;
5213f5d069Sjmcneill 
5313f5d069Sjmcneill struct efinetinfo {
5413f5d069Sjmcneill 	EFI_SIMPLE_NETWORK *net;
5513f5d069Sjmcneill 	bool bootdev;
5613f5d069Sjmcneill 	size_t pktbufsz;
5713f5d069Sjmcneill 	UINT8 *pktbuf;
5813f5d069Sjmcneill 	struct {
5913f5d069Sjmcneill 		int type;
6013f5d069Sjmcneill 		u_int tag;
6113f5d069Sjmcneill 	} bus;
6213f5d069Sjmcneill };
6313f5d069Sjmcneill #if notyet
6413f5d069Sjmcneill static struct btinfo_netif bi_netif;
6513f5d069Sjmcneill #endif
6613f5d069Sjmcneill 
6713f5d069Sjmcneill static int	efinet_match(struct netif *, void *);
6813f5d069Sjmcneill static int	efinet_probe(struct netif *, void *);
6913f5d069Sjmcneill static void	efinet_init(struct iodesc *, void *);
7013f5d069Sjmcneill static int	efinet_get(struct iodesc *, void *, size_t, saseconds_t);
7113f5d069Sjmcneill static int	efinet_put(struct iodesc *, void *, size_t);
7213f5d069Sjmcneill static void	efinet_end(struct netif *);
7313f5d069Sjmcneill 
7413f5d069Sjmcneill struct netif_driver efinetif = {
7513f5d069Sjmcneill 	.netif_bname = "net",
7613f5d069Sjmcneill 	.netif_match = efinet_match,
7713f5d069Sjmcneill 	.netif_probe = efinet_probe,
7813f5d069Sjmcneill 	.netif_init = efinet_init,
7913f5d069Sjmcneill 	.netif_get = efinet_get,
8013f5d069Sjmcneill 	.netif_put = efinet_put,
8113f5d069Sjmcneill 	.netif_end = efinet_end,
8213f5d069Sjmcneill 	.netif_ifs = NULL,
8313f5d069Sjmcneill 	.netif_nifs = 0
8413f5d069Sjmcneill };
8513f5d069Sjmcneill 
8613f5d069Sjmcneill #ifdef EFINET_DEBUG
8713f5d069Sjmcneill static void
dump_mode(EFI_SIMPLE_NETWORK_MODE * mode)8813f5d069Sjmcneill dump_mode(EFI_SIMPLE_NETWORK_MODE *mode)
8913f5d069Sjmcneill {
9013f5d069Sjmcneill 	int i;
9113f5d069Sjmcneill 
9213f5d069Sjmcneill 	printf("State                 = %x\n", mode->State);
9313f5d069Sjmcneill 	printf("HwAddressSize         = %u\n", mode->HwAddressSize);
9413f5d069Sjmcneill 	printf("MediaHeaderSize       = %u\n", mode->MediaHeaderSize);
9513f5d069Sjmcneill 	printf("MaxPacketSize         = %u\n", mode->MaxPacketSize);
9613f5d069Sjmcneill 	printf("NvRamSize             = %u\n", mode->NvRamSize);
9713f5d069Sjmcneill 	printf("NvRamAccessSize       = %u\n", mode->NvRamAccessSize);
9813f5d069Sjmcneill 	printf("ReceiveFilterMask     = %x\n", mode->ReceiveFilterMask);
9913f5d069Sjmcneill 	printf("ReceiveFilterSetting  = %u\n", mode->ReceiveFilterSetting);
10013f5d069Sjmcneill 	printf("MaxMCastFilterCount   = %u\n", mode->MaxMCastFilterCount);
10113f5d069Sjmcneill 	printf("MCastFilterCount      = %u\n", mode->MCastFilterCount);
10213f5d069Sjmcneill 	printf("MCastFilter           = {");
10313f5d069Sjmcneill 	for (i = 0; i < mode->MCastFilterCount; i++)
10413f5d069Sjmcneill 		printf(" %s", ether_sprintf(mode->MCastFilter[i].Addr));
10513f5d069Sjmcneill 	printf(" }\n");
10613f5d069Sjmcneill 	printf("CurrentAddress        = %s\n",
10713f5d069Sjmcneill 	    ether_sprintf(mode->CurrentAddress.Addr));
10813f5d069Sjmcneill 	printf("BroadcastAddress      = %s\n",
10913f5d069Sjmcneill 	    ether_sprintf(mode->BroadcastAddress.Addr));
11013f5d069Sjmcneill 	printf("PermanentAddress      = %s\n",
11113f5d069Sjmcneill 	    ether_sprintf(mode->PermanentAddress.Addr));
11213f5d069Sjmcneill 	printf("IfType                = %u\n", mode->IfType);
11313f5d069Sjmcneill 	printf("MacAddressChangeable  = %d\n", mode->MacAddressChangeable);
11413f5d069Sjmcneill 	printf("MultipleTxSupported   = %d\n", mode->MultipleTxSupported);
11513f5d069Sjmcneill 	printf("MediaPresentSupported = %d\n", mode->MediaPresentSupported);
11613f5d069Sjmcneill 	printf("MediaPresent          = %d\n", mode->MediaPresent);
11713f5d069Sjmcneill }
11813f5d069Sjmcneill #endif
11913f5d069Sjmcneill 
120d26a1212Sjmcneill static const EFI_MAC_ADDRESS *
efinet_hwaddr(const EFI_SIMPLE_NETWORK_MODE * mode)121d26a1212Sjmcneill efinet_hwaddr(const EFI_SIMPLE_NETWORK_MODE *mode)
122d26a1212Sjmcneill {
123d26a1212Sjmcneill 	int valid, n;
124d26a1212Sjmcneill 
125d26a1212Sjmcneill 	for (valid = 0, n = 0; n < mode->HwAddressSize; n++)
126d26a1212Sjmcneill 		if (mode->CurrentAddress.Addr[n] != 0x00) {
127d26a1212Sjmcneill 			valid = true;
128d26a1212Sjmcneill 			break;
129d26a1212Sjmcneill 		}
130d26a1212Sjmcneill 	if (!valid)
131d26a1212Sjmcneill 		goto use_permanent;
132d26a1212Sjmcneill 
133d26a1212Sjmcneill 	for (valid = 0, n = 0; n < mode->HwAddressSize; n++)
134d26a1212Sjmcneill 		if (mode->CurrentAddress.Addr[n] != 0xff) {
135d26a1212Sjmcneill 			valid = true;
136d26a1212Sjmcneill 			break;
137d26a1212Sjmcneill 		}
138d26a1212Sjmcneill 	if (!valid)
139d26a1212Sjmcneill 		goto use_permanent;
140d26a1212Sjmcneill 
141d26a1212Sjmcneill 	return &mode->CurrentAddress;
142d26a1212Sjmcneill 
143d26a1212Sjmcneill use_permanent:
144d26a1212Sjmcneill 	return &mode->PermanentAddress;
145d26a1212Sjmcneill }
146d26a1212Sjmcneill 
14713f5d069Sjmcneill static int
efinet_match(struct netif * nif,void * machdep_hint)14813f5d069Sjmcneill efinet_match(struct netif *nif, void *machdep_hint)
14913f5d069Sjmcneill {
15013f5d069Sjmcneill 	struct devdesc *dev = machdep_hint;
15113f5d069Sjmcneill 
15213f5d069Sjmcneill 	if (dev->d_unit != nif->nif_unit)
15313f5d069Sjmcneill 		return 0;
15413f5d069Sjmcneill 
15513f5d069Sjmcneill 	return 1;
15613f5d069Sjmcneill }
15713f5d069Sjmcneill 
15813f5d069Sjmcneill static int
efinet_probe(struct netif * nif,void * machdep_hint)15913f5d069Sjmcneill efinet_probe(struct netif *nif, void *machdep_hint)
16013f5d069Sjmcneill {
16113f5d069Sjmcneill 
16213f5d069Sjmcneill 	return 0;
16313f5d069Sjmcneill }
16413f5d069Sjmcneill 
16513f5d069Sjmcneill static int
efinet_put(struct iodesc * desc,void * pkt,size_t len)16613f5d069Sjmcneill efinet_put(struct iodesc *desc, void *pkt, size_t len)
16713f5d069Sjmcneill {
16813f5d069Sjmcneill 	struct netif *nif = desc->io_netif;
16913f5d069Sjmcneill 	struct efinetinfo *eni = nif->nif_devdata;
17013f5d069Sjmcneill 	EFI_SIMPLE_NETWORK *net;
17113f5d069Sjmcneill 	EFI_STATUS status;
17213f5d069Sjmcneill 	void *buf;
173d26a1212Sjmcneill 	char *ptr;
17413f5d069Sjmcneill 
17513f5d069Sjmcneill 	if (eni == NULL)
17613f5d069Sjmcneill 		return -1;
17713f5d069Sjmcneill 	net = eni->net;
17813f5d069Sjmcneill 
179d26a1212Sjmcneill 	ptr = eni->pktbuf;
180d26a1212Sjmcneill 
181d26a1212Sjmcneill 	memcpy(ptr, pkt, len);
182d26a1212Sjmcneill 	status = uefi_call_wrapper(net->Transmit, 7, net, 0, (UINTN)len, ptr, NULL,
18313f5d069Sjmcneill 	    NULL, NULL);
18413f5d069Sjmcneill 	if (EFI_ERROR(status))
18513f5d069Sjmcneill 		return -1;
18613f5d069Sjmcneill 
18713f5d069Sjmcneill 	/* Wait for the buffer to be transmitted */
18813f5d069Sjmcneill 	do {
18913f5d069Sjmcneill 		buf = NULL;	/* XXX Is this needed? */
19013f5d069Sjmcneill 		status = uefi_call_wrapper(net->GetStatus, 3, net, NULL, &buf);
19113f5d069Sjmcneill 		/*
19213f5d069Sjmcneill 		 * XXX EFI1.1 and the E1000 card returns a different
19313f5d069Sjmcneill 		 * address than we gave.  Sigh.
19413f5d069Sjmcneill 		 */
19513f5d069Sjmcneill 	} while (!EFI_ERROR(status) && buf == NULL);
19613f5d069Sjmcneill 
19713f5d069Sjmcneill 	/* XXX How do we deal with status != EFI_SUCCESS now? */
19813f5d069Sjmcneill 	return EFI_ERROR(status) ? -1 : len;
19913f5d069Sjmcneill }
20013f5d069Sjmcneill 
20113f5d069Sjmcneill static int
efinet_get(struct iodesc * desc,void * pkt,size_t len,saseconds_t timeout)20213f5d069Sjmcneill efinet_get(struct iodesc *desc, void *pkt, size_t len, saseconds_t timeout)
20313f5d069Sjmcneill {
20413f5d069Sjmcneill 	struct netif *nif = desc->io_netif;
20513f5d069Sjmcneill 	struct efinetinfo *eni = nif->nif_devdata;
20613f5d069Sjmcneill 	EFI_SIMPLE_NETWORK *net;
20713f5d069Sjmcneill 	EFI_STATUS status;
20813f5d069Sjmcneill 	UINTN bufsz, rsz;
20913f5d069Sjmcneill 	time_t t;
21013f5d069Sjmcneill 	char *buf, *ptr;
21113f5d069Sjmcneill 	int ret = -1;
21213f5d069Sjmcneill 
21313f5d069Sjmcneill 	if (eni == NULL)
21413f5d069Sjmcneill 		return -1;
21513f5d069Sjmcneill 	net = eni->net;
21613f5d069Sjmcneill 
21713f5d069Sjmcneill 	if (eni->pktbufsz < net->Mode->MaxPacketSize + ETHER_EXT_LEN) {
21813f5d069Sjmcneill 		bufsz = net->Mode->MaxPacketSize + ETHER_EXT_LEN;
21913f5d069Sjmcneill 		buf = alloc(bufsz);
22013f5d069Sjmcneill 		if (buf == NULL)
22113f5d069Sjmcneill 			return -1;
22213f5d069Sjmcneill 		dealloc(eni->pktbuf, eni->pktbufsz);
22313f5d069Sjmcneill 		eni->pktbufsz = bufsz;
22413f5d069Sjmcneill 		eni->pktbuf = buf;
22513f5d069Sjmcneill 	}
22613f5d069Sjmcneill 	ptr = eni->pktbuf + ETHER_ALIGN;
22713f5d069Sjmcneill 
22813f5d069Sjmcneill 	t = getsecs();
22913f5d069Sjmcneill 	while ((getsecs() - t) < timeout) {
23013f5d069Sjmcneill 		rsz = eni->pktbufsz;
23113f5d069Sjmcneill 		status = uefi_call_wrapper(net->Receive, 7, net, NULL, &rsz, ptr,
23213f5d069Sjmcneill 		    NULL, NULL, NULL);
23313f5d069Sjmcneill 		if (!EFI_ERROR(status)) {
234b5d131ffSriastradh 			rsz = uimin(rsz, len);
23513f5d069Sjmcneill 			memcpy(pkt, ptr, rsz);
236d26a1212Sjmcneill 
23713f5d069Sjmcneill 			ret = (int)rsz;
23813f5d069Sjmcneill 			break;
23913f5d069Sjmcneill 		}
24013f5d069Sjmcneill 		if (status != EFI_NOT_READY)
24113f5d069Sjmcneill 			break;
24213f5d069Sjmcneill 	}
24313f5d069Sjmcneill 
24413f5d069Sjmcneill 	return ret;
24513f5d069Sjmcneill }
24613f5d069Sjmcneill 
24713f5d069Sjmcneill static void
efinet_init(struct iodesc * desc,void * machdep_hint)24813f5d069Sjmcneill efinet_init(struct iodesc *desc, void *machdep_hint)
24913f5d069Sjmcneill {
25013f5d069Sjmcneill 	struct netif *nif = desc->io_netif;
25113f5d069Sjmcneill 	struct efinetinfo *eni;
25213f5d069Sjmcneill 	EFI_SIMPLE_NETWORK *net;
25313f5d069Sjmcneill 	EFI_STATUS status;
25413f5d069Sjmcneill 	UINT32 mask;
25513f5d069Sjmcneill 
25613f5d069Sjmcneill 	if (nif->nif_driver->netif_ifs[nif->nif_unit].dif_unit < 0) {
25713f5d069Sjmcneill 		printf("Invalid network interface %d\n", nif->nif_unit);
25813f5d069Sjmcneill 		return;
25913f5d069Sjmcneill 	}
26013f5d069Sjmcneill 
26113f5d069Sjmcneill 	eni = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private;
26213f5d069Sjmcneill 	nif->nif_devdata = eni;
26313f5d069Sjmcneill 	net = eni->net;
26413f5d069Sjmcneill 	if (net->Mode->State == EfiSimpleNetworkStopped) {
26513f5d069Sjmcneill 		status = uefi_call_wrapper(net->Start, 1, net);
26613f5d069Sjmcneill 		if (EFI_ERROR(status)) {
26713f5d069Sjmcneill 			printf("net%d: cannot start interface (status=%"
26813f5d069Sjmcneill 			    PRIxMAX ")\n", nif->nif_unit, (uintmax_t)status);
26913f5d069Sjmcneill 			return;
27013f5d069Sjmcneill 		}
27113f5d069Sjmcneill 	}
27213f5d069Sjmcneill 
27313f5d069Sjmcneill 	if (net->Mode->State != EfiSimpleNetworkInitialized) {
27413f5d069Sjmcneill 		status = uefi_call_wrapper(net->Initialize, 3, net, 0, 0);
27513f5d069Sjmcneill 		if (EFI_ERROR(status)) {
27613f5d069Sjmcneill 			printf("net%d: cannot init. interface (status=%"
27713f5d069Sjmcneill 			    PRIxMAX ")\n", nif->nif_unit, (uintmax_t)status);
27813f5d069Sjmcneill 			return;
27913f5d069Sjmcneill 		}
28013f5d069Sjmcneill 	}
28113f5d069Sjmcneill 
28213f5d069Sjmcneill 	mask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
28313f5d069Sjmcneill 	    EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
28413f5d069Sjmcneill 
28513f5d069Sjmcneill 	status = uefi_call_wrapper(net->ReceiveFilters, 6, net, mask, 0, FALSE,
28613f5d069Sjmcneill 	    0, NULL);
287d26a1212Sjmcneill 	if (EFI_ERROR(status) && status != EFI_INVALID_PARAMETER && status != EFI_UNSUPPORTED) {
28813f5d069Sjmcneill 		printf("net%d: cannot set rx. filters (status=%" PRIxMAX ")\n",
28913f5d069Sjmcneill 		    nif->nif_unit, (uintmax_t)status);
29013f5d069Sjmcneill 		return;
29113f5d069Sjmcneill 	}
29213f5d069Sjmcneill 
29313f5d069Sjmcneill #if notyet
29413f5d069Sjmcneill 	if (!kernel_loaded) {
29513f5d069Sjmcneill 		bi_netif.bus = eni->bus.type;
29613f5d069Sjmcneill 		bi_netif.addr.tag = eni->bus.tag;
29713f5d069Sjmcneill 		snprintf(bi_netif.ifname, sizeof(bi_netif.ifname), "net%d",
29813f5d069Sjmcneill 		    nif->nif_unit);
29913f5d069Sjmcneill 		BI_ADD(&bi_netif, BTINFO_NETIF, sizeof(bi_netif));
30013f5d069Sjmcneill 	}
30113f5d069Sjmcneill #endif
30213f5d069Sjmcneill 
30313f5d069Sjmcneill #ifdef EFINET_DEBUG
30413f5d069Sjmcneill 	dump_mode(net->Mode);
30513f5d069Sjmcneill #endif
30613f5d069Sjmcneill 
307d26a1212Sjmcneill 	memcpy(desc->myea, efinet_hwaddr(net->Mode)->Addr, 6);
30813f5d069Sjmcneill 	desc->xid = 1;
30913f5d069Sjmcneill }
31013f5d069Sjmcneill 
31113f5d069Sjmcneill static void
efinet_end(struct netif * nif)31213f5d069Sjmcneill efinet_end(struct netif *nif)
31313f5d069Sjmcneill {
31413f5d069Sjmcneill 	struct efinetinfo *eni = nif->nif_devdata;
31513f5d069Sjmcneill 	EFI_SIMPLE_NETWORK *net;
31613f5d069Sjmcneill 
31713f5d069Sjmcneill 	if (eni == NULL)
31813f5d069Sjmcneill 		return;
31913f5d069Sjmcneill 	net = eni->net;
32013f5d069Sjmcneill 
32113f5d069Sjmcneill 	uefi_call_wrapper(net->Shutdown, 1, net);
32213f5d069Sjmcneill }
32313f5d069Sjmcneill 
32413f5d069Sjmcneill void
efi_net_probe(void)32513f5d069Sjmcneill efi_net_probe(void)
32613f5d069Sjmcneill {
32713f5d069Sjmcneill 	struct efinetinfo *enis;
32813f5d069Sjmcneill 	struct netif_dif *dif;
32913f5d069Sjmcneill 	struct netif_stats *stats;
330d26a1212Sjmcneill 	EFI_DEVICE_PATH *dp0, *dp;
33113f5d069Sjmcneill 	EFI_SIMPLE_NETWORK *net;
33213f5d069Sjmcneill 	EFI_HANDLE *handles;
33313f5d069Sjmcneill 	EFI_STATUS status;
33413f5d069Sjmcneill 	UINTN i, nhandles;
33596816df7Sjmcneill 	int nifs, depth = -1;
336*71d224f4Srin 	bool found;
33713f5d069Sjmcneill 
33813f5d069Sjmcneill 	status = LibLocateHandle(ByProtocol, &SimpleNetworkProtocol, NULL,
33913f5d069Sjmcneill 	    &nhandles, &handles);
34013f5d069Sjmcneill 	if (EFI_ERROR(status) || nhandles == 0)
34113f5d069Sjmcneill 		return;
34213f5d069Sjmcneill 
34313f5d069Sjmcneill 	enis = alloc(nhandles * sizeof(*enis));
34413f5d069Sjmcneill 	if (enis == NULL)
34513f5d069Sjmcneill 		return;
34613f5d069Sjmcneill 	memset(enis, 0, nhandles * sizeof(*enis));
34713f5d069Sjmcneill 
34896816df7Sjmcneill 	if (efi_bootdp) {
3499b625a96Srin 		/*
3509b625a96Srin 		 * Either Hardware or Messaging Device Paths can be used
3519b625a96Srin 		 * here, see Sec 10.4.4 of UEFI Spec 2.10. Try both.
3529b625a96Srin 		 */
35396816df7Sjmcneill 		depth = efi_device_path_depth(efi_bootdp, HARDWARE_DEVICE_PATH);
3549b625a96Srin 		if (depth == -1) {
3559b625a96Srin 			depth = efi_device_path_depth(efi_bootdp,
3569b625a96Srin 			    MESSAGING_DEVICE_PATH);
3579b625a96Srin 		}
35896816df7Sjmcneill 		if (depth == 0)
35996816df7Sjmcneill 			depth = 1;
36096816df7Sjmcneill 	}
36196816df7Sjmcneill 
36213f5d069Sjmcneill 	nifs = 0;
36313f5d069Sjmcneill 	for (i = 0; i < nhandles; i++) {
36413f5d069Sjmcneill 		status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i],
36513f5d069Sjmcneill 		    &DevicePathProtocol, (void **)&dp0);
36613f5d069Sjmcneill 		if (EFI_ERROR(status))
36713f5d069Sjmcneill 			continue;
36813f5d069Sjmcneill 
36913f5d069Sjmcneill 		found = false;
37013f5d069Sjmcneill 		for (dp = dp0; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp)) {
37113f5d069Sjmcneill 			if (DevicePathType(dp) == MESSAGING_DEVICE_PATH &&
37213f5d069Sjmcneill 			    DevicePathSubType(dp) == MSG_MAC_ADDR_DP) {
37313f5d069Sjmcneill 				found = true;
37413f5d069Sjmcneill 				break;
37513f5d069Sjmcneill 			}
37613f5d069Sjmcneill 		}
37713f5d069Sjmcneill 		if (!found)
37813f5d069Sjmcneill 			continue;
37913f5d069Sjmcneill 
38013f5d069Sjmcneill 		status = uefi_call_wrapper(BS->OpenProtocol, 6, handles[i],
38113f5d069Sjmcneill 		    &SimpleNetworkProtocol, (void **)&net, IH, NULL,
38213f5d069Sjmcneill 		    EFI_OPEN_PROTOCOL_EXCLUSIVE);
38313f5d069Sjmcneill 		if (EFI_ERROR(status)) {
38413f5d069Sjmcneill 			printf("Unable to open network interface %" PRIuMAX
38513f5d069Sjmcneill 			    " for exclusive access: %" PRIxMAX "\n",
38613f5d069Sjmcneill 			    (uintmax_t)i, (uintmax_t)status);
387d26a1212Sjmcneill 			continue;
38813f5d069Sjmcneill 		}
38913f5d069Sjmcneill 
39013f5d069Sjmcneill 		enis[nifs].net = net;
39113f5d069Sjmcneill 		enis[nifs].bootdev = efi_pxe_match_booted_interface(
392d26a1212Sjmcneill 		    efinet_hwaddr(net->Mode), net->Mode->HwAddressSize);
39313f5d069Sjmcneill 		enis[nifs].pktbufsz = net->Mode->MaxPacketSize +
39413f5d069Sjmcneill 		    ETHER_EXT_LEN;
39513f5d069Sjmcneill 		enis[nifs].pktbuf = alloc(enis[nifs].pktbufsz);
39613f5d069Sjmcneill 		if (enis[nifs].pktbuf == NULL) {
39713f5d069Sjmcneill 			while (i-- > 0) {
39813f5d069Sjmcneill 				dealloc(enis[i].pktbuf, enis[i].pktbufsz);
39913f5d069Sjmcneill 				if (i == 0)
40013f5d069Sjmcneill 					break;
40113f5d069Sjmcneill 			}
40213f5d069Sjmcneill 			dealloc(enis, nhandles * sizeof(*enis));
40313f5d069Sjmcneill 			FreePool(handles);
40413f5d069Sjmcneill 			return;
40513f5d069Sjmcneill 		}
40696816df7Sjmcneill 
407*71d224f4Srin 		if (depth > 0 && efi_device_path_ncmp(efi_bootdp, dp0, depth) == 0) {
40896816df7Sjmcneill 			char devname[9];
40996816df7Sjmcneill 			snprintf(devname, sizeof(devname), "net%u", nifs);
41096816df7Sjmcneill 			set_default_device(devname);
41196816df7Sjmcneill 		}
41296816df7Sjmcneill 
41313f5d069Sjmcneill 		nifs++;
41413f5d069Sjmcneill 	}
41513f5d069Sjmcneill 
41613f5d069Sjmcneill 	FreePool(handles);
41713f5d069Sjmcneill 
41813f5d069Sjmcneill 	if (nifs == 0)
41913f5d069Sjmcneill 		return;
42013f5d069Sjmcneill 
42113f5d069Sjmcneill 	efinetif.netif_ifs = alloc(nifs * sizeof(*dif));
42213f5d069Sjmcneill 	stats = alloc(nifs * sizeof(*stats));
42313f5d069Sjmcneill 	if (efinetif.netif_ifs == NULL || stats == NULL) {
42413f5d069Sjmcneill 		if (efinetif.netif_ifs != NULL) {
42513f5d069Sjmcneill 			dealloc(efinetif.netif_ifs, nifs * sizeof(*dif));
42613f5d069Sjmcneill 			efinetif.netif_ifs = NULL;
42713f5d069Sjmcneill 		}
42813f5d069Sjmcneill 		if (stats != NULL)
42913f5d069Sjmcneill 			dealloc(stats, nifs * sizeof(*stats));
43013f5d069Sjmcneill 		for (i = 0; i < nifs; i++)
43113f5d069Sjmcneill 			dealloc(enis[i].pktbuf, enis[i].pktbufsz);
43213f5d069Sjmcneill 		dealloc(enis, nhandles * sizeof(*enis));
43313f5d069Sjmcneill 		return;
43413f5d069Sjmcneill 	}
43513f5d069Sjmcneill 	memset(efinetif.netif_ifs, 0, nifs * sizeof(*dif));
43613f5d069Sjmcneill 	memset(stats, 0, nifs * sizeof(*stats));
43713f5d069Sjmcneill 	efinetif.netif_nifs = nifs;
43813f5d069Sjmcneill 
43913f5d069Sjmcneill 	for (i = 0; i < nifs; i++) {
44013f5d069Sjmcneill 		dif = &efinetif.netif_ifs[i];
44113f5d069Sjmcneill 		dif->dif_unit = i;
44213f5d069Sjmcneill 		dif->dif_nsel = 1;
44313f5d069Sjmcneill 		dif->dif_stats = &stats[i];
44413f5d069Sjmcneill 		dif->dif_private = &enis[i];
44513f5d069Sjmcneill 	}
44613f5d069Sjmcneill }
44713f5d069Sjmcneill 
44813f5d069Sjmcneill void
efi_net_show(void)44913f5d069Sjmcneill efi_net_show(void)
45013f5d069Sjmcneill {
45113f5d069Sjmcneill 	const struct netif_dif *dif;
45213f5d069Sjmcneill 	const struct efinetinfo *eni;
45313f5d069Sjmcneill 	EFI_SIMPLE_NETWORK *net;
45413f5d069Sjmcneill 	int i;
45513f5d069Sjmcneill 
45613f5d069Sjmcneill 	for (i = 0; i < efinetif.netif_nifs; i++) {
45713f5d069Sjmcneill 		dif = &efinetif.netif_ifs[i];
45813f5d069Sjmcneill 		eni = dif->dif_private;
45913f5d069Sjmcneill 		net = eni->net;
46013f5d069Sjmcneill 
461a158dd7eSjmcneill 		printf("net%d", dif->dif_unit);
46213f5d069Sjmcneill 		if (net->Mode != NULL) {
463d26a1212Sjmcneill 			const EFI_MAC_ADDRESS *mac = efinet_hwaddr(net->Mode);
46413f5d069Sjmcneill 			for (UINT32 x = 0; x < net->Mode->HwAddressSize; x++) {
46513f5d069Sjmcneill 				printf("%c%02x", x == 0 ? ' ' : ':',
466d26a1212Sjmcneill 				    mac->Addr[x]);
46713f5d069Sjmcneill 			}
46813f5d069Sjmcneill 		}
46913f5d069Sjmcneill 		if (eni->bootdev)
47013f5d069Sjmcneill 			printf(" pxeboot");
47113f5d069Sjmcneill 		printf("\n");
47213f5d069Sjmcneill 	}
47313f5d069Sjmcneill }
47413f5d069Sjmcneill 
47513f5d069Sjmcneill int
efi_net_get_booted_interface_unit(void)47613f5d069Sjmcneill efi_net_get_booted_interface_unit(void)
47713f5d069Sjmcneill {
47813f5d069Sjmcneill 	const struct netif_dif *dif;
47913f5d069Sjmcneill 	const struct efinetinfo *eni;
48013f5d069Sjmcneill 	int i;
48113f5d069Sjmcneill 
48213f5d069Sjmcneill 	for (i = 0; i < efinetif.netif_nifs; i++) {
48313f5d069Sjmcneill 		dif = &efinetif.netif_ifs[i];
48413f5d069Sjmcneill 		eni = dif->dif_private;
48513f5d069Sjmcneill 		if (eni->bootdev)
48613f5d069Sjmcneill 			return dif->dif_unit;
48713f5d069Sjmcneill 	}
48813f5d069Sjmcneill 	return -1;
48913f5d069Sjmcneill }
49013f5d069Sjmcneill 
49113f5d069Sjmcneill int
efi_net_get_booted_macaddr(uint8_t * mac)492a158dd7eSjmcneill efi_net_get_booted_macaddr(uint8_t *mac)
493a158dd7eSjmcneill {
494a158dd7eSjmcneill 	const struct netif_dif *dif;
495a158dd7eSjmcneill 	const struct efinetinfo *eni;
496a158dd7eSjmcneill 	EFI_SIMPLE_NETWORK *net;
497a158dd7eSjmcneill 	int i;
498a158dd7eSjmcneill 
499a158dd7eSjmcneill 	for (i = 0; i < efinetif.netif_nifs; i++) {
500a158dd7eSjmcneill 		dif = &efinetif.netif_ifs[i];
501a158dd7eSjmcneill 		eni = dif->dif_private;
502a158dd7eSjmcneill 		net = eni->net;
503a158dd7eSjmcneill 		if (eni->bootdev && net->Mode != NULL && net->Mode->HwAddressSize == 6) {
504a158dd7eSjmcneill 			memcpy(mac, net->Mode->PermanentAddress.Addr, 6);
505a158dd7eSjmcneill 			return 0;
506a158dd7eSjmcneill 		}
507a158dd7eSjmcneill 	}
508a158dd7eSjmcneill 
509a158dd7eSjmcneill 	return -1;
510a158dd7eSjmcneill }
511a158dd7eSjmcneill 
512a158dd7eSjmcneill int
efi_net_open(struct open_file * f,...)51313f5d069Sjmcneill efi_net_open(struct open_file *f, ...)
51413f5d069Sjmcneill {
51596816df7Sjmcneill 	char **file, pathbuf[PATH_MAX], *default_device, *path, *ep;
51696816df7Sjmcneill 	const char *fname, *full_path;
51713f5d069Sjmcneill 	struct devdesc desc;
51813f5d069Sjmcneill 	intmax_t dev;
51913f5d069Sjmcneill 	va_list ap;
520a158dd7eSjmcneill 	int n, error;
52113f5d069Sjmcneill 
52213f5d069Sjmcneill 	va_start(ap, f);
52313f5d069Sjmcneill 	fname = va_arg(ap, const char *);
52413f5d069Sjmcneill 	file = va_arg(ap, char **);
52513f5d069Sjmcneill 	va_end(ap);
52613f5d069Sjmcneill 
52796816df7Sjmcneill 	default_device = get_default_device();
52896816df7Sjmcneill 	if (strchr(fname, ':') == NULL) {
52996816df7Sjmcneill 		if (strlen(default_device) > 0) {
53096816df7Sjmcneill 			snprintf(pathbuf, sizeof(pathbuf), "%s:%s", default_device, fname);
53196816df7Sjmcneill 			full_path = pathbuf;
53296816df7Sjmcneill 			path = __UNCONST(fname);
53396816df7Sjmcneill 		} else {
53413f5d069Sjmcneill 			return EINVAL;
53596816df7Sjmcneill 		}
53696816df7Sjmcneill 	} else {
53796816df7Sjmcneill 		full_path = fname;
53896816df7Sjmcneill 		path = strchr(fname, ':') + 1;
53996816df7Sjmcneill 	}
54096816df7Sjmcneill 
54196816df7Sjmcneill 	if (strncmp(full_path, "net", 3) != 0)
54296816df7Sjmcneill 		return EINVAL;
54396816df7Sjmcneill         dev = strtoimax(full_path + 3, &ep, 10);
54413f5d069Sjmcneill         if (dev < 0 || dev >= efinetif.netif_nifs)
54513f5d069Sjmcneill                 return ENXIO;
54613f5d069Sjmcneill 
54713f5d069Sjmcneill         for (n = 0; n < ndevs; n++)
54813f5d069Sjmcneill                 if (strcmp(DEV_NAME(&devsw[n]), "net") == 0) {
54913f5d069Sjmcneill                         f->f_dev = &devsw[n];
55013f5d069Sjmcneill                         break;
55113f5d069Sjmcneill                 }
55213f5d069Sjmcneill         if (n == ndevs)
55313f5d069Sjmcneill                 return ENXIO;
55413f5d069Sjmcneill 
55596816df7Sjmcneill 	*file = path;
55613f5d069Sjmcneill 
55713f5d069Sjmcneill 	//try_bootp = 1;
55813f5d069Sjmcneill 
55913f5d069Sjmcneill 	memset(&desc, 0, sizeof(desc));
56013f5d069Sjmcneill 	strlcpy(desc.d_name, "net", sizeof(desc.d_name));
56113f5d069Sjmcneill 	desc.d_unit = dev;
56213f5d069Sjmcneill 
563a158dd7eSjmcneill 	error = DEV_OPEN(f->f_dev)(f, &desc);
564a158dd7eSjmcneill 	if (error)
565a158dd7eSjmcneill 		return error;
566a158dd7eSjmcneill 
567a158dd7eSjmcneill 	return 0;
56813f5d069Sjmcneill }
569