183828Sdfr/*-
283828Sdfr * Copyright (c) 2001 Doug Rabson
3164010Smarcel * Copyright (c) 2002, 2006 Marcel Moolenaar
483828Sdfr * All rights reserved.
583828Sdfr *
683828Sdfr * Redistribution and use in source and binary forms, with or without
783828Sdfr * modification, are permitted provided that the following conditions
883828Sdfr * are met:
983828Sdfr * 1. Redistributions of source code must retain the above copyright
1083828Sdfr *    notice, this list of conditions and the following disclaimer.
1183828Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1283828Sdfr *    notice, this list of conditions and the following disclaimer in the
1383828Sdfr *    documentation and/or other materials provided with the distribution.
1483828Sdfr *
1583828Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1683828Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1783828Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1883828Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1983828Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2083828Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2183828Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2283828Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2383828Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2483828Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2583828Sdfr * SUCH DAMAGE.
2683828Sdfr */
2783828Sdfr
28124140Sobrien#include <sys/cdefs.h>
29124140Sobrien__FBSDID("$FreeBSD: stable/11/stand/efi/libefi/efinet.c 332156 2018-04-06 21:50:09Z kevans $");
30124140Sobrien
3183828Sdfr#include <sys/param.h>
32329100Skevans#include <net/ethernet.h>
3383828Sdfr#include <netinet/in.h>
3483828Sdfr#include <netinet/in_systm.h>
3583828Sdfr
3683828Sdfr#include <stand.h>
3783828Sdfr#include <net.h>
3883828Sdfr#include <netif.h>
3983828Sdfr
4083828Sdfr#include <efi.h>
4183828Sdfr#include <efilib.h>
4283828Sdfr
43164010Smarcelstatic EFI_GUID sn_guid = EFI_SIMPLE_NETWORK_PROTOCOL;
4483828Sdfr
45164010Smarcelstatic void efinet_end(struct netif *);
46329100Skevansstatic ssize_t efinet_get(struct iodesc *, void **, time_t);
47164010Smarcelstatic void efinet_init(struct iodesc *, void *);
48164010Smarcelstatic int efinet_match(struct netif *, void *);
49164010Smarcelstatic int efinet_probe(struct netif *, void *);
50329100Skevansstatic ssize_t efinet_put(struct iodesc *, void *, size_t);
51164010Smarcel
52292625Semastestruct netif_driver efinetif = {
53164010Smarcel	.netif_bname = "efinet",
54164010Smarcel	.netif_match = efinet_match,
55164010Smarcel	.netif_probe = efinet_probe,
56164010Smarcel	.netif_init = efinet_init,
57164010Smarcel	.netif_get = efinet_get,
58164010Smarcel	.netif_put = efinet_put,
59164010Smarcel	.netif_end = efinet_end,
60164010Smarcel	.netif_ifs = NULL,
61164010Smarcel	.netif_nifs = 0
62164010Smarcel};
63164010Smarcel
6493409Smarcel#ifdef EFINET_DEBUG
6593409Smarcelstatic void
6693409Smarceldump_mode(EFI_SIMPLE_NETWORK_MODE *mode)
6793409Smarcel{
6893409Smarcel	int i;
6993409Smarcel
7093409Smarcel	printf("State                 = %x\n", mode->State);
7193409Smarcel	printf("HwAddressSize         = %u\n", mode->HwAddressSize);
7293409Smarcel	printf("MediaHeaderSize       = %u\n", mode->MediaHeaderSize);
7393409Smarcel	printf("MaxPacketSize         = %u\n", mode->MaxPacketSize);
7493409Smarcel	printf("NvRamSize             = %u\n", mode->NvRamSize);
7593409Smarcel	printf("NvRamAccessSize       = %u\n", mode->NvRamAccessSize);
7693409Smarcel	printf("ReceiveFilterMask     = %x\n", mode->ReceiveFilterMask);
7793409Smarcel	printf("ReceiveFilterSetting  = %u\n", mode->ReceiveFilterSetting);
7893409Smarcel	printf("MaxMCastFilterCount   = %u\n", mode->MaxMCastFilterCount);
7993409Smarcel	printf("MCastFilterCount      = %u\n", mode->MCastFilterCount);
8093409Smarcel	printf("MCastFilter           = {");
8193409Smarcel	for (i = 0; i < mode->MCastFilterCount; i++)
8293409Smarcel		printf(" %s", ether_sprintf(mode->MCastFilter[i].Addr));
8393409Smarcel	printf(" }\n");
8493409Smarcel	printf("CurrentAddress        = %s\n",
8593409Smarcel	    ether_sprintf(mode->CurrentAddress.Addr));
8693409Smarcel	printf("BroadcastAddress      = %s\n",
8793409Smarcel	    ether_sprintf(mode->BroadcastAddress.Addr));
8893409Smarcel	printf("PermanentAddress      = %s\n",
8993409Smarcel	    ether_sprintf(mode->PermanentAddress.Addr));
9093409Smarcel	printf("IfType                = %u\n", mode->IfType);
9193409Smarcel	printf("MacAddressChangeable  = %d\n", mode->MacAddressChangeable);
9293409Smarcel	printf("MultipleTxSupported   = %d\n", mode->MultipleTxSupported);
9393409Smarcel	printf("MediaPresentSupported = %d\n", mode->MediaPresentSupported);
9493409Smarcel	printf("MediaPresent          = %d\n", mode->MediaPresent);
9593409Smarcel}
9693409Smarcel#endif
9793409Smarcel
98164010Smarcelstatic int
9983828Sdfrefinet_match(struct netif *nif, void *machdep_hint)
10083828Sdfr{
101277943Sambrisko	struct devdesc *dev = machdep_hint;
10283828Sdfr
103300810Sjhb	if (dev->d_unit == nif->nif_unit)
104277943Sambrisko		return (1);
105277943Sambrisko	return(0);
10683828Sdfr}
10783828Sdfr
108164010Smarcelstatic int
10983828Sdfrefinet_probe(struct netif *nif, void *machdep_hint)
11083828Sdfr{
11183828Sdfr
11283828Sdfr	return (0);
11383828Sdfr}
11483828Sdfr
115329100Skevansstatic ssize_t
11683828Sdfrefinet_put(struct iodesc *desc, void *pkt, size_t len)
11783828Sdfr{
11893403Smarcel	struct netif *nif = desc->io_netif;
11993403Smarcel	EFI_SIMPLE_NETWORK *net;
12083828Sdfr	EFI_STATUS status;
12193403Smarcel	void *buf;
12283828Sdfr
12393403Smarcel	net = nif->nif_devdata;
124300791Sjhb	if (net == NULL)
125300791Sjhb		return (-1);
12693403Smarcel
127329100Skevans	status = net->Transmit(net, 0, len, pkt, NULL, NULL, NULL);
12893403Smarcel	if (status != EFI_SUCCESS)
129164010Smarcel		return (-1);
13093403Smarcel
13193403Smarcel	/* Wait for the buffer to be transmitted */
13293403Smarcel	do {
133315221Spfg		buf = NULL;	/* XXX Is this needed? */
134329100Skevans		status = net->GetStatus(net, NULL, &buf);
135100389Speter		/*
136292625Semaste		 * XXX EFI1.1 and the E1000 card returns a different
137100389Speter		 * address than we gave.  Sigh.
138100389Speter		 */
139315221Spfg	} while (status == EFI_SUCCESS && buf == NULL);
14093403Smarcel
14193403Smarcel	/* XXX How do we deal with status != EFI_SUCCESS now? */
142164010Smarcel	return ((status == EFI_SUCCESS) ? len : -1);
14383828Sdfr}
14483828Sdfr
145329100Skevansstatic ssize_t
146329100Skevansefinet_get(struct iodesc *desc, void **pkt, time_t timeout)
14783828Sdfr{
14893403Smarcel	struct netif *nif = desc->io_netif;
14993403Smarcel	EFI_SIMPLE_NETWORK *net;
15083828Sdfr	EFI_STATUS status;
15183828Sdfr	UINTN bufsz;
15283828Sdfr	time_t t;
153329100Skevans	char *buf, *ptr;
154329100Skevans	ssize_t ret = -1;
15583828Sdfr
15693403Smarcel	net = nif->nif_devdata;
157300791Sjhb	if (net == NULL)
158329100Skevans		return (ret);
15993403Smarcel
160329100Skevans	bufsz = net->Mode->MaxPacketSize + ETHER_HDR_LEN + ETHER_CRC_LEN;
161329100Skevans	buf = malloc(bufsz + ETHER_ALIGN);
162329100Skevans	if (buf == NULL)
163329100Skevans		return (ret);
164329100Skevans	ptr = buf + ETHER_ALIGN;
165329100Skevans
166329100Skevans	t = getsecs();
167329100Skevans	while ((getsecs() - t) < timeout) {
168329100Skevans		status = net->Receive(net, NULL, &bufsz, ptr, NULL, NULL, NULL);
169100389Speter		if (status == EFI_SUCCESS) {
170329100Skevans			*pkt = buf;
171329100Skevans			ret = (ssize_t)bufsz;
172329100Skevans			break;
173100389Speter		}
17483828Sdfr		if (status != EFI_NOT_READY)
175329100Skevans			break;
17683828Sdfr	}
17783828Sdfr
178329100Skevans	if (ret == -1)
179329100Skevans		free(buf);
180329100Skevans	return (ret);
18183828Sdfr}
18283828Sdfr
183164010Smarcelstatic void
18483828Sdfrefinet_init(struct iodesc *desc, void *machdep_hint)
18583828Sdfr{
18693403Smarcel	struct netif *nif = desc->io_netif;
18793403Smarcel	EFI_SIMPLE_NETWORK *net;
188164010Smarcel	EFI_HANDLE h;
18993409Smarcel	EFI_STATUS status;
190329114Skevans	UINT32 mask;
19183828Sdfr
192295144Sandrew	if (nif->nif_driver->netif_ifs[nif->nif_unit].dif_unit < 0) {
193295144Sandrew		printf("Invalid network interface %d\n", nif->nif_unit);
194295144Sandrew		return;
195295144Sandrew	}
196295144Sandrew
197164010Smarcel	h = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private;
198164010Smarcel	status = BS->HandleProtocol(h, &sn_guid, (VOID **)&nif->nif_devdata);
199164010Smarcel	if (status != EFI_SUCCESS) {
200300791Sjhb		printf("net%d: cannot fetch interface data (status=%lu)\n",
201295144Sandrew		    nif->nif_unit, EFI_ERROR_CODE(status));
202164010Smarcel		return;
203164010Smarcel	}
20483828Sdfr
205164010Smarcel	net = nif->nif_devdata;
20693409Smarcel	if (net->Mode->State == EfiSimpleNetworkStopped) {
20793409Smarcel		status = net->Start(net);
20893409Smarcel		if (status != EFI_SUCCESS) {
209329100Skevans			printf("net%d: cannot start interface (status=%lu)\n",
210329100Skevans			    nif->nif_unit, EFI_ERROR_CODE(status));
21193409Smarcel			return;
21293409Smarcel		}
21393409Smarcel	}
21483828Sdfr
21593409Smarcel	if (net->Mode->State != EfiSimpleNetworkInitialized) {
21693409Smarcel		status = net->Initialize(net, 0, 0);
21793409Smarcel		if (status != EFI_SUCCESS) {
218329100Skevans			printf("net%d: cannot init. interface (status=%lu)\n",
219329100Skevans			    nif->nif_unit, EFI_ERROR_CODE(status));
22093409Smarcel			return;
22193409Smarcel		}
22293409Smarcel	}
22393409Smarcel
224329114Skevans	mask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
225329114Skevans	    EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
22693409Smarcel
227329114Skevans	status = net->ReceiveFilters(net, mask, 0, FALSE, 0, NULL);
228332156Skevans	if (status != EFI_SUCCESS)
229329114Skevans		printf("net%d: cannot set rx. filters (status=%lu)\n",
230329114Skevans		    nif->nif_unit, EFI_ERROR_CODE(status));
23193409Smarcel
23293409Smarcel#ifdef EFINET_DEBUG
23393409Smarcel	dump_mode(net->Mode);
23493409Smarcel#endif
23593409Smarcel
23683828Sdfr	bcopy(net->Mode->CurrentAddress.Addr, desc->myea, 6);
23783828Sdfr	desc->xid = 1;
238164010Smarcel}
23983828Sdfr
240164010Smarcelstatic void
241164010Smarcelefinet_end(struct netif *nif)
242164010Smarcel{
243292625Semaste	EFI_SIMPLE_NETWORK *net = nif->nif_devdata;
244164010Smarcel
245300791Sjhb	if (net == NULL)
246300791Sjhb		return;
247300791Sjhb
248164010Smarcel	net->Shutdown(net);
24983828Sdfr}
25083828Sdfr
251164010Smarcelstatic int efinet_dev_init(void);
252328889Skevansstatic int efinet_dev_print(int);
253164010Smarcel
254164010Smarcelstruct devsw efinet_dev = {
255164010Smarcel	.dv_name = "net",
256164010Smarcel	.dv_type = DEVT_NET,
257164010Smarcel	.dv_init = efinet_dev_init,
258329100Skevans	.dv_strategy = NULL,		/* Will be set in efinet_dev_init */
259329100Skevans	.dv_open = NULL,		/* Will be set in efinet_dev_init */
260329100Skevans	.dv_close = NULL,		/* Will be set in efinet_dev_init */
261164010Smarcel	.dv_ioctl = noioctl,
262164010Smarcel	.dv_print = efinet_dev_print,
263164010Smarcel	.dv_cleanup = NULL
264164010Smarcel};
265164010Smarcel
266164010Smarcelstatic int
267164010Smarcelefinet_dev_init()
26883828Sdfr{
269164010Smarcel	struct netif_dif *dif;
270164010Smarcel	struct netif_stats *stats;
271300810Sjhb	EFI_DEVICE_PATH *devpath, *node;
272300810Sjhb	EFI_SIMPLE_NETWORK *net;
273300810Sjhb	EFI_HANDLE *handles, *handles2;
274164010Smarcel	EFI_STATUS status;
275164010Smarcel	UINTN sz;
276164010Smarcel	int err, i, nifs;
277329100Skevans	extern struct devsw netdev;
27883828Sdfr
27983828Sdfr	sz = 0;
280217067Smarcel	handles = NULL;
281329100Skevans	status = BS->LocateHandle(ByProtocol, &sn_guid, NULL, &sz, NULL);
282164010Smarcel	if (status == EFI_BUFFER_TOO_SMALL) {
283164010Smarcel		handles = (EFI_HANDLE *)malloc(sz);
284329100Skevans		status = BS->LocateHandle(ByProtocol, &sn_guid, NULL, &sz,
285164010Smarcel		    handles);
286164010Smarcel		if (EFI_ERROR(status))
287164010Smarcel			free(handles);
28883828Sdfr	}
289164010Smarcel	if (EFI_ERROR(status))
290164010Smarcel		return (efi_status_to_errno(status));
291300810Sjhb	handles2 = (EFI_HANDLE *)malloc(sz);
292329099Skevans	if (handles2 == NULL) {
293329099Skevans		free(handles);
294329099Skevans		return (ENOMEM);
295329099Skevans	}
296300810Sjhb	nifs = 0;
297300810Sjhb	for (i = 0; i < sz / sizeof(EFI_HANDLE); i++) {
298300810Sjhb		devpath = efi_lookup_devpath(handles[i]);
299300810Sjhb		if (devpath == NULL)
300300810Sjhb			continue;
301329099Skevans		if ((node = efi_devpath_last_node(devpath)) == NULL)
302329099Skevans			continue;
303329099Skevans
304300810Sjhb		if (DevicePathType(node) != MESSAGING_DEVICE_PATH ||
305300810Sjhb		    DevicePathSubType(node) != MSG_MAC_ADDR_DP)
306300810Sjhb			continue;
307300810Sjhb
308300810Sjhb		/*
309300810Sjhb		 * Open the network device in exclusive mode. Without this
310300810Sjhb		 * we will be racing with the UEFI network stack. It will
311300810Sjhb		 * pull packets off the network leading to lost packets.
312300810Sjhb		 */
313300810Sjhb		status = BS->OpenProtocol(handles[i], &sn_guid, (void **)&net,
314329100Skevans		    IH, NULL, EFI_OPEN_PROTOCOL_EXCLUSIVE);
315300810Sjhb		if (status != EFI_SUCCESS) {
316300810Sjhb			printf("Unable to open network interface %d for "
317329100Skevans			    "exclusive access: %lu\n", i,
318329100Skevans			    EFI_ERROR_CODE(status));
319300810Sjhb		}
320300810Sjhb
321300810Sjhb		handles2[nifs] = handles[i];
322300810Sjhb		nifs++;
323300810Sjhb	}
324164010Smarcel	free(handles);
325300810Sjhb	if (nifs == 0) {
326329099Skevans		err = ENOENT;
327329099Skevans		goto done;
328300810Sjhb	}
329300810Sjhb
330300810Sjhb	err = efi_register_handles(&efinet_dev, handles2, NULL, nifs);
331329099Skevans	if (err != 0)
332329099Skevans		goto done;
33383828Sdfr
334164010Smarcel	efinetif.netif_ifs = calloc(nifs, sizeof(struct netif_dif));
335164010Smarcel	stats = calloc(nifs, sizeof(struct netif_stats));
336329099Skevans	if (efinetif.netif_ifs == NULL || stats == NULL) {
337329099Skevans		free(efinetif.netif_ifs);
338329099Skevans		free(stats);
339329099Skevans		efinetif.netif_ifs = NULL;
340329099Skevans		err = ENOMEM;
341329099Skevans		goto done;
342329099Skevans	}
343329099Skevans	efinetif.netif_nifs = nifs;
344164010Smarcel
34583828Sdfr	for (i = 0; i < nifs; i++) {
346295144Sandrew
347164010Smarcel		dif = &efinetif.netif_ifs[i];
34883828Sdfr		dif->dif_unit = i;
34983828Sdfr		dif->dif_nsel = 1;
35083828Sdfr		dif->dif_stats = &stats[i];
351300810Sjhb		dif->dif_private = handles2[i];
35283828Sdfr	}
353329100Skevans
354329100Skevans	efinet_dev.dv_open = netdev.dv_open;
355329100Skevans	efinet_dev.dv_close = netdev.dv_close;
356329100Skevans	efinet_dev.dv_strategy = netdev.dv_strategy;
357329100Skevans
358329099Skevansdone:
359300810Sjhb	free(handles2);
360329099Skevans	return (err);
36183828Sdfr}
36283828Sdfr
363328889Skevansstatic int
364164010Smarcelefinet_dev_print(int verbose)
36583828Sdfr{
366300782Sjhb	CHAR16 *text;
367164010Smarcel	EFI_HANDLE h;
368328889Skevans	int unit, ret = 0;
36983828Sdfr
370328889Skevans	printf("%s devices:", efinet_dev.dv_name);
371328889Skevans	if ((ret = pager_output("\n")) != 0)
372328889Skevans		return (ret);
373328889Skevans
374164010Smarcel	for (unit = 0, h = efi_find_handle(&efinet_dev, 0);
375164010Smarcel	    h != NULL; h = efi_find_handle(&efinet_dev, ++unit)) {
376300782Sjhb		printf("    %s%d:", efinet_dev.dv_name, unit);
377329011Skevans		if (verbose) {
378329011Skevans			text = efi_devpath_name(efi_lookup_devpath(h));
379329011Skevans			if (text != NULL) {
380329011Skevans				printf("    %S", text);
381329011Skevans				efi_free_devpath_name(text);
382329011Skevans			}
383300782Sjhb		}
384328889Skevans		if ((ret = pager_output("\n")) != 0)
385300117Simp			break;
386164010Smarcel	}
387328889Skevans	return (ret);
38883828Sdfr}
389