efinet.c revision 300117
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: head/sys/boot/efi/libefi/efinet.c 300117 2016-05-18 05:59:05Z imp $");
30124140Sobrien
3183828Sdfr#include <sys/param.h>
3283828Sdfr#include <netinet/in.h>
3383828Sdfr#include <netinet/in_systm.h>
3483828Sdfr
3583828Sdfr#include <stand.h>
3683828Sdfr#include <net.h>
3783828Sdfr#include <netif.h>
3883828Sdfr
39164010Smarcel#include <dev_net.c>
40164010Smarcel
4183828Sdfr#include <efi.h>
4283828Sdfr#include <efilib.h>
4383828Sdfr
44164010Smarcelstatic EFI_GUID sn_guid = EFI_SIMPLE_NETWORK_PROTOCOL;
4583828Sdfr
46164010Smarcelstatic void efinet_end(struct netif *);
47164010Smarcelstatic int efinet_get(struct iodesc *, void *, size_t, time_t);
48164010Smarcelstatic void efinet_init(struct iodesc *, void *);
49164010Smarcelstatic int efinet_match(struct netif *, void *);
50164010Smarcelstatic int efinet_probe(struct netif *, void *);
51164010Smarcelstatic int efinet_put(struct iodesc *, void *, size_t);
52164010Smarcel
53292625Semastestruct netif_driver efinetif = {
54164010Smarcel	.netif_bname = "efinet",
55164010Smarcel	.netif_match = efinet_match,
56164010Smarcel	.netif_probe = efinet_probe,
57164010Smarcel	.netif_init = efinet_init,
58164010Smarcel	.netif_get = efinet_get,
59164010Smarcel	.netif_put = efinet_put,
60164010Smarcel	.netif_end = efinet_end,
61164010Smarcel	.netif_ifs = NULL,
62164010Smarcel	.netif_nifs = 0
63164010Smarcel};
64164010Smarcel
6593409Smarcel#ifdef EFINET_DEBUG
6693409Smarcelstatic void
6793409Smarceldump_mode(EFI_SIMPLE_NETWORK_MODE *mode)
6893409Smarcel{
6993409Smarcel	int i;
7093409Smarcel
7193409Smarcel	printf("State                 = %x\n", mode->State);
7293409Smarcel	printf("HwAddressSize         = %u\n", mode->HwAddressSize);
7393409Smarcel	printf("MediaHeaderSize       = %u\n", mode->MediaHeaderSize);
7493409Smarcel	printf("MaxPacketSize         = %u\n", mode->MaxPacketSize);
7593409Smarcel	printf("NvRamSize             = %u\n", mode->NvRamSize);
7693409Smarcel	printf("NvRamAccessSize       = %u\n", mode->NvRamAccessSize);
7793409Smarcel	printf("ReceiveFilterMask     = %x\n", mode->ReceiveFilterMask);
7893409Smarcel	printf("ReceiveFilterSetting  = %u\n", mode->ReceiveFilterSetting);
7993409Smarcel	printf("MaxMCastFilterCount   = %u\n", mode->MaxMCastFilterCount);
8093409Smarcel	printf("MCastFilterCount      = %u\n", mode->MCastFilterCount);
8193409Smarcel	printf("MCastFilter           = {");
8293409Smarcel	for (i = 0; i < mode->MCastFilterCount; i++)
8393409Smarcel		printf(" %s", ether_sprintf(mode->MCastFilter[i].Addr));
8493409Smarcel	printf(" }\n");
8593409Smarcel	printf("CurrentAddress        = %s\n",
8693409Smarcel	    ether_sprintf(mode->CurrentAddress.Addr));
8793409Smarcel	printf("BroadcastAddress      = %s\n",
8893409Smarcel	    ether_sprintf(mode->BroadcastAddress.Addr));
8993409Smarcel	printf("PermanentAddress      = %s\n",
9093409Smarcel	    ether_sprintf(mode->PermanentAddress.Addr));
9193409Smarcel	printf("IfType                = %u\n", mode->IfType);
9293409Smarcel	printf("MacAddressChangeable  = %d\n", mode->MacAddressChangeable);
9393409Smarcel	printf("MultipleTxSupported   = %d\n", mode->MultipleTxSupported);
9493409Smarcel	printf("MediaPresentSupported = %d\n", mode->MediaPresentSupported);
9593409Smarcel	printf("MediaPresent          = %d\n", mode->MediaPresent);
9693409Smarcel}
9793409Smarcel#endif
9893409Smarcel
99164010Smarcelstatic int
10083828Sdfrefinet_match(struct netif *nif, void *machdep_hint)
10183828Sdfr{
102277943Sambrisko	struct devdesc *dev = machdep_hint;
10383828Sdfr
104277943Sambrisko	if (dev->d_unit - 1 == nif->nif_unit)
105277943Sambrisko		return (1);
106277943Sambrisko	return(0);
10783828Sdfr}
10883828Sdfr
109164010Smarcelstatic int
11083828Sdfrefinet_probe(struct netif *nif, void *machdep_hint)
11183828Sdfr{
11283828Sdfr
11383828Sdfr	return (0);
11483828Sdfr}
11583828Sdfr
116164010Smarcelstatic int
11783828Sdfrefinet_put(struct iodesc *desc, void *pkt, size_t len)
11883828Sdfr{
11993403Smarcel	struct netif *nif = desc->io_netif;
12093403Smarcel	EFI_SIMPLE_NETWORK *net;
12183828Sdfr	EFI_STATUS status;
12293403Smarcel	void *buf;
12383828Sdfr
12493403Smarcel	net = nif->nif_devdata;
12593403Smarcel
12683828Sdfr	status = net->Transmit(net, 0, len, pkt, 0, 0, 0);
12793403Smarcel	if (status != EFI_SUCCESS)
128164010Smarcel		return (-1);
12993403Smarcel
13093403Smarcel	/* Wait for the buffer to be transmitted */
13193403Smarcel	do {
132100389Speter		buf = 0;	/* XXX Is this needed? */
13393403Smarcel		status = net->GetStatus(net, 0, &buf);
134100389Speter		/*
135292625Semaste		 * XXX EFI1.1 and the E1000 card returns a different
136100389Speter		 * address than we gave.  Sigh.
137100389Speter		 */
138100389Speter	} while (status == EFI_SUCCESS && buf == 0);
13993403Smarcel
14093403Smarcel	/* XXX How do we deal with status != EFI_SUCCESS now? */
141164010Smarcel	return ((status == EFI_SUCCESS) ? len : -1);
14283828Sdfr}
14383828Sdfr
144164010Smarcelstatic int
14583828Sdfrefinet_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout)
14683828Sdfr{
14793403Smarcel	struct netif *nif = desc->io_netif;
14893403Smarcel	EFI_SIMPLE_NETWORK *net;
14983828Sdfr	EFI_STATUS status;
15083828Sdfr	UINTN bufsz;
15183828Sdfr	time_t t;
152100389Speter	char buf[2048];
15383828Sdfr
15493403Smarcel	net = nif->nif_devdata;
15593403Smarcel
15683828Sdfr	t = time(0);
15783828Sdfr	while ((time(0) - t) < timeout) {
158100389Speter		bufsz = sizeof(buf);
159100389Speter		status = net->Receive(net, 0, &bufsz, buf, 0, 0, 0);
160100389Speter		if (status == EFI_SUCCESS) {
161100389Speter			/*
162100389Speter			 * XXX EFI1.1 and the E1000 card trash our
163100389Speter			 * workspace if we do not do this silly copy.
164100389Speter			 * Either they are not respecting the len
165100389Speter			 * value or do not like the alignment.
166100389Speter			 */
167100389Speter			if (bufsz > len)
168100389Speter				bufsz = len;
169100389Speter			bcopy(buf, pkt, bufsz);
170164010Smarcel			return (bufsz);
171100389Speter		}
17283828Sdfr		if (status != EFI_NOT_READY)
173164010Smarcel			return (0);
17483828Sdfr	}
17583828Sdfr
176164010Smarcel	return (0);
17783828Sdfr}
17883828Sdfr
179164010Smarcelstatic void
18083828Sdfrefinet_init(struct iodesc *desc, void *machdep_hint)
18183828Sdfr{
18293403Smarcel	struct netif *nif = desc->io_netif;
18393403Smarcel	EFI_SIMPLE_NETWORK *net;
184164010Smarcel	EFI_HANDLE h;
18593409Smarcel	EFI_STATUS status;
18683828Sdfr
187295144Sandrew	if (nif->nif_driver->netif_ifs[nif->nif_unit].dif_unit < 0) {
188295144Sandrew		printf("Invalid network interface %d\n", nif->nif_unit);
189295144Sandrew		return;
190295144Sandrew	}
191295144Sandrew
192164010Smarcel	h = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private;
193164010Smarcel	status = BS->HandleProtocol(h, &sn_guid, (VOID **)&nif->nif_devdata);
194164010Smarcel	if (status != EFI_SUCCESS) {
195295144Sandrew		printf("net%d: cannot start interface (status=%lu)\n",
196295144Sandrew		    nif->nif_unit, EFI_ERROR_CODE(status));
197164010Smarcel		return;
198164010Smarcel	}
19983828Sdfr
200164010Smarcel	net = nif->nif_devdata;
20193409Smarcel	if (net->Mode->State == EfiSimpleNetworkStopped) {
20293409Smarcel		status = net->Start(net);
20393409Smarcel		if (status != EFI_SUCCESS) {
204100390Speter			printf("net%d: cannot start interface (status=%ld)\n",
205164010Smarcel			    nif->nif_unit, (long)status);
20693409Smarcel			return;
20793409Smarcel		}
20893409Smarcel	}
20983828Sdfr
21093409Smarcel	if (net->Mode->State != EfiSimpleNetworkInitialized) {
21193409Smarcel		status = net->Initialize(net, 0, 0);
21293409Smarcel		if (status != EFI_SUCCESS) {
213100390Speter			printf("net%d: cannot init. interface (status=%ld)\n",
214164010Smarcel			    nif->nif_unit, (long)status);
21593409Smarcel			return;
21693409Smarcel		}
21793409Smarcel	}
21893409Smarcel
21993409Smarcel	if (net->Mode->ReceiveFilterSetting == 0) {
22093409Smarcel		UINT32 mask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
22193409Smarcel		    EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
22293409Smarcel
22393409Smarcel		status = net->ReceiveFilters(net, mask, 0, FALSE, 0, 0);
22493409Smarcel		if (status != EFI_SUCCESS) {
225100390Speter			printf("net%d: cannot set rx. filters (status=%ld)\n",
226164010Smarcel			    nif->nif_unit, (long)status);
22793409Smarcel			return;
22893409Smarcel		}
22993409Smarcel	}
23093409Smarcel
23193409Smarcel#ifdef EFINET_DEBUG
23293409Smarcel	dump_mode(net->Mode);
23393409Smarcel#endif
23493409Smarcel
23583828Sdfr	bcopy(net->Mode->CurrentAddress.Addr, desc->myea, 6);
23683828Sdfr	desc->xid = 1;
237164010Smarcel}
23883828Sdfr
239164010Smarcelstatic void
240164010Smarcelefinet_end(struct netif *nif)
241164010Smarcel{
242292625Semaste	EFI_SIMPLE_NETWORK *net = nif->nif_devdata;
243164010Smarcel
244164010Smarcel	net->Shutdown(net);
24583828Sdfr}
24683828Sdfr
247164010Smarcelstatic int efinet_dev_init(void);
248164010Smarcelstatic void efinet_dev_print(int);
249164010Smarcel
250164010Smarcelstruct devsw efinet_dev = {
251164010Smarcel	.dv_name = "net",
252164010Smarcel	.dv_type = DEVT_NET,
253164010Smarcel	.dv_init = efinet_dev_init,
254164010Smarcel	.dv_strategy = net_strategy,
255164010Smarcel	.dv_open = net_open,
256164010Smarcel	.dv_close = net_close,
257164010Smarcel	.dv_ioctl = noioctl,
258164010Smarcel	.dv_print = efinet_dev_print,
259164010Smarcel	.dv_cleanup = NULL
260164010Smarcel};
261164010Smarcel
262164010Smarcelstatic int
263164010Smarcelefinet_dev_init()
26483828Sdfr{
265164010Smarcel	struct netif_dif *dif;
266164010Smarcel	struct netif_stats *stats;
267164010Smarcel	EFI_HANDLE *handles;
268164010Smarcel	EFI_STATUS status;
269164010Smarcel	UINTN sz;
270164010Smarcel	int err, i, nifs;
27183828Sdfr
27283828Sdfr	sz = 0;
273217067Smarcel	handles = NULL;
274164010Smarcel	status = BS->LocateHandle(ByProtocol, &sn_guid, 0, &sz, 0);
275164010Smarcel	if (status == EFI_BUFFER_TOO_SMALL) {
276164010Smarcel		handles = (EFI_HANDLE *)malloc(sz);
277164010Smarcel		status = BS->LocateHandle(ByProtocol, &sn_guid, 0, &sz,
278164010Smarcel		    handles);
279164010Smarcel		if (EFI_ERROR(status))
280164010Smarcel			free(handles);
28183828Sdfr	}
282164010Smarcel	if (EFI_ERROR(status))
283164010Smarcel		return (efi_status_to_errno(status));
28483828Sdfr	nifs = sz / sizeof(EFI_HANDLE);
285264088Semaste	err = efi_register_handles(&efinet_dev, handles, NULL, nifs);
286164010Smarcel	free(handles);
287164010Smarcel	if (err != 0)
288164010Smarcel		return (err);
28983828Sdfr
290164010Smarcel	efinetif.netif_nifs = nifs;
291164010Smarcel	efinetif.netif_ifs = calloc(nifs, sizeof(struct netif_dif));
29283828Sdfr
293164010Smarcel	stats = calloc(nifs, sizeof(struct netif_stats));
294164010Smarcel
29583828Sdfr	for (i = 0; i < nifs; i++) {
296295144Sandrew		EFI_SIMPLE_NETWORK *net;
297295144Sandrew		EFI_HANDLE h;
298295144Sandrew
299164010Smarcel		dif = &efinetif.netif_ifs[i];
300295144Sandrew		dif->dif_unit = -1;
301295144Sandrew
302295144Sandrew		h = efi_find_handle(&efinet_dev, i);
303295144Sandrew
304295144Sandrew		/*
305295144Sandrew		 * Open the network device in exclusive mode. Without this
306295144Sandrew		 * we will be racing with the UEFI network stack. It will
307295144Sandrew		 * pull packets off the network leading to lost packets.
308295144Sandrew		 */
309295144Sandrew		status = BS->OpenProtocol(h, &sn_guid, (void **)&net,
310295144Sandrew		    IH, 0, EFI_OPEN_PROTOCOL_EXCLUSIVE);
311295144Sandrew		if (status != EFI_SUCCESS) {
312295210Sandrew			printf("Unable to open network interface %d for "
313295210Sandrew			    "exclusive access\n", i);
314295144Sandrew		}
315295144Sandrew
31683828Sdfr		dif->dif_unit = i;
31783828Sdfr		dif->dif_nsel = 1;
31883828Sdfr		dif->dif_stats = &stats[i];
319295144Sandrew		dif->dif_private = h;
32083828Sdfr	}
32183828Sdfr
322164010Smarcel	return (0);
32383828Sdfr}
32483828Sdfr
325164010Smarcelstatic void
326164010Smarcelefinet_dev_print(int verbose)
32783828Sdfr{
328164010Smarcel	char line[80];
329164010Smarcel	EFI_HANDLE h;
330164010Smarcel	int unit;
33183828Sdfr
332300117Simp	pager_open();
333164010Smarcel	for (unit = 0, h = efi_find_handle(&efinet_dev, 0);
334164010Smarcel	    h != NULL; h = efi_find_handle(&efinet_dev, ++unit)) {
335164010Smarcel		sprintf(line, "    %s%d:\n", efinet_dev.dv_name, unit);
336300117Simp		if (pager_output(line))
337300117Simp			break;
338164010Smarcel	}
339300117Simp	pager_close();
34083828Sdfr}
341