efinet.c revision 100389
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 * $FreeBSD: head/sys/boot/efi/libefi/efinet.c 100389 2002-07-20 03:51:53Z peter $
2783828Sdfr */
2883828Sdfr
2983828Sdfr#include <sys/param.h>
3083828Sdfr#include <netinet/in.h>
3183828Sdfr#include <netinet/in_systm.h>
3283828Sdfr
3383828Sdfr#include <stand.h>
3483828Sdfr#include <net.h>
3583828Sdfr#include <netif.h>
3683828Sdfr
3783828Sdfr#include <efi.h>
3883828Sdfr#include <efilib.h>
3983828Sdfr
4083828Sdfrextern struct netif_driver efi_net;
4183828Sdfr
4293409Smarcel#ifdef EFINET_DEBUG
4393409Smarcelstatic void
4493409Smarceldump_mode(EFI_SIMPLE_NETWORK_MODE *mode)
4593409Smarcel{
4693409Smarcel	int i;
4793409Smarcel
4893409Smarcel	printf("State                 = %x\n", mode->State);
4993409Smarcel	printf("HwAddressSize         = %u\n", mode->HwAddressSize);
5093409Smarcel	printf("MediaHeaderSize       = %u\n", mode->MediaHeaderSize);
5193409Smarcel	printf("MaxPacketSize         = %u\n", mode->MaxPacketSize);
5293409Smarcel	printf("NvRamSize             = %u\n", mode->NvRamSize);
5393409Smarcel	printf("NvRamAccessSize       = %u\n", mode->NvRamAccessSize);
5493409Smarcel	printf("ReceiveFilterMask     = %x\n", mode->ReceiveFilterMask);
5593409Smarcel	printf("ReceiveFilterSetting  = %u\n", mode->ReceiveFilterSetting);
5693409Smarcel	printf("MaxMCastFilterCount   = %u\n", mode->MaxMCastFilterCount);
5793409Smarcel	printf("MCastFilterCount      = %u\n", mode->MCastFilterCount);
5893409Smarcel	printf("MCastFilter           = {");
5993409Smarcel	for (i = 0; i < mode->MCastFilterCount; i++)
6093409Smarcel		printf(" %s", ether_sprintf(mode->MCastFilter[i].Addr));
6193409Smarcel	printf(" }\n");
6293409Smarcel	printf("CurrentAddress        = %s\n",
6393409Smarcel	    ether_sprintf(mode->CurrentAddress.Addr));
6493409Smarcel	printf("BroadcastAddress      = %s\n",
6593409Smarcel	    ether_sprintf(mode->BroadcastAddress.Addr));
6693409Smarcel	printf("PermanentAddress      = %s\n",
6793409Smarcel	    ether_sprintf(mode->PermanentAddress.Addr));
6893409Smarcel	printf("IfType                = %u\n", mode->IfType);
6993409Smarcel	printf("MacAddressChangeable  = %d\n", mode->MacAddressChangeable);
7093409Smarcel	printf("MultipleTxSupported   = %d\n", mode->MultipleTxSupported);
7193409Smarcel	printf("MediaPresentSupported = %d\n", mode->MediaPresentSupported);
7293409Smarcel	printf("MediaPresent          = %d\n", mode->MediaPresent);
7393409Smarcel}
7493409Smarcel#endif
7593409Smarcel
7683828Sdfrint
7783828Sdfrefinet_match(struct netif *nif, void *machdep_hint)
7883828Sdfr{
7983828Sdfr
8083828Sdfr	return (1);
8183828Sdfr}
8283828Sdfr
8383828Sdfrint
8483828Sdfrefinet_probe(struct netif *nif, void *machdep_hint)
8583828Sdfr{
8683828Sdfr
8783828Sdfr	return (0);
8883828Sdfr}
8983828Sdfr
9083828Sdfrint
9183828Sdfrefinet_put(struct iodesc *desc, void *pkt, size_t len)
9283828Sdfr{
9393403Smarcel	struct netif *nif = desc->io_netif;
9493403Smarcel	EFI_SIMPLE_NETWORK *net;
9583828Sdfr	EFI_STATUS status;
9693403Smarcel	void *buf;
9783828Sdfr
9893403Smarcel	net = nif->nif_devdata;
9993403Smarcel
10083828Sdfr	status = net->Transmit(net, 0, len, pkt, 0, 0, 0);
10193403Smarcel	if (status != EFI_SUCCESS)
10283828Sdfr		return -1;
10393403Smarcel
10493403Smarcel	/* Wait for the buffer to be transmitted */
10593403Smarcel	do {
106100389Speter		buf = 0;	/* XXX Is this needed? */
10793403Smarcel		status = net->GetStatus(net, 0, &buf);
108100389Speter		/*
109100389Speter		 * XXX EFI1.1 and the E1000 card returns a different
110100389Speter		 * address than we gave.  Sigh.
111100389Speter		 */
112100389Speter	} while (status == EFI_SUCCESS && buf == 0);
11393403Smarcel
11493403Smarcel	/* XXX How do we deal with status != EFI_SUCCESS now? */
11593403Smarcel	return (status == EFI_SUCCESS) ? len : -1;
11683828Sdfr}
11783828Sdfr
11883828Sdfr
11983828Sdfrint
12083828Sdfrefinet_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout)
12183828Sdfr{
12293403Smarcel	struct netif *nif = desc->io_netif;
12393403Smarcel	EFI_SIMPLE_NETWORK *net;
12483828Sdfr	EFI_STATUS status;
12583828Sdfr	UINTN bufsz;
12683828Sdfr	time_t t;
127100389Speter	char buf[2048];
12883828Sdfr
12993403Smarcel	net = nif->nif_devdata;
13093403Smarcel
13183828Sdfr	t = time(0);
13283828Sdfr	while ((time(0) - t) < timeout) {
133100389Speter		bufsz = sizeof(buf);
134100389Speter		status = net->Receive(net, 0, &bufsz, buf, 0, 0, 0);
135100389Speter		if (status == EFI_SUCCESS) {
136100389Speter			/*
137100389Speter			 * XXX EFI1.1 and the E1000 card trash our
138100389Speter			 * workspace if we do not do this silly copy.
139100389Speter			 * Either they are not respecting the len
140100389Speter			 * value or do not like the alignment.
141100389Speter			 */
142100389Speter			if (bufsz > len)
143100389Speter				bufsz = len;
144100389Speter			bcopy(buf, pkt, bufsz);
14583828Sdfr			return bufsz;
146100389Speter		}
14783828Sdfr		if (status != EFI_NOT_READY)
14883828Sdfr			return 0;
14983828Sdfr	}
15083828Sdfr
15183828Sdfr	return 0;
15283828Sdfr}
15383828Sdfr
15483828Sdfrvoid
15583828Sdfrefinet_init(struct iodesc *desc, void *machdep_hint)
15683828Sdfr{
15793403Smarcel	struct netif *nif = desc->io_netif;
15893403Smarcel	EFI_SIMPLE_NETWORK *net;
15993409Smarcel	EFI_STATUS status;
16083828Sdfr
16183828Sdfr	net = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private;
16293403Smarcel	nif->nif_devdata = net;
16383828Sdfr
16493409Smarcel	if (net->Mode->State == EfiSimpleNetworkStopped) {
16593409Smarcel		status = net->Start(net);
16693409Smarcel		if (status != EFI_SUCCESS) {
16793409Smarcel			printf("net%d: cannot start interface (status=%d)\n",
16893409Smarcel			    nif->nif_unit, status);
16993409Smarcel			return;
17093409Smarcel		}
17193409Smarcel	}
17283828Sdfr
17393409Smarcel	if (net->Mode->State != EfiSimpleNetworkInitialized) {
17493409Smarcel		status = net->Initialize(net, 0, 0);
17593409Smarcel		if (status != EFI_SUCCESS) {
17693409Smarcel			printf("net%d: cannot init. interface (status=%d)\n",
17793409Smarcel			    nif->nif_unit, status);
17893409Smarcel			return;
17993409Smarcel		}
18093409Smarcel	}
18193409Smarcel
18293409Smarcel	if (net->Mode->ReceiveFilterSetting == 0) {
18393409Smarcel		UINT32 mask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
18493409Smarcel		    EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
18593409Smarcel
18693409Smarcel		status = net->ReceiveFilters(net, mask, 0, FALSE, 0, 0);
18793409Smarcel		if (status != EFI_SUCCESS) {
18893409Smarcel			printf("net%d: cannot set rx. filters (status=%d)\n",
18993409Smarcel			    nif->nif_unit, status);
19093409Smarcel			return;
19193409Smarcel		}
19293409Smarcel	}
19393409Smarcel
19493409Smarcel#ifdef EFINET_DEBUG
19593409Smarcel	dump_mode(net->Mode);
19693409Smarcel#endif
19793409Smarcel
19883828Sdfr	bcopy(net->Mode->CurrentAddress.Addr, desc->myea, 6);
19983828Sdfr	desc->xid = 1;
20083828Sdfr
20183828Sdfr	return;
20283828Sdfr}
20383828Sdfr
20483828Sdfrvoid
20583828Sdfrefinet_init_driver()
20683828Sdfr{
20783828Sdfr	EFI_STATUS	status;
20883828Sdfr	UINTN		sz;
20983828Sdfr	static EFI_GUID netid = EFI_SIMPLE_NETWORK_PROTOCOL;
21083828Sdfr	EFI_HANDLE	*handles;
21183828Sdfr	int		nifs, i;
21283828Sdfr#define MAX_INTERFACES	4
21383828Sdfr	static struct netif_dif difs[MAX_INTERFACES];
21483828Sdfr	static struct netif_stats stats[MAX_INTERFACES];
21583828Sdfr
21683828Sdfr	sz = 0;
21783828Sdfr	status = BS->LocateHandle(ByProtocol, &netid, 0, &sz, 0);
21883828Sdfr	if (status != EFI_BUFFER_TOO_SMALL)
21983828Sdfr		return;
22083828Sdfr	handles = (EFI_HANDLE *) malloc(sz);
22183828Sdfr	status = BS->LocateHandle(ByProtocol, &netid, 0, &sz, handles);
22283828Sdfr	if (EFI_ERROR(status)) {
22383828Sdfr		free(handles);
22483828Sdfr		return;
22583828Sdfr	}
22683828Sdfr
22783828Sdfr	nifs = sz / sizeof(EFI_HANDLE);
22883828Sdfr	if (nifs > MAX_INTERFACES)
22983828Sdfr		nifs = MAX_INTERFACES;
23083828Sdfr
23183828Sdfr	efi_net.netif_nifs = nifs;
23283828Sdfr	efi_net.netif_ifs = difs;
23383828Sdfr
23483828Sdfr	bzero(stats, sizeof(stats));
23583828Sdfr	for (i = 0; i < nifs; i++) {
23683828Sdfr		struct netif_dif *dif = &efi_net.netif_ifs[i];
23783828Sdfr		dif->dif_unit = i;
23883828Sdfr		dif->dif_nsel = 1;
23983828Sdfr		dif->dif_stats = &stats[i];
24083828Sdfr
24183828Sdfr		BS->HandleProtocol(handles[i], &netid,
24283828Sdfr				   (VOID**) &dif->dif_private);
24383828Sdfr	}
24483828Sdfr
24583828Sdfr	return;
24683828Sdfr}
24783828Sdfr
24883828Sdfrvoid
24983828Sdfrefinet_end(struct netif *nif)
25083828Sdfr{
25183828Sdfr	EFI_SIMPLE_NETWORK *net = nif->nif_devdata;
25283828Sdfr
25383828Sdfr	net->Shutdown(net);
25483828Sdfr}
25583828Sdfr
25683828Sdfrstruct netif_driver efi_net = {
25783828Sdfr	"net",			/* netif_bname */
25883828Sdfr	efinet_match,		/* netif_match */
25983828Sdfr	efinet_probe,		/* netif_probe */
26083828Sdfr	efinet_init,		/* netif_init */
26183828Sdfr	efinet_get,		/* netif_get */
26283828Sdfr	efinet_put,		/* netif_put */
26383828Sdfr	efinet_end,		/* netif_end */
26483828Sdfr	0,			/* netif_ifs */
26583828Sdfr	0			/* netif_nifs */
26683828Sdfr};
26783828Sdfr
268