Home | History | Annotate | Line # | Download | only in libefi
efinet.c revision 1.6.44.1
      1  1.6.44.1  pgoyette /*	$NetBSD: efinet.c,v 1.6.44.1 2016/08/06 00:19:05 pgoyette Exp $	*/
      2       1.1    cherry 
      3       1.1    cherry /*-
      4       1.1    cherry  * Copyright (c) 2001 Doug Rabson
      5       1.1    cherry  * All rights reserved.
      6       1.1    cherry  *
      7       1.1    cherry  * Redistribution and use in source and binary forms, with or without
      8       1.1    cherry  * modification, are permitted provided that the following conditions
      9       1.1    cherry  * are met:
     10       1.1    cherry  * 1. Redistributions of source code must retain the above copyright
     11       1.1    cherry  *    notice, this list of conditions and the following disclaimer.
     12       1.1    cherry  * 2. Redistributions in binary form must reproduce the above copyright
     13       1.1    cherry  *    notice, this list of conditions and the following disclaimer in the
     14       1.1    cherry  *    documentation and/or other materials provided with the distribution.
     15       1.1    cherry  *
     16       1.1    cherry  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     17       1.1    cherry  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18       1.1    cherry  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19       1.1    cherry  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     20       1.1    cherry  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21       1.1    cherry  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22       1.1    cherry  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23       1.1    cherry  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24       1.1    cherry  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25       1.1    cherry  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26       1.1    cherry  * SUCH DAMAGE.
     27       1.1    cherry  */
     28       1.1    cherry 
     29       1.1    cherry #include <sys/cdefs.h>
     30       1.2    cherry /* __FBSDID("$FreeBSD: src/sys/boot/efi/libefi/efinet.c,v 1.6 2004/01/04 23:28:16 obrien Exp $"); */
     31       1.1    cherry 
     32       1.1    cherry #include <sys/param.h>
     33       1.1    cherry 
     34       1.1    cherry #include <lib/libsa/stand.h>
     35  1.6.44.1  pgoyette #include <lib/libsa/loadfile.h>
     36  1.6.44.1  pgoyette #include <lib/libsa/net.h>
     37  1.6.44.1  pgoyette #include <lib/libsa/netif.h>
     38  1.6.44.1  pgoyette 
     39  1.6.44.1  pgoyette #ifdef EFINET_DEBUG
     40  1.6.44.1  pgoyette #include <lib/libsa/ether_sprintf.c>
     41  1.6.44.1  pgoyette #endif
     42       1.1    cherry 
     43       1.1    cherry #include <efi.h>
     44       1.1    cherry #include <efilib.h>
     45       1.1    cherry 
     46       1.1    cherry extern struct netif_driver efi_net;
     47       1.1    cherry 
     48  1.6.44.1  pgoyette int  efinet_match(struct netif *, void *);
     49  1.6.44.1  pgoyette int  efinet_probe(struct netif *, void *);
     50  1.6.44.1  pgoyette void efinet_init(struct iodesc *, void *);
     51  1.6.44.1  pgoyette int  efinet_get(struct iodesc *, void *, size_t, saseconds_t);
     52  1.6.44.1  pgoyette int  efinet_put(struct iodesc *, void *, size_t);
     53  1.6.44.1  pgoyette void efinet_end(struct netif *);
     54  1.6.44.1  pgoyette 
     55  1.6.44.1  pgoyette struct netif_driver efi_net = {
     56  1.6.44.1  pgoyette 	"net",			/* netif_bname */
     57  1.6.44.1  pgoyette 	efinet_match,		/* netif_match */
     58  1.6.44.1  pgoyette 	efinet_probe,		/* netif_probe */
     59  1.6.44.1  pgoyette 	efinet_init,		/* netif_init */
     60  1.6.44.1  pgoyette 	efinet_get,		/* netif_get */
     61  1.6.44.1  pgoyette 	efinet_put,		/* netif_put */
     62  1.6.44.1  pgoyette 	efinet_end,		/* netif_end */
     63  1.6.44.1  pgoyette 	0,			/* netif_ifs */
     64  1.6.44.1  pgoyette 	0			/* netif_nifs */
     65  1.6.44.1  pgoyette };
     66  1.6.44.1  pgoyette 
     67       1.1    cherry #ifdef EFINET_DEBUG
     68       1.1    cherry static void
     69       1.1    cherry dump_mode(EFI_SIMPLE_NETWORK_MODE *mode)
     70       1.1    cherry {
     71       1.1    cherry 	int i;
     72       1.1    cherry 
     73       1.1    cherry 	printf("State                 = %x\n", mode->State);
     74       1.1    cherry 	printf("HwAddressSize         = %u\n", mode->HwAddressSize);
     75       1.1    cherry 	printf("MediaHeaderSize       = %u\n", mode->MediaHeaderSize);
     76       1.1    cherry 	printf("MaxPacketSize         = %u\n", mode->MaxPacketSize);
     77       1.1    cherry 	printf("NvRamSize             = %u\n", mode->NvRamSize);
     78       1.1    cherry 	printf("NvRamAccessSize       = %u\n", mode->NvRamAccessSize);
     79       1.1    cherry 	printf("ReceiveFilterMask     = %x\n", mode->ReceiveFilterMask);
     80       1.1    cherry 	printf("ReceiveFilterSetting  = %u\n", mode->ReceiveFilterSetting);
     81       1.1    cherry 	printf("MaxMCastFilterCount   = %u\n", mode->MaxMCastFilterCount);
     82       1.1    cherry 	printf("MCastFilterCount      = %u\n", mode->MCastFilterCount);
     83       1.1    cherry 	printf("MCastFilter           = {");
     84       1.1    cherry 	for (i = 0; i < mode->MCastFilterCount; i++)
     85       1.1    cherry 		printf(" %s", ether_sprintf(mode->MCastFilter[i].Addr));
     86       1.1    cherry 	printf(" }\n");
     87       1.1    cherry 	printf("CurrentAddress        = %s\n",
     88       1.1    cherry 	    ether_sprintf(mode->CurrentAddress.Addr));
     89       1.1    cherry 	printf("BroadcastAddress      = %s\n",
     90       1.1    cherry 	    ether_sprintf(mode->BroadcastAddress.Addr));
     91       1.1    cherry 	printf("PermanentAddress      = %s\n",
     92       1.1    cherry 	    ether_sprintf(mode->PermanentAddress.Addr));
     93       1.1    cherry 	printf("IfType                = %u\n", mode->IfType);
     94       1.1    cherry 	printf("MacAddressChangeable  = %d\n", mode->MacAddressChangeable);
     95       1.1    cherry 	printf("MultipleTxSupported   = %d\n", mode->MultipleTxSupported);
     96       1.1    cherry 	printf("MediaPresentSupported = %d\n", mode->MediaPresentSupported);
     97       1.1    cherry 	printf("MediaPresent          = %d\n", mode->MediaPresent);
     98       1.1    cherry }
     99       1.1    cherry #endif
    100       1.1    cherry 
    101       1.1    cherry int
    102       1.1    cherry efinet_match(struct netif *nif, void *machdep_hint)
    103       1.1    cherry {
    104       1.1    cherry 
    105       1.1    cherry 	return (1);
    106       1.1    cherry }
    107       1.1    cherry 
    108       1.1    cherry int
    109       1.1    cherry efinet_probe(struct netif *nif, void *machdep_hint)
    110       1.1    cherry {
    111       1.1    cherry 
    112       1.1    cherry 	return (0);
    113       1.1    cherry }
    114       1.1    cherry 
    115       1.1    cherry int
    116       1.1    cherry efinet_put(struct iodesc *desc, void *pkt, size_t len)
    117       1.1    cherry {
    118       1.1    cherry 	struct netif *nif = desc->io_netif;
    119       1.1    cherry 	EFI_SIMPLE_NETWORK *net;
    120       1.1    cherry 	EFI_STATUS status;
    121       1.1    cherry 	void *buf;
    122       1.1    cherry 
    123       1.1    cherry 	net = nif->nif_devdata;
    124       1.1    cherry 
    125       1.1    cherry 	status = net->Transmit(net, 0, len, pkt, 0, 0, 0);
    126       1.1    cherry 	if (status != EFI_SUCCESS)
    127       1.1    cherry 		return -1;
    128       1.1    cherry 
    129       1.1    cherry 	/* Wait for the buffer to be transmitted */
    130       1.1    cherry 	do {
    131       1.1    cherry 		buf = 0;	/* XXX Is this needed? */
    132       1.1    cherry 		status = net->GetStatus(net, 0, &buf);
    133       1.1    cherry 		/*
    134       1.1    cherry 		 * XXX EFI1.1 and the E1000 card returns a different
    135       1.1    cherry 		 * address than we gave.  Sigh.
    136       1.1    cherry 		 */
    137       1.1    cherry 	} while (status == EFI_SUCCESS && buf == 0);
    138       1.1    cherry 
    139       1.1    cherry 	/* XXX How do we deal with status != EFI_SUCCESS now? */
    140       1.1    cherry 	return (status == EFI_SUCCESS) ? len : -1;
    141       1.1    cherry }
    142       1.1    cherry 
    143       1.1    cherry 
    144       1.1    cherry int
    145  1.6.44.1  pgoyette efinet_get(struct iodesc *desc, void *pkt, size_t len, saseconds_t timeout)
    146       1.1    cherry {
    147       1.1    cherry 	struct netif *nif = desc->io_netif;
    148       1.1    cherry 	EFI_SIMPLE_NETWORK *net;
    149       1.1    cherry 	EFI_STATUS status;
    150       1.1    cherry 	UINTN bufsz;
    151       1.1    cherry 	time_t t;
    152       1.1    cherry 	char buf[2048];
    153       1.1    cherry 
    154       1.1    cherry 	net = nif->nif_devdata;
    155       1.1    cherry 
    156       1.1    cherry 	t = time(0);
    157       1.1    cherry 	while ((time(0) - t) < timeout) {
    158       1.1    cherry 		bufsz = sizeof(buf);
    159       1.1    cherry 		status = net->Receive(net, 0, &bufsz, buf, 0, 0, 0);
    160       1.1    cherry 		if (status == EFI_SUCCESS) {
    161       1.1    cherry 			/*
    162       1.1    cherry 			 * XXX EFI1.1 and the E1000 card trash our
    163       1.1    cherry 			 * workspace if we do not do this silly copy.
    164       1.1    cherry 			 * Either they are not respecting the len
    165       1.1    cherry 			 * value or do not like the alignment.
    166       1.1    cherry 			 */
    167       1.1    cherry 			if (bufsz > len)
    168       1.1    cherry 				bufsz = len;
    169       1.6    cegger 			memcpy(pkt, buf, bufsz);
    170       1.1    cherry 			return bufsz;
    171       1.1    cherry 		}
    172       1.1    cherry 		if (status != EFI_NOT_READY)
    173       1.1    cherry 			return 0;
    174       1.1    cherry 	}
    175       1.1    cherry 
    176       1.1    cherry 	return 0;
    177       1.1    cherry }
    178       1.1    cherry 
    179       1.1    cherry void
    180       1.1    cherry efinet_init(struct iodesc *desc, void *machdep_hint)
    181       1.1    cherry {
    182       1.1    cherry 	struct netif *nif = desc->io_netif;
    183       1.1    cherry 	EFI_SIMPLE_NETWORK *net;
    184       1.1    cherry 	EFI_STATUS status;
    185       1.1    cherry 
    186       1.1    cherry 	net = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private;
    187       1.1    cherry 	nif->nif_devdata = net;
    188       1.1    cherry 
    189       1.1    cherry 	if (net->Mode->State == EfiSimpleNetworkStopped) {
    190       1.1    cherry 		status = net->Start(net);
    191       1.1    cherry 		if (status != EFI_SUCCESS) {
    192       1.1    cherry 			printf("net%d: cannot start interface (status=%ld)\n",
    193       1.1    cherry 			    nif->nif_unit, status);
    194       1.1    cherry 			return;
    195       1.1    cherry 		}
    196       1.1    cherry 	}
    197       1.1    cherry 
    198       1.1    cherry 	if (net->Mode->State != EfiSimpleNetworkInitialized) {
    199       1.1    cherry 		status = net->Initialize(net, 0, 0);
    200       1.1    cherry 		if (status != EFI_SUCCESS) {
    201       1.1    cherry 			printf("net%d: cannot init. interface (status=%ld)\n",
    202       1.1    cherry 			    nif->nif_unit, status);
    203       1.1    cherry 			return;
    204       1.1    cherry 		}
    205       1.1    cherry 	}
    206       1.1    cherry 
    207       1.1    cherry 	if (net->Mode->ReceiveFilterSetting == 0) {
    208       1.1    cherry 		UINT32 mask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
    209       1.1    cherry 		    EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
    210       1.1    cherry 
    211       1.1    cherry 		status = net->ReceiveFilters(net, mask, 0, FALSE, 0, 0);
    212       1.1    cherry 		if (status != EFI_SUCCESS) {
    213       1.1    cherry 			printf("net%d: cannot set rx. filters (status=%ld)\n",
    214       1.1    cherry 			    nif->nif_unit, status);
    215       1.1    cherry 			return;
    216       1.1    cherry 		}
    217       1.1    cherry 	}
    218       1.1    cherry 
    219       1.1    cherry #ifdef EFINET_DEBUG
    220       1.1    cherry 	dump_mode(net->Mode);
    221       1.1    cherry #endif
    222       1.1    cherry 
    223       1.6    cegger 	memcpy(desc->myea, net->Mode->CurrentAddress.Addr, 6);
    224       1.1    cherry 	desc->xid = 1;
    225       1.1    cherry 
    226       1.1    cherry 	return;
    227       1.1    cherry }
    228       1.1    cherry 
    229       1.1    cherry void
    230       1.3    cegger efinet_init_driver(void)
    231       1.1    cherry {
    232       1.1    cherry 	EFI_STATUS	status;
    233       1.1    cherry 	UINTN		sz;
    234       1.1    cherry 	static EFI_GUID netid = EFI_SIMPLE_NETWORK_PROTOCOL;
    235       1.1    cherry 	EFI_HANDLE	*handles;
    236       1.1    cherry 	int		nifs, i;
    237       1.1    cherry #define MAX_INTERFACES	4
    238       1.1    cherry 	static struct netif_dif difs[MAX_INTERFACES];
    239       1.1    cherry 	static struct netif_stats stats[MAX_INTERFACES];
    240       1.1    cherry 
    241       1.1    cherry 	sz = 0;
    242       1.1    cherry 	status = BS->LocateHandle(ByProtocol, &netid, 0, &sz, 0);
    243       1.1    cherry 	if (status != EFI_BUFFER_TOO_SMALL)
    244       1.1    cherry 		return;
    245       1.1    cherry 	handles = (EFI_HANDLE *) alloc(sz);
    246       1.1    cherry 	status = BS->LocateHandle(ByProtocol, &netid, 0, &sz, handles);
    247       1.1    cherry 	if (EFI_ERROR(status)) {
    248  1.6.44.1  pgoyette                 free(handles);
    249       1.1    cherry 		return;
    250       1.1    cherry 	}
    251       1.1    cherry 
    252       1.1    cherry 	nifs = sz / sizeof(EFI_HANDLE);
    253       1.1    cherry 	if (nifs > MAX_INTERFACES)
    254       1.1    cherry 		nifs = MAX_INTERFACES;
    255       1.1    cherry 
    256       1.1    cherry 	efi_net.netif_nifs = nifs;
    257       1.1    cherry 	efi_net.netif_ifs = difs;
    258       1.1    cherry 
    259       1.4    cegger 	memset(stats, 0, sizeof(stats));
    260       1.1    cherry 	for (i = 0; i < nifs; i++) {
    261       1.1    cherry 		struct netif_dif *dif = &efi_net.netif_ifs[i];
    262       1.1    cherry 		dif->dif_unit = i;
    263       1.1    cherry 		dif->dif_nsel = 1;
    264       1.1    cherry 		dif->dif_stats = &stats[i];
    265       1.1    cherry 
    266       1.1    cherry 		BS->HandleProtocol(handles[i], &netid,
    267       1.1    cherry 				   (VOID**) &dif->dif_private);
    268       1.1    cherry 	}
    269       1.1    cherry 
    270       1.1    cherry 	return;
    271       1.1    cherry }
    272       1.1    cherry 
    273       1.1    cherry void
    274       1.1    cherry efinet_end(struct netif *nif)
    275       1.1    cherry {
    276       1.1    cherry 	EFI_SIMPLE_NETWORK *net = nif->nif_devdata;
    277       1.1    cherry 
    278       1.1    cherry 	net->Shutdown(net);
    279       1.1    cherry }
    280