Home | History | Annotate | Line # | Download | only in efiboot
efinet.c revision 1.6.32.1
      1  1.6.32.1    martin /*	$NetBSD: efinet.c,v 1.6.32.1 2023/12/30 19:33:25 martin Exp $	*/
      2       1.1  jmcneill 
      3       1.1  jmcneill /*-
      4       1.1  jmcneill  * Copyright (c) 2001 Doug Rabson
      5       1.1  jmcneill  * Copyright (c) 2002, 2006 Marcel Moolenaar
      6       1.1  jmcneill  * All rights reserved.
      7       1.1  jmcneill  *
      8       1.1  jmcneill  * Redistribution and use in source and binary forms, with or without
      9       1.1  jmcneill  * modification, are permitted provided that the following conditions
     10       1.1  jmcneill  * are met:
     11       1.1  jmcneill  * 1. Redistributions of source code must retain the above copyright
     12       1.1  jmcneill  *    notice, this list of conditions and the following disclaimer.
     13       1.1  jmcneill  * 2. Redistributions in binary form must reproduce the above copyright
     14       1.1  jmcneill  *    notice, this list of conditions and the following disclaimer in the
     15       1.1  jmcneill  *    documentation and/or other materials provided with the distribution.
     16       1.1  jmcneill  *
     17       1.1  jmcneill  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     18       1.1  jmcneill  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     19       1.1  jmcneill  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     20       1.1  jmcneill  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     21       1.1  jmcneill  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22       1.1  jmcneill  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     23       1.1  jmcneill  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     24       1.1  jmcneill  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     25       1.1  jmcneill  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     26       1.1  jmcneill  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     27       1.1  jmcneill  * SUCH DAMAGE.
     28       1.1  jmcneill  */
     29       1.1  jmcneill 
     30       1.1  jmcneill #include <sys/cdefs.h>
     31       1.3  jmcneill #include <sys/param.h>
     32       1.1  jmcneill 
     33       1.1  jmcneill #include "efiboot.h"
     34       1.1  jmcneill 
     35       1.1  jmcneill #include <lib/libsa/net.h>
     36       1.1  jmcneill #include <lib/libsa/netif.h>
     37       1.1  jmcneill #include <lib/libsa/dev_net.h>
     38       1.1  jmcneill 
     39       1.1  jmcneill #include "devopen.h"
     40       1.1  jmcneill 
     41       1.1  jmcneill #define ETHER_EXT_LEN	(ETHER_HDR_LEN + ETHER_CRC_LEN + ETHER_ALIGN)
     42       1.1  jmcneill 
     43       1.1  jmcneill #if defined(DEBUG) || defined(ARP_DEBUG) || defined(BOOTP_DEBUG) || \
     44       1.1  jmcneill     defined(NET_DEBUG) || defined(NETIF_DEBUG) || defined(NFS_DEBUG) || \
     45       1.1  jmcneill     defined(RARP_DEBUG) || defined(RPC_DEBUG)
     46       1.1  jmcneill int debug = 1;
     47       1.1  jmcneill #else
     48       1.1  jmcneill int debug = 0;
     49       1.1  jmcneill #endif
     50       1.1  jmcneill 
     51       1.1  jmcneill extern bool kernel_loaded;
     52       1.1  jmcneill 
     53       1.1  jmcneill struct efinetinfo {
     54       1.1  jmcneill 	EFI_SIMPLE_NETWORK *net;
     55       1.1  jmcneill 	bool bootdev;
     56       1.1  jmcneill 	size_t pktbufsz;
     57       1.1  jmcneill 	UINT8 *pktbuf;
     58       1.1  jmcneill 	struct {
     59       1.1  jmcneill 		int type;
     60       1.1  jmcneill 		u_int tag;
     61       1.1  jmcneill 	} bus;
     62       1.1  jmcneill };
     63       1.1  jmcneill #if notyet
     64       1.1  jmcneill static struct btinfo_netif bi_netif;
     65       1.1  jmcneill #endif
     66       1.1  jmcneill 
     67       1.1  jmcneill static int	efinet_match(struct netif *, void *);
     68       1.1  jmcneill static int	efinet_probe(struct netif *, void *);
     69       1.1  jmcneill static void	efinet_init(struct iodesc *, void *);
     70       1.1  jmcneill static int	efinet_get(struct iodesc *, void *, size_t, saseconds_t);
     71       1.1  jmcneill static int	efinet_put(struct iodesc *, void *, size_t);
     72       1.1  jmcneill static void	efinet_end(struct netif *);
     73       1.1  jmcneill 
     74       1.1  jmcneill struct netif_driver efinetif = {
     75       1.1  jmcneill 	.netif_bname = "net",
     76       1.1  jmcneill 	.netif_match = efinet_match,
     77       1.1  jmcneill 	.netif_probe = efinet_probe,
     78       1.1  jmcneill 	.netif_init = efinet_init,
     79       1.1  jmcneill 	.netif_get = efinet_get,
     80       1.1  jmcneill 	.netif_put = efinet_put,
     81       1.1  jmcneill 	.netif_end = efinet_end,
     82       1.1  jmcneill 	.netif_ifs = NULL,
     83       1.1  jmcneill 	.netif_nifs = 0
     84       1.1  jmcneill };
     85       1.1  jmcneill 
     86       1.1  jmcneill #ifdef EFINET_DEBUG
     87       1.1  jmcneill static void
     88       1.1  jmcneill dump_mode(EFI_SIMPLE_NETWORK_MODE *mode)
     89       1.1  jmcneill {
     90       1.1  jmcneill 	int i;
     91       1.1  jmcneill 
     92       1.1  jmcneill 	printf("State                 = %x\n", mode->State);
     93       1.1  jmcneill 	printf("HwAddressSize         = %u\n", mode->HwAddressSize);
     94       1.1  jmcneill 	printf("MediaHeaderSize       = %u\n", mode->MediaHeaderSize);
     95       1.1  jmcneill 	printf("MaxPacketSize         = %u\n", mode->MaxPacketSize);
     96       1.1  jmcneill 	printf("NvRamSize             = %u\n", mode->NvRamSize);
     97       1.1  jmcneill 	printf("NvRamAccessSize       = %u\n", mode->NvRamAccessSize);
     98       1.1  jmcneill 	printf("ReceiveFilterMask     = %x\n", mode->ReceiveFilterMask);
     99       1.1  jmcneill 	printf("ReceiveFilterSetting  = %u\n", mode->ReceiveFilterSetting);
    100       1.1  jmcneill 	printf("MaxMCastFilterCount   = %u\n", mode->MaxMCastFilterCount);
    101       1.1  jmcneill 	printf("MCastFilterCount      = %u\n", mode->MCastFilterCount);
    102       1.1  jmcneill 	printf("MCastFilter           = {");
    103       1.1  jmcneill 	for (i = 0; i < mode->MCastFilterCount; i++)
    104       1.1  jmcneill 		printf(" %s", ether_sprintf(mode->MCastFilter[i].Addr));
    105       1.1  jmcneill 	printf(" }\n");
    106       1.1  jmcneill 	printf("CurrentAddress        = %s\n",
    107       1.1  jmcneill 	    ether_sprintf(mode->CurrentAddress.Addr));
    108       1.1  jmcneill 	printf("BroadcastAddress      = %s\n",
    109       1.1  jmcneill 	    ether_sprintf(mode->BroadcastAddress.Addr));
    110       1.1  jmcneill 	printf("PermanentAddress      = %s\n",
    111       1.1  jmcneill 	    ether_sprintf(mode->PermanentAddress.Addr));
    112       1.1  jmcneill 	printf("IfType                = %u\n", mode->IfType);
    113       1.1  jmcneill 	printf("MacAddressChangeable  = %d\n", mode->MacAddressChangeable);
    114       1.1  jmcneill 	printf("MultipleTxSupported   = %d\n", mode->MultipleTxSupported);
    115       1.1  jmcneill 	printf("MediaPresentSupported = %d\n", mode->MediaPresentSupported);
    116       1.1  jmcneill 	printf("MediaPresent          = %d\n", mode->MediaPresent);
    117       1.1  jmcneill }
    118       1.1  jmcneill #endif
    119       1.1  jmcneill 
    120       1.6  jmcneill static const EFI_MAC_ADDRESS *
    121       1.6  jmcneill efinet_hwaddr(const EFI_SIMPLE_NETWORK_MODE *mode)
    122       1.6  jmcneill {
    123       1.6  jmcneill 	int valid, n;
    124       1.6  jmcneill 
    125       1.6  jmcneill 	for (valid = 0, n = 0; n < mode->HwAddressSize; n++)
    126       1.6  jmcneill 		if (mode->CurrentAddress.Addr[n] != 0x00) {
    127       1.6  jmcneill 			valid = true;
    128       1.6  jmcneill 			break;
    129       1.6  jmcneill 		}
    130       1.6  jmcneill 	if (!valid)
    131       1.6  jmcneill 		goto use_permanent;
    132       1.6  jmcneill 
    133       1.6  jmcneill 	for (valid = 0, n = 0; n < mode->HwAddressSize; n++)
    134       1.6  jmcneill 		if (mode->CurrentAddress.Addr[n] != 0xff) {
    135       1.6  jmcneill 			valid = true;
    136       1.6  jmcneill 			break;
    137       1.6  jmcneill 		}
    138       1.6  jmcneill 	if (!valid)
    139       1.6  jmcneill 		goto use_permanent;
    140       1.6  jmcneill 
    141       1.6  jmcneill 	return &mode->CurrentAddress;
    142       1.6  jmcneill 
    143       1.6  jmcneill use_permanent:
    144       1.6  jmcneill 	return &mode->PermanentAddress;
    145       1.6  jmcneill }
    146       1.6  jmcneill 
    147       1.1  jmcneill static int
    148       1.1  jmcneill efinet_match(struct netif *nif, void *machdep_hint)
    149       1.1  jmcneill {
    150       1.1  jmcneill 	struct devdesc *dev = machdep_hint;
    151       1.1  jmcneill 
    152       1.1  jmcneill 	if (dev->d_unit != nif->nif_unit)
    153       1.1  jmcneill 		return 0;
    154       1.1  jmcneill 
    155       1.1  jmcneill 	return 1;
    156       1.1  jmcneill }
    157       1.1  jmcneill 
    158       1.1  jmcneill static int
    159       1.1  jmcneill efinet_probe(struct netif *nif, void *machdep_hint)
    160       1.1  jmcneill {
    161       1.1  jmcneill 
    162       1.1  jmcneill 	return 0;
    163       1.1  jmcneill }
    164       1.1  jmcneill 
    165       1.1  jmcneill static int
    166       1.1  jmcneill efinet_put(struct iodesc *desc, void *pkt, size_t len)
    167       1.1  jmcneill {
    168       1.1  jmcneill 	struct netif *nif = desc->io_netif;
    169       1.1  jmcneill 	struct efinetinfo *eni = nif->nif_devdata;
    170       1.1  jmcneill 	EFI_SIMPLE_NETWORK *net;
    171       1.1  jmcneill 	EFI_STATUS status;
    172       1.1  jmcneill 	void *buf;
    173       1.6  jmcneill 	char *ptr;
    174       1.1  jmcneill 
    175       1.1  jmcneill 	if (eni == NULL)
    176       1.1  jmcneill 		return -1;
    177       1.1  jmcneill 	net = eni->net;
    178       1.1  jmcneill 
    179       1.6  jmcneill 	ptr = eni->pktbuf;
    180       1.6  jmcneill 
    181       1.6  jmcneill 	memcpy(ptr, pkt, len);
    182       1.6  jmcneill 	status = uefi_call_wrapper(net->Transmit, 7, net, 0, (UINTN)len, ptr, NULL,
    183       1.1  jmcneill 	    NULL, NULL);
    184       1.1  jmcneill 	if (EFI_ERROR(status))
    185       1.1  jmcneill 		return -1;
    186       1.1  jmcneill 
    187       1.1  jmcneill 	/* Wait for the buffer to be transmitted */
    188       1.1  jmcneill 	do {
    189       1.1  jmcneill 		buf = NULL;	/* XXX Is this needed? */
    190       1.1  jmcneill 		status = uefi_call_wrapper(net->GetStatus, 3, net, NULL, &buf);
    191       1.1  jmcneill 		/*
    192       1.1  jmcneill 		 * XXX EFI1.1 and the E1000 card returns a different
    193       1.1  jmcneill 		 * address than we gave.  Sigh.
    194       1.1  jmcneill 		 */
    195       1.1  jmcneill 	} while (!EFI_ERROR(status) && buf == NULL);
    196       1.1  jmcneill 
    197       1.1  jmcneill 	/* XXX How do we deal with status != EFI_SUCCESS now? */
    198       1.1  jmcneill 	return EFI_ERROR(status) ? -1 : len;
    199       1.1  jmcneill }
    200       1.1  jmcneill 
    201       1.1  jmcneill static int
    202       1.1  jmcneill efinet_get(struct iodesc *desc, void *pkt, size_t len, saseconds_t timeout)
    203       1.1  jmcneill {
    204       1.1  jmcneill 	struct netif *nif = desc->io_netif;
    205       1.1  jmcneill 	struct efinetinfo *eni = nif->nif_devdata;
    206       1.1  jmcneill 	EFI_SIMPLE_NETWORK *net;
    207       1.1  jmcneill 	EFI_STATUS status;
    208       1.1  jmcneill 	UINTN bufsz, rsz;
    209       1.1  jmcneill 	time_t t;
    210       1.1  jmcneill 	char *buf, *ptr;
    211       1.1  jmcneill 	int ret = -1;
    212       1.1  jmcneill 
    213       1.1  jmcneill 	if (eni == NULL)
    214       1.1  jmcneill 		return -1;
    215       1.1  jmcneill 	net = eni->net;
    216       1.1  jmcneill 
    217       1.1  jmcneill 	if (eni->pktbufsz < net->Mode->MaxPacketSize + ETHER_EXT_LEN) {
    218       1.1  jmcneill 		bufsz = net->Mode->MaxPacketSize + ETHER_EXT_LEN;
    219       1.1  jmcneill 		buf = alloc(bufsz);
    220       1.1  jmcneill 		if (buf == NULL)
    221       1.1  jmcneill 			return -1;
    222       1.1  jmcneill 		dealloc(eni->pktbuf, eni->pktbufsz);
    223       1.1  jmcneill 		eni->pktbufsz = bufsz;
    224       1.1  jmcneill 		eni->pktbuf = buf;
    225       1.1  jmcneill 	}
    226       1.1  jmcneill 	ptr = eni->pktbuf + ETHER_ALIGN;
    227       1.1  jmcneill 
    228       1.1  jmcneill 	t = getsecs();
    229       1.1  jmcneill 	while ((getsecs() - t) < timeout) {
    230       1.1  jmcneill 		rsz = eni->pktbufsz;
    231       1.1  jmcneill 		status = uefi_call_wrapper(net->Receive, 7, net, NULL, &rsz, ptr,
    232       1.1  jmcneill 		    NULL, NULL, NULL);
    233       1.1  jmcneill 		if (!EFI_ERROR(status)) {
    234       1.2  riastrad 			rsz = uimin(rsz, len);
    235       1.1  jmcneill 			memcpy(pkt, ptr, rsz);
    236       1.6  jmcneill 
    237       1.1  jmcneill 			ret = (int)rsz;
    238       1.1  jmcneill 			break;
    239       1.1  jmcneill 		}
    240       1.1  jmcneill 		if (status != EFI_NOT_READY)
    241       1.1  jmcneill 			break;
    242       1.1  jmcneill 	}
    243       1.1  jmcneill 
    244       1.1  jmcneill 	return ret;
    245       1.1  jmcneill }
    246       1.1  jmcneill 
    247       1.1  jmcneill static void
    248       1.1  jmcneill efinet_init(struct iodesc *desc, void *machdep_hint)
    249       1.1  jmcneill {
    250       1.1  jmcneill 	struct netif *nif = desc->io_netif;
    251       1.1  jmcneill 	struct efinetinfo *eni;
    252       1.1  jmcneill 	EFI_SIMPLE_NETWORK *net;
    253       1.1  jmcneill 	EFI_STATUS status;
    254       1.1  jmcneill 	UINT32 mask;
    255       1.1  jmcneill 
    256       1.1  jmcneill 	if (nif->nif_driver->netif_ifs[nif->nif_unit].dif_unit < 0) {
    257       1.1  jmcneill 		printf("Invalid network interface %d\n", nif->nif_unit);
    258       1.1  jmcneill 		return;
    259       1.1  jmcneill 	}
    260       1.1  jmcneill 
    261       1.1  jmcneill 	eni = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private;
    262       1.1  jmcneill 	nif->nif_devdata = eni;
    263       1.1  jmcneill 	net = eni->net;
    264       1.1  jmcneill 	if (net->Mode->State == EfiSimpleNetworkStopped) {
    265       1.1  jmcneill 		status = uefi_call_wrapper(net->Start, 1, net);
    266       1.1  jmcneill 		if (EFI_ERROR(status)) {
    267       1.1  jmcneill 			printf("net%d: cannot start interface (status=%"
    268       1.1  jmcneill 			    PRIxMAX ")\n", nif->nif_unit, (uintmax_t)status);
    269       1.1  jmcneill 			return;
    270       1.1  jmcneill 		}
    271       1.1  jmcneill 	}
    272       1.1  jmcneill 
    273       1.1  jmcneill 	if (net->Mode->State != EfiSimpleNetworkInitialized) {
    274       1.1  jmcneill 		status = uefi_call_wrapper(net->Initialize, 3, net, 0, 0);
    275       1.1  jmcneill 		if (EFI_ERROR(status)) {
    276       1.1  jmcneill 			printf("net%d: cannot init. interface (status=%"
    277       1.1  jmcneill 			    PRIxMAX ")\n", nif->nif_unit, (uintmax_t)status);
    278       1.1  jmcneill 			return;
    279       1.1  jmcneill 		}
    280       1.1  jmcneill 	}
    281       1.1  jmcneill 
    282       1.1  jmcneill 	mask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
    283       1.1  jmcneill 	    EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
    284       1.1  jmcneill 
    285       1.1  jmcneill 	status = uefi_call_wrapper(net->ReceiveFilters, 6, net, mask, 0, FALSE,
    286       1.1  jmcneill 	    0, NULL);
    287       1.6  jmcneill 	if (EFI_ERROR(status) && status != EFI_INVALID_PARAMETER && status != EFI_UNSUPPORTED) {
    288       1.1  jmcneill 		printf("net%d: cannot set rx. filters (status=%" PRIxMAX ")\n",
    289       1.1  jmcneill 		    nif->nif_unit, (uintmax_t)status);
    290       1.1  jmcneill 		return;
    291       1.1  jmcneill 	}
    292       1.1  jmcneill 
    293       1.1  jmcneill #if notyet
    294       1.1  jmcneill 	if (!kernel_loaded) {
    295       1.1  jmcneill 		bi_netif.bus = eni->bus.type;
    296       1.1  jmcneill 		bi_netif.addr.tag = eni->bus.tag;
    297       1.1  jmcneill 		snprintf(bi_netif.ifname, sizeof(bi_netif.ifname), "net%d",
    298       1.1  jmcneill 		    nif->nif_unit);
    299       1.1  jmcneill 		BI_ADD(&bi_netif, BTINFO_NETIF, sizeof(bi_netif));
    300       1.1  jmcneill 	}
    301       1.1  jmcneill #endif
    302       1.1  jmcneill 
    303       1.1  jmcneill #ifdef EFINET_DEBUG
    304       1.1  jmcneill 	dump_mode(net->Mode);
    305       1.1  jmcneill #endif
    306       1.1  jmcneill 
    307       1.6  jmcneill 	memcpy(desc->myea, efinet_hwaddr(net->Mode)->Addr, 6);
    308       1.1  jmcneill 	desc->xid = 1;
    309       1.1  jmcneill }
    310       1.1  jmcneill 
    311       1.1  jmcneill static void
    312       1.1  jmcneill efinet_end(struct netif *nif)
    313       1.1  jmcneill {
    314       1.1  jmcneill 	struct efinetinfo *eni = nif->nif_devdata;
    315       1.1  jmcneill 	EFI_SIMPLE_NETWORK *net;
    316       1.1  jmcneill 
    317       1.1  jmcneill 	if (eni == NULL)
    318       1.1  jmcneill 		return;
    319       1.1  jmcneill 	net = eni->net;
    320       1.1  jmcneill 
    321       1.1  jmcneill 	uefi_call_wrapper(net->Shutdown, 1, net);
    322       1.1  jmcneill }
    323       1.1  jmcneill 
    324       1.1  jmcneill void
    325       1.1  jmcneill efi_net_probe(void)
    326       1.1  jmcneill {
    327       1.1  jmcneill 	struct efinetinfo *enis;
    328       1.1  jmcneill 	struct netif_dif *dif;
    329       1.1  jmcneill 	struct netif_stats *stats;
    330       1.6  jmcneill 	EFI_DEVICE_PATH *dp0, *dp;
    331       1.1  jmcneill 	EFI_SIMPLE_NETWORK *net;
    332       1.1  jmcneill 	EFI_HANDLE *handles;
    333       1.1  jmcneill 	EFI_STATUS status;
    334       1.1  jmcneill 	UINTN i, nhandles;
    335       1.3  jmcneill 	int nifs, depth = -1;
    336  1.6.32.1    martin 	bool found, is_bootdp;
    337       1.1  jmcneill 
    338       1.1  jmcneill 	status = LibLocateHandle(ByProtocol, &SimpleNetworkProtocol, NULL,
    339       1.1  jmcneill 	    &nhandles, &handles);
    340       1.1  jmcneill 	if (EFI_ERROR(status) || nhandles == 0)
    341       1.1  jmcneill 		return;
    342       1.1  jmcneill 
    343       1.1  jmcneill 	enis = alloc(nhandles * sizeof(*enis));
    344       1.1  jmcneill 	if (enis == NULL)
    345       1.1  jmcneill 		return;
    346       1.1  jmcneill 	memset(enis, 0, nhandles * sizeof(*enis));
    347       1.1  jmcneill 
    348       1.3  jmcneill 	if (efi_bootdp) {
    349  1.6.32.1    martin 		/*
    350  1.6.32.1    martin 		 * Either Hardware or Messaging Device Paths can be used
    351  1.6.32.1    martin 		 * here, see Sec 10.4.4 of UEFI Spec 2.10. Try both.
    352  1.6.32.1    martin 		 */
    353       1.3  jmcneill 		depth = efi_device_path_depth(efi_bootdp, HARDWARE_DEVICE_PATH);
    354  1.6.32.1    martin 		if (depth == -1) {
    355  1.6.32.1    martin 			depth = efi_device_path_depth(efi_bootdp,
    356  1.6.32.1    martin 			    MESSAGING_DEVICE_PATH);
    357  1.6.32.1    martin 		}
    358       1.3  jmcneill 		if (depth == 0)
    359       1.3  jmcneill 			depth = 1;
    360       1.3  jmcneill 	}
    361       1.3  jmcneill 
    362       1.1  jmcneill 	nifs = 0;
    363       1.1  jmcneill 	for (i = 0; i < nhandles; i++) {
    364       1.1  jmcneill 		status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i],
    365       1.1  jmcneill 		    &DevicePathProtocol, (void **)&dp0);
    366       1.1  jmcneill 		if (EFI_ERROR(status))
    367       1.1  jmcneill 			continue;
    368       1.1  jmcneill 
    369       1.1  jmcneill 		found = false;
    370       1.1  jmcneill 		for (dp = dp0; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp)) {
    371       1.1  jmcneill 			if (DevicePathType(dp) == MESSAGING_DEVICE_PATH &&
    372       1.1  jmcneill 			    DevicePathSubType(dp) == MSG_MAC_ADDR_DP) {
    373       1.1  jmcneill 				found = true;
    374       1.1  jmcneill 				break;
    375       1.1  jmcneill 			}
    376       1.1  jmcneill 		}
    377       1.1  jmcneill 		if (!found)
    378       1.1  jmcneill 			continue;
    379       1.1  jmcneill 
    380  1.6.32.1    martin 		is_bootdp = depth > 0 &&
    381  1.6.32.1    martin 		    efi_device_path_ncmp(efi_bootdp, dp0, depth) == 0;
    382  1.6.32.1    martin 
    383       1.1  jmcneill 		status = uefi_call_wrapper(BS->OpenProtocol, 6, handles[i],
    384       1.1  jmcneill 		    &SimpleNetworkProtocol, (void **)&net, IH, NULL,
    385       1.1  jmcneill 		    EFI_OPEN_PROTOCOL_EXCLUSIVE);
    386       1.1  jmcneill 		if (EFI_ERROR(status)) {
    387       1.1  jmcneill 			printf("Unable to open network interface %" PRIuMAX
    388       1.1  jmcneill 			    " for exclusive access: %" PRIxMAX "\n",
    389       1.1  jmcneill 			    (uintmax_t)i, (uintmax_t)status);
    390       1.6  jmcneill 			continue;
    391       1.1  jmcneill 		}
    392       1.1  jmcneill 
    393       1.6  jmcneill 		enis[nifs].net = net;
    394       1.6  jmcneill 		enis[nifs].bootdev = efi_pxe_match_booted_interface(
    395       1.6  jmcneill 		    efinet_hwaddr(net->Mode), net->Mode->HwAddressSize);
    396       1.6  jmcneill 		enis[nifs].pktbufsz = net->Mode->MaxPacketSize +
    397       1.6  jmcneill 		    ETHER_EXT_LEN;
    398       1.6  jmcneill 		enis[nifs].pktbuf = alloc(enis[nifs].pktbufsz);
    399       1.6  jmcneill 		if (enis[nifs].pktbuf == NULL) {
    400       1.6  jmcneill 			while (i-- > 0) {
    401       1.6  jmcneill 				dealloc(enis[i].pktbuf, enis[i].pktbufsz);
    402       1.6  jmcneill 				if (i == 0)
    403       1.6  jmcneill 					break;
    404       1.1  jmcneill 			}
    405       1.6  jmcneill 			dealloc(enis, nhandles * sizeof(*enis));
    406       1.6  jmcneill 			FreePool(handles);
    407       1.6  jmcneill 			return;
    408       1.1  jmcneill 		}
    409       1.3  jmcneill 
    410  1.6.32.1    martin 		if (is_bootdp) {
    411  1.6.32.1    martin 			/*
    412  1.6.32.1    martin 			 * This is boot device...
    413  1.6.32.1    martin 			 */
    414       1.6  jmcneill 			char devname[9];
    415  1.6.32.1    martin 
    416       1.6  jmcneill 			snprintf(devname, sizeof(devname), "net%u", nifs);
    417       1.6  jmcneill 			set_default_device(devname);
    418  1.6.32.1    martin 
    419  1.6.32.1    martin 			/*
    420  1.6.32.1    martin 			 * and now opened for us excluively. Therefore,
    421  1.6.32.1    martin 			 * access via device path is illegal.
    422  1.6.32.1    martin 			 */
    423  1.6.32.1    martin 			efi_bootdp = NULL;
    424  1.6.32.1    martin 			depth = -1;
    425       1.6  jmcneill 		}
    426       1.3  jmcneill 
    427       1.6  jmcneill 		nifs++;
    428       1.1  jmcneill 	}
    429       1.1  jmcneill 
    430       1.1  jmcneill 	FreePool(handles);
    431       1.1  jmcneill 
    432       1.1  jmcneill 	if (nifs == 0)
    433       1.1  jmcneill 		return;
    434       1.1  jmcneill 
    435       1.1  jmcneill 	efinetif.netif_ifs = alloc(nifs * sizeof(*dif));
    436       1.1  jmcneill 	stats = alloc(nifs * sizeof(*stats));
    437       1.1  jmcneill 	if (efinetif.netif_ifs == NULL || stats == NULL) {
    438       1.1  jmcneill 		if (efinetif.netif_ifs != NULL) {
    439       1.1  jmcneill 			dealloc(efinetif.netif_ifs, nifs * sizeof(*dif));
    440       1.1  jmcneill 			efinetif.netif_ifs = NULL;
    441       1.1  jmcneill 		}
    442       1.1  jmcneill 		if (stats != NULL)
    443       1.1  jmcneill 			dealloc(stats, nifs * sizeof(*stats));
    444       1.1  jmcneill 		for (i = 0; i < nifs; i++)
    445       1.1  jmcneill 			dealloc(enis[i].pktbuf, enis[i].pktbufsz);
    446       1.1  jmcneill 		dealloc(enis, nhandles * sizeof(*enis));
    447       1.1  jmcneill 		return;
    448       1.1  jmcneill 	}
    449       1.1  jmcneill 	memset(efinetif.netif_ifs, 0, nifs * sizeof(*dif));
    450       1.1  jmcneill 	memset(stats, 0, nifs * sizeof(*stats));
    451       1.1  jmcneill 	efinetif.netif_nifs = nifs;
    452       1.1  jmcneill 
    453       1.1  jmcneill 	for (i = 0; i < nifs; i++) {
    454       1.1  jmcneill 		dif = &efinetif.netif_ifs[i];
    455       1.1  jmcneill 		dif->dif_unit = i;
    456       1.1  jmcneill 		dif->dif_nsel = 1;
    457       1.1  jmcneill 		dif->dif_stats = &stats[i];
    458       1.1  jmcneill 		dif->dif_private = &enis[i];
    459       1.1  jmcneill 	}
    460       1.1  jmcneill }
    461       1.1  jmcneill 
    462       1.1  jmcneill void
    463       1.1  jmcneill efi_net_show(void)
    464       1.1  jmcneill {
    465       1.1  jmcneill 	const struct netif_dif *dif;
    466       1.1  jmcneill 	const struct efinetinfo *eni;
    467       1.1  jmcneill 	EFI_SIMPLE_NETWORK *net;
    468       1.1  jmcneill 	int i;
    469       1.1  jmcneill 
    470       1.1  jmcneill 	for (i = 0; i < efinetif.netif_nifs; i++) {
    471       1.1  jmcneill 		dif = &efinetif.netif_ifs[i];
    472       1.1  jmcneill 		eni = dif->dif_private;
    473       1.1  jmcneill 		net = eni->net;
    474       1.1  jmcneill 
    475       1.4  jmcneill 		printf("net%d", dif->dif_unit);
    476       1.1  jmcneill 		if (net->Mode != NULL) {
    477       1.6  jmcneill 			const EFI_MAC_ADDRESS *mac = efinet_hwaddr(net->Mode);
    478       1.1  jmcneill 			for (UINT32 x = 0; x < net->Mode->HwAddressSize; x++) {
    479       1.1  jmcneill 				printf("%c%02x", x == 0 ? ' ' : ':',
    480       1.6  jmcneill 				    mac->Addr[x]);
    481       1.1  jmcneill 			}
    482       1.1  jmcneill 		}
    483       1.1  jmcneill 		if (eni->bootdev)
    484       1.1  jmcneill 			printf(" pxeboot");
    485       1.1  jmcneill 		printf("\n");
    486       1.1  jmcneill 	}
    487       1.1  jmcneill }
    488       1.1  jmcneill 
    489       1.1  jmcneill int
    490       1.1  jmcneill efi_net_get_booted_interface_unit(void)
    491       1.1  jmcneill {
    492       1.1  jmcneill 	const struct netif_dif *dif;
    493       1.1  jmcneill 	const struct efinetinfo *eni;
    494       1.1  jmcneill 	int i;
    495       1.1  jmcneill 
    496       1.1  jmcneill 	for (i = 0; i < efinetif.netif_nifs; i++) {
    497       1.1  jmcneill 		dif = &efinetif.netif_ifs[i];
    498       1.1  jmcneill 		eni = dif->dif_private;
    499       1.1  jmcneill 		if (eni->bootdev)
    500       1.1  jmcneill 			return dif->dif_unit;
    501       1.1  jmcneill 	}
    502       1.1  jmcneill 	return -1;
    503       1.1  jmcneill }
    504       1.1  jmcneill 
    505       1.1  jmcneill int
    506       1.4  jmcneill efi_net_get_booted_macaddr(uint8_t *mac)
    507       1.4  jmcneill {
    508       1.4  jmcneill 	const struct netif_dif *dif;
    509       1.4  jmcneill 	const struct efinetinfo *eni;
    510       1.4  jmcneill 	EFI_SIMPLE_NETWORK *net;
    511       1.4  jmcneill 	int i;
    512       1.4  jmcneill 
    513       1.4  jmcneill 	for (i = 0; i < efinetif.netif_nifs; i++) {
    514       1.4  jmcneill 		dif = &efinetif.netif_ifs[i];
    515       1.4  jmcneill 		eni = dif->dif_private;
    516       1.4  jmcneill 		net = eni->net;
    517       1.4  jmcneill 		if (eni->bootdev && net->Mode != NULL && net->Mode->HwAddressSize == 6) {
    518       1.4  jmcneill 			memcpy(mac, net->Mode->PermanentAddress.Addr, 6);
    519       1.4  jmcneill 			return 0;
    520       1.4  jmcneill 		}
    521       1.4  jmcneill 	}
    522       1.4  jmcneill 
    523       1.4  jmcneill 	return -1;
    524       1.4  jmcneill }
    525       1.4  jmcneill 
    526       1.4  jmcneill int
    527       1.1  jmcneill efi_net_open(struct open_file *f, ...)
    528       1.1  jmcneill {
    529       1.3  jmcneill 	char **file, pathbuf[PATH_MAX], *default_device, *path, *ep;
    530       1.3  jmcneill 	const char *fname, *full_path;
    531       1.1  jmcneill 	struct devdesc desc;
    532       1.1  jmcneill 	intmax_t dev;
    533       1.1  jmcneill 	va_list ap;
    534       1.4  jmcneill 	int n, error;
    535       1.1  jmcneill 
    536       1.1  jmcneill 	va_start(ap, f);
    537       1.1  jmcneill 	fname = va_arg(ap, const char *);
    538       1.1  jmcneill 	file = va_arg(ap, char **);
    539       1.1  jmcneill 	va_end(ap);
    540       1.1  jmcneill 
    541       1.3  jmcneill 	default_device = get_default_device();
    542       1.3  jmcneill 	if (strchr(fname, ':') == NULL) {
    543       1.3  jmcneill 		if (strlen(default_device) > 0) {
    544       1.3  jmcneill 			snprintf(pathbuf, sizeof(pathbuf), "%s:%s", default_device, fname);
    545       1.3  jmcneill 			full_path = pathbuf;
    546       1.3  jmcneill 			path = __UNCONST(fname);
    547       1.3  jmcneill 		} else {
    548       1.3  jmcneill 			return EINVAL;
    549       1.3  jmcneill 		}
    550       1.3  jmcneill 	} else {
    551       1.3  jmcneill 		full_path = fname;
    552       1.3  jmcneill 		path = strchr(fname, ':') + 1;
    553       1.3  jmcneill 	}
    554       1.3  jmcneill 
    555       1.3  jmcneill 	if (strncmp(full_path, "net", 3) != 0)
    556       1.1  jmcneill 		return EINVAL;
    557       1.3  jmcneill         dev = strtoimax(full_path + 3, &ep, 10);
    558       1.1  jmcneill         if (dev < 0 || dev >= efinetif.netif_nifs)
    559       1.1  jmcneill                 return ENXIO;
    560       1.1  jmcneill 
    561       1.1  jmcneill         for (n = 0; n < ndevs; n++)
    562       1.1  jmcneill                 if (strcmp(DEV_NAME(&devsw[n]), "net") == 0) {
    563       1.1  jmcneill                         f->f_dev = &devsw[n];
    564       1.1  jmcneill                         break;
    565       1.1  jmcneill                 }
    566       1.1  jmcneill         if (n == ndevs)
    567       1.1  jmcneill                 return ENXIO;
    568       1.1  jmcneill 
    569       1.3  jmcneill 	*file = path;
    570       1.1  jmcneill 
    571       1.1  jmcneill 	//try_bootp = 1;
    572       1.1  jmcneill 
    573       1.1  jmcneill 	memset(&desc, 0, sizeof(desc));
    574       1.1  jmcneill 	strlcpy(desc.d_name, "net", sizeof(desc.d_name));
    575       1.1  jmcneill 	desc.d_unit = dev;
    576       1.1  jmcneill 
    577       1.4  jmcneill 	error = DEV_OPEN(f->f_dev)(f, &desc);
    578       1.4  jmcneill 	if (error)
    579       1.4  jmcneill 		return error;
    580       1.4  jmcneill 
    581       1.4  jmcneill 	return 0;
    582       1.1  jmcneill }
    583