efinet.c revision 1.6.4.2 1 /* $NetBSD: efinet.c,v 1.6.4.2 2019/06/10 22:09:56 christos 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 #include <sys/param.h>
32
33 #include "efiboot.h"
34
35 #include <lib/libsa/net.h>
36 #include <lib/libsa/netif.h>
37 #include <lib/libsa/dev_net.h>
38
39 #include "devopen.h"
40
41 #define ETHER_EXT_LEN (ETHER_HDR_LEN + ETHER_CRC_LEN + ETHER_ALIGN)
42
43 #if defined(DEBUG) || defined(ARP_DEBUG) || defined(BOOTP_DEBUG) || \
44 defined(NET_DEBUG) || defined(NETIF_DEBUG) || defined(NFS_DEBUG) || \
45 defined(RARP_DEBUG) || defined(RPC_DEBUG)
46 int debug = 1;
47 #else
48 int debug = 0;
49 #endif
50
51 extern bool kernel_loaded;
52
53 struct efinetinfo {
54 EFI_SIMPLE_NETWORK *net;
55 bool bootdev;
56 size_t pktbufsz;
57 UINT8 *pktbuf;
58 struct {
59 int type;
60 u_int tag;
61 } bus;
62 };
63 #if notyet
64 static struct btinfo_netif bi_netif;
65 #endif
66
67 static int efinet_match(struct netif *, void *);
68 static int efinet_probe(struct netif *, void *);
69 static void efinet_init(struct iodesc *, void *);
70 static int efinet_get(struct iodesc *, void *, size_t, saseconds_t);
71 static int efinet_put(struct iodesc *, void *, size_t);
72 static void efinet_end(struct netif *);
73
74 struct 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
87 static void
88 dump_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
120 static const EFI_MAC_ADDRESS *
121 efinet_hwaddr(const EFI_SIMPLE_NETWORK_MODE *mode)
122 {
123 int valid, n;
124
125 for (valid = 0, n = 0; n < mode->HwAddressSize; n++)
126 if (mode->CurrentAddress.Addr[n] != 0x00) {
127 valid = true;
128 break;
129 }
130 if (!valid)
131 goto use_permanent;
132
133 for (valid = 0, n = 0; n < mode->HwAddressSize; n++)
134 if (mode->CurrentAddress.Addr[n] != 0xff) {
135 valid = true;
136 break;
137 }
138 if (!valid)
139 goto use_permanent;
140
141 return &mode->CurrentAddress;
142
143 use_permanent:
144 return &mode->PermanentAddress;
145 }
146
147 static int
148 efinet_match(struct netif *nif, void *machdep_hint)
149 {
150 struct devdesc *dev = machdep_hint;
151
152 if (dev->d_unit != nif->nif_unit)
153 return 0;
154
155 return 1;
156 }
157
158 static int
159 efinet_probe(struct netif *nif, void *machdep_hint)
160 {
161
162 return 0;
163 }
164
165 static int
166 efinet_put(struct iodesc *desc, void *pkt, size_t len)
167 {
168 struct netif *nif = desc->io_netif;
169 struct efinetinfo *eni = nif->nif_devdata;
170 EFI_SIMPLE_NETWORK *net;
171 EFI_STATUS status;
172 void *buf;
173 char *ptr;
174
175 if (eni == NULL)
176 return -1;
177 net = eni->net;
178
179 ptr = eni->pktbuf;
180
181 memcpy(ptr, pkt, len);
182 status = uefi_call_wrapper(net->Transmit, 7, net, 0, (UINTN)len, ptr, NULL,
183 NULL, NULL);
184 if (EFI_ERROR(status))
185 return -1;
186
187 /* Wait for the buffer to be transmitted */
188 do {
189 buf = NULL; /* XXX Is this needed? */
190 status = uefi_call_wrapper(net->GetStatus, 3, net, NULL, &buf);
191 /*
192 * XXX EFI1.1 and the E1000 card returns a different
193 * address than we gave. Sigh.
194 */
195 } while (!EFI_ERROR(status) && buf == NULL);
196
197 /* XXX How do we deal with status != EFI_SUCCESS now? */
198 return EFI_ERROR(status) ? -1 : len;
199 }
200
201 static int
202 efinet_get(struct iodesc *desc, void *pkt, size_t len, saseconds_t timeout)
203 {
204 struct netif *nif = desc->io_netif;
205 struct efinetinfo *eni = nif->nif_devdata;
206 EFI_SIMPLE_NETWORK *net;
207 EFI_STATUS status;
208 UINTN bufsz, rsz;
209 time_t t;
210 char *buf, *ptr;
211 int ret = -1;
212
213 if (eni == NULL)
214 return -1;
215 net = eni->net;
216
217 if (eni->pktbufsz < net->Mode->MaxPacketSize + ETHER_EXT_LEN) {
218 bufsz = net->Mode->MaxPacketSize + ETHER_EXT_LEN;
219 buf = alloc(bufsz);
220 if (buf == NULL)
221 return -1;
222 dealloc(eni->pktbuf, eni->pktbufsz);
223 eni->pktbufsz = bufsz;
224 eni->pktbuf = buf;
225 }
226 ptr = eni->pktbuf + ETHER_ALIGN;
227
228 t = getsecs();
229 while ((getsecs() - t) < timeout) {
230 rsz = eni->pktbufsz;
231 status = uefi_call_wrapper(net->Receive, 7, net, NULL, &rsz, ptr,
232 NULL, NULL, NULL);
233 if (!EFI_ERROR(status)) {
234 rsz = uimin(rsz, len);
235 memcpy(pkt, ptr, rsz);
236
237 ret = (int)rsz;
238 break;
239 }
240 if (status != EFI_NOT_READY)
241 break;
242 }
243
244 return ret;
245 }
246
247 static void
248 efinet_init(struct iodesc *desc, void *machdep_hint)
249 {
250 struct netif *nif = desc->io_netif;
251 struct efinetinfo *eni;
252 EFI_SIMPLE_NETWORK *net;
253 EFI_STATUS status;
254 UINT32 mask;
255
256 if (nif->nif_driver->netif_ifs[nif->nif_unit].dif_unit < 0) {
257 printf("Invalid network interface %d\n", nif->nif_unit);
258 return;
259 }
260
261 eni = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private;
262 nif->nif_devdata = eni;
263 net = eni->net;
264 if (net->Mode->State == EfiSimpleNetworkStopped) {
265 status = uefi_call_wrapper(net->Start, 1, net);
266 if (EFI_ERROR(status)) {
267 printf("net%d: cannot start interface (status=%"
268 PRIxMAX ")\n", nif->nif_unit, (uintmax_t)status);
269 return;
270 }
271 }
272
273 if (net->Mode->State != EfiSimpleNetworkInitialized) {
274 status = uefi_call_wrapper(net->Initialize, 3, net, 0, 0);
275 if (EFI_ERROR(status)) {
276 printf("net%d: cannot init. interface (status=%"
277 PRIxMAX ")\n", nif->nif_unit, (uintmax_t)status);
278 return;
279 }
280 }
281
282 mask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
283 EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
284
285 status = uefi_call_wrapper(net->ReceiveFilters, 6, net, mask, 0, FALSE,
286 0, NULL);
287 if (EFI_ERROR(status) && status != EFI_INVALID_PARAMETER && status != EFI_UNSUPPORTED) {
288 printf("net%d: cannot set rx. filters (status=%" PRIxMAX ")\n",
289 nif->nif_unit, (uintmax_t)status);
290 return;
291 }
292
293 #if notyet
294 if (!kernel_loaded) {
295 bi_netif.bus = eni->bus.type;
296 bi_netif.addr.tag = eni->bus.tag;
297 snprintf(bi_netif.ifname, sizeof(bi_netif.ifname), "net%d",
298 nif->nif_unit);
299 BI_ADD(&bi_netif, BTINFO_NETIF, sizeof(bi_netif));
300 }
301 #endif
302
303 #ifdef EFINET_DEBUG
304 dump_mode(net->Mode);
305 #endif
306
307 memcpy(desc->myea, efinet_hwaddr(net->Mode)->Addr, 6);
308 desc->xid = 1;
309 }
310
311 static void
312 efinet_end(struct netif *nif)
313 {
314 struct efinetinfo *eni = nif->nif_devdata;
315 EFI_SIMPLE_NETWORK *net;
316
317 if (eni == NULL)
318 return;
319 net = eni->net;
320
321 uefi_call_wrapper(net->Shutdown, 1, net);
322 }
323
324 void
325 efi_net_probe(void)
326 {
327 struct efinetinfo *enis;
328 struct netif_dif *dif;
329 struct netif_stats *stats;
330 EFI_DEVICE_PATH *dp0, *dp;
331 EFI_SIMPLE_NETWORK *net;
332 EFI_HANDLE *handles;
333 EFI_STATUS status;
334 UINTN i, nhandles;
335 int nifs, depth = -1;
336 bool found;
337
338 status = LibLocateHandle(ByProtocol, &SimpleNetworkProtocol, NULL,
339 &nhandles, &handles);
340 if (EFI_ERROR(status) || nhandles == 0)
341 return;
342
343 enis = alloc(nhandles * sizeof(*enis));
344 if (enis == NULL)
345 return;
346 memset(enis, 0, nhandles * sizeof(*enis));
347
348 if (efi_bootdp) {
349 depth = efi_device_path_depth(efi_bootdp, HARDWARE_DEVICE_PATH);
350 if (depth == 0)
351 depth = 1;
352 }
353
354 nifs = 0;
355 for (i = 0; i < nhandles; i++) {
356 status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i],
357 &DevicePathProtocol, (void **)&dp0);
358 if (EFI_ERROR(status))
359 continue;
360
361 found = false;
362 for (dp = dp0; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp)) {
363 if (DevicePathType(dp) == MESSAGING_DEVICE_PATH &&
364 DevicePathSubType(dp) == MSG_MAC_ADDR_DP) {
365 found = true;
366 break;
367 }
368 }
369 if (!found)
370 continue;
371
372 status = uefi_call_wrapper(BS->OpenProtocol, 6, handles[i],
373 &SimpleNetworkProtocol, (void **)&net, IH, NULL,
374 EFI_OPEN_PROTOCOL_EXCLUSIVE);
375 if (EFI_ERROR(status)) {
376 printf("Unable to open network interface %" PRIuMAX
377 " for exclusive access: %" PRIxMAX "\n",
378 (uintmax_t)i, (uintmax_t)status);
379 continue;
380 }
381
382 enis[nifs].net = net;
383 enis[nifs].bootdev = efi_pxe_match_booted_interface(
384 efinet_hwaddr(net->Mode), net->Mode->HwAddressSize);
385 enis[nifs].pktbufsz = net->Mode->MaxPacketSize +
386 ETHER_EXT_LEN;
387 enis[nifs].pktbuf = alloc(enis[nifs].pktbufsz);
388 if (enis[nifs].pktbuf == NULL) {
389 while (i-- > 0) {
390 dealloc(enis[i].pktbuf, enis[i].pktbufsz);
391 if (i == 0)
392 break;
393 }
394 dealloc(enis, nhandles * sizeof(*enis));
395 FreePool(handles);
396 return;
397 }
398
399 if (depth > 0 && efi_device_path_ncmp(efi_bootdp, dp0, depth) == 0) {
400 char devname[9];
401 snprintf(devname, sizeof(devname), "net%u", nifs);
402 set_default_device(devname);
403 }
404
405 nifs++;
406 }
407
408 FreePool(handles);
409
410 if (nifs == 0)
411 return;
412
413 efinetif.netif_ifs = alloc(nifs * sizeof(*dif));
414 stats = alloc(nifs * sizeof(*stats));
415 if (efinetif.netif_ifs == NULL || stats == NULL) {
416 if (efinetif.netif_ifs != NULL) {
417 dealloc(efinetif.netif_ifs, nifs * sizeof(*dif));
418 efinetif.netif_ifs = NULL;
419 }
420 if (stats != NULL)
421 dealloc(stats, nifs * sizeof(*stats));
422 for (i = 0; i < nifs; i++)
423 dealloc(enis[i].pktbuf, enis[i].pktbufsz);
424 dealloc(enis, nhandles * sizeof(*enis));
425 return;
426 }
427 memset(efinetif.netif_ifs, 0, nifs * sizeof(*dif));
428 memset(stats, 0, nifs * sizeof(*stats));
429 efinetif.netif_nifs = nifs;
430
431 for (i = 0; i < nifs; i++) {
432 dif = &efinetif.netif_ifs[i];
433 dif->dif_unit = i;
434 dif->dif_nsel = 1;
435 dif->dif_stats = &stats[i];
436 dif->dif_private = &enis[i];
437 }
438 }
439
440 void
441 efi_net_show(void)
442 {
443 const struct netif_dif *dif;
444 const struct efinetinfo *eni;
445 EFI_SIMPLE_NETWORK *net;
446 int i;
447
448 for (i = 0; i < efinetif.netif_nifs; i++) {
449 dif = &efinetif.netif_ifs[i];
450 eni = dif->dif_private;
451 net = eni->net;
452
453 printf("net%d", dif->dif_unit);
454 if (net->Mode != NULL) {
455 const EFI_MAC_ADDRESS *mac = efinet_hwaddr(net->Mode);
456 for (UINT32 x = 0; x < net->Mode->HwAddressSize; x++) {
457 printf("%c%02x", x == 0 ? ' ' : ':',
458 mac->Addr[x]);
459 }
460 }
461 if (eni->bootdev)
462 printf(" pxeboot");
463 printf("\n");
464 }
465 }
466
467 int
468 efi_net_get_booted_interface_unit(void)
469 {
470 const struct netif_dif *dif;
471 const struct efinetinfo *eni;
472 int i;
473
474 for (i = 0; i < efinetif.netif_nifs; i++) {
475 dif = &efinetif.netif_ifs[i];
476 eni = dif->dif_private;
477 if (eni->bootdev)
478 return dif->dif_unit;
479 }
480 return -1;
481 }
482
483 int
484 efi_net_get_booted_macaddr(uint8_t *mac)
485 {
486 const struct netif_dif *dif;
487 const struct efinetinfo *eni;
488 EFI_SIMPLE_NETWORK *net;
489 int i;
490
491 for (i = 0; i < efinetif.netif_nifs; i++) {
492 dif = &efinetif.netif_ifs[i];
493 eni = dif->dif_private;
494 net = eni->net;
495 if (eni->bootdev && net->Mode != NULL && net->Mode->HwAddressSize == 6) {
496 memcpy(mac, net->Mode->PermanentAddress.Addr, 6);
497 return 0;
498 }
499 }
500
501 return -1;
502 }
503
504 int
505 efi_net_open(struct open_file *f, ...)
506 {
507 char **file, pathbuf[PATH_MAX], *default_device, *path, *ep;
508 const char *fname, *full_path;
509 struct devdesc desc;
510 intmax_t dev;
511 va_list ap;
512 int n, error;
513
514 va_start(ap, f);
515 fname = va_arg(ap, const char *);
516 file = va_arg(ap, char **);
517 va_end(ap);
518
519 default_device = get_default_device();
520 if (strchr(fname, ':') == NULL) {
521 if (strlen(default_device) > 0) {
522 snprintf(pathbuf, sizeof(pathbuf), "%s:%s", default_device, fname);
523 full_path = pathbuf;
524 path = __UNCONST(fname);
525 } else {
526 return EINVAL;
527 }
528 } else {
529 full_path = fname;
530 path = strchr(fname, ':') + 1;
531 }
532
533 if (strncmp(full_path, "net", 3) != 0)
534 return EINVAL;
535 dev = strtoimax(full_path + 3, &ep, 10);
536 if (dev < 0 || dev >= efinetif.netif_nifs)
537 return ENXIO;
538
539 for (n = 0; n < ndevs; n++)
540 if (strcmp(DEV_NAME(&devsw[n]), "net") == 0) {
541 f->f_dev = &devsw[n];
542 break;
543 }
544 if (n == ndevs)
545 return ENXIO;
546
547 *file = path;
548
549 //try_bootp = 1;
550
551 memset(&desc, 0, sizeof(desc));
552 strlcpy(desc.d_name, "net", sizeof(desc.d_name));
553 desc.d_unit = dev;
554
555 error = DEV_OPEN(f->f_dev)(f, &desc);
556 if (error)
557 return error;
558
559 return 0;
560 }
561