1 /* $NetBSD: efinet.c,v 1.1 2018/04/11 10:32:09 nonaka 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 #ifndef ETHER_ALIGN 44 #define ETHER_ALIGN 2 45 #endif 46 47 #define ETHER_EXT_LEN (ETHER_HDR_LEN + ETHER_CRC_LEN + ETHER_ALIGN) 48 49 #if defined(DEBUG) || defined(ARP_DEBUG) || defined(BOOTP_DEBUG) || \ 50 defined(NET_DEBUG) || defined(NETIF_DEBUG) || defined(NFS_DEBUG) || \ 51 defined(RARP_DEBUG) || defined(RPC_DEBUG) 52 int debug = 1; 53 #else 54 int debug = 0; 55 #endif 56 57 extern bool kernel_loaded; 58 59 struct efinetinfo { 60 EFI_SIMPLE_NETWORK *net; 61 bool bootdev; 62 size_t pktbufsz; 63 UINT8 *pktbuf; 64 struct { 65 int type; 66 u_int tag; 67 } bus; 68 }; 69 static struct btinfo_netif bi_netif; 70 71 static int efinet_match(struct netif *, void *); 72 static int efinet_probe(struct netif *, void *); 73 static void efinet_init(struct iodesc *, void *); 74 static int efinet_get(struct iodesc *, void *, size_t, saseconds_t); 75 static int efinet_put(struct iodesc *, void *, size_t); 76 static void efinet_end(struct netif *); 77 78 struct netif_driver efinetif = { 79 .netif_bname = "net", 80 .netif_match = efinet_match, 81 .netif_probe = efinet_probe, 82 .netif_init = efinet_init, 83 .netif_get = efinet_get, 84 .netif_put = efinet_put, 85 .netif_end = efinet_end, 86 .netif_ifs = NULL, 87 .netif_nifs = 0 88 }; 89 90 #ifdef EFINET_DEBUG 91 static void 92 dump_mode(EFI_SIMPLE_NETWORK_MODE *mode) 93 { 94 int i; 95 96 printf("State = %x\n", mode->State); 97 printf("HwAddressSize = %u\n", mode->HwAddressSize); 98 printf("MediaHeaderSize = %u\n", mode->MediaHeaderSize); 99 printf("MaxPacketSize = %u\n", mode->MaxPacketSize); 100 printf("NvRamSize = %u\n", mode->NvRamSize); 101 printf("NvRamAccessSize = %u\n", mode->NvRamAccessSize); 102 printf("ReceiveFilterMask = %x\n", mode->ReceiveFilterMask); 103 printf("ReceiveFilterSetting = %u\n", mode->ReceiveFilterSetting); 104 printf("MaxMCastFilterCount = %u\n", mode->MaxMCastFilterCount); 105 printf("MCastFilterCount = %u\n", mode->MCastFilterCount); 106 printf("MCastFilter = {"); 107 for (i = 0; i < mode->MCastFilterCount; i++) 108 printf(" %s", ether_sprintf(mode->MCastFilter[i].Addr)); 109 printf(" }\n"); 110 printf("CurrentAddress = %s\n", 111 ether_sprintf(mode->CurrentAddress.Addr)); 112 printf("BroadcastAddress = %s\n", 113 ether_sprintf(mode->BroadcastAddress.Addr)); 114 printf("PermanentAddress = %s\n", 115 ether_sprintf(mode->PermanentAddress.Addr)); 116 printf("IfType = %u\n", mode->IfType); 117 printf("MacAddressChangeable = %d\n", mode->MacAddressChangeable); 118 printf("MultipleTxSupported = %d\n", mode->MultipleTxSupported); 119 printf("MediaPresentSupported = %d\n", mode->MediaPresentSupported); 120 printf("MediaPresent = %d\n", mode->MediaPresent); 121 } 122 #endif 123 124 static int 125 efinet_match(struct netif *nif, void *machdep_hint) 126 { 127 struct devdesc *dev = machdep_hint; 128 129 if (dev->d_unit != nif->nif_unit) 130 return 0; 131 132 return 1; 133 } 134 135 static int 136 efinet_probe(struct netif *nif, void *machdep_hint) 137 { 138 139 return 0; 140 } 141 142 static int 143 efinet_put(struct iodesc *desc, void *pkt, size_t len) 144 { 145 struct netif *nif = desc->io_netif; 146 struct efinetinfo *eni = nif->nif_devdata; 147 EFI_SIMPLE_NETWORK *net; 148 EFI_STATUS status; 149 void *buf; 150 151 if (eni == NULL) 152 return -1; 153 net = eni->net; 154 155 status = uefi_call_wrapper(net->Transmit, 7, net, 0, (UINTN)len, pkt, NULL, 156 NULL, NULL); 157 if (EFI_ERROR(status)) 158 return -1; 159 160 /* Wait for the buffer to be transmitted */ 161 do { 162 buf = NULL; /* XXX Is this needed? */ 163 status = uefi_call_wrapper(net->GetStatus, 3, net, NULL, &buf); 164 /* 165 * XXX EFI1.1 and the E1000 card returns a different 166 * address than we gave. Sigh. 167 */ 168 } while (!EFI_ERROR(status) && buf == NULL); 169 170 /* XXX How do we deal with status != EFI_SUCCESS now? */ 171 return EFI_ERROR(status) ? -1 : len; 172 } 173 174 static int 175 efinet_get(struct iodesc *desc, void *pkt, size_t len, saseconds_t timeout) 176 { 177 struct netif *nif = desc->io_netif; 178 struct efinetinfo *eni = nif->nif_devdata; 179 EFI_SIMPLE_NETWORK *net; 180 EFI_STATUS status; 181 UINTN bufsz, rsz; 182 time_t t; 183 char *buf, *ptr; 184 int ret = -1; 185 186 if (eni == NULL) 187 return -1; 188 net = eni->net; 189 190 if (eni->pktbufsz < net->Mode->MaxPacketSize + ETHER_EXT_LEN) { 191 bufsz = net->Mode->MaxPacketSize + ETHER_EXT_LEN; 192 buf = alloc(bufsz); 193 if (buf == NULL) 194 return -1; 195 dealloc(eni->pktbuf, eni->pktbufsz); 196 eni->pktbufsz = bufsz; 197 eni->pktbuf = buf; 198 } 199 ptr = eni->pktbuf + ETHER_ALIGN; 200 201 t = getsecs(); 202 while ((getsecs() - t) < timeout) { 203 rsz = eni->pktbufsz; 204 status = uefi_call_wrapper(net->Receive, 7, net, NULL, &rsz, ptr, 205 NULL, NULL, NULL); 206 if (!EFI_ERROR(status)) { 207 rsz = min(rsz, len); 208 memcpy(pkt, ptr, rsz); 209 ret = (int)rsz; 210 break; 211 } 212 if (status != EFI_NOT_READY) 213 break; 214 } 215 216 return ret; 217 } 218 219 static void 220 efinet_init(struct iodesc *desc, void *machdep_hint) 221 { 222 struct netif *nif = desc->io_netif; 223 struct efinetinfo *eni; 224 EFI_SIMPLE_NETWORK *net; 225 EFI_STATUS status; 226 UINT32 mask; 227 228 if (nif->nif_driver->netif_ifs[nif->nif_unit].dif_unit < 0) { 229 printf("Invalid network interface %d\n", nif->nif_unit); 230 return; 231 } 232 233 eni = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private; 234 nif->nif_devdata = eni; 235 net = eni->net; 236 if (net->Mode->State == EfiSimpleNetworkStopped) { 237 status = uefi_call_wrapper(net->Start, 1, net); 238 if (EFI_ERROR(status)) { 239 printf("net%d: cannot start interface (status=%" 240 PRIxMAX ")\n", nif->nif_unit, (uintmax_t)status); 241 return; 242 } 243 } 244 245 if (net->Mode->State != EfiSimpleNetworkInitialized) { 246 status = uefi_call_wrapper(net->Initialize, 3, net, 0, 0); 247 if (EFI_ERROR(status)) { 248 printf("net%d: cannot init. interface (status=%" 249 PRIxMAX ")\n", nif->nif_unit, (uintmax_t)status); 250 return; 251 } 252 } 253 254 mask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | 255 EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST; 256 257 status = uefi_call_wrapper(net->ReceiveFilters, 6, net, mask, 0, FALSE, 258 0, NULL); 259 if (EFI_ERROR(status)) { 260 printf("net%d: cannot set rx. filters (status=%" PRIxMAX ")\n", 261 nif->nif_unit, (uintmax_t)status); 262 return; 263 } 264 265 if (!kernel_loaded) { 266 bi_netif.bus = eni->bus.type; 267 bi_netif.addr.tag = eni->bus.tag; 268 snprintf(bi_netif.ifname, sizeof(bi_netif.ifname), "net%d", 269 nif->nif_unit); 270 BI_ADD(&bi_netif, BTINFO_NETIF, sizeof(bi_netif)); 271 } 272 273 #ifdef EFINET_DEBUG 274 dump_mode(net->Mode); 275 #endif 276 277 memcpy(desc->myea, net->Mode->CurrentAddress.Addr, 6); 278 desc->xid = 1; 279 } 280 281 static void 282 efinet_end(struct netif *nif) 283 { 284 struct efinetinfo *eni = nif->nif_devdata; 285 EFI_SIMPLE_NETWORK *net; 286 287 if (eni == NULL) 288 return; 289 net = eni->net; 290 291 uefi_call_wrapper(net->Shutdown, 1, net); 292 } 293 294 static bool 295 efi_net_pci_probe(struct efinetinfo *eni, EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *pdp) 296 { 297 PCI_DEVICE_PATH *pci = (PCI_DEVICE_PATH *)dp; 298 int bus = -1; 299 300 if (pdp != NULL && 301 DevicePathType(pdp) == ACPI_DEVICE_PATH && 302 (DevicePathSubType(pdp) == ACPI_DP || 303 DevicePathSubType(pdp) == EXPANDED_ACPI_DP)) { 304 ACPI_HID_DEVICE_PATH *acpi = (ACPI_HID_DEVICE_PATH *)pdp; 305 /* PCI root bus */ 306 if (acpi->HID == EISA_PNP_ID(0x0A08) || 307 acpi->HID == EISA_PNP_ID(0x0A03)) { 308 bus = acpi->UID; 309 } 310 } 311 if (bus < 0) 312 return false; 313 314 eni->bus.type = BI_BUS_PCI; 315 eni->bus.tag = (bus & 0xff) << 8; 316 eni->bus.tag |= (pci->Device & 0x1f) << 3; 317 eni->bus.tag |= pci->Function & 0x7; 318 return true; 319 } 320 321 void 322 efi_net_probe(void) 323 { 324 struct efinetinfo *enis; 325 struct netif_dif *dif; 326 struct netif_stats *stats; 327 EFI_DEVICE_PATH *dp0, *dp, *pdp; 328 EFI_SIMPLE_NETWORK *net; 329 EFI_HANDLE *handles; 330 EFI_STATUS status; 331 UINTN i, nhandles; 332 int nifs; 333 bool found; 334 335 status = LibLocateHandle(ByProtocol, &SimpleNetworkProtocol, NULL, 336 &nhandles, &handles); 337 if (EFI_ERROR(status) || nhandles == 0) 338 return; 339 340 enis = alloc(nhandles * sizeof(*enis)); 341 if (enis == NULL) 342 return; 343 memset(enis, 0, nhandles * sizeof(*enis)); 344 345 nifs = 0; 346 for (i = 0; i < nhandles; i++) { 347 status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i], 348 &DevicePathProtocol, (void **)&dp0); 349 if (EFI_ERROR(status)) 350 continue; 351 352 found = false; 353 for (dp = dp0; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp)) { 354 if (DevicePathType(dp) == MESSAGING_DEVICE_PATH && 355 DevicePathSubType(dp) == MSG_MAC_ADDR_DP) { 356 found = true; 357 break; 358 } 359 } 360 if (!found) 361 continue; 362 363 status = uefi_call_wrapper(BS->OpenProtocol, 6, handles[i], 364 &SimpleNetworkProtocol, (void **)&net, IH, NULL, 365 EFI_OPEN_PROTOCOL_EXCLUSIVE); 366 if (EFI_ERROR(status)) { 367 printf("Unable to open network interface %" PRIuMAX 368 " for exclusive access: %" PRIxMAX "\n", 369 (uintmax_t)i, (uintmax_t)status); 370 } 371 372 found = false; 373 for (pdp = NULL, dp = dp0; 374 !IsDevicePathEnd(dp); 375 pdp = dp, dp = NextDevicePathNode(dp)) { 376 if (DevicePathType(dp) == HARDWARE_DEVICE_PATH) { 377 if (DevicePathSubType(dp) == HW_PCI_DP) 378 found = efi_net_pci_probe(&enis[nifs], 379 dp, pdp); 380 break; 381 } 382 } 383 if (found) { 384 enis[nifs].net = net; 385 enis[nifs].bootdev = efi_pxe_match_booted_interface( 386 &net->Mode->CurrentAddress, net->Mode->HwAddressSize); 387 enis[nifs].pktbufsz = net->Mode->MaxPacketSize + 388 ETHER_EXT_LEN; 389 enis[nifs].pktbuf = alloc(enis[nifs].pktbufsz); 390 if (enis[nifs].pktbuf == NULL) { 391 while (i-- > 0) { 392 dealloc(enis[i].pktbuf, enis[i].pktbufsz); 393 if (i == 0) 394 break; 395 } 396 dealloc(enis, nhandles * sizeof(*enis)); 397 FreePool(handles); 398 return; 399 } 400 nifs++; 401 } 402 } 403 404 FreePool(handles); 405 406 if (nifs == 0) 407 return; 408 409 efinetif.netif_ifs = alloc(nifs * sizeof(*dif)); 410 stats = alloc(nifs * sizeof(*stats)); 411 if (efinetif.netif_ifs == NULL || stats == NULL) { 412 if (efinetif.netif_ifs != NULL) { 413 dealloc(efinetif.netif_ifs, nifs * sizeof(*dif)); 414 efinetif.netif_ifs = NULL; 415 } 416 if (stats != NULL) 417 dealloc(stats, nifs * sizeof(*stats)); 418 for (i = 0; i < nifs; i++) 419 dealloc(enis[i].pktbuf, enis[i].pktbufsz); 420 dealloc(enis, nhandles * sizeof(*enis)); 421 return; 422 } 423 memset(efinetif.netif_ifs, 0, nifs * sizeof(*dif)); 424 memset(stats, 0, nifs * sizeof(*stats)); 425 efinetif.netif_nifs = nifs; 426 427 for (i = 0; i < nifs; i++) { 428 dif = &efinetif.netif_ifs[i]; 429 dif->dif_unit = i; 430 dif->dif_nsel = 1; 431 dif->dif_stats = &stats[i]; 432 dif->dif_private = &enis[i]; 433 } 434 } 435 436 void 437 efi_net_show(void) 438 { 439 const struct netif_dif *dif; 440 const struct efinetinfo *eni; 441 EFI_SIMPLE_NETWORK *net; 442 int i; 443 444 for (i = 0; i < efinetif.netif_nifs; i++) { 445 dif = &efinetif.netif_ifs[i]; 446 eni = dif->dif_private; 447 net = eni->net; 448 449 printf("net net%d", dif->dif_unit); 450 if (net->Mode != NULL) { 451 for (UINT32 x = 0; x < net->Mode->HwAddressSize; x++) { 452 printf("%c%02x", x == 0 ? ' ' : ':', 453 net->Mode->CurrentAddress.Addr[x]); 454 } 455 } 456 if (eni->bus.type == BI_BUS_PCI) { 457 printf(" pci%d,%d,%d", (eni->bus.tag >> 8) & 0xff, 458 (eni->bus.tag >> 3) & 0x1f, eni->bus.tag & 0x7); 459 } 460 if (eni->bootdev) 461 printf(" pxeboot"); 462 printf("\n"); 463 } 464 } 465 466 int 467 efi_net_get_booted_interface_unit(void) 468 { 469 const struct netif_dif *dif; 470 const struct efinetinfo *eni; 471 int i; 472 473 for (i = 0; i < efinetif.netif_nifs; i++) { 474 dif = &efinetif.netif_ifs[i]; 475 eni = dif->dif_private; 476 if (eni->bootdev) 477 return dif->dif_unit; 478 } 479 return -1; 480 } 481