efinet.c revision 124140
183828Sdfr/*-
283828Sdfr * Copyright (c) 2001 Doug Rabson
383828Sdfr * All rights reserved.
483828Sdfr *
583828Sdfr * Redistribution and use in source and binary forms, with or without
683828Sdfr * modification, are permitted provided that the following conditions
783828Sdfr * are met:
883828Sdfr * 1. Redistributions of source code must retain the above copyright
983828Sdfr *    notice, this list of conditions and the following disclaimer.
1083828Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1183828Sdfr *    notice, this list of conditions and the following disclaimer in the
1283828Sdfr *    documentation and/or other materials provided with the distribution.
1383828Sdfr *
1483828Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1583828Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1683828Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1783828Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1883828Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1983828Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2083828Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2183828Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2283828Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2383828Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2483828Sdfr * SUCH DAMAGE.
2583828Sdfr */
2683828Sdfr
27124140Sobrien#include <sys/cdefs.h>
28124140Sobrien__FBSDID("$FreeBSD: head/sys/boot/efi/libefi/efinet.c 124140 2004-01-04 23:30:47Z obrien $");
29124140Sobrien
3083828Sdfr#include <sys/param.h>
3183828Sdfr#include <netinet/in.h>
3283828Sdfr#include <netinet/in_systm.h>
3383828Sdfr
3483828Sdfr#include <stand.h>
3583828Sdfr#include <net.h>
3683828Sdfr#include <netif.h>
3783828Sdfr
3883828Sdfr#include <efi.h>
3983828Sdfr#include <efilib.h>
4083828Sdfr
4183828Sdfrextern struct netif_driver efi_net;
4283828Sdfr
4393409Smarcel#ifdef EFINET_DEBUG
4493409Smarcelstatic void
4593409Smarceldump_mode(EFI_SIMPLE_NETWORK_MODE *mode)
4693409Smarcel{
4793409Smarcel	int i;
4893409Smarcel
4993409Smarcel	printf("State                 = %x\n", mode->State);
5093409Smarcel	printf("HwAddressSize         = %u\n", mode->HwAddressSize);
5193409Smarcel	printf("MediaHeaderSize       = %u\n", mode->MediaHeaderSize);
5293409Smarcel	printf("MaxPacketSize         = %u\n", mode->MaxPacketSize);
5393409Smarcel	printf("NvRamSize             = %u\n", mode->NvRamSize);
5493409Smarcel	printf("NvRamAccessSize       = %u\n", mode->NvRamAccessSize);
5593409Smarcel	printf("ReceiveFilterMask     = %x\n", mode->ReceiveFilterMask);
5693409Smarcel	printf("ReceiveFilterSetting  = %u\n", mode->ReceiveFilterSetting);
5793409Smarcel	printf("MaxMCastFilterCount   = %u\n", mode->MaxMCastFilterCount);
5893409Smarcel	printf("MCastFilterCount      = %u\n", mode->MCastFilterCount);
5993409Smarcel	printf("MCastFilter           = {");
6093409Smarcel	for (i = 0; i < mode->MCastFilterCount; i++)
6193409Smarcel		printf(" %s", ether_sprintf(mode->MCastFilter[i].Addr));
6293409Smarcel	printf(" }\n");
6393409Smarcel	printf("CurrentAddress        = %s\n",
6493409Smarcel	    ether_sprintf(mode->CurrentAddress.Addr));
6593409Smarcel	printf("BroadcastAddress      = %s\n",
6693409Smarcel	    ether_sprintf(mode->BroadcastAddress.Addr));
6793409Smarcel	printf("PermanentAddress      = %s\n",
6893409Smarcel	    ether_sprintf(mode->PermanentAddress.Addr));
6993409Smarcel	printf("IfType                = %u\n", mode->IfType);
7093409Smarcel	printf("MacAddressChangeable  = %d\n", mode->MacAddressChangeable);
7193409Smarcel	printf("MultipleTxSupported   = %d\n", mode->MultipleTxSupported);
7293409Smarcel	printf("MediaPresentSupported = %d\n", mode->MediaPresentSupported);
7393409Smarcel	printf("MediaPresent          = %d\n", mode->MediaPresent);
7493409Smarcel}
7593409Smarcel#endif
7693409Smarcel
7783828Sdfrint
7883828Sdfrefinet_match(struct netif *nif, void *machdep_hint)
7983828Sdfr{
8083828Sdfr
8183828Sdfr	return (1);
8283828Sdfr}
8383828Sdfr
8483828Sdfrint
8583828Sdfrefinet_probe(struct netif *nif, void *machdep_hint)
8683828Sdfr{
8783828Sdfr
8883828Sdfr	return (0);
8983828Sdfr}
9083828Sdfr
9183828Sdfrint
9283828Sdfrefinet_put(struct iodesc *desc, void *pkt, size_t len)
9383828Sdfr{
9493403Smarcel	struct netif *nif = desc->io_netif;
9593403Smarcel	EFI_SIMPLE_NETWORK *net;
9683828Sdfr	EFI_STATUS status;
9793403Smarcel	void *buf;
9883828Sdfr
9993403Smarcel	net = nif->nif_devdata;
10093403Smarcel
10183828Sdfr	status = net->Transmit(net, 0, len, pkt, 0, 0, 0);
10293403Smarcel	if (status != EFI_SUCCESS)
10383828Sdfr		return -1;
10493403Smarcel
10593403Smarcel	/* Wait for the buffer to be transmitted */
10693403Smarcel	do {
107100389Speter		buf = 0;	/* XXX Is this needed? */
10893403Smarcel		status = net->GetStatus(net, 0, &buf);
109100389Speter		/*
110100389Speter		 * XXX EFI1.1 and the E1000 card returns a different
111100389Speter		 * address than we gave.  Sigh.
112100389Speter		 */
113100389Speter	} while (status == EFI_SUCCESS && buf == 0);
11493403Smarcel
11593403Smarcel	/* XXX How do we deal with status != EFI_SUCCESS now? */
11693403Smarcel	return (status == EFI_SUCCESS) ? len : -1;
11783828Sdfr}
11883828Sdfr
11983828Sdfr
12083828Sdfrint
12183828Sdfrefinet_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout)
12283828Sdfr{
12393403Smarcel	struct netif *nif = desc->io_netif;
12493403Smarcel	EFI_SIMPLE_NETWORK *net;
12583828Sdfr	EFI_STATUS status;
12683828Sdfr	UINTN bufsz;
12783828Sdfr	time_t t;
128100389Speter	char buf[2048];
12983828Sdfr
13093403Smarcel	net = nif->nif_devdata;
13193403Smarcel
13283828Sdfr	t = time(0);
13383828Sdfr	while ((time(0) - t) < timeout) {
134100389Speter		bufsz = sizeof(buf);
135100389Speter		status = net->Receive(net, 0, &bufsz, buf, 0, 0, 0);
136100389Speter		if (status == EFI_SUCCESS) {
137100389Speter			/*
138100389Speter			 * XXX EFI1.1 and the E1000 card trash our
139100389Speter			 * workspace if we do not do this silly copy.
140100389Speter			 * Either they are not respecting the len
141100389Speter			 * value or do not like the alignment.
142100389Speter			 */
143100389Speter			if (bufsz > len)
144100389Speter				bufsz = len;
145100389Speter			bcopy(buf, pkt, bufsz);
14683828Sdfr			return bufsz;
147100389Speter		}
14883828Sdfr		if (status != EFI_NOT_READY)
14983828Sdfr			return 0;
15083828Sdfr	}
15183828Sdfr
15283828Sdfr	return 0;
15383828Sdfr}
15483828Sdfr
15583828Sdfrvoid
15683828Sdfrefinet_init(struct iodesc *desc, void *machdep_hint)
15783828Sdfr{
15893403Smarcel	struct netif *nif = desc->io_netif;
15993403Smarcel	EFI_SIMPLE_NETWORK *net;
16093409Smarcel	EFI_STATUS status;
16183828Sdfr
16283828Sdfr	net = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private;
16393403Smarcel	nif->nif_devdata = net;
16483828Sdfr
16593409Smarcel	if (net->Mode->State == EfiSimpleNetworkStopped) {
16693409Smarcel		status = net->Start(net);
16793409Smarcel		if (status != EFI_SUCCESS) {
168100390Speter			printf("net%d: cannot start interface (status=%ld)\n",
16993409Smarcel			    nif->nif_unit, status);
17093409Smarcel			return;
17193409Smarcel		}
17293409Smarcel	}
17383828Sdfr
17493409Smarcel	if (net->Mode->State != EfiSimpleNetworkInitialized) {
17593409Smarcel		status = net->Initialize(net, 0, 0);
17693409Smarcel		if (status != EFI_SUCCESS) {
177100390Speter			printf("net%d: cannot init. interface (status=%ld)\n",
17893409Smarcel			    nif->nif_unit, status);
17993409Smarcel			return;
18093409Smarcel		}
18193409Smarcel	}
18293409Smarcel
18393409Smarcel	if (net->Mode->ReceiveFilterSetting == 0) {
18493409Smarcel		UINT32 mask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
18593409Smarcel		    EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
18693409Smarcel
18793409Smarcel		status = net->ReceiveFilters(net, mask, 0, FALSE, 0, 0);
18893409Smarcel		if (status != EFI_SUCCESS) {
189100390Speter			printf("net%d: cannot set rx. filters (status=%ld)\n",
19093409Smarcel			    nif->nif_unit, status);
19193409Smarcel			return;
19293409Smarcel		}
19393409Smarcel	}
19493409Smarcel
19593409Smarcel#ifdef EFINET_DEBUG
19693409Smarcel	dump_mode(net->Mode);
19793409Smarcel#endif
19893409Smarcel
19983828Sdfr	bcopy(net->Mode->CurrentAddress.Addr, desc->myea, 6);
20083828Sdfr	desc->xid = 1;
20183828Sdfr
20283828Sdfr	return;
20383828Sdfr}
20483828Sdfr
20583828Sdfrvoid
20683828Sdfrefinet_init_driver()
20783828Sdfr{
20883828Sdfr	EFI_STATUS	status;
20983828Sdfr	UINTN		sz;
21083828Sdfr	static EFI_GUID netid = EFI_SIMPLE_NETWORK_PROTOCOL;
21183828Sdfr	EFI_HANDLE	*handles;
21283828Sdfr	int		nifs, i;
21383828Sdfr#define MAX_INTERFACES	4
21483828Sdfr	static struct netif_dif difs[MAX_INTERFACES];
21583828Sdfr	static struct netif_stats stats[MAX_INTERFACES];
21683828Sdfr
21783828Sdfr	sz = 0;
21883828Sdfr	status = BS->LocateHandle(ByProtocol, &netid, 0, &sz, 0);
21983828Sdfr	if (status != EFI_BUFFER_TOO_SMALL)
22083828Sdfr		return;
22183828Sdfr	handles = (EFI_HANDLE *) malloc(sz);
22283828Sdfr	status = BS->LocateHandle(ByProtocol, &netid, 0, &sz, handles);
22383828Sdfr	if (EFI_ERROR(status)) {
22483828Sdfr		free(handles);
22583828Sdfr		return;
22683828Sdfr	}
22783828Sdfr
22883828Sdfr	nifs = sz / sizeof(EFI_HANDLE);
22983828Sdfr	if (nifs > MAX_INTERFACES)
23083828Sdfr		nifs = MAX_INTERFACES;
23183828Sdfr
23283828Sdfr	efi_net.netif_nifs = nifs;
23383828Sdfr	efi_net.netif_ifs = difs;
23483828Sdfr
23583828Sdfr	bzero(stats, sizeof(stats));
23683828Sdfr	for (i = 0; i < nifs; i++) {
23783828Sdfr		struct netif_dif *dif = &efi_net.netif_ifs[i];
23883828Sdfr		dif->dif_unit = i;
23983828Sdfr		dif->dif_nsel = 1;
24083828Sdfr		dif->dif_stats = &stats[i];
24183828Sdfr
24283828Sdfr		BS->HandleProtocol(handles[i], &netid,
24383828Sdfr				   (VOID**) &dif->dif_private);
24483828Sdfr	}
24583828Sdfr
24683828Sdfr	return;
24783828Sdfr}
24883828Sdfr
24983828Sdfrvoid
25083828Sdfrefinet_end(struct netif *nif)
25183828Sdfr{
25283828Sdfr	EFI_SIMPLE_NETWORK *net = nif->nif_devdata;
25383828Sdfr
25483828Sdfr	net->Shutdown(net);
25583828Sdfr}
25683828Sdfr
25783828Sdfrstruct netif_driver efi_net = {
25883828Sdfr	"net",			/* netif_bname */
25983828Sdfr	efinet_match,		/* netif_match */
26083828Sdfr	efinet_probe,		/* netif_probe */
26183828Sdfr	efinet_init,		/* netif_init */
26283828Sdfr	efinet_get,		/* netif_get */
26383828Sdfr	efinet_put,		/* netif_put */
26483828Sdfr	efinet_end,		/* netif_end */
26583828Sdfr	0,			/* netif_ifs */
26683828Sdfr	0			/* netif_nifs */
26783828Sdfr};
26883828Sdfr
269