1 /*- 2 * Copyright (c) 2001 Doug Rabson 3 * Copyright (c) 2002, 2006 Marcel Moolenaar 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/param.h> 32 #include <net/ethernet.h> 33 #include <netinet/in.h> 34 #include <netinet/in_systm.h> 35 36 #include <stand.h> 37 #include <net.h> 38 #include <netif.h> 39 40 #include <efi.h> 41 #include <efilib.h> 42 43 #include "dev_net.h" 44 45 static EFI_GUID sn_guid = EFI_SIMPLE_NETWORK_PROTOCOL; 46 47 static void efinet_end(struct netif *); 48 static ssize_t efinet_get(struct iodesc *, void **, time_t); 49 static void efinet_init(struct iodesc *, void *); 50 static int efinet_match(struct netif *, void *); 51 static int efinet_probe(struct netif *, void *); 52 static ssize_t efinet_put(struct iodesc *, void *, size_t); 53 54 struct netif_driver efinetif = { 55 .netif_bname = "efinet", 56 .netif_match = efinet_match, 57 .netif_probe = efinet_probe, 58 .netif_init = efinet_init, 59 .netif_get = efinet_get, 60 .netif_put = efinet_put, 61 .netif_end = efinet_end, 62 .netif_ifs = NULL, 63 .netif_nifs = 0 64 }; 65 66 #ifdef EFINET_DEBUG 67 static void 68 dump_mode(EFI_SIMPLE_NETWORK_MODE *mode) 69 { 70 int i; 71 72 printf("State = %x\n", mode->State); 73 printf("HwAddressSize = %u\n", mode->HwAddressSize); 74 printf("MediaHeaderSize = %u\n", mode->MediaHeaderSize); 75 printf("MaxPacketSize = %u\n", mode->MaxPacketSize); 76 printf("NvRamSize = %u\n", mode->NvRamSize); 77 printf("NvRamAccessSize = %u\n", mode->NvRamAccessSize); 78 printf("ReceiveFilterMask = %x\n", mode->ReceiveFilterMask); 79 printf("ReceiveFilterSetting = %u\n", mode->ReceiveFilterSetting); 80 printf("MaxMCastFilterCount = %u\n", mode->MaxMCastFilterCount); 81 printf("MCastFilterCount = %u\n", mode->MCastFilterCount); 82 printf("MCastFilter = {"); 83 for (i = 0; i < mode->MCastFilterCount; i++) 84 printf(" %s", ether_sprintf(mode->MCastFilter[i].Addr)); 85 printf(" }\n"); 86 printf("CurrentAddress = %s\n", 87 ether_sprintf(mode->CurrentAddress.Addr)); 88 printf("BroadcastAddress = %s\n", 89 ether_sprintf(mode->BroadcastAddress.Addr)); 90 printf("PermanentAddress = %s\n", 91 ether_sprintf(mode->PermanentAddress.Addr)); 92 printf("IfType = %u\n", mode->IfType); 93 printf("MacAddressChangeable = %d\n", mode->MacAddressChangeable); 94 printf("MultipleTxSupported = %d\n", mode->MultipleTxSupported); 95 printf("MediaPresentSupported = %d\n", mode->MediaPresentSupported); 96 printf("MediaPresent = %d\n", mode->MediaPresent); 97 } 98 #endif 99 100 static int 101 efinet_match(struct netif *nif, void *machdep_hint) 102 { 103 struct devdesc *dev = machdep_hint; 104 105 if (dev->d_unit == nif->nif_unit) 106 return (1); 107 return(0); 108 } 109 110 static int 111 efinet_probe(struct netif *nif, void *machdep_hint) 112 { 113 EFI_SIMPLE_NETWORK *net; 114 EFI_HANDLE h; 115 EFI_STATUS status; 116 117 h = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private; 118 /* 119 * Open the network device in exclusive mode. Without this 120 * we will be racing with the UEFI network stack. It will 121 * pull packets off the network leading to lost packets. 122 */ 123 status = BS->OpenProtocol(h, &sn_guid, (void **)&net, 124 IH, NULL, EFI_OPEN_PROTOCOL_EXCLUSIVE); 125 if (status != EFI_SUCCESS) { 126 printf("Unable to open network interface %d for " 127 "exclusive access: %lu\n", nif->nif_unit, 128 EFI_ERROR_CODE(status)); 129 return (efi_status_to_errno(status)); 130 } 131 132 return (0); 133 } 134 135 static ssize_t 136 efinet_put(struct iodesc *desc, void *pkt, size_t len) 137 { 138 struct netif *nif = desc->io_netif; 139 EFI_SIMPLE_NETWORK *net; 140 EFI_STATUS status; 141 void *buf; 142 143 net = nif->nif_devdata; 144 if (net == NULL) 145 return (-1); 146 147 status = net->Transmit(net, 0, len, pkt, NULL, NULL, NULL); 148 if (status != EFI_SUCCESS) 149 return (-1); 150 151 /* Wait for the buffer to be transmitted */ 152 do { 153 buf = NULL; /* XXX Is this needed? */ 154 status = net->GetStatus(net, NULL, &buf); 155 /* 156 * XXX EFI1.1 and the E1000 card returns a different 157 * address than we gave. Sigh. 158 */ 159 } while (status == EFI_SUCCESS && buf == NULL); 160 161 /* XXX How do we deal with status != EFI_SUCCESS now? */ 162 return ((status == EFI_SUCCESS) ? len : -1); 163 } 164 165 static ssize_t 166 efinet_get(struct iodesc *desc, void **pkt, time_t timeout) 167 { 168 struct netif *nif = desc->io_netif; 169 EFI_SIMPLE_NETWORK *net; 170 EFI_STATUS status; 171 UINTN bufsz; 172 time_t t; 173 char *buf, *ptr; 174 ssize_t ret = -1; 175 176 net = nif->nif_devdata; 177 if (net == NULL) 178 return (ret); 179 180 bufsz = net->Mode->MaxPacketSize + ETHER_HDR_LEN + ETHER_CRC_LEN; 181 buf = malloc(bufsz + ETHER_ALIGN); 182 if (buf == NULL) 183 return (ret); 184 ptr = buf + ETHER_ALIGN; 185 186 t = getsecs(); 187 while ((getsecs() - t) < timeout) { 188 status = net->Receive(net, NULL, &bufsz, ptr, NULL, NULL, NULL); 189 if (status == EFI_SUCCESS) { 190 *pkt = buf; 191 ret = (ssize_t)bufsz; 192 break; 193 } 194 if (status != EFI_NOT_READY) 195 break; 196 } 197 198 if (ret == -1) 199 free(buf); 200 return (ret); 201 } 202 203 /* 204 * Loader uses BOOTP/DHCP and also uses RARP as a fallback to populate 205 * network parameters and problems with DHCP servers can cause the loader 206 * to fail to populate them. Allow the device to ask about the basic 207 * network parameters and if present use them. 208 */ 209 static void 210 efi_env_net_params(struct iodesc *desc) 211 { 212 char *envstr; 213 in_addr_t ipaddr, mask, gwaddr, serveraddr; 214 n_long rootaddr; 215 216 if ((envstr = getenv("rootpath")) != NULL) 217 strlcpy(rootpath, envstr, sizeof(rootpath)); 218 219 /* 220 * Get network parameters. 221 */ 222 envstr = getenv("ipaddr"); 223 ipaddr = (envstr != NULL) ? inet_addr(envstr) : 0; 224 225 envstr = getenv("netmask"); 226 mask = (envstr != NULL) ? inet_addr(envstr) : 0; 227 228 envstr = getenv("gatewayip"); 229 gwaddr = (envstr != NULL) ? inet_addr(envstr) : 0; 230 231 envstr = getenv("serverip"); 232 serveraddr = (envstr != NULL) ? inet_addr(envstr) : 0; 233 234 /* No network params. */ 235 if (ipaddr == 0 && mask == 0 && gwaddr == 0 && serveraddr == 0) 236 return; 237 238 /* Partial network params. */ 239 if (ipaddr == 0 || mask == 0 || gwaddr == 0 || serveraddr == 0) { 240 printf("Incomplete network settings from U-Boot\n"); 241 return; 242 } 243 244 /* 245 * Set network parameters. 246 */ 247 myip.s_addr = ipaddr; 248 netmask = mask; 249 gateip.s_addr = gwaddr; 250 servip.s_addr = serveraddr; 251 252 /* 253 * There must be a rootpath. It may be ip:/path or it may be just the 254 * path in which case the ip needs to be serverip. 255 */ 256 rootaddr = net_parse_rootpath(); 257 if (rootaddr == INADDR_NONE) 258 rootaddr = serveraddr; 259 rootip.s_addr = rootaddr; 260 261 #ifdef EFINET_DEBUG 262 printf("%s: ip=%s\n", __func__, inet_ntoa(myip)); 263 printf("%s: mask=%s\n", __func__, intoa(netmask)); 264 printf("%s: gateway=%s\n", __func__, inet_ntoa(gateip)); 265 printf("%s: server=%s\n", __func__, inet_ntoa(servip)); 266 #endif 267 268 desc->myip = myip; 269 } 270 271 static void 272 efinet_init(struct iodesc *desc, void *machdep_hint) 273 { 274 struct netif *nif = desc->io_netif; 275 EFI_SIMPLE_NETWORK *net; 276 EFI_HANDLE h; 277 EFI_STATUS status; 278 UINT32 mask; 279 280 /* Attempt to get netboot params from env */ 281 efi_env_net_params(desc); 282 283 if (nif->nif_driver->netif_ifs[nif->nif_unit].dif_unit < 0) { 284 printf("Invalid network interface %d\n", nif->nif_unit); 285 return; 286 } 287 288 h = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private; 289 status = OpenProtocolByHandle(h, &sn_guid, (void **)&nif->nif_devdata); 290 if (status != EFI_SUCCESS) { 291 printf("net%d: cannot fetch interface data (status=%lu)\n", 292 nif->nif_unit, EFI_ERROR_CODE(status)); 293 return; 294 } 295 296 net = nif->nif_devdata; 297 if (net->Mode->State == EfiSimpleNetworkStopped) { 298 status = net->Start(net); 299 if (status != EFI_SUCCESS) { 300 printf("net%d: cannot start interface (status=%lu)\n", 301 nif->nif_unit, EFI_ERROR_CODE(status)); 302 return; 303 } 304 } 305 306 if (net->Mode->State != EfiSimpleNetworkInitialized) { 307 status = net->Initialize(net, 0, 0); 308 if (status != EFI_SUCCESS) { 309 printf("net%d: cannot init. interface (status=%lu)\n", 310 nif->nif_unit, EFI_ERROR_CODE(status)); 311 return; 312 } 313 } 314 315 mask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | 316 EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST; 317 318 status = net->ReceiveFilters(net, mask, 0, FALSE, 0, NULL); 319 if (status != EFI_SUCCESS) 320 printf("net%d: cannot set rx. filters (status=%lu)\n", 321 nif->nif_unit, EFI_ERROR_CODE(status)); 322 323 #ifdef EFINET_DEBUG 324 dump_mode(net->Mode); 325 #endif 326 327 bcopy(net->Mode->CurrentAddress.Addr, desc->myea, 6); 328 desc->xid = 1; 329 } 330 331 static void 332 efinet_end(struct netif *nif) 333 { 334 EFI_SIMPLE_NETWORK *net = nif->nif_devdata; 335 336 if (net == NULL) 337 return; 338 339 net->Shutdown(net); 340 } 341 342 static int efinet_dev_init(void); 343 static int efinet_dev_print(int); 344 345 struct devsw efinet_dev = { 346 .dv_name = "net", 347 .dv_type = DEVT_NET, 348 .dv_init = efinet_dev_init, 349 .dv_strategy = NULL, /* Will be set in efinet_dev_init */ 350 .dv_open = NULL, /* Will be set in efinet_dev_init */ 351 .dv_close = NULL, /* Will be set in efinet_dev_init */ 352 .dv_ioctl = noioctl, 353 .dv_print = efinet_dev_print, 354 .dv_cleanup = nullsys, 355 }; 356 357 static int 358 efinet_dev_init() 359 { 360 struct netif_dif *dif; 361 struct netif_stats *stats; 362 EFI_DEVICE_PATH *devpath, *node; 363 EFI_HANDLE *handles, *handles2; 364 EFI_STATUS status; 365 UINTN sz; 366 int err, i, nifs; 367 extern struct devsw netdev; 368 369 sz = 0; 370 handles = NULL; 371 status = BS->LocateHandle(ByProtocol, &sn_guid, NULL, &sz, NULL); 372 if (status == EFI_BUFFER_TOO_SMALL) { 373 handles = (EFI_HANDLE *)malloc(sz); 374 if (handles == NULL) 375 return (ENOMEM); 376 status = BS->LocateHandle(ByProtocol, &sn_guid, NULL, &sz, 377 handles); 378 if (EFI_ERROR(status)) 379 free(handles); 380 } 381 if (EFI_ERROR(status)) 382 return (efi_status_to_errno(status)); 383 handles2 = (EFI_HANDLE *)malloc(sz); 384 if (handles2 == NULL) { 385 free(handles); 386 return (ENOMEM); 387 } 388 nifs = 0; 389 for (i = 0; i < sz / sizeof(EFI_HANDLE); i++) { 390 devpath = efi_lookup_devpath(handles[i]); 391 if (devpath == NULL) 392 continue; 393 if ((node = efi_devpath_last_node(devpath)) == NULL) 394 continue; 395 396 if (DevicePathType(node) != MESSAGING_DEVICE_PATH || 397 DevicePathSubType(node) != MSG_MAC_ADDR_DP) 398 continue; 399 400 handles2[nifs] = handles[i]; 401 nifs++; 402 } 403 free(handles); 404 if (nifs == 0) { 405 err = ENOENT; 406 goto done; 407 } 408 409 err = efi_register_handles(&efinet_dev, handles2, NULL, nifs); 410 if (err != 0) 411 goto done; 412 413 efinetif.netif_ifs = calloc(nifs, sizeof(struct netif_dif)); 414 stats = calloc(nifs, sizeof(struct netif_stats)); 415 if (efinetif.netif_ifs == NULL || stats == NULL) { 416 free(efinetif.netif_ifs); 417 free(stats); 418 efinetif.netif_ifs = NULL; 419 err = ENOMEM; 420 goto done; 421 } 422 efinetif.netif_nifs = nifs; 423 424 for (i = 0; i < nifs; i++) { 425 426 dif = &efinetif.netif_ifs[i]; 427 dif->dif_unit = i; 428 dif->dif_nsel = 1; 429 dif->dif_stats = &stats[i]; 430 dif->dif_private = handles2[i]; 431 } 432 433 efinet_dev.dv_open = netdev.dv_open; 434 efinet_dev.dv_close = netdev.dv_close; 435 efinet_dev.dv_strategy = netdev.dv_strategy; 436 437 done: 438 free(handles2); 439 return (err); 440 } 441 442 static int 443 efinet_dev_print(int verbose) 444 { 445 CHAR16 *text; 446 EFI_HANDLE h; 447 int unit, ret = 0; 448 449 printf("%s devices:", efinet_dev.dv_name); 450 if ((ret = pager_output("\n")) != 0) 451 return (ret); 452 453 for (unit = 0, h = efi_find_handle(&efinet_dev, 0); 454 h != NULL; h = efi_find_handle(&efinet_dev, ++unit)) { 455 printf(" %s%d:", efinet_dev.dv_name, unit); 456 if (verbose) { 457 text = efi_devpath_name(efi_lookup_devpath(h)); 458 if (text != NULL) { 459 printf(" %S", text); 460 efi_free_devpath_name(text); 461 } 462 } 463 if ((ret = pager_output("\n")) != 0) 464 break; 465 } 466 return (ret); 467 } 468