[test] Allow self-tests to report exit status when running under Linux
[ipxe.git] / src / interface / efi / efi_snp.c
1 /*
2 * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 */
19
20 FILE_LICENCE ( GPL2_OR_LATER );
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <assert.h>
26 #include <byteswap.h>
27 #include <ipxe/netdevice.h>
28 #include <ipxe/iobuf.h>
29 #include <ipxe/in.h>
30 #include <ipxe/version.h>
31 #include <ipxe/efi/efi.h>
32 #include <ipxe/efi/efi_driver.h>
33 #include <ipxe/efi/efi_strings.h>
34 #include <ipxe/efi/efi_utils.h>
35 #include <ipxe/efi/efi_watchdog.h>
36 #include <ipxe/efi/efi_snp.h>
37 #include <usr/autoboot.h>
38 #include <config/general.h>
39
40 /** List of SNP devices */
41 static LIST_HEAD ( efi_snp_devices );
42
43 /** Network devices are currently claimed for use by iPXE */
44 static int efi_snp_claimed;
45
46 /* Downgrade user experience if configured to do so
47 *
48 * The default UEFI user experience for network boot is somewhat
49 * excremental: only TFTP is available as a download protocol, and if
50 * anything goes wrong the user will be shown just a dot on an
51 * otherwise blank screen. (Some programmer was clearly determined to
52 * win a bet that they could outshine Apple at producing uninformative
53 * error messages.)
54 *
55 * For comparison, the default iPXE user experience provides the
56 * option to use protocols designed more recently than 1980 (such as
57 * HTTP and iSCSI), and if anything goes wrong the the user will be
58 * shown one of over 1200 different error messages, complete with a
59 * link to a wiki page describing that specific error.
60 *
61 * We default to upgrading the user experience to match that available
62 * in a "legacy" BIOS environment, by installing our own instance of
63 * EFI_LOAD_FILE_PROTOCOL.
64 *
65 * Note that unfortunately we can't sensibly provide the choice of
66 * both options to the user in the same build, because the UEFI boot
67 * menu ignores the multitude of ways in which a network device handle
68 * can be described and opaquely labels both menu entries as just "EFI
69 * Network".
70 */
71 #ifdef EFI_DOWNGRADE_UX
72 static EFI_GUID dummy_load_file_protocol_guid = {
73 0x6f6c7323, 0x2077, 0x7523,
74 { 0x6e, 0x68, 0x65, 0x6c, 0x70, 0x66, 0x75, 0x6c }
75 };
76 #define efi_load_file_protocol_guid dummy_load_file_protocol_guid
77 #endif
78
79 /**
80 * Set EFI SNP mode state
81 *
82 * @v snp SNP interface
83 */
84 static void efi_snp_set_state ( struct efi_snp_device *snpdev ) {
85 struct net_device *netdev = snpdev->netdev;
86 EFI_SIMPLE_NETWORK_MODE *mode = &snpdev->mode;
87
88 /* Calculate state */
89 if ( ! snpdev->started ) {
90 /* Start() method not called; report as Stopped */
91 mode->State = EfiSimpleNetworkStopped;
92 } else if ( ! netdev_is_open ( netdev ) ) {
93 /* Network device not opened; report as Started */
94 mode->State = EfiSimpleNetworkStarted;
95 } else if ( efi_snp_claimed ) {
96 /* Network device opened but claimed for use by iPXE; report
97 * as Started to inhibit receive polling.
98 */
99 mode->State = EfiSimpleNetworkStarted;
100 } else {
101 /* Network device opened and available for use via SNP; report
102 * as Initialized.
103 */
104 mode->State = EfiSimpleNetworkInitialized;
105 }
106 }
107
108 /**
109 * Set EFI SNP mode based on iPXE net device parameters
110 *
111 * @v snp SNP interface
112 */
113 static void efi_snp_set_mode ( struct efi_snp_device *snpdev ) {
114 struct net_device *netdev = snpdev->netdev;
115 EFI_SIMPLE_NETWORK_MODE *mode = &snpdev->mode;
116 struct ll_protocol *ll_protocol = netdev->ll_protocol;
117 unsigned int ll_addr_len = ll_protocol->ll_addr_len;
118
119 mode->HwAddressSize = ll_addr_len;
120 mode->MediaHeaderSize = ll_protocol->ll_header_len;
121 mode->MaxPacketSize = netdev->max_pkt_len;
122 mode->ReceiveFilterMask = ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
123 EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
124 EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST );
125 assert ( ll_addr_len <= sizeof ( mode->CurrentAddress ) );
126 memcpy ( &mode->CurrentAddress, netdev->ll_addr, ll_addr_len );
127 memcpy ( &mode->BroadcastAddress, netdev->ll_broadcast, ll_addr_len );
128 ll_protocol->init_addr ( netdev->hw_addr, &mode->PermanentAddress );
129 mode->IfType = ntohs ( ll_protocol->ll_proto );
130 mode->MacAddressChangeable = TRUE;
131 mode->MediaPresentSupported = TRUE;
132 mode->MediaPresent = ( netdev_link_ok ( netdev ) ? TRUE : FALSE );
133 }
134
135 /**
136 * Flush transmit ring and receive queue
137 *
138 * @v snpdev SNP device
139 */
140 static void efi_snp_flush ( struct efi_snp_device *snpdev ) {
141 struct io_buffer *iobuf;
142 struct io_buffer *tmp;
143
144 /* Reset transmit completion ring */
145 snpdev->tx_prod = 0;
146 snpdev->tx_cons = 0;
147
148 /* Discard any queued receive buffers */
149 list_for_each_entry_safe ( iobuf, tmp, &snpdev->rx, list ) {
150 list_del ( &iobuf->list );
151 free_iob ( iobuf );
152 }
153 }
154
155 /**
156 * Poll net device and count received packets
157 *
158 * @v snpdev SNP device
159 */
160 static void efi_snp_poll ( struct efi_snp_device *snpdev ) {
161 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
162 struct io_buffer *iobuf;
163
164 /* Poll network device */
165 netdev_poll ( snpdev->netdev );
166
167 /* Retrieve any received packets */
168 while ( ( iobuf = netdev_rx_dequeue ( snpdev->netdev ) ) ) {
169 list_add_tail ( &iobuf->list, &snpdev->rx );
170 snpdev->interrupts |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
171 bs->SignalEvent ( &snpdev->snp.WaitForPacket );
172 }
173 }
174
175 /**
176 * Change SNP state from "stopped" to "started"
177 *
178 * @v snp SNP interface
179 * @ret efirc EFI status code
180 */
181 static EFI_STATUS EFIAPI
182 efi_snp_start ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
183 struct efi_snp_device *snpdev =
184 container_of ( snp, struct efi_snp_device, snp );
185
186 DBGC2 ( snpdev, "SNPDEV %p START\n", snpdev );
187
188 /* Fail if net device is currently claimed for use by iPXE */
189 if ( efi_snp_claimed )
190 return EFI_NOT_READY;
191
192 snpdev->started = 1;
193 efi_snp_set_state ( snpdev );
194 return 0;
195 }
196
197 /**
198 * Change SNP state from "started" to "stopped"
199 *
200 * @v snp SNP interface
201 * @ret efirc EFI status code
202 */
203 static EFI_STATUS EFIAPI
204 efi_snp_stop ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
205 struct efi_snp_device *snpdev =
206 container_of ( snp, struct efi_snp_device, snp );
207
208 DBGC2 ( snpdev, "SNPDEV %p STOP\n", snpdev );
209
210 /* Fail if net device is currently claimed for use by iPXE */
211 if ( efi_snp_claimed )
212 return EFI_NOT_READY;
213
214 snpdev->started = 0;
215 efi_snp_set_state ( snpdev );
216 return 0;
217 }
218
219 /**
220 * Open the network device
221 *
222 * @v snp SNP interface
223 * @v extra_rx_bufsize Extra RX buffer size, in bytes
224 * @v extra_tx_bufsize Extra TX buffer size, in bytes
225 * @ret efirc EFI status code
226 */
227 static EFI_STATUS EFIAPI
228 efi_snp_initialize ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
229 UINTN extra_rx_bufsize, UINTN extra_tx_bufsize ) {
230 struct efi_snp_device *snpdev =
231 container_of ( snp, struct efi_snp_device, snp );
232 int rc;
233
234 DBGC2 ( snpdev, "SNPDEV %p INITIALIZE (%ld extra RX, %ld extra TX)\n",
235 snpdev, ( ( unsigned long ) extra_rx_bufsize ),
236 ( ( unsigned long ) extra_tx_bufsize ) );
237
238 /* Fail if net device is currently claimed for use by iPXE */
239 if ( efi_snp_claimed )
240 return EFI_NOT_READY;
241
242 if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
243 DBGC ( snpdev, "SNPDEV %p could not open %s: %s\n",
244 snpdev, snpdev->netdev->name, strerror ( rc ) );
245 return EFIRC ( rc );
246 }
247 efi_snp_set_state ( snpdev );
248
249 return 0;
250 }
251
252 /**
253 * Reset the network device
254 *
255 * @v snp SNP interface
256 * @v ext_verify Extended verification required
257 * @ret efirc EFI status code
258 */
259 static EFI_STATUS EFIAPI
260 efi_snp_reset ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ext_verify ) {
261 struct efi_snp_device *snpdev =
262 container_of ( snp, struct efi_snp_device, snp );
263 int rc;
264
265 DBGC2 ( snpdev, "SNPDEV %p RESET (%s extended verification)\n",
266 snpdev, ( ext_verify ? "with" : "without" ) );
267
268 /* Fail if net device is currently claimed for use by iPXE */
269 if ( efi_snp_claimed )
270 return EFI_NOT_READY;
271
272 netdev_close ( snpdev->netdev );
273 efi_snp_set_state ( snpdev );
274 efi_snp_flush ( snpdev );
275
276 if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
277 DBGC ( snpdev, "SNPDEV %p could not reopen %s: %s\n",
278 snpdev, snpdev->netdev->name, strerror ( rc ) );
279 return EFIRC ( rc );
280 }
281 efi_snp_set_state ( snpdev );
282
283 return 0;
284 }
285
286 /**
287 * Shut down the network device
288 *
289 * @v snp SNP interface
290 * @ret efirc EFI status code
291 */
292 static EFI_STATUS EFIAPI
293 efi_snp_shutdown ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
294 struct efi_snp_device *snpdev =
295 container_of ( snp, struct efi_snp_device, snp );
296
297 DBGC2 ( snpdev, "SNPDEV %p SHUTDOWN\n", snpdev );
298
299 /* Fail if net device is currently claimed for use by iPXE */
300 if ( efi_snp_claimed )
301 return EFI_NOT_READY;
302
303 netdev_close ( snpdev->netdev );
304 efi_snp_set_state ( snpdev );
305 efi_snp_flush ( snpdev );
306
307 return 0;
308 }
309
310 /**
311 * Manage receive filters
312 *
313 * @v snp SNP interface
314 * @v enable Receive filters to enable
315 * @v disable Receive filters to disable
316 * @v mcast_reset Reset multicast filters
317 * @v mcast_count Number of multicast filters
318 * @v mcast Multicast filters
319 * @ret efirc EFI status code
320 */
321 static EFI_STATUS EFIAPI
322 efi_snp_receive_filters ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, UINT32 enable,
323 UINT32 disable, BOOLEAN mcast_reset,
324 UINTN mcast_count, EFI_MAC_ADDRESS *mcast ) {
325 struct efi_snp_device *snpdev =
326 container_of ( snp, struct efi_snp_device, snp );
327 unsigned int i;
328
329 DBGC2 ( snpdev, "SNPDEV %p RECEIVE_FILTERS %08x&~%08x%s %ld mcast\n",
330 snpdev, enable, disable, ( mcast_reset ? " reset" : "" ),
331 ( ( unsigned long ) mcast_count ) );
332 for ( i = 0 ; i < mcast_count ; i++ ) {
333 DBGC2_HDA ( snpdev, i, &mcast[i],
334 snpdev->netdev->ll_protocol->ll_addr_len );
335 }
336
337 /* Fail if net device is currently claimed for use by iPXE */
338 if ( efi_snp_claimed )
339 return EFI_NOT_READY;
340
341 /* Lie through our teeth, otherwise MNP refuses to accept us */
342 return 0;
343 }
344
345 /**
346 * Set station address
347 *
348 * @v snp SNP interface
349 * @v reset Reset to permanent address
350 * @v new New station address
351 * @ret efirc EFI status code
352 */
353 static EFI_STATUS EFIAPI
354 efi_snp_station_address ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset,
355 EFI_MAC_ADDRESS *new ) {
356 struct efi_snp_device *snpdev =
357 container_of ( snp, struct efi_snp_device, snp );
358 struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
359
360 DBGC2 ( snpdev, "SNPDEV %p STATION_ADDRESS %s\n", snpdev,
361 ( reset ? "reset" : ll_protocol->ntoa ( new ) ) );
362
363 /* Fail if net device is currently claimed for use by iPXE */
364 if ( efi_snp_claimed )
365 return EFI_NOT_READY;
366
367 /* Set the MAC address */
368 if ( reset )
369 new = &snpdev->mode.PermanentAddress;
370 memcpy ( snpdev->netdev->ll_addr, new, ll_protocol->ll_addr_len );
371
372 /* MAC address changes take effect only on netdev_open() */
373 if ( netdev_is_open ( snpdev->netdev ) ) {
374 DBGC ( snpdev, "SNPDEV %p MAC address changed while net "
375 "device open\n", snpdev );
376 }
377
378 return 0;
379 }
380
381 /**
382 * Get (or reset) statistics
383 *
384 * @v snp SNP interface
385 * @v reset Reset statistics
386 * @v stats_len Size of statistics table
387 * @v stats Statistics table
388 * @ret efirc EFI status code
389 */
390 static EFI_STATUS EFIAPI
391 efi_snp_statistics ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset,
392 UINTN *stats_len, EFI_NETWORK_STATISTICS *stats ) {
393 struct efi_snp_device *snpdev =
394 container_of ( snp, struct efi_snp_device, snp );
395 EFI_NETWORK_STATISTICS stats_buf;
396
397 DBGC2 ( snpdev, "SNPDEV %p STATISTICS%s", snpdev,
398 ( reset ? " reset" : "" ) );
399
400 /* Fail if net device is currently claimed for use by iPXE */
401 if ( efi_snp_claimed )
402 return EFI_NOT_READY;
403
404 /* Gather statistics */
405 memset ( &stats_buf, 0, sizeof ( stats_buf ) );
406 stats_buf.TxGoodFrames = snpdev->netdev->tx_stats.good;
407 stats_buf.TxDroppedFrames = snpdev->netdev->tx_stats.bad;
408 stats_buf.TxTotalFrames = ( snpdev->netdev->tx_stats.good +
409 snpdev->netdev->tx_stats.bad );
410 stats_buf.RxGoodFrames = snpdev->netdev->rx_stats.good;
411 stats_buf.RxDroppedFrames = snpdev->netdev->rx_stats.bad;
412 stats_buf.RxTotalFrames = ( snpdev->netdev->rx_stats.good +
413 snpdev->netdev->rx_stats.bad );
414 if ( *stats_len > sizeof ( stats_buf ) )
415 *stats_len = sizeof ( stats_buf );
416 if ( stats )
417 memcpy ( stats, &stats_buf, *stats_len );
418
419 /* Reset statistics if requested to do so */
420 if ( reset ) {
421 memset ( &snpdev->netdev->tx_stats, 0,
422 sizeof ( snpdev->netdev->tx_stats ) );
423 memset ( &snpdev->netdev->rx_stats, 0,
424 sizeof ( snpdev->netdev->rx_stats ) );
425 }
426
427 return 0;
428 }
429
430 /**
431 * Convert multicast IP address to MAC address
432 *
433 * @v snp SNP interface
434 * @v ipv6 Address is IPv6
435 * @v ip IP address
436 * @v mac MAC address
437 * @ret efirc EFI status code
438 */
439 static EFI_STATUS EFIAPI
440 efi_snp_mcast_ip_to_mac ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ipv6,
441 EFI_IP_ADDRESS *ip, EFI_MAC_ADDRESS *mac ) {
442 struct efi_snp_device *snpdev =
443 container_of ( snp, struct efi_snp_device, snp );
444 struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
445 const char *ip_str;
446 int rc;
447
448 ip_str = ( ipv6 ? "(IPv6)" /* FIXME when we have inet6_ntoa() */ :
449 inet_ntoa ( *( ( struct in_addr * ) ip ) ) );
450 DBGC2 ( snpdev, "SNPDEV %p MCAST_IP_TO_MAC %s\n", snpdev, ip_str );
451
452 /* Fail if net device is currently claimed for use by iPXE */
453 if ( efi_snp_claimed )
454 return EFI_NOT_READY;
455
456 /* Try to hash the address */
457 if ( ( rc = ll_protocol->mc_hash ( ( ipv6 ? AF_INET6 : AF_INET ),
458 ip, mac ) ) != 0 ) {
459 DBGC ( snpdev, "SNPDEV %p could not hash %s: %s\n",
460 snpdev, ip_str, strerror ( rc ) );
461 return EFIRC ( rc );
462 }
463
464 return 0;
465 }
466
467 /**
468 * Read or write non-volatile storage
469 *
470 * @v snp SNP interface
471 * @v read Operation is a read
472 * @v offset Starting offset within NVRAM
473 * @v len Length of data buffer
474 * @v data Data buffer
475 * @ret efirc EFI status code
476 */
477 static EFI_STATUS EFIAPI
478 efi_snp_nvdata ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN read,
479 UINTN offset, UINTN len, VOID *data ) {
480 struct efi_snp_device *snpdev =
481 container_of ( snp, struct efi_snp_device, snp );
482
483 DBGC2 ( snpdev, "SNPDEV %p NVDATA %s %lx+%lx\n", snpdev,
484 ( read ? "read" : "write" ), ( ( unsigned long ) offset ),
485 ( ( unsigned long ) len ) );
486 if ( ! read )
487 DBGC2_HDA ( snpdev, offset, data, len );
488
489 /* Fail if net device is currently claimed for use by iPXE */
490 if ( efi_snp_claimed )
491 return EFI_NOT_READY;
492
493 return EFI_UNSUPPORTED;
494 }
495
496 /**
497 * Read interrupt status and TX recycled buffer status
498 *
499 * @v snp SNP interface
500 * @v interrupts Interrupt status, or NULL
501 * @v txbuf Recycled transmit buffer address, or NULL
502 * @ret efirc EFI status code
503 */
504 static EFI_STATUS EFIAPI
505 efi_snp_get_status ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
506 UINT32 *interrupts, VOID **txbuf ) {
507 struct efi_snp_device *snpdev =
508 container_of ( snp, struct efi_snp_device, snp );
509
510 DBGC2 ( snpdev, "SNPDEV %p GET_STATUS", snpdev );
511
512 /* Fail if net device is currently claimed for use by iPXE */
513 if ( efi_snp_claimed ) {
514 DBGC2 ( snpdev, "\n" );
515 return EFI_NOT_READY;
516 }
517
518 /* Poll the network device */
519 efi_snp_poll ( snpdev );
520
521 /* Interrupt status. In practice, this seems to be used only
522 * to detect TX completions.
523 */
524 if ( interrupts ) {
525 *interrupts = snpdev->interrupts;
526 DBGC2 ( snpdev, " INTS:%02x", *interrupts );
527 snpdev->interrupts = 0;
528 }
529
530 /* TX completions */
531 if ( txbuf ) {
532 if ( snpdev->tx_prod != snpdev->tx_cons ) {
533 *txbuf = snpdev->tx[snpdev->tx_cons++ % EFI_SNP_NUM_TX];
534 } else {
535 *txbuf = NULL;
536 }
537 DBGC2 ( snpdev, " TX:%p", *txbuf );
538 }
539
540 DBGC2 ( snpdev, "\n" );
541 return 0;
542 }
543
544 /**
545 * Start packet transmission
546 *
547 * @v snp SNP interface
548 * @v ll_header_len Link-layer header length, if to be filled in
549 * @v len Length of data buffer
550 * @v data Data buffer
551 * @v ll_src Link-layer source address, if specified
552 * @v ll_dest Link-layer destination address, if specified
553 * @v net_proto Network-layer protocol (in host order)
554 * @ret efirc EFI status code
555 */
556 static EFI_STATUS EFIAPI
557 efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
558 UINTN ll_header_len, UINTN len, VOID *data,
559 EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest,
560 UINT16 *net_proto ) {
561 struct efi_snp_device *snpdev =
562 container_of ( snp, struct efi_snp_device, snp );
563 struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
564 struct io_buffer *iobuf;
565 size_t payload_len;
566 unsigned int tx_fill;
567 int rc;
568
569 DBGC2 ( snpdev, "SNPDEV %p TRANSMIT %p+%lx", snpdev, data,
570 ( ( unsigned long ) len ) );
571 if ( ll_header_len ) {
572 if ( ll_src ) {
573 DBGC2 ( snpdev, " src %s",
574 ll_protocol->ntoa ( ll_src ) );
575 }
576 if ( ll_dest ) {
577 DBGC2 ( snpdev, " dest %s",
578 ll_protocol->ntoa ( ll_dest ) );
579 }
580 if ( net_proto ) {
581 DBGC2 ( snpdev, " proto %04x", *net_proto );
582 }
583 }
584 DBGC2 ( snpdev, "\n" );
585
586 /* Fail if net device is currently claimed for use by iPXE */
587 if ( efi_snp_claimed )
588 return EFI_NOT_READY;
589
590 /* Sanity checks */
591 if ( ll_header_len ) {
592 if ( ll_header_len != ll_protocol->ll_header_len ) {
593 DBGC ( snpdev, "SNPDEV %p TX invalid header length "
594 "%ld\n", snpdev,
595 ( ( unsigned long ) ll_header_len ) );
596 rc = -EINVAL;
597 goto err_sanity;
598 }
599 if ( len < ll_header_len ) {
600 DBGC ( snpdev, "SNPDEV %p invalid packet length %ld\n",
601 snpdev, ( ( unsigned long ) len ) );
602 rc = -EINVAL;
603 goto err_sanity;
604 }
605 if ( ! ll_dest ) {
606 DBGC ( snpdev, "SNPDEV %p TX missing destination "
607 "address\n", snpdev );
608 rc = -EINVAL;
609 goto err_sanity;
610 }
611 if ( ! net_proto ) {
612 DBGC ( snpdev, "SNPDEV %p TX missing network "
613 "protocol\n", snpdev );
614 rc = -EINVAL;
615 goto err_sanity;
616 }
617 if ( ! ll_src )
618 ll_src = &snpdev->mode.CurrentAddress;
619 }
620
621 /* Allocate buffer */
622 payload_len = ( len - ll_protocol->ll_header_len );
623 iobuf = alloc_iob ( MAX_LL_HEADER_LEN + ( ( payload_len > IOB_ZLEN ) ?
624 payload_len : IOB_ZLEN ) );
625 if ( ! iobuf ) {
626 DBGC ( snpdev, "SNPDEV %p TX could not allocate %ld-byte "
627 "buffer\n", snpdev, ( ( unsigned long ) len ) );
628 rc = -ENOMEM;
629 goto err_alloc_iob;
630 }
631 iob_reserve ( iobuf, ( MAX_LL_HEADER_LEN -
632 ll_protocol->ll_header_len ) );
633 memcpy ( iob_put ( iobuf, len ), data, len );
634
635 /* Create link-layer header, if specified */
636 if ( ll_header_len ) {
637 iob_pull ( iobuf, ll_protocol->ll_header_len );
638 if ( ( rc = ll_protocol->push ( snpdev->netdev,
639 iobuf, ll_dest, ll_src,
640 htons ( *net_proto ) )) != 0 ){
641 DBGC ( snpdev, "SNPDEV %p TX could not construct "
642 "header: %s\n", snpdev, strerror ( rc ) );
643 goto err_ll_push;
644 }
645 }
646
647 /* Transmit packet */
648 if ( ( rc = netdev_tx ( snpdev->netdev, iob_disown ( iobuf ) ) ) != 0){
649 DBGC ( snpdev, "SNPDEV %p TX could not transmit: %s\n",
650 snpdev, strerror ( rc ) );
651 goto err_tx;
652 }
653
654 /* Record in transmit completion ring. If we run out of
655 * space, report the failure even though we have already
656 * transmitted the packet.
657 *
658 * This allows us to report completions only for packets for
659 * which we had reported successfully initiating transmission,
660 * while continuing to support clients that never poll for
661 * transmit completions.
662 */
663 tx_fill = ( snpdev->tx_prod - snpdev->tx_cons );
664 if ( tx_fill >= EFI_SNP_NUM_TX ) {
665 DBGC ( snpdev, "SNPDEV %p TX completion ring full\n", snpdev );
666 rc = -ENOBUFS;
667 goto err_ring_full;
668 }
669 snpdev->tx[ snpdev->tx_prod++ % EFI_SNP_NUM_TX ] = data;
670 snpdev->interrupts |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
671
672 return 0;
673
674 err_ring_full:
675 err_tx:
676 err_ll_push:
677 free_iob ( iobuf );
678 err_alloc_iob:
679 err_sanity:
680 return EFIRC ( rc );
681 }
682
683 /**
684 * Receive packet
685 *
686 * @v snp SNP interface
687 * @v ll_header_len Link-layer header length, if to be filled in
688 * @v len Length of data buffer
689 * @v data Data buffer
690 * @v ll_src Link-layer source address, if specified
691 * @v ll_dest Link-layer destination address, if specified
692 * @v net_proto Network-layer protocol (in host order)
693 * @ret efirc EFI status code
694 */
695 static EFI_STATUS EFIAPI
696 efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
697 UINTN *ll_header_len, UINTN *len, VOID *data,
698 EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest,
699 UINT16 *net_proto ) {
700 struct efi_snp_device *snpdev =
701 container_of ( snp, struct efi_snp_device, snp );
702 struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
703 struct io_buffer *iobuf;
704 const void *iob_ll_dest;
705 const void *iob_ll_src;
706 uint16_t iob_net_proto;
707 unsigned int iob_flags;
708 int rc;
709
710 DBGC2 ( snpdev, "SNPDEV %p RECEIVE %p(+%lx)", snpdev, data,
711 ( ( unsigned long ) *len ) );
712
713 /* Fail if net device is currently claimed for use by iPXE */
714 if ( efi_snp_claimed )
715 return EFI_NOT_READY;
716
717 /* Poll the network device */
718 efi_snp_poll ( snpdev );
719
720 /* Dequeue a packet, if one is available */
721 iobuf = list_first_entry ( &snpdev->rx, struct io_buffer, list );
722 if ( ! iobuf ) {
723 DBGC2 ( snpdev, "\n" );
724 rc = -EAGAIN;
725 goto out_no_packet;
726 }
727 list_del ( &iobuf->list );
728 DBGC2 ( snpdev, "+%zx\n", iob_len ( iobuf ) );
729
730 /* Return packet to caller */
731 memcpy ( data, iobuf->data, iob_len ( iobuf ) );
732 *len = iob_len ( iobuf );
733
734 /* Attempt to decode link-layer header */
735 if ( ( rc = ll_protocol->pull ( snpdev->netdev, iobuf, &iob_ll_dest,
736 &iob_ll_src, &iob_net_proto,
737 &iob_flags ) ) != 0 ) {
738 DBGC ( snpdev, "SNPDEV %p could not parse header: %s\n",
739 snpdev, strerror ( rc ) );
740 goto out_bad_ll_header;
741 }
742
743 /* Return link-layer header parameters to caller, if required */
744 if ( ll_header_len )
745 *ll_header_len = ll_protocol->ll_header_len;
746 if ( ll_src )
747 memcpy ( ll_src, iob_ll_src, ll_protocol->ll_addr_len );
748 if ( ll_dest )
749 memcpy ( ll_dest, iob_ll_dest, ll_protocol->ll_addr_len );
750 if ( net_proto )
751 *net_proto = ntohs ( iob_net_proto );
752
753 rc = 0;
754
755 out_bad_ll_header:
756 free_iob ( iobuf );
757 out_no_packet:
758 return EFIRC ( rc );
759 }
760
761 /**
762 * Poll event
763 *
764 * @v event Event
765 * @v context Event context
766 */
767 static VOID EFIAPI efi_snp_wait_for_packet ( EFI_EVENT event __unused,
768 VOID *context ) {
769 struct efi_snp_device *snpdev = context;
770
771 DBGCP ( snpdev, "SNPDEV %p WAIT_FOR_PACKET\n", snpdev );
772
773 /* Do nothing unless the net device is open */
774 if ( ! netdev_is_open ( snpdev->netdev ) )
775 return;
776
777 /* Do nothing if net device is currently claimed for use by iPXE */
778 if ( efi_snp_claimed )
779 return;
780
781 /* Poll the network device */
782 efi_snp_poll ( snpdev );
783 }
784
785 /** SNP interface */
786 static EFI_SIMPLE_NETWORK_PROTOCOL efi_snp_device_snp = {
787 .Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION,
788 .Start = efi_snp_start,
789 .Stop = efi_snp_stop,
790 .Initialize = efi_snp_initialize,
791 .Reset = efi_snp_reset,
792 .Shutdown = efi_snp_shutdown,
793 .ReceiveFilters = efi_snp_receive_filters,
794 .StationAddress = efi_snp_station_address,
795 .Statistics = efi_snp_statistics,
796 .MCastIpToMac = efi_snp_mcast_ip_to_mac,
797 .NvData = efi_snp_nvdata,
798 .GetStatus = efi_snp_get_status,
799 .Transmit = efi_snp_transmit,
800 .Receive = efi_snp_receive,
801 };
802
803 /******************************************************************************
804 *
805 * Component name protocol
806 *
807 ******************************************************************************
808 */
809
810 /**
811 * Look up driver name
812 *
813 * @v name2 Component name protocol
814 * @v language Language to use
815 * @v driver_name Driver name to fill in
816 * @ret efirc EFI status code
817 */
818 static EFI_STATUS EFIAPI
819 efi_snp_get_driver_name ( EFI_COMPONENT_NAME2_PROTOCOL *name2,
820 CHAR8 *language __unused, CHAR16 **driver_name ) {
821 struct efi_snp_device *snpdev =
822 container_of ( name2, struct efi_snp_device, name2 );
823
824 *driver_name = snpdev->driver_name;
825 return 0;
826 }
827
828 /**
829 * Look up controller name
830 *
831 * @v name2 Component name protocol
832 * @v device Device
833 * @v child Child device, or NULL
834 * @v language Language to use
835 * @v driver_name Device name to fill in
836 * @ret efirc EFI status code
837 */
838 static EFI_STATUS EFIAPI
839 efi_snp_get_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *name2,
840 EFI_HANDLE device __unused,
841 EFI_HANDLE child __unused,
842 CHAR8 *language __unused,
843 CHAR16 **controller_name ) {
844 struct efi_snp_device *snpdev =
845 container_of ( name2, struct efi_snp_device, name2 );
846
847 *controller_name = snpdev->controller_name;
848 return 0;
849 }
850
851 /******************************************************************************
852 *
853 * Load file protocol
854 *
855 ******************************************************************************
856 */
857
858 /**
859 * Load file
860 *
861 * @v loadfile Load file protocol
862 * @v path File path
863 * @v booting Loading as part of a boot attempt
864 * @ret efirc EFI status code
865 */
866 static EFI_STATUS EFIAPI
867 efi_snp_load_file ( EFI_LOAD_FILE_PROTOCOL *load_file,
868 EFI_DEVICE_PATH_PROTOCOL *path __unused,
869 BOOLEAN booting, UINTN *len __unused,
870 VOID *data __unused ) {
871 struct efi_snp_device *snpdev =
872 container_of ( load_file, struct efi_snp_device, load_file );
873 struct net_device *netdev = snpdev->netdev;
874 int rc;
875
876 /* Fail unless this is a boot attempt */
877 if ( ! booting ) {
878 DBGC ( snpdev, "SNPDEV %p cannot load non-boot file\n",
879 snpdev );
880 return EFI_UNSUPPORTED;
881 }
882
883 /* Claim network devices for use by iPXE */
884 efi_snp_claim();
885
886 /* Start watchdog holdoff timer */
887 efi_watchdog_start();
888
889 /* Boot from network device */
890 if ( ( rc = ipxe ( netdev ) ) != 0 )
891 goto err_ipxe;
892
893 err_ipxe:
894 efi_watchdog_stop();
895 efi_snp_release();
896 return EFIRC ( rc );
897 }
898
899 /** Load file protocol */
900 static EFI_LOAD_FILE_PROTOCOL efi_snp_load_file_protocol = {
901 .LoadFile = efi_snp_load_file,
902 };
903
904 /******************************************************************************
905 *
906 * iPXE network driver
907 *
908 ******************************************************************************
909 */
910
911 /**
912 * Locate SNP device corresponding to network device
913 *
914 * @v netdev Network device
915 * @ret snp SNP device, or NULL if not found
916 */
917 static struct efi_snp_device * efi_snp_demux ( struct net_device *netdev ) {
918 struct efi_snp_device *snpdev;
919
920 list_for_each_entry ( snpdev, &efi_snp_devices, list ) {
921 if ( snpdev->netdev == netdev )
922 return snpdev;
923 }
924 return NULL;
925 }
926
927 /**
928 * Create SNP device
929 *
930 * @v netdev Network device
931 * @ret rc Return status code
932 */
933 static int efi_snp_probe ( struct net_device *netdev ) {
934 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
935 struct efi_device *efidev;
936 struct efi_snp_device *snpdev;
937 union {
938 EFI_DEVICE_PATH_PROTOCOL *path;
939 void *interface;
940 } path;
941 EFI_DEVICE_PATH_PROTOCOL *path_end;
942 MAC_ADDR_DEVICE_PATH *macpath;
943 size_t path_prefix_len = 0;
944 EFI_STATUS efirc;
945 int rc;
946
947 /* Find parent EFI device */
948 efidev = efidev_parent ( netdev->dev );
949 if ( ! efidev ) {
950 DBG ( "SNP skipping non-EFI device %s\n", netdev->name );
951 rc = 0;
952 goto err_no_efidev;
953 }
954
955 /* Allocate the SNP device */
956 snpdev = zalloc ( sizeof ( *snpdev ) );
957 if ( ! snpdev ) {
958 rc = -ENOMEM;
959 goto err_alloc_snp;
960 }
961 snpdev->netdev = netdev_get ( netdev );
962 snpdev->efidev = efidev;
963 INIT_LIST_HEAD ( &snpdev->rx );
964
965 /* Sanity check */
966 if ( netdev->ll_protocol->ll_addr_len > sizeof ( EFI_MAC_ADDRESS ) ) {
967 DBGC ( snpdev, "SNPDEV %p cannot support link-layer address "
968 "length %d for %s\n", snpdev,
969 netdev->ll_protocol->ll_addr_len, netdev->name );
970 rc = -ENOTSUP;
971 goto err_ll_addr_len;
972 }
973
974 /* Populate the SNP structure */
975 memcpy ( &snpdev->snp, &efi_snp_device_snp, sizeof ( snpdev->snp ) );
976 snpdev->snp.Mode = &snpdev->mode;
977 if ( ( efirc = bs->CreateEvent ( EVT_NOTIFY_WAIT, TPL_NOTIFY,
978 efi_snp_wait_for_packet, snpdev,
979 &snpdev->snp.WaitForPacket ) ) != 0 ){
980 rc = -EEFI ( efirc );
981 DBGC ( snpdev, "SNPDEV %p could not create event: %s\n",
982 snpdev, strerror ( rc ) );
983 goto err_create_event;
984 }
985
986 /* Populate the SNP mode structure */
987 snpdev->mode.State = EfiSimpleNetworkStopped;
988 efi_snp_set_mode ( snpdev );
989
990 /* Populate the NII structure */
991 snpdev->nii.Revision =
992 EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION;
993 strncpy ( snpdev->nii.StringId, "iPXE",
994 sizeof ( snpdev->nii.StringId ) );
995
996 /* Populate the component name structure */
997 efi_snprintf ( snpdev->driver_name,
998 ( sizeof ( snpdev->driver_name ) /
999 sizeof ( snpdev->driver_name[0] ) ),
1000 "%s %s", product_short_name, netdev->dev->driver_name );
1001 efi_snprintf ( snpdev->controller_name,
1002 ( sizeof ( snpdev->controller_name ) /
1003 sizeof ( snpdev->controller_name[0] ) ),
1004 "%s %s (%s, %s)", product_short_name,
1005 netdev->dev->driver_name, netdev->dev->name,
1006 netdev_addr ( netdev ) );
1007 snpdev->name2.GetDriverName = efi_snp_get_driver_name;
1008 snpdev->name2.GetControllerName = efi_snp_get_controller_name;
1009 snpdev->name2.SupportedLanguages = "en";
1010
1011 /* Populate the load file protocol structure */
1012 memcpy ( &snpdev->load_file, &efi_snp_load_file_protocol,
1013 sizeof ( snpdev->load_file ) );
1014
1015 /* Populate the device name */
1016 efi_snprintf ( snpdev->name, ( sizeof ( snpdev->name ) /
1017 sizeof ( snpdev->name[0] ) ),
1018 "%s", netdev->name );
1019
1020 /* Get the parent device path */
1021 if ( ( efirc = bs->OpenProtocol ( efidev->device,
1022 &efi_device_path_protocol_guid,
1023 &path.interface, efi_image_handle,
1024 efidev->device,
1025 EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
1026 rc = -EEFI ( efirc );
1027 DBGC ( snpdev, "SNPDEV %p cannot get %p %s device path: %s\n",
1028 snpdev, efidev->device,
1029 efi_handle_name ( efidev->device ), strerror ( rc ) );
1030 goto err_open_device_path;
1031 }
1032
1033 /* Allocate the new device path */
1034 path_end = efi_devpath_end ( path.path );
1035 path_prefix_len = ( ( ( void * ) path_end ) - ( ( void * ) path.path ));
1036 snpdev->path = zalloc ( path_prefix_len + sizeof ( *macpath ) +
1037 sizeof ( *path_end ) );
1038 if ( ! snpdev->path ) {
1039 rc = -ENOMEM;
1040 goto err_alloc_device_path;
1041 }
1042
1043 /* Populate the device path */
1044 memcpy ( snpdev->path, path.path, path_prefix_len );
1045 macpath = ( ( ( void * ) snpdev->path ) + path_prefix_len );
1046 path_end = ( ( void * ) ( macpath + 1 ) );
1047 memset ( macpath, 0, sizeof ( *macpath ) );
1048 macpath->Header.Type = MESSAGING_DEVICE_PATH;
1049 macpath->Header.SubType = MSG_MAC_ADDR_DP;
1050 macpath->Header.Length[0] = sizeof ( *macpath );
1051 memcpy ( &macpath->MacAddress, netdev->ll_addr,
1052 sizeof ( macpath->MacAddress ) );
1053 macpath->IfType = ntohs ( netdev->ll_protocol->ll_proto );
1054 memset ( path_end, 0, sizeof ( *path_end ) );
1055 path_end->Type = END_DEVICE_PATH_TYPE;
1056 path_end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
1057 path_end->Length[0] = sizeof ( *path_end );
1058
1059 /* Install the SNP */
1060 if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
1061 &snpdev->handle,
1062 &efi_simple_network_protocol_guid, &snpdev->snp,
1063 &efi_device_path_protocol_guid, snpdev->path,
1064 &efi_nii_protocol_guid, &snpdev->nii,
1065 &efi_nii31_protocol_guid, &snpdev->nii,
1066 &efi_component_name2_protocol_guid, &snpdev->name2,
1067 &efi_load_file_protocol_guid, &snpdev->load_file,
1068 NULL ) ) != 0 ) {
1069 rc = -EEFI ( efirc );
1070 DBGC ( snpdev, "SNPDEV %p could not install protocols: "
1071 "%s\n", snpdev, strerror ( rc ) );
1072 goto err_install_protocol_interface;
1073 }
1074
1075 /* Add as child of EFI parent device */
1076 if ( ( rc = efi_child_add ( efidev->device, snpdev->handle ) ) != 0 ) {
1077 DBGC ( snpdev, "SNPDEV %p could not become child of %p %s: "
1078 "%s\n", snpdev, efidev->device,
1079 efi_handle_name ( efidev->device ), strerror ( rc ) );
1080 goto err_efi_child_add;
1081 }
1082
1083 /* Install HII */
1084 if ( ( rc = efi_snp_hii_install ( snpdev ) ) != 0 ) {
1085 DBGC ( snpdev, "SNPDEV %p could not install HII: %s\n",
1086 snpdev, strerror ( rc ) );
1087 /* HII fails on several platforms. It's
1088 * non-essential, so treat this as a non-fatal
1089 * error.
1090 */
1091 }
1092
1093 /* Add to list of SNP devices */
1094 list_add ( &snpdev->list, &efi_snp_devices );
1095
1096 /* Close device path */
1097 bs->CloseProtocol ( efidev->device, &efi_device_path_protocol_guid,
1098 efi_image_handle, efidev->device );
1099
1100 DBGC ( snpdev, "SNPDEV %p installed for %s as device %p %s\n",
1101 snpdev, netdev->name, snpdev->handle,
1102 efi_handle_name ( snpdev->handle ) );
1103 return 0;
1104
1105 if ( snpdev->package_list )
1106 efi_snp_hii_uninstall ( snpdev );
1107 efi_child_del ( efidev->device, snpdev->handle );
1108 err_efi_child_add:
1109 bs->UninstallMultipleProtocolInterfaces (
1110 snpdev->handle,
1111 &efi_simple_network_protocol_guid, &snpdev->snp,
1112 &efi_device_path_protocol_guid, snpdev->path,
1113 &efi_nii_protocol_guid, &snpdev->nii,
1114 &efi_nii31_protocol_guid, &snpdev->nii,
1115 &efi_component_name2_protocol_guid, &snpdev->name2,
1116 &efi_load_file_protocol_guid, &snpdev->load_file,
1117 NULL );
1118 err_install_protocol_interface:
1119 free ( snpdev->path );
1120 err_alloc_device_path:
1121 bs->CloseProtocol ( efidev->device, &efi_device_path_protocol_guid,
1122 efi_image_handle, efidev->device );
1123 err_open_device_path:
1124 bs->CloseEvent ( snpdev->snp.WaitForPacket );
1125 err_create_event:
1126 err_ll_addr_len:
1127 netdev_put ( netdev );
1128 free ( snpdev );
1129 err_alloc_snp:
1130 err_no_efidev:
1131 return rc;
1132 }
1133
1134 /**
1135 * Handle SNP device or link state change
1136 *
1137 * @v netdev Network device
1138 */
1139 static void efi_snp_notify ( struct net_device *netdev ) {
1140 struct efi_snp_device *snpdev;
1141
1142 /* Locate SNP device */
1143 snpdev = efi_snp_demux ( netdev );
1144 if ( ! snpdev ) {
1145 DBG ( "SNP skipping non-SNP device %s\n", netdev->name );
1146 return;
1147 }
1148
1149 /* Update link state */
1150 snpdev->mode.MediaPresent =
1151 ( netdev_link_ok ( netdev ) ? TRUE : FALSE );
1152 DBGC ( snpdev, "SNPDEV %p link is %s\n", snpdev,
1153 ( snpdev->mode.MediaPresent ? "up" : "down" ) );
1154
1155 /* Update mode state */
1156 efi_snp_set_state ( snpdev );
1157 }
1158
1159 /**
1160 * Destroy SNP device
1161 *
1162 * @v netdev Network device
1163 */
1164 static void efi_snp_remove ( struct net_device *netdev ) {
1165 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
1166 struct efi_snp_device *snpdev;
1167
1168 /* Locate SNP device */
1169 snpdev = efi_snp_demux ( netdev );
1170 if ( ! snpdev ) {
1171 DBG ( "SNP skipping non-SNP device %s\n", netdev->name );
1172 return;
1173 }
1174
1175 /* Uninstall the SNP */
1176 if ( snpdev->package_list )
1177 efi_snp_hii_uninstall ( snpdev );
1178 efi_child_del ( snpdev->efidev->device, snpdev->handle );
1179 list_del ( &snpdev->list );
1180 bs->UninstallMultipleProtocolInterfaces (
1181 snpdev->handle,
1182 &efi_simple_network_protocol_guid, &snpdev->snp,
1183 &efi_device_path_protocol_guid, snpdev->path,
1184 &efi_nii_protocol_guid, &snpdev->nii,
1185 &efi_nii31_protocol_guid, &snpdev->nii,
1186 &efi_component_name2_protocol_guid, &snpdev->name2,
1187 &efi_load_file_protocol_guid, &snpdev->load_file,
1188 NULL );
1189 free ( snpdev->path );
1190 bs->CloseEvent ( snpdev->snp.WaitForPacket );
1191 netdev_put ( snpdev->netdev );
1192 free ( snpdev );
1193 }
1194
1195 /** SNP driver */
1196 struct net_driver efi_snp_driver __net_driver = {
1197 .name = "SNP",
1198 .probe = efi_snp_probe,
1199 .notify = efi_snp_notify,
1200 .remove = efi_snp_remove,
1201 };
1202
1203 /**
1204 * Find SNP device by EFI device handle
1205 *
1206 * @v handle EFI device handle
1207 * @ret snpdev SNP device, or NULL
1208 */
1209 struct efi_snp_device * find_snpdev ( EFI_HANDLE handle ) {
1210 struct efi_snp_device *snpdev;
1211
1212 list_for_each_entry ( snpdev, &efi_snp_devices, list ) {
1213 if ( snpdev->handle == handle )
1214 return snpdev;
1215 }
1216 return NULL;
1217 }
1218
1219 /**
1220 * Get most recently opened SNP device
1221 *
1222 * @ret snpdev Most recently opened SNP device, or NULL
1223 */
1224 struct efi_snp_device * last_opened_snpdev ( void ) {
1225 struct net_device *netdev;
1226
1227 netdev = last_opened_netdev();
1228 if ( ! netdev )
1229 return NULL;
1230
1231 return efi_snp_demux ( netdev );
1232 }
1233
1234 /**
1235 * Set SNP claimed/released state
1236 *
1237 * @v claimed Network devices are claimed for use by iPXE
1238 */
1239 void efi_snp_set_claimed ( int claimed ) {
1240 struct efi_snp_device *snpdev;
1241
1242 /* Claim SNP devices */
1243 efi_snp_claimed = claimed;
1244
1245 /* Update SNP mode state for each interface */
1246 list_for_each_entry ( snpdev, &efi_snp_devices, list )
1247 efi_snp_set_state ( snpdev );
1248 }