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