These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / ipxe / 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 }