10384eafeSToomas Soome /*
2199767f8SToomas Soome  * Copyright (c) 2001 Doug Rabson
3199767f8SToomas Soome  * Copyright (c) 2002, 2006 Marcel Moolenaar
4199767f8SToomas Soome  * All rights reserved.
5199767f8SToomas Soome  *
6199767f8SToomas Soome  * Redistribution and use in source and binary forms, with or without
7199767f8SToomas Soome  * modification, are permitted provided that the following conditions
8199767f8SToomas Soome  * are met:
9199767f8SToomas Soome  * 1. Redistributions of source code must retain the above copyright
10199767f8SToomas Soome  *    notice, this list of conditions and the following disclaimer.
11199767f8SToomas Soome  * 2. Redistributions in binary form must reproduce the above copyright
12199767f8SToomas Soome  *    notice, this list of conditions and the following disclaimer in the
13199767f8SToomas Soome  *    documentation and/or other materials provided with the distribution.
14199767f8SToomas Soome  *
15199767f8SToomas Soome  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16199767f8SToomas Soome  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17199767f8SToomas Soome  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18199767f8SToomas Soome  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19199767f8SToomas Soome  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20199767f8SToomas Soome  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21199767f8SToomas Soome  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22199767f8SToomas Soome  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23199767f8SToomas Soome  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24199767f8SToomas Soome  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25199767f8SToomas Soome  * SUCH DAMAGE.
26199767f8SToomas Soome  */
27199767f8SToomas Soome 
28199767f8SToomas Soome #include <sys/cdefs.h>
29199767f8SToomas Soome 
30199767f8SToomas Soome #include <sys/param.h>
31859472daSToomas Soome #include <net/ethernet.h>
32199767f8SToomas Soome #include <netinet/in.h>
33199767f8SToomas Soome #include <netinet/in_systm.h>
34199767f8SToomas Soome 
35199767f8SToomas Soome #include <stand.h>
36199767f8SToomas Soome #include <net.h>
37199767f8SToomas Soome #include <netif.h>
38199767f8SToomas Soome 
39199767f8SToomas Soome #include <efi.h>
40199767f8SToomas Soome #include <efilib.h>
41199767f8SToomas Soome 
42199767f8SToomas Soome static EFI_GUID sn_guid = EFI_SIMPLE_NETWORK_PROTOCOL;
43199767f8SToomas Soome 
44199767f8SToomas Soome static void efinet_end(struct netif *);
45859472daSToomas Soome static ssize_t efinet_get(struct iodesc *, void **, time_t);
46199767f8SToomas Soome static void efinet_init(struct iodesc *, void *);
47199767f8SToomas Soome static int efinet_match(struct netif *, void *);
48199767f8SToomas Soome static int efinet_probe(struct netif *, void *);
49859472daSToomas Soome static ssize_t efinet_put(struct iodesc *, void *, size_t);
50199767f8SToomas Soome 
51696c22afSToomas Soome struct netif_driver efinetif = {
52199767f8SToomas Soome 	.netif_bname = "efinet",
53199767f8SToomas Soome 	.netif_match = efinet_match,
54199767f8SToomas Soome 	.netif_probe = efinet_probe,
55199767f8SToomas Soome 	.netif_init = efinet_init,
56199767f8SToomas Soome 	.netif_get = efinet_get,
57199767f8SToomas Soome 	.netif_put = efinet_put,
58199767f8SToomas Soome 	.netif_end = efinet_end,
59199767f8SToomas Soome 	.netif_ifs = NULL,
60199767f8SToomas Soome 	.netif_nifs = 0
61199767f8SToomas Soome };
62199767f8SToomas Soome 
63199767f8SToomas Soome #ifdef EFINET_DEBUG
64199767f8SToomas Soome static void
dump_mode(EFI_SIMPLE_NETWORK_MODE * mode)65199767f8SToomas Soome dump_mode(EFI_SIMPLE_NETWORK_MODE *mode)
66199767f8SToomas Soome {
67199767f8SToomas Soome 	int i;
68199767f8SToomas Soome 
69199767f8SToomas Soome 	printf("State                 = %x\n", mode->State);
70199767f8SToomas Soome 	printf("HwAddressSize         = %u\n", mode->HwAddressSize);
71199767f8SToomas Soome 	printf("MediaHeaderSize       = %u\n", mode->MediaHeaderSize);
72199767f8SToomas Soome 	printf("MaxPacketSize         = %u\n", mode->MaxPacketSize);
73199767f8SToomas Soome 	printf("NvRamSize             = %u\n", mode->NvRamSize);
74199767f8SToomas Soome 	printf("NvRamAccessSize       = %u\n", mode->NvRamAccessSize);
75199767f8SToomas Soome 	printf("ReceiveFilterMask     = %x\n", mode->ReceiveFilterMask);
76199767f8SToomas Soome 	printf("ReceiveFilterSetting  = %u\n", mode->ReceiveFilterSetting);
77199767f8SToomas Soome 	printf("MaxMCastFilterCount   = %u\n", mode->MaxMCastFilterCount);
78199767f8SToomas Soome 	printf("MCastFilterCount      = %u\n", mode->MCastFilterCount);
79199767f8SToomas Soome 	printf("MCastFilter           = {");
80199767f8SToomas Soome 	for (i = 0; i < mode->MCastFilterCount; i++)
81199767f8SToomas Soome 		printf(" %s", ether_sprintf(mode->MCastFilter[i].Addr));
82199767f8SToomas Soome 	printf(" }\n");
83199767f8SToomas Soome 	printf("CurrentAddress        = %s\n",
84199767f8SToomas Soome 	    ether_sprintf(mode->CurrentAddress.Addr));
85199767f8SToomas Soome 	printf("BroadcastAddress      = %s\n",
86199767f8SToomas Soome 	    ether_sprintf(mode->BroadcastAddress.Addr));
87199767f8SToomas Soome 	printf("PermanentAddress      = %s\n",
88199767f8SToomas Soome 	    ether_sprintf(mode->PermanentAddress.Addr));
89199767f8SToomas Soome 	printf("IfType                = %u\n", mode->IfType);
90199767f8SToomas Soome 	printf("MacAddressChangeable  = %d\n", mode->MacAddressChangeable);
91199767f8SToomas Soome 	printf("MultipleTxSupported   = %d\n", mode->MultipleTxSupported);
92199767f8SToomas Soome 	printf("MediaPresentSupported = %d\n", mode->MediaPresentSupported);
93199767f8SToomas Soome 	printf("MediaPresent          = %d\n", mode->MediaPresent);
94199767f8SToomas Soome }
95199767f8SToomas Soome #endif
96199767f8SToomas Soome 
97199767f8SToomas Soome static int
efinet_match(struct netif * nif,void * machdep_hint)98199767f8SToomas Soome efinet_match(struct netif *nif, void *machdep_hint)
99199767f8SToomas Soome {
100199767f8SToomas Soome 	struct devdesc *dev = machdep_hint;
101199767f8SToomas Soome 
102ab8c1d40SToomas Soome 	if (dev->d_unit == nif->nif_unit)
103199767f8SToomas Soome 		return (1);
1040384eafeSToomas Soome 	return (0);
105199767f8SToomas Soome }
106199767f8SToomas Soome 
107199767f8SToomas Soome static int
efinet_probe(struct netif * nif,void * machdep_hint __unused)1081998b081SToomas Soome efinet_probe(struct netif *nif, void *machdep_hint __unused)
109199767f8SToomas Soome {
1101998b081SToomas Soome 	EFI_SIMPLE_NETWORK *net;
1111998b081SToomas Soome 	EFI_HANDLE h;
1121998b081SToomas Soome 	EFI_STATUS status;
1131998b081SToomas Soome 
1141998b081SToomas Soome 	h = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private;
1151998b081SToomas Soome 
1161998b081SToomas Soome 	/*
1171998b081SToomas Soome 	 * Open the network device in exclusive mode. Without this
1181998b081SToomas Soome 	 * we will be racing with the UEFI network stack. It will
1191998b081SToomas Soome 	 * pull packets off the network leading to lost packets.
1201998b081SToomas Soome 	 */
1211998b081SToomas Soome 	status = BS->OpenProtocol(h, &sn_guid, (void **)&net,
1221998b081SToomas Soome 	    IH, NULL, EFI_OPEN_PROTOCOL_EXCLUSIVE);
1231998b081SToomas Soome 	if (status != EFI_SUCCESS) {
1241998b081SToomas Soome 		printf("Unable to open network interface %d for "
1251998b081SToomas Soome 		    "exclusive access: %lu\n", nif->nif_unit,
1261998b081SToomas Soome 		    EFI_ERROR_CODE(status));
1271998b081SToomas Soome 	}
128199767f8SToomas Soome 
129199767f8SToomas Soome 	return (0);
130199767f8SToomas Soome }
131199767f8SToomas Soome 
132859472daSToomas Soome static ssize_t
efinet_put(struct iodesc * desc,void * pkt,size_t len)133199767f8SToomas Soome efinet_put(struct iodesc *desc, void *pkt, size_t len)
134199767f8SToomas Soome {
135199767f8SToomas Soome 	struct netif *nif = desc->io_netif;
136199767f8SToomas Soome 	EFI_SIMPLE_NETWORK *net;
137199767f8SToomas Soome 	EFI_STATUS status;
138199767f8SToomas Soome 	void *buf;
139199767f8SToomas Soome 
140199767f8SToomas Soome 	net = nif->nif_devdata;
141ab8c1d40SToomas Soome 	if (net == NULL)
142ab8c1d40SToomas Soome 		return (-1);
143199767f8SToomas Soome 
144859472daSToomas Soome 	status = net->Transmit(net, 0, len, pkt, NULL, NULL, NULL);
145199767f8SToomas Soome 	if (status != EFI_SUCCESS)
146199767f8SToomas Soome 		return (-1);
147199767f8SToomas Soome 
148199767f8SToomas Soome 	/* Wait for the buffer to be transmitted */
149199767f8SToomas Soome 	do {
150859472daSToomas Soome 		buf = NULL;	/* XXX Is this needed? */
151859472daSToomas Soome 		status = net->GetStatus(net, NULL, &buf);
152199767f8SToomas Soome 		/*
153696c22afSToomas Soome 		 * XXX EFI1.1 and the E1000 card returns a different
154199767f8SToomas Soome 		 * address than we gave.  Sigh.
155199767f8SToomas Soome 		 */
156859472daSToomas Soome 	} while (status == EFI_SUCCESS && buf == NULL);
157199767f8SToomas Soome 
158199767f8SToomas Soome 	/* XXX How do we deal with status != EFI_SUCCESS now? */
159199767f8SToomas Soome 	return ((status == EFI_SUCCESS) ? len : -1);
160199767f8SToomas Soome }
161199767f8SToomas Soome 
162859472daSToomas Soome static ssize_t
efinet_get(struct iodesc * desc,void ** pkt,time_t timeout)163859472daSToomas Soome efinet_get(struct iodesc *desc, void **pkt, time_t timeout)
164199767f8SToomas Soome {
165199767f8SToomas Soome 	struct netif *nif = desc->io_netif;
166199767f8SToomas Soome 	EFI_SIMPLE_NETWORK *net;
167199767f8SToomas Soome 	EFI_STATUS status;
168199767f8SToomas Soome 	UINTN bufsz;
169199767f8SToomas Soome 	time_t t;
170859472daSToomas Soome 	char *buf, *ptr;
171859472daSToomas Soome 	ssize_t ret = -1;
172199767f8SToomas Soome 
173199767f8SToomas Soome 	net = nif->nif_devdata;
174ab8c1d40SToomas Soome 	if (net == NULL)
175859472daSToomas Soome 		return (ret);
176859472daSToomas Soome 
177859472daSToomas Soome 	bufsz = net->Mode->MaxPacketSize + ETHER_HDR_LEN + ETHER_CRC_LEN;
178859472daSToomas Soome 	buf = malloc(bufsz + ETHER_ALIGN);
179859472daSToomas Soome 	if (buf == NULL)
180859472daSToomas Soome 		return (ret);
181859472daSToomas Soome 	ptr = buf + ETHER_ALIGN;
182199767f8SToomas Soome 
183859472daSToomas Soome 	t = getsecs();
184859472daSToomas Soome 	while ((getsecs() - t) < timeout) {
185859472daSToomas Soome 		status = net->Receive(net, NULL, &bufsz, ptr, NULL, NULL, NULL);
186199767f8SToomas Soome 		if (status == EFI_SUCCESS) {
187859472daSToomas Soome 			*pkt = buf;
188859472daSToomas Soome 			ret = (ssize_t)bufsz;
189859472daSToomas Soome 			break;
190199767f8SToomas Soome 		}
191199767f8SToomas Soome 		if (status != EFI_NOT_READY)
192859472daSToomas Soome 			break;
193199767f8SToomas Soome 	}
194199767f8SToomas Soome 
195859472daSToomas Soome 	if (ret == -1)
196859472daSToomas Soome 		free(buf);
197859472daSToomas Soome 	return (ret);
198199767f8SToomas Soome }
199199767f8SToomas Soome 
200199767f8SToomas Soome static void
efinet_init(struct iodesc * desc,void * machdep_hint __unused)2018eef2ab6SToomas Soome efinet_init(struct iodesc *desc, void *machdep_hint __unused)
202199767f8SToomas Soome {
203199767f8SToomas Soome 	struct netif *nif = desc->io_netif;
204199767f8SToomas Soome 	EFI_SIMPLE_NETWORK *net;
205199767f8SToomas Soome 	EFI_HANDLE h;
206199767f8SToomas Soome 	EFI_STATUS status;
207ec36cb92SToomas Soome 	UINT32 mask;
208199767f8SToomas Soome 
209199767f8SToomas Soome 	if (nif->nif_driver->netif_ifs[nif->nif_unit].dif_unit < 0) {
210199767f8SToomas Soome 		printf("Invalid network interface %d\n", nif->nif_unit);
211199767f8SToomas Soome 		return;
212199767f8SToomas Soome 	}
213199767f8SToomas Soome 
214199767f8SToomas Soome 	h = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private;
215bf693dc9SToomas Soome 	status = OpenProtocolByHandle(h, &sn_guid, (void **)&nif->nif_devdata);
216199767f8SToomas Soome 	if (status != EFI_SUCCESS) {
217ab8c1d40SToomas Soome 		printf("net%d: cannot fetch interface data (status=%lu)\n",
218199767f8SToomas Soome 		    nif->nif_unit, EFI_ERROR_CODE(status));
219199767f8SToomas Soome 		return;
220199767f8SToomas Soome 	}
221199767f8SToomas Soome 
222199767f8SToomas Soome 	net = nif->nif_devdata;
223199767f8SToomas Soome 	if (net->Mode->State == EfiSimpleNetworkStopped) {
224199767f8SToomas Soome 		status = net->Start(net);
225199767f8SToomas Soome 		if (status != EFI_SUCCESS) {
226859472daSToomas Soome 			printf("net%d: cannot start interface (status=%lu)\n",
227859472daSToomas Soome 			    nif->nif_unit, EFI_ERROR_CODE(status));
228199767f8SToomas Soome 			return;
229199767f8SToomas Soome 		}
230199767f8SToomas Soome 	}
231199767f8SToomas Soome 
232199767f8SToomas Soome 	if (net->Mode->State != EfiSimpleNetworkInitialized) {
233199767f8SToomas Soome 		status = net->Initialize(net, 0, 0);
234199767f8SToomas Soome 		if (status != EFI_SUCCESS) {
235859472daSToomas Soome 			printf("net%d: cannot init. interface (status=%lu)\n",
236859472daSToomas Soome 			    nif->nif_unit, EFI_ERROR_CODE(status));
237199767f8SToomas Soome 			return;
238199767f8SToomas Soome 		}
239199767f8SToomas Soome 	}
240199767f8SToomas Soome 
241ec36cb92SToomas Soome 	mask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
242ec36cb92SToomas Soome 	    EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
243199767f8SToomas Soome 
244ec36cb92SToomas Soome 	status = net->ReceiveFilters(net, mask, 0, FALSE, 0, NULL);
245696c22afSToomas Soome 	if (status != EFI_SUCCESS)
246ec36cb92SToomas Soome 		printf("net%d: cannot set rx. filters (status=%lu)\n",
247ec36cb92SToomas Soome 		    nif->nif_unit, EFI_ERROR_CODE(status));
248199767f8SToomas Soome 
249199767f8SToomas Soome #ifdef EFINET_DEBUG
250199767f8SToomas Soome 	dump_mode(net->Mode);
251199767f8SToomas Soome #endif
252199767f8SToomas Soome 
253199767f8SToomas Soome 	bcopy(net->Mode->CurrentAddress.Addr, desc->myea, 6);
254199767f8SToomas Soome 	desc->xid = 1;
255199767f8SToomas Soome }
256199767f8SToomas Soome 
257199767f8SToomas Soome static void
efinet_end(struct netif * nif)258199767f8SToomas Soome efinet_end(struct netif *nif)
259199767f8SToomas Soome {
260696c22afSToomas Soome 	EFI_SIMPLE_NETWORK *net = nif->nif_devdata;
261199767f8SToomas Soome 
262ab8c1d40SToomas Soome 	if (net == NULL)
263ab8c1d40SToomas Soome 		return;
264ab8c1d40SToomas Soome 
265199767f8SToomas Soome 	net->Shutdown(net);
266199767f8SToomas Soome }
267199767f8SToomas Soome 
268199767f8SToomas Soome static int efinet_dev_init(void);
269199767f8SToomas Soome static int efinet_dev_print(int);
270199767f8SToomas Soome 
271199767f8SToomas Soome struct devsw efinet_dev = {
272199767f8SToomas Soome 	.dv_name = "net",
273199767f8SToomas Soome 	.dv_type = DEVT_NET,
274199767f8SToomas Soome 	.dv_init = efinet_dev_init,
275859472daSToomas Soome 	.dv_strategy = NULL,		/* Will be set in efinet_dev_init */
276859472daSToomas Soome 	.dv_open = NULL,		/* Will be set in efinet_dev_init */
277859472daSToomas Soome 	.dv_close = NULL,		/* Will be set in efinet_dev_init */
278199767f8SToomas Soome 	.dv_ioctl = noioctl,
279199767f8SToomas Soome 	.dv_print = efinet_dev_print,
280199767f8SToomas Soome 	.dv_cleanup = NULL
281199767f8SToomas Soome };
282199767f8SToomas Soome 
283199767f8SToomas Soome static int
efinet_dev_init(void)2840384eafeSToomas Soome efinet_dev_init(void)
285199767f8SToomas Soome {
286199767f8SToomas Soome 	struct netif_dif *dif;
287199767f8SToomas Soome 	struct netif_stats *stats;
288ab8c1d40SToomas Soome 	EFI_DEVICE_PATH *devpath, *node;
289ab8c1d40SToomas Soome 	EFI_HANDLE *handles, *handles2;
290199767f8SToomas Soome 	EFI_STATUS status;
291199767f8SToomas Soome 	UINTN sz;
292199767f8SToomas Soome 	int err, i, nifs;
293859472daSToomas Soome 	extern struct devsw netdev;
294199767f8SToomas Soome 
295199767f8SToomas Soome 	sz = 0;
296199767f8SToomas Soome 	handles = NULL;
297859472daSToomas Soome 	status = BS->LocateHandle(ByProtocol, &sn_guid, NULL, &sz, NULL);
298199767f8SToomas Soome 	if (status == EFI_BUFFER_TOO_SMALL) {
299199767f8SToomas Soome 		handles = (EFI_HANDLE *)malloc(sz);
300*89145554SToomas Soome 		if (handles == NULL)
301*89145554SToomas Soome 			return (ENOMEM);
302859472daSToomas Soome 		status = BS->LocateHandle(ByProtocol, &sn_guid, NULL, &sz,
303199767f8SToomas Soome 		    handles);
304199767f8SToomas Soome 		if (EFI_ERROR(status))
305199767f8SToomas Soome 			free(handles);
306199767f8SToomas Soome 	}
307199767f8SToomas Soome 	if (EFI_ERROR(status))
308199767f8SToomas Soome 		return (efi_status_to_errno(status));
309ab8c1d40SToomas Soome 	handles2 = (EFI_HANDLE *)malloc(sz);
310ab8c1d40SToomas Soome 	if (handles2 == NULL) {
311ab8c1d40SToomas Soome 		free(handles);
312ab8c1d40SToomas Soome 		return (ENOMEM);
313ab8c1d40SToomas Soome 	}
314ab8c1d40SToomas Soome 	nifs = 0;
3150384eafeSToomas Soome 	for (i = 0; i < sz / sizeof (EFI_HANDLE); i++) {
316ab8c1d40SToomas Soome 		devpath = efi_lookup_devpath(handles[i]);
317ab8c1d40SToomas Soome 		if (devpath == NULL)
318ab8c1d40SToomas Soome 			continue;
319ab8c1d40SToomas Soome 		if ((node = efi_devpath_last_node(devpath)) == NULL)
320ab8c1d40SToomas Soome 			continue;
321ab8c1d40SToomas Soome 
322ab8c1d40SToomas Soome 		if (DevicePathType(node) != MESSAGING_DEVICE_PATH ||
323ab8c1d40SToomas Soome 		    DevicePathSubType(node) != MSG_MAC_ADDR_DP)
324ab8c1d40SToomas Soome 			continue;
325199767f8SToomas Soome 
326ab8c1d40SToomas Soome 		handles2[nifs] = handles[i];
327ab8c1d40SToomas Soome 		nifs++;
328ab8c1d40SToomas Soome 	}
329ab8c1d40SToomas Soome 	free(handles);
330ab8c1d40SToomas Soome 	if (nifs == 0) {
331ab8c1d40SToomas Soome 		err = ENOENT;
332ab8c1d40SToomas Soome 		goto done;
333ab8c1d40SToomas Soome 	}
334ab8c1d40SToomas Soome 
335ab8c1d40SToomas Soome 	err = efi_register_handles(&efinet_dev, handles2, NULL, nifs);
336ab8c1d40SToomas Soome 	if (err != 0)
337ab8c1d40SToomas Soome 		goto done;
338ab8c1d40SToomas Soome 
3390384eafeSToomas Soome 	efinetif.netif_ifs = calloc(nifs, sizeof (struct netif_dif));
3400384eafeSToomas Soome 	stats = calloc(nifs, sizeof (struct netif_stats));
341ab8c1d40SToomas Soome 	if (efinetif.netif_ifs == NULL || stats == NULL) {
342ab8c1d40SToomas Soome 		free(efinetif.netif_ifs);
343ab8c1d40SToomas Soome 		free(stats);
344ab8c1d40SToomas Soome 		efinetif.netif_ifs = NULL;
345ab8c1d40SToomas Soome 		err = ENOMEM;
346ab8c1d40SToomas Soome 		goto done;
347ab8c1d40SToomas Soome 	}
348ab8c1d40SToomas Soome 	efinetif.netif_nifs = nifs;
349ab8c1d40SToomas Soome 
350ab8c1d40SToomas Soome 	for (i = 0; i < nifs; i++) {
351ab8c1d40SToomas Soome 
352ab8c1d40SToomas Soome 		dif = &efinetif.netif_ifs[i];
353199767f8SToomas Soome 		dif->dif_unit = i;
354199767f8SToomas Soome 		dif->dif_nsel = 1;
355199767f8SToomas Soome 		dif->dif_stats = &stats[i];
356ab8c1d40SToomas Soome 		dif->dif_private = handles2[i];
357199767f8SToomas Soome 	}
358859472daSToomas Soome 
359859472daSToomas Soome 	efinet_dev.dv_open = netdev.dv_open;
360859472daSToomas Soome 	efinet_dev.dv_close = netdev.dv_close;
361859472daSToomas Soome 	efinet_dev.dv_strategy = netdev.dv_strategy;
362859472daSToomas Soome 
363ab8c1d40SToomas Soome done:
364ab8c1d40SToomas Soome 	free(handles2);
365ab8c1d40SToomas Soome 	return (err);
366199767f8SToomas Soome }
367199767f8SToomas Soome 
368199767f8SToomas Soome static int
efinet_dev_print(int verbose)369199767f8SToomas Soome efinet_dev_print(int verbose)
370199767f8SToomas Soome {
371ab8c1d40SToomas Soome 	CHAR16 *text;
372199767f8SToomas Soome 	EFI_HANDLE h;
37372136b48SToomas Soome 	int unit, ret = 0;
374199767f8SToomas Soome 
375502b33a5SToomas Soome 	printf("%s devices:", efinet_dev.dv_name);
376502b33a5SToomas Soome 	if ((ret = pager_output("\n")) != 0)
377502b33a5SToomas Soome 		return (ret);
378502b33a5SToomas Soome 
379199767f8SToomas Soome 	for (unit = 0, h = efi_find_handle(&efinet_dev, 0);
380199767f8SToomas Soome 	    h != NULL; h = efi_find_handle(&efinet_dev, ++unit)) {
381ab8c1d40SToomas Soome 		printf("    %s%d:", efinet_dev.dv_name, unit);
38272136b48SToomas Soome 		if (verbose) {
38372136b48SToomas Soome 			text = efi_devpath_name(efi_lookup_devpath(h));
38472136b48SToomas Soome 			if (text != NULL) {
38572136b48SToomas Soome 				printf("    %S", text);
38672136b48SToomas Soome 				efi_free_devpath_name(text);
38772136b48SToomas Soome 			}
388ab8c1d40SToomas Soome 		}
38972136b48SToomas Soome 		if ((ret = pager_output("\n")) != 0)
390199767f8SToomas Soome 			break;
391199767f8SToomas Soome 	}
392199767f8SToomas Soome 	return (ret);
393199767f8SToomas Soome }
394