1/* $NetBSD: efinet.c,v 1.3 2019/03/05 08:25:02 msaitoh Exp $ */ 2 3/*- 4 * Copyright (c) 2001 Doug Rabson 5 * Copyright (c) 2002, 2006 Marcel Moolenaar 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#include <sys/cdefs.h> 31#if 0 32__FBSDID("$FreeBSD: head/stand/efi/libefi/efinet.c 321621 2017-07-27 15:06:34Z andrew $"); 33#endif 34 35#include "efiboot.h" 36 37#include <lib/libsa/net.h> 38#include <lib/libsa/netif.h> 39 40#include <bootinfo.h> 41#include "devopen.h" 42 43#define ETHER_EXT_LEN (ETHER_HDR_LEN + ETHER_CRC_LEN + ETHER_ALIGN) 44 45#if defined(DEBUG) || defined(ARP_DEBUG) || defined(BOOTP_DEBUG) || \ 46 defined(NET_DEBUG) || defined(NETIF_DEBUG) || defined(NFS_DEBUG) || \ 47 defined(RARP_DEBUG) || defined(RPC_DEBUG) 48int debug = 1; 49#else 50int debug = 0; 51#endif 52 53extern bool kernel_loaded; 54 55struct efinetinfo { 56 EFI_SIMPLE_NETWORK *net; 57 bool bootdev; 58 size_t pktbufsz; 59 UINT8 *pktbuf; 60 struct { 61 int type; 62 u_int tag; 63 } bus; 64}; 65static struct btinfo_netif bi_netif; 66 67static int efinet_match(struct netif *, void *); 68static int efinet_probe(struct netif *, void *); 69static void efinet_init(struct iodesc *, void *); 70static int efinet_get(struct iodesc *, void *, size_t, saseconds_t); 71static int efinet_put(struct iodesc *, void *, size_t); 72static void efinet_end(struct netif *); 73 74struct netif_driver efinetif = { 75 .netif_bname = "net", 76 .netif_match = efinet_match, 77 .netif_probe = efinet_probe, 78 .netif_init = efinet_init, 79 .netif_get = efinet_get, 80 .netif_put = efinet_put, 81 .netif_end = efinet_end, 82 .netif_ifs = NULL, 83 .netif_nifs = 0 84}; 85 86#ifdef EFINET_DEBUG 87static void 88dump_mode(EFI_SIMPLE_NETWORK_MODE *mode) 89{ 90 int i; 91 92 printf("State = %x\n", mode->State); 93 printf("HwAddressSize = %u\n", mode->HwAddressSize); 94 printf("MediaHeaderSize = %u\n", mode->MediaHeaderSize); 95 printf("MaxPacketSize = %u\n", mode->MaxPacketSize); 96 printf("NvRamSize = %u\n", mode->NvRamSize); 97 printf("NvRamAccessSize = %u\n", mode->NvRamAccessSize); 98 printf("ReceiveFilterMask = %x\n", mode->ReceiveFilterMask); 99 printf("ReceiveFilterSetting = %u\n", mode->ReceiveFilterSetting); 100 printf("MaxMCastFilterCount = %u\n", mode->MaxMCastFilterCount); 101 printf("MCastFilterCount = %u\n", mode->MCastFilterCount); 102 printf("MCastFilter = {"); 103 for (i = 0; i < mode->MCastFilterCount; i++) 104 printf(" %s", ether_sprintf(mode->MCastFilter[i].Addr)); 105 printf(" }\n"); 106 printf("CurrentAddress = %s\n", 107 ether_sprintf(mode->CurrentAddress.Addr)); 108 printf("BroadcastAddress = %s\n", 109 ether_sprintf(mode->BroadcastAddress.Addr)); 110 printf("PermanentAddress = %s\n", 111 ether_sprintf(mode->PermanentAddress.Addr)); 112 printf("IfType = %u\n", mode->IfType); 113 printf("MacAddressChangeable = %d\n", mode->MacAddressChangeable); 114 printf("MultipleTxSupported = %d\n", mode->MultipleTxSupported); 115 printf("MediaPresentSupported = %d\n", mode->MediaPresentSupported); 116 printf("MediaPresent = %d\n", mode->MediaPresent); 117} 118#endif 119 120static int 121efinet_match(struct netif *nif, void *machdep_hint) 122{ 123 struct devdesc *dev = machdep_hint; 124 125 if (dev->d_unit != nif->nif_unit) 126 return 0; 127 128 return 1; 129} 130 131static int 132efinet_probe(struct netif *nif, void *machdep_hint) 133{ 134 135 return 0; 136} 137 138static int 139efinet_put(struct iodesc *desc, void *pkt, size_t len) 140{ 141 struct netif *nif = desc->io_netif; 142 struct efinetinfo *eni = nif->nif_devdata; 143 EFI_SIMPLE_NETWORK *net; 144 EFI_STATUS status; 145 void *buf; 146 147 if (eni == NULL) 148 return -1; 149 net = eni->net; 150 151 status = uefi_call_wrapper(net->Transmit, 7, net, 0, (UINTN)len, pkt, NULL, 152 NULL, NULL); 153 if (EFI_ERROR(status)) 154 return -1; 155 156 /* Wait for the buffer to be transmitted */ 157 do { 158 buf = NULL; /* XXX Is this needed? */ 159 status = uefi_call_wrapper(net->GetStatus, 3, net, NULL, &buf); 160 /* 161 * XXX EFI1.1 and the E1000 card returns a different 162 * address than we gave. Sigh. 163 */ 164 } while (!EFI_ERROR(status) && buf == NULL); 165 166 /* XXX How do we deal with status != EFI_SUCCESS now? */ 167 return EFI_ERROR(status) ? -1 : len; 168} 169 170static int 171efinet_get(struct iodesc *desc, void *pkt, size_t len, saseconds_t timeout) 172{ 173 struct netif *nif = desc->io_netif; 174 struct efinetinfo *eni = nif->nif_devdata; 175 EFI_SIMPLE_NETWORK *net; 176 EFI_STATUS status; 177 UINTN bufsz, rsz; 178 time_t t; 179 char *buf, *ptr; 180 int ret = -1; 181 182 if (eni == NULL) 183 return -1; 184 net = eni->net; 185 186 if (eni->pktbufsz < net->Mode->MaxPacketSize + ETHER_EXT_LEN) { 187 bufsz = net->Mode->MaxPacketSize + ETHER_EXT_LEN; 188 buf = alloc(bufsz); 189 if (buf == NULL) 190 return -1; 191 dealloc(eni->pktbuf, eni->pktbufsz); 192 eni->pktbufsz = bufsz; 193 eni->pktbuf = buf; 194 } 195 ptr = eni->pktbuf + ETHER_ALIGN; 196 197 t = getsecs(); 198 while ((getsecs() - t) < timeout) { 199 rsz = eni->pktbufsz; 200 status = uefi_call_wrapper(net->Receive, 7, net, NULL, &rsz, ptr, 201 NULL, NULL, NULL); 202 if (!EFI_ERROR(status)) { 203 rsz = uimin(rsz, len); 204 memcpy(pkt, ptr, rsz); 205 ret = (int)rsz; 206 break; 207 } 208 if (status != EFI_NOT_READY) 209 break; 210 } 211 212 return ret; 213} 214 215static void 216efinet_init(struct iodesc *desc, void *machdep_hint) 217{ 218 struct netif *nif = desc->io_netif; 219 struct efinetinfo *eni; 220 EFI_SIMPLE_NETWORK *net; 221 EFI_STATUS status; 222 UINT32 mask; 223 224 if (nif->nif_driver->netif_ifs[nif->nif_unit].dif_unit < 0) { 225 printf("Invalid network interface %d\n", nif->nif_unit); 226 return; 227 } 228 229 eni = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private; 230 nif->nif_devdata = eni; 231 net = eni->net; 232 if (net->Mode->State == EfiSimpleNetworkStopped) { 233 status = uefi_call_wrapper(net->Start, 1, net); 234 if (EFI_ERROR(status)) { 235 printf("net%d: cannot start interface (status=%" 236 PRIxMAX ")\n", nif->nif_unit, (uintmax_t)status); 237 return; 238 } 239 } 240 241 if (net->Mode->State != EfiSimpleNetworkInitialized) { 242 status = uefi_call_wrapper(net->Initialize, 3, net, 0, 0); 243 if (EFI_ERROR(status)) { 244 printf("net%d: cannot init. interface (status=%" 245 PRIxMAX ")\n", nif->nif_unit, (uintmax_t)status); 246 return; 247 } 248 } 249 250 mask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | 251 EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST; 252 253 status = uefi_call_wrapper(net->ReceiveFilters, 6, net, mask, 0, FALSE, 254 0, NULL); 255 if (EFI_ERROR(status)) { 256 printf("net%d: cannot set rx. filters (status=%" PRIxMAX ")\n", 257 nif->nif_unit, (uintmax_t)status); 258 return; 259 } 260 261 if (!kernel_loaded) { 262 bi_netif.bus = eni->bus.type; 263 bi_netif.addr.tag = eni->bus.tag; 264 snprintf(bi_netif.ifname, sizeof(bi_netif.ifname), "net%d", 265 nif->nif_unit); 266 BI_ADD(&bi_netif, BTINFO_NETIF, sizeof(bi_netif)); 267 } 268 269#ifdef EFINET_DEBUG 270 dump_mode(net->Mode); 271#endif 272 273 memcpy(desc->myea, net->Mode->CurrentAddress.Addr, 6); 274 desc->xid = 1; 275} 276 277static void 278efinet_end(struct netif *nif) 279{ 280 struct efinetinfo *eni = nif->nif_devdata; 281 EFI_SIMPLE_NETWORK *net; 282 283 if (eni == NULL) 284 return; 285 net = eni->net; 286 287 uefi_call_wrapper(net->Shutdown, 1, net); 288} 289 290static bool 291efi_net_pci_probe(struct efinetinfo *eni, EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *pdp) 292{ 293 PCI_DEVICE_PATH *pci = (PCI_DEVICE_PATH *)dp; 294 int bus = -1; 295 296 if (pdp != NULL && 297 DevicePathType(pdp) == ACPI_DEVICE_PATH && 298 (DevicePathSubType(pdp) == ACPI_DP || 299 DevicePathSubType(pdp) == EXPANDED_ACPI_DP)) { 300 ACPI_HID_DEVICE_PATH *acpi = (ACPI_HID_DEVICE_PATH *)pdp; 301 /* PCI root bus */ 302 if (acpi->HID == EISA_PNP_ID(0x0A08) || 303 acpi->HID == EISA_PNP_ID(0x0A03)) { 304 bus = acpi->UID; 305 } 306 } 307 if (bus < 0) 308 return false; 309 310 eni->bus.type = BI_BUS_PCI; 311 eni->bus.tag = (bus & 0xff) << 8; 312 eni->bus.tag |= (pci->Device & 0x1f) << 3; 313 eni->bus.tag |= pci->Function & 0x7; 314 return true; 315} 316 317void 318efi_net_probe(void) 319{ 320 struct efinetinfo *enis; 321 struct netif_dif *dif; 322 struct netif_stats *stats; 323 EFI_DEVICE_PATH *dp0, *dp, *pdp; 324 EFI_SIMPLE_NETWORK *net; 325 EFI_HANDLE *handles; 326 EFI_STATUS status; 327 UINTN i, nhandles; 328 int nifs; 329 bool found; 330 331 status = LibLocateHandle(ByProtocol, &SimpleNetworkProtocol, NULL, 332 &nhandles, &handles); 333 if (EFI_ERROR(status) || nhandles == 0) 334 return; 335 336 enis = alloc(nhandles * sizeof(*enis)); 337 if (enis == NULL) 338 return; 339 memset(enis, 0, nhandles * sizeof(*enis)); 340 341 nifs = 0; 342 for (i = 0; i < nhandles; i++) { 343 status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i], 344 &DevicePathProtocol, (void **)&dp0); 345 if (EFI_ERROR(status)) 346 continue; 347 348 found = false; 349 for (dp = dp0; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp)) { 350 if (DevicePathType(dp) == MESSAGING_DEVICE_PATH && 351 DevicePathSubType(dp) == MSG_MAC_ADDR_DP) { 352 found = true; 353 break; 354 } 355 } 356 if (!found) 357 continue; 358 359 status = uefi_call_wrapper(BS->OpenProtocol, 6, handles[i], 360 &SimpleNetworkProtocol, (void **)&net, IH, NULL, 361 EFI_OPEN_PROTOCOL_EXCLUSIVE); 362 if (EFI_ERROR(status)) { 363 printf("Unable to open network interface %" PRIuMAX 364 " for exclusive access: %" PRIxMAX "\n", 365 (uintmax_t)i, (uintmax_t)status); 366 } 367 368 found = false; 369 for (pdp = NULL, dp = dp0; 370 !IsDevicePathEnd(dp); 371 pdp = dp, dp = NextDevicePathNode(dp)) { 372 if (DevicePathType(dp) == HARDWARE_DEVICE_PATH) { 373 if (DevicePathSubType(dp) == HW_PCI_DP) 374 found = efi_net_pci_probe(&enis[nifs], 375 dp, pdp); 376 break; 377 } 378 } 379 if (found) { 380 enis[nifs].net = net; 381 enis[nifs].bootdev = efi_pxe_match_booted_interface( 382 &net->Mode->CurrentAddress, net->Mode->HwAddressSize); 383 enis[nifs].pktbufsz = net->Mode->MaxPacketSize + 384 ETHER_EXT_LEN; 385 enis[nifs].pktbuf = alloc(enis[nifs].pktbufsz); 386 if (enis[nifs].pktbuf == NULL) { 387 while (i-- > 0) { 388 dealloc(enis[i].pktbuf, enis[i].pktbufsz); 389 if (i == 0) 390 break; 391 } 392 dealloc(enis, nhandles * sizeof(*enis)); 393 FreePool(handles); 394 return; 395 } 396 nifs++; 397 } 398 } 399 400 FreePool(handles); 401 402 if (nifs == 0) 403 return; 404 405 efinetif.netif_ifs = alloc(nifs * sizeof(*dif)); 406 stats = alloc(nifs * sizeof(*stats)); 407 if (efinetif.netif_ifs == NULL || stats == NULL) { 408 if (efinetif.netif_ifs != NULL) { 409 dealloc(efinetif.netif_ifs, nifs * sizeof(*dif)); 410 efinetif.netif_ifs = NULL; 411 } 412 if (stats != NULL) 413 dealloc(stats, nifs * sizeof(*stats)); 414 for (i = 0; i < nifs; i++) 415 dealloc(enis[i].pktbuf, enis[i].pktbufsz); 416 dealloc(enis, nhandles * sizeof(*enis)); 417 return; 418 } 419 memset(efinetif.netif_ifs, 0, nifs * sizeof(*dif)); 420 memset(stats, 0, nifs * sizeof(*stats)); 421 efinetif.netif_nifs = nifs; 422 423 for (i = 0; i < nifs; i++) { 424 dif = &efinetif.netif_ifs[i]; 425 dif->dif_unit = i; 426 dif->dif_nsel = 1; 427 dif->dif_stats = &stats[i]; 428 dif->dif_private = &enis[i]; 429 } 430} 431 432void 433efi_net_show(void) 434{ 435 const struct netif_dif *dif; 436 const struct efinetinfo *eni; 437 EFI_SIMPLE_NETWORK *net; 438 int i; 439 440 for (i = 0; i < efinetif.netif_nifs; i++) { 441 dif = &efinetif.netif_ifs[i]; 442 eni = dif->dif_private; 443 net = eni->net; 444 445 printf("net net%d", dif->dif_unit); 446 if (net->Mode != NULL) { 447 for (UINT32 x = 0; x < net->Mode->HwAddressSize; x++) { 448 printf("%c%02x", x == 0 ? ' ' : ':', 449 net->Mode->CurrentAddress.Addr[x]); 450 } 451 } 452 if (eni->bus.type == BI_BUS_PCI) { 453 printf(" pci%d,%d,%d", (eni->bus.tag >> 8) & 0xff, 454 (eni->bus.tag >> 3) & 0x1f, eni->bus.tag & 0x7); 455 } 456 if (eni->bootdev) 457 printf(" pxeboot"); 458 printf("\n"); 459 } 460} 461 462int 463efi_net_get_booted_interface_unit(void) 464{ 465 const struct netif_dif *dif; 466 const struct efinetinfo *eni; 467 int i; 468 469 for (i = 0; i < efinetif.netif_nifs; i++) { 470 dif = &efinetif.netif_ifs[i]; 471 eni = dif->dif_private; 472 if (eni->bootdev) 473 return dif->dif_unit; 474 } 475 return -1; 476} 477