iPXE
efi_snp.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  */
00019 
00020 FILE_LICENCE ( GPL2_OR_LATER );
00021 
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <errno.h>
00025 #include <assert.h>
00026 #include <byteswap.h>
00027 #include <ipxe/netdevice.h>
00028 #include <ipxe/vlan.h>
00029 #include <ipxe/iobuf.h>
00030 #include <ipxe/in.h>
00031 #include <ipxe/version.h>
00032 #include <ipxe/console.h>
00033 #include <ipxe/efi/efi.h>
00034 #include <ipxe/efi/efi_driver.h>
00035 #include <ipxe/efi/efi_strings.h>
00036 #include <ipxe/efi/efi_utils.h>
00037 #include <ipxe/efi/efi_watchdog.h>
00038 #include <ipxe/efi/efi_snp.h>
00039 #include <usr/autoboot.h>
00040 #include <config/general.h>
00041 
00042 /** List of SNP devices */
00043 static LIST_HEAD ( efi_snp_devices );
00044 
00045 /** Network devices are currently claimed for use by iPXE */
00046 static int efi_snp_claimed;
00047 
00048 /** TPL prior to network devices being claimed */
00049 static EFI_TPL efi_snp_old_tpl;
00050 
00051 /* Downgrade user experience if configured to do so
00052  *
00053  * The default UEFI user experience for network boot is somewhat
00054  * excremental: only TFTP is available as a download protocol, and if
00055  * anything goes wrong the user will be shown just a dot on an
00056  * otherwise blank screen.  (Some programmer was clearly determined to
00057  * win a bet that they could outshine Apple at producing uninformative
00058  * error messages.)
00059  *
00060  * For comparison, the default iPXE user experience provides the
00061  * option to use protocols designed more recently than 1980 (such as
00062  * HTTP and iSCSI), and if anything goes wrong the the user will be
00063  * shown one of over 1200 different error messages, complete with a
00064  * link to a wiki page describing that specific error.
00065  *
00066  * We default to upgrading the user experience to match that available
00067  * in a "legacy" BIOS environment, by installing our own instance of
00068  * EFI_LOAD_FILE_PROTOCOL.
00069  *
00070  * Note that unfortunately we can't sensibly provide the choice of
00071  * both options to the user in the same build, because the UEFI boot
00072  * menu ignores the multitude of ways in which a network device handle
00073  * can be described and opaquely labels both menu entries as just "EFI
00074  * Network".
00075  */
00076 #ifdef EFI_DOWNGRADE_UX
00077 static EFI_GUID dummy_load_file_protocol_guid = {
00078         0x6f6c7323, 0x2077, 0x7523,
00079         { 0x6e, 0x68, 0x65, 0x6c, 0x70, 0x66, 0x75, 0x6c }
00080 };
00081 #define efi_load_file_protocol_guid dummy_load_file_protocol_guid
00082 #endif
00083 
00084 /**
00085  * Set EFI SNP mode state
00086  *
00087  * @v snp               SNP interface
00088  */
00089 static void efi_snp_set_state ( struct efi_snp_device *snpdev ) {
00090         struct net_device *netdev = snpdev->netdev;
00091         EFI_SIMPLE_NETWORK_MODE *mode = &snpdev->mode;
00092 
00093         /* Calculate state */
00094         if ( ! snpdev->started ) {
00095                 /* Start() method not called; report as Stopped */
00096                 mode->State = EfiSimpleNetworkStopped;
00097         } else if ( ! netdev_is_open ( netdev ) ) {
00098                 /* Network device not opened; report as Started */
00099                 mode->State = EfiSimpleNetworkStarted;
00100         } else if ( efi_snp_claimed ) {
00101                 /* Network device opened but claimed for use by iPXE; report
00102                  * as Started to inhibit receive polling.
00103                  */
00104                 mode->State = EfiSimpleNetworkStarted;
00105         } else {
00106                 /* Network device opened and available for use via SNP; report
00107                  * as Initialized.
00108                  */
00109                 mode->State = EfiSimpleNetworkInitialized;
00110         }
00111 }
00112 
00113 /**
00114  * Set EFI SNP mode based on iPXE net device parameters
00115  *
00116  * @v snp               SNP interface
00117  */
00118 static void efi_snp_set_mode ( struct efi_snp_device *snpdev ) {
00119         struct net_device *netdev = snpdev->netdev;
00120         EFI_SIMPLE_NETWORK_MODE *mode = &snpdev->mode;
00121         struct ll_protocol *ll_protocol = netdev->ll_protocol;
00122         unsigned int ll_addr_len = ll_protocol->ll_addr_len;
00123 
00124         mode->HwAddressSize = ll_addr_len;
00125         mode->MediaHeaderSize = ll_protocol->ll_header_len;
00126         mode->MaxPacketSize = netdev->mtu;
00127         mode->ReceiveFilterMask = ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
00128                                     EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
00129                                     EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST );
00130         assert ( ll_addr_len <= sizeof ( mode->CurrentAddress ) );
00131         memcpy ( &mode->CurrentAddress, netdev->ll_addr, ll_addr_len );
00132         memcpy ( &mode->BroadcastAddress, netdev->ll_broadcast, ll_addr_len );
00133         ll_protocol->init_addr ( netdev->hw_addr, &mode->PermanentAddress );
00134         mode->IfType = ntohs ( ll_protocol->ll_proto );
00135         mode->MacAddressChangeable = TRUE;
00136         mode->MediaPresentSupported = TRUE;
00137         mode->MediaPresent = ( netdev_link_ok ( netdev ) ? TRUE : FALSE );
00138 }
00139 
00140 /**
00141  * Flush transmit ring and receive queue
00142  *
00143  * @v snpdev            SNP device
00144  */
00145 static void efi_snp_flush ( struct efi_snp_device *snpdev ) {
00146         struct io_buffer *iobuf;
00147         struct io_buffer *tmp;
00148 
00149         /* Reset transmit completion ring */
00150         snpdev->tx_prod = 0;
00151         snpdev->tx_cons = 0;
00152 
00153         /* Discard any queued receive buffers */
00154         list_for_each_entry_safe ( iobuf, tmp, &snpdev->rx, list ) {
00155                 list_del ( &iobuf->list );
00156                 free_iob ( iobuf );
00157         }
00158 }
00159 
00160 /**
00161  * Poll net device and count received packets
00162  *
00163  * @v snpdev            SNP device
00164  */
00165 static void efi_snp_poll ( struct efi_snp_device *snpdev ) {
00166         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
00167         struct io_buffer *iobuf;
00168 
00169         /* Poll network device */
00170         netdev_poll ( snpdev->netdev );
00171 
00172         /* Retrieve any received packets */
00173         while ( ( iobuf = netdev_rx_dequeue ( snpdev->netdev ) ) ) {
00174                 list_add_tail ( &iobuf->list, &snpdev->rx );
00175                 snpdev->interrupts |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
00176                 bs->SignalEvent ( &snpdev->snp.WaitForPacket );
00177         }
00178 }
00179 
00180 /**
00181  * Change SNP state from "stopped" to "started"
00182  *
00183  * @v snp               SNP interface
00184  * @ret efirc           EFI status code
00185  */
00186 static EFI_STATUS EFIAPI
00187 efi_snp_start ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
00188         struct efi_snp_device *snpdev =
00189                 container_of ( snp, struct efi_snp_device, snp );
00190 
00191         DBGC ( snpdev, "SNPDEV %p START\n", snpdev );
00192 
00193         /* Fail if net device is currently claimed for use by iPXE */
00194         if ( efi_snp_claimed )
00195                 return EFI_NOT_READY;
00196 
00197         snpdev->started = 1;
00198         efi_snp_set_state ( snpdev );
00199         return 0;
00200 }
00201 
00202 /**
00203  * Change SNP state from "started" to "stopped"
00204  *
00205  * @v snp               SNP interface
00206  * @ret efirc           EFI status code
00207  */
00208 static EFI_STATUS EFIAPI
00209 efi_snp_stop ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
00210         struct efi_snp_device *snpdev =
00211                 container_of ( snp, struct efi_snp_device, snp );
00212 
00213         DBGC ( snpdev, "SNPDEV %p STOP\n", snpdev );
00214 
00215         /* Fail if net device is currently claimed for use by iPXE */
00216         if ( efi_snp_claimed )
00217                 return EFI_NOT_READY;
00218 
00219         snpdev->started = 0;
00220         efi_snp_set_state ( snpdev );
00221 
00222         return 0;
00223 }
00224 
00225 /**
00226  * Open the network device
00227  *
00228  * @v snp               SNP interface
00229  * @v extra_rx_bufsize  Extra RX buffer size, in bytes
00230  * @v extra_tx_bufsize  Extra TX buffer size, in bytes
00231  * @ret efirc           EFI status code
00232  */
00233 static EFI_STATUS EFIAPI
00234 efi_snp_initialize ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
00235                      UINTN extra_rx_bufsize, UINTN extra_tx_bufsize ) {
00236         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
00237         struct efi_snp_device *snpdev =
00238                 container_of ( snp, struct efi_snp_device, snp );
00239         EFI_TPL saved_tpl;
00240         int rc;
00241 
00242         DBGC ( snpdev, "SNPDEV %p INITIALIZE (%ld extra RX, %ld extra TX)\n",
00243                snpdev, ( ( unsigned long ) extra_rx_bufsize ),
00244                ( ( unsigned long ) extra_tx_bufsize ) );
00245 
00246         /* Fail if net device is currently claimed for use by iPXE */
00247         if ( efi_snp_claimed ) {
00248                 rc = -EAGAIN;
00249                 goto err_claimed;
00250         }
00251 
00252         /* Raise TPL */
00253         saved_tpl = bs->RaiseTPL ( TPL_CALLBACK );
00254 
00255         /* Open network device */
00256         if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
00257                 DBGC ( snpdev, "SNPDEV %p could not open %s: %s\n",
00258                        snpdev, snpdev->netdev->name, strerror ( rc ) );
00259                 goto err_open;
00260         }
00261         efi_snp_set_state ( snpdev );
00262 
00263  err_open:
00264         bs->RestoreTPL ( saved_tpl );
00265  err_claimed:
00266         return EFIRC ( rc );
00267 }
00268 
00269 /**
00270  * Reset the network device
00271  *
00272  * @v snp               SNP interface
00273  * @v ext_verify        Extended verification required
00274  * @ret efirc           EFI status code
00275  */
00276 static EFI_STATUS EFIAPI
00277 efi_snp_reset ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ext_verify ) {
00278         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
00279         struct efi_snp_device *snpdev =
00280                 container_of ( snp, struct efi_snp_device, snp );
00281         EFI_TPL saved_tpl;
00282         int rc;
00283 
00284         DBGC ( snpdev, "SNPDEV %p RESET (%s extended verification)\n",
00285                snpdev, ( ext_verify ? "with" : "without" ) );
00286 
00287         /* Fail if net device is currently claimed for use by iPXE */
00288         if ( efi_snp_claimed ) {
00289                 rc = -EAGAIN;
00290                 goto err_claimed;
00291         }
00292 
00293         /* Raise TPL */
00294         saved_tpl = bs->RaiseTPL ( TPL_CALLBACK );
00295 
00296         /* Close network device */
00297         netdev_close ( snpdev->netdev );
00298         efi_snp_set_state ( snpdev );
00299         efi_snp_flush ( snpdev );
00300 
00301         /* Reopen network device */
00302         if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
00303                 DBGC ( snpdev, "SNPDEV %p could not reopen %s: %s\n",
00304                        snpdev, snpdev->netdev->name, strerror ( rc ) );
00305                 goto err_open;
00306         }
00307         efi_snp_set_state ( snpdev );
00308 
00309  err_open:
00310         bs->RestoreTPL ( saved_tpl );
00311  err_claimed:
00312         return EFIRC ( rc );
00313 }
00314 
00315 /**
00316  * Shut down the network device
00317  *
00318  * @v snp               SNP interface
00319  * @ret efirc           EFI status code
00320  */
00321 static EFI_STATUS EFIAPI
00322 efi_snp_shutdown ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
00323         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
00324         struct efi_snp_device *snpdev =
00325                 container_of ( snp, struct efi_snp_device, snp );
00326         EFI_TPL saved_tpl;
00327 
00328         DBGC ( snpdev, "SNPDEV %p SHUTDOWN\n", snpdev );
00329 
00330         /* Fail if net device is currently claimed for use by iPXE */
00331         if ( efi_snp_claimed )
00332                 return EFI_NOT_READY;
00333 
00334         /* Raise TPL */
00335         saved_tpl = bs->RaiseTPL ( TPL_CALLBACK );
00336 
00337         /* Close network device */
00338         netdev_close ( snpdev->netdev );
00339         efi_snp_set_state ( snpdev );
00340         efi_snp_flush ( snpdev );
00341 
00342         /* Restore TPL */
00343         bs->RestoreTPL ( saved_tpl );
00344 
00345         return 0;
00346 }
00347 
00348 /**
00349  * Manage receive filters
00350  *
00351  * @v snp               SNP interface
00352  * @v enable            Receive filters to enable
00353  * @v disable           Receive filters to disable
00354  * @v mcast_reset       Reset multicast filters
00355  * @v mcast_count       Number of multicast filters
00356  * @v mcast             Multicast filters
00357  * @ret efirc           EFI status code
00358  */
00359 static EFI_STATUS EFIAPI
00360 efi_snp_receive_filters ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, UINT32 enable,
00361                           UINT32 disable, BOOLEAN mcast_reset,
00362                           UINTN mcast_count, EFI_MAC_ADDRESS *mcast ) {
00363         struct efi_snp_device *snpdev =
00364                 container_of ( snp, struct efi_snp_device, snp );
00365         unsigned int i;
00366 
00367         DBGC ( snpdev, "SNPDEV %p RECEIVE_FILTERS %08x&~%08x%s %ld mcast\n",
00368                snpdev, enable, disable, ( mcast_reset ? " reset" : "" ),
00369                ( ( unsigned long ) mcast_count ) );
00370         for ( i = 0 ; i < mcast_count ; i++ ) {
00371                 DBGC2_HDA ( snpdev, i, &mcast[i],
00372                             snpdev->netdev->ll_protocol->ll_addr_len );
00373         }
00374 
00375         /* Lie through our teeth, otherwise MNP refuses to accept us.
00376          *
00377          * Return success even if the SNP device is currently claimed
00378          * for use by iPXE, since otherwise Windows Deployment
00379          * Services refuses to attempt to receive further packets via
00380          * our EFI PXE Base Code protocol.
00381          */
00382         return 0;
00383 }
00384 
00385 /**
00386  * Set station address
00387  *
00388  * @v snp               SNP interface
00389  * @v reset             Reset to permanent address
00390  * @v new               New station address
00391  * @ret efirc           EFI status code
00392  */
00393 static EFI_STATUS EFIAPI
00394 efi_snp_station_address ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset,
00395                           EFI_MAC_ADDRESS *new ) {
00396         struct efi_snp_device *snpdev =
00397                 container_of ( snp, struct efi_snp_device, snp );
00398         struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
00399 
00400         DBGC ( snpdev, "SNPDEV %p STATION_ADDRESS %s\n", snpdev,
00401                ( reset ? "reset" : ll_protocol->ntoa ( new ) ) );
00402 
00403         /* Fail if net device is currently claimed for use by iPXE */
00404         if ( efi_snp_claimed )
00405                 return EFI_NOT_READY;
00406 
00407         /* Set the MAC address */
00408         if ( reset )
00409                 new = &snpdev->mode.PermanentAddress;
00410         memcpy ( snpdev->netdev->ll_addr, new, ll_protocol->ll_addr_len );
00411 
00412         /* MAC address changes take effect only on netdev_open() */
00413         if ( netdev_is_open ( snpdev->netdev ) ) {
00414                 DBGC ( snpdev, "SNPDEV %p MAC address changed while net "
00415                        "device open\n", snpdev );
00416         }
00417 
00418         return 0;
00419 }
00420 
00421 /**
00422  * Get (or reset) statistics
00423  *
00424  * @v snp               SNP interface
00425  * @v reset             Reset statistics
00426  * @v stats_len         Size of statistics table
00427  * @v stats             Statistics table
00428  * @ret efirc           EFI status code
00429  */
00430 static EFI_STATUS EFIAPI
00431 efi_snp_statistics ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset,
00432                      UINTN *stats_len, EFI_NETWORK_STATISTICS *stats ) {
00433         struct efi_snp_device *snpdev =
00434                 container_of ( snp, struct efi_snp_device, snp );
00435         EFI_NETWORK_STATISTICS stats_buf;
00436 
00437         DBGC ( snpdev, "SNPDEV %p STATISTICS%s", snpdev,
00438                ( reset ? " reset" : "" ) );
00439 
00440         /* Fail if net device is currently claimed for use by iPXE */
00441         if ( efi_snp_claimed )
00442                 return EFI_NOT_READY;
00443 
00444         /* Gather statistics */
00445         memset ( &stats_buf, 0, sizeof ( stats_buf ) );
00446         stats_buf.TxGoodFrames = snpdev->netdev->tx_stats.good;
00447         stats_buf.TxDroppedFrames = snpdev->netdev->tx_stats.bad;
00448         stats_buf.TxTotalFrames = ( snpdev->netdev->tx_stats.good +
00449                                     snpdev->netdev->tx_stats.bad );
00450         stats_buf.RxGoodFrames = snpdev->netdev->rx_stats.good;
00451         stats_buf.RxDroppedFrames = snpdev->netdev->rx_stats.bad;
00452         stats_buf.RxTotalFrames = ( snpdev->netdev->rx_stats.good +
00453                                     snpdev->netdev->rx_stats.bad );
00454         if ( *stats_len > sizeof ( stats_buf ) )
00455                 *stats_len = sizeof ( stats_buf );
00456         if ( stats )
00457                 memcpy ( stats, &stats_buf, *stats_len );
00458 
00459         /* Reset statistics if requested to do so */
00460         if ( reset ) {
00461                 memset ( &snpdev->netdev->tx_stats, 0,
00462                          sizeof ( snpdev->netdev->tx_stats ) );
00463                 memset ( &snpdev->netdev->rx_stats, 0,
00464                          sizeof ( snpdev->netdev->rx_stats ) );
00465         }
00466 
00467         return 0;
00468 }
00469 
00470 /**
00471  * Convert multicast IP address to MAC address
00472  *
00473  * @v snp               SNP interface
00474  * @v ipv6              Address is IPv6
00475  * @v ip                IP address
00476  * @v mac               MAC address
00477  * @ret efirc           EFI status code
00478  */
00479 static EFI_STATUS EFIAPI
00480 efi_snp_mcast_ip_to_mac ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ipv6,
00481                           EFI_IP_ADDRESS *ip, EFI_MAC_ADDRESS *mac ) {
00482         struct efi_snp_device *snpdev =
00483                 container_of ( snp, struct efi_snp_device, snp );
00484         struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
00485         const char *ip_str;
00486         int rc;
00487 
00488         ip_str = ( ipv6 ? "(IPv6)" /* FIXME when we have inet6_ntoa() */ :
00489                    inet_ntoa ( *( ( struct in_addr * ) ip ) ) );
00490         DBGC ( snpdev, "SNPDEV %p MCAST_IP_TO_MAC %s\n", snpdev, ip_str );
00491 
00492         /* Fail if net device is currently claimed for use by iPXE */
00493         if ( efi_snp_claimed )
00494                 return EFI_NOT_READY;
00495 
00496         /* Try to hash the address */
00497         if ( ( rc = ll_protocol->mc_hash ( ( ipv6 ? AF_INET6 : AF_INET ),
00498                                            ip, mac ) ) != 0 ) {
00499                 DBGC ( snpdev, "SNPDEV %p could not hash %s: %s\n",
00500                        snpdev, ip_str, strerror ( rc ) );
00501                 return EFIRC ( rc );
00502         }
00503 
00504         return 0;
00505 }
00506 
00507 /**
00508  * Read or write non-volatile storage
00509  *
00510  * @v snp               SNP interface
00511  * @v read              Operation is a read
00512  * @v offset            Starting offset within NVRAM
00513  * @v len               Length of data buffer
00514  * @v data              Data buffer
00515  * @ret efirc           EFI status code
00516  */
00517 static EFI_STATUS EFIAPI
00518 efi_snp_nvdata ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN read,
00519                  UINTN offset, UINTN len, VOID *data ) {
00520         struct efi_snp_device *snpdev =
00521                 container_of ( snp, struct efi_snp_device, snp );
00522 
00523         DBGC ( snpdev, "SNPDEV %p NVDATA %s %lx+%lx\n", snpdev,
00524                ( read ? "read" : "write" ), ( ( unsigned long ) offset ),
00525                ( ( unsigned long ) len ) );
00526         if ( ! read )
00527                 DBGC2_HDA ( snpdev, offset, data, len );
00528 
00529         /* Fail if net device is currently claimed for use by iPXE */
00530         if ( efi_snp_claimed )
00531                 return EFI_NOT_READY;
00532 
00533         return EFI_UNSUPPORTED;
00534 }
00535 
00536 /**
00537  * Read interrupt status and TX recycled buffer status
00538  *
00539  * @v snp               SNP interface
00540  * @v interrupts        Interrupt status, or NULL
00541  * @v txbuf             Recycled transmit buffer address, or NULL
00542  * @ret efirc           EFI status code
00543  */
00544 static EFI_STATUS EFIAPI
00545 efi_snp_get_status ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
00546                      UINT32 *interrupts, VOID **txbuf ) {
00547         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
00548         struct efi_snp_device *snpdev =
00549                 container_of ( snp, struct efi_snp_device, snp );
00550         EFI_TPL saved_tpl;
00551 
00552         DBGC2 ( snpdev, "SNPDEV %p GET_STATUS", snpdev );
00553 
00554         /* Fail if net device is currently claimed for use by iPXE */
00555         if ( efi_snp_claimed ) {
00556                 DBGC2 ( snpdev, "\n" );
00557                 return EFI_NOT_READY;
00558         }
00559 
00560         /* Raise TPL */
00561         saved_tpl = bs->RaiseTPL ( TPL_CALLBACK );
00562 
00563         /* Poll the network device */
00564         efi_snp_poll ( snpdev );
00565 
00566         /* Interrupt status.  In practice, this seems to be used only
00567          * to detect TX completions.
00568          */
00569         if ( interrupts ) {
00570                 *interrupts = snpdev->interrupts;
00571                 DBGC2 ( snpdev, " INTS:%02x", *interrupts );
00572                 snpdev->interrupts = 0;
00573         }
00574 
00575         /* TX completions */
00576         if ( txbuf ) {
00577                 if ( snpdev->tx_prod != snpdev->tx_cons ) {
00578                         *txbuf = snpdev->tx[snpdev->tx_cons++ % EFI_SNP_NUM_TX];
00579                 } else {
00580                         *txbuf = NULL;
00581                 }
00582                 DBGC2 ( snpdev, " TX:%p", *txbuf );
00583         }
00584 
00585         /* Restore TPL */
00586         bs->RestoreTPL ( saved_tpl );
00587 
00588         DBGC2 ( snpdev, "\n" );
00589         return 0;
00590 }
00591 
00592 /**
00593  * Start packet transmission
00594  *
00595  * @v snp               SNP interface
00596  * @v ll_header_len     Link-layer header length, if to be filled in
00597  * @v len               Length of data buffer
00598  * @v data              Data buffer
00599  * @v ll_src            Link-layer source address, if specified
00600  * @v ll_dest           Link-layer destination address, if specified
00601  * @v net_proto         Network-layer protocol (in host order)
00602  * @ret efirc           EFI status code
00603  */
00604 static EFI_STATUS EFIAPI
00605 efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
00606                    UINTN ll_header_len, UINTN len, VOID *data,
00607                    EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest,
00608                    UINT16 *net_proto ) {
00609         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
00610         struct efi_snp_device *snpdev =
00611                 container_of ( snp, struct efi_snp_device, snp );
00612         struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
00613         struct io_buffer *iobuf;
00614         size_t payload_len;
00615         unsigned int tx_fill;
00616         EFI_TPL saved_tpl;
00617         int rc;
00618 
00619         DBGC2 ( snpdev, "SNPDEV %p TRANSMIT %p+%lx", snpdev, data,
00620                 ( ( unsigned long ) len ) );
00621         if ( ll_header_len ) {
00622                 if ( ll_src ) {
00623                         DBGC2 ( snpdev, " src %s",
00624                                 ll_protocol->ntoa ( ll_src ) );
00625                 }
00626                 if ( ll_dest ) {
00627                         DBGC2 ( snpdev, " dest %s",
00628                                 ll_protocol->ntoa ( ll_dest ) );
00629                 }
00630                 if ( net_proto ) {
00631                         DBGC2 ( snpdev, " proto %04x", *net_proto );
00632                 }
00633         }
00634         DBGC2 ( snpdev, "\n" );
00635 
00636         /* Fail if net device is currently claimed for use by iPXE */
00637         if ( efi_snp_claimed ) {
00638                 rc = -EAGAIN;
00639                 goto err_claimed;
00640         }
00641 
00642         /* Raise TPL */
00643         saved_tpl = bs->RaiseTPL ( TPL_CALLBACK );
00644 
00645         /* Sanity checks */
00646         if ( ll_header_len ) {
00647                 if ( ll_header_len != ll_protocol->ll_header_len ) {
00648                         DBGC ( snpdev, "SNPDEV %p TX invalid header length "
00649                                "%ld\n", snpdev,
00650                                ( ( unsigned long ) ll_header_len ) );
00651                         rc = -EINVAL;
00652                         goto err_sanity;
00653                 }
00654                 if ( len < ll_header_len ) {
00655                         DBGC ( snpdev, "SNPDEV %p invalid packet length %ld\n",
00656                                snpdev, ( ( unsigned long ) len ) );
00657                         rc = -EINVAL;
00658                         goto err_sanity;
00659                 }
00660                 if ( ! ll_dest ) {
00661                         DBGC ( snpdev, "SNPDEV %p TX missing destination "
00662                                "address\n", snpdev );
00663                         rc = -EINVAL;
00664                         goto err_sanity;
00665                 }
00666                 if ( ! net_proto ) {
00667                         DBGC ( snpdev, "SNPDEV %p TX missing network "
00668                                "protocol\n", snpdev );
00669                         rc = -EINVAL;
00670                         goto err_sanity;
00671                 }
00672                 if ( ! ll_src )
00673                         ll_src = &snpdev->mode.CurrentAddress;
00674         }
00675 
00676         /* Allocate buffer */
00677         payload_len = ( len - ll_protocol->ll_header_len );
00678         iobuf = alloc_iob ( MAX_LL_HEADER_LEN + ( ( payload_len > IOB_ZLEN ) ?
00679                                                   payload_len : IOB_ZLEN ) );
00680         if ( ! iobuf ) {
00681                 DBGC ( snpdev, "SNPDEV %p TX could not allocate %ld-byte "
00682                        "buffer\n", snpdev, ( ( unsigned long ) len ) );
00683                 rc = -ENOMEM;
00684                 goto err_alloc_iob;
00685         }
00686         iob_reserve ( iobuf, ( MAX_LL_HEADER_LEN -
00687                                ll_protocol->ll_header_len ) );
00688         memcpy ( iob_put ( iobuf, len ), data, len );
00689 
00690         /* Create link-layer header, if specified */
00691         if ( ll_header_len ) {
00692                 iob_pull ( iobuf, ll_protocol->ll_header_len );
00693                 if ( ( rc = ll_protocol->push ( snpdev->netdev,
00694                                                 iobuf, ll_dest, ll_src,
00695                                                 htons ( *net_proto ) )) != 0 ){
00696                         DBGC ( snpdev, "SNPDEV %p TX could not construct "
00697                                "header: %s\n", snpdev, strerror ( rc ) );
00698                         goto err_ll_push;
00699                 }
00700         }
00701 
00702         /* Transmit packet */
00703         if ( ( rc = netdev_tx ( snpdev->netdev, iob_disown ( iobuf ) ) ) != 0){
00704                 DBGC ( snpdev, "SNPDEV %p TX could not transmit: %s\n",
00705                        snpdev, strerror ( rc ) );
00706                 goto err_tx;
00707         }
00708 
00709         /* Record in transmit completion ring.  If we run out of
00710          * space, report the failure even though we have already
00711          * transmitted the packet.
00712          *
00713          * This allows us to report completions only for packets for
00714          * which we had reported successfully initiating transmission,
00715          * while continuing to support clients that never poll for
00716          * transmit completions.
00717          */
00718         tx_fill = ( snpdev->tx_prod - snpdev->tx_cons );
00719         if ( tx_fill >= EFI_SNP_NUM_TX ) {
00720                 DBGC ( snpdev, "SNPDEV %p TX completion ring full\n", snpdev );
00721                 rc = -ENOBUFS;
00722                 goto err_ring_full;
00723         }
00724         snpdev->tx[ snpdev->tx_prod++ % EFI_SNP_NUM_TX ] = data;
00725         snpdev->interrupts |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
00726 
00727         /* Restore TPL */
00728         bs->RestoreTPL ( saved_tpl );
00729 
00730         return 0;
00731 
00732  err_ring_full:
00733  err_tx:
00734  err_ll_push:
00735         free_iob ( iobuf );
00736  err_alloc_iob:
00737  err_sanity:
00738         bs->RestoreTPL ( saved_tpl );
00739  err_claimed:
00740         return EFIRC ( rc );
00741 }
00742 
00743 /**
00744  * Receive packet
00745  *
00746  * @v snp               SNP interface
00747  * @v ll_header_len     Link-layer header length, if to be filled in
00748  * @v len               Length of data buffer
00749  * @v data              Data buffer
00750  * @v ll_src            Link-layer source address, if specified
00751  * @v ll_dest           Link-layer destination address, if specified
00752  * @v net_proto         Network-layer protocol (in host order)
00753  * @ret efirc           EFI status code
00754  */
00755 static EFI_STATUS EFIAPI
00756 efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
00757                   UINTN *ll_header_len, UINTN *len, VOID *data,
00758                   EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest,
00759                   UINT16 *net_proto ) {
00760         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
00761         struct efi_snp_device *snpdev =
00762                 container_of ( snp, struct efi_snp_device, snp );
00763         struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
00764         struct io_buffer *iobuf;
00765         const void *iob_ll_dest;
00766         const void *iob_ll_src;
00767         uint16_t iob_net_proto;
00768         unsigned int iob_flags;
00769         size_t copy_len;
00770         EFI_TPL saved_tpl;
00771         int rc;
00772 
00773         DBGC2 ( snpdev, "SNPDEV %p RECEIVE %p(+%lx)", snpdev, data,
00774                 ( ( unsigned long ) *len ) );
00775 
00776         /* Fail if net device is currently claimed for use by iPXE */
00777         if ( efi_snp_claimed ) {
00778                 rc = -EAGAIN;
00779                 goto err_claimed;
00780         }
00781 
00782         /* Raise TPL */
00783         saved_tpl = bs->RaiseTPL ( TPL_CALLBACK );
00784 
00785         /* Poll the network device */
00786         efi_snp_poll ( snpdev );
00787 
00788         /* Check for an available packet */
00789         iobuf = list_first_entry ( &snpdev->rx, struct io_buffer, list );
00790         if ( ! iobuf ) {
00791                 DBGC2 ( snpdev, "\n" );
00792                 rc = -EAGAIN;
00793                 goto out_no_packet;
00794         }
00795         DBGC2 ( snpdev, "+%zx\n", iob_len ( iobuf ) );
00796 
00797         /* Dequeue packet */
00798         list_del ( &iobuf->list );
00799 
00800         /* Return packet to caller, truncating to buffer length */
00801         copy_len = iob_len ( iobuf );
00802         if ( copy_len > *len )
00803                 copy_len = *len;
00804         memcpy ( data, iobuf->data, copy_len );
00805         *len = iob_len ( iobuf );
00806 
00807         /* Attempt to decode link-layer header */
00808         if ( ( rc = ll_protocol->pull ( snpdev->netdev, iobuf, &iob_ll_dest,
00809                                         &iob_ll_src, &iob_net_proto,
00810                                         &iob_flags ) ) != 0 ) {
00811                 DBGC ( snpdev, "SNPDEV %p could not parse header: %s\n",
00812                        snpdev, strerror ( rc ) );
00813                 goto out_bad_ll_header;
00814         }
00815 
00816         /* Return link-layer header parameters to caller, if required */
00817         if ( ll_header_len )
00818                 *ll_header_len = ll_protocol->ll_header_len;
00819         if ( ll_src )
00820                 memcpy ( ll_src, iob_ll_src, ll_protocol->ll_addr_len );
00821         if ( ll_dest )
00822                 memcpy ( ll_dest, iob_ll_dest, ll_protocol->ll_addr_len );
00823         if ( net_proto )
00824                 *net_proto = ntohs ( iob_net_proto );
00825 
00826         /* Check buffer length */
00827         rc = ( ( copy_len == *len ) ? 0 : -ERANGE );
00828 
00829  out_bad_ll_header:
00830         free_iob ( iobuf );
00831  out_no_packet:
00832         bs->RestoreTPL ( saved_tpl );
00833  err_claimed:
00834         return EFIRC ( rc );
00835 }
00836 
00837 /**
00838  * Poll event
00839  *
00840  * @v event             Event
00841  * @v context           Event context
00842  */
00843 static VOID EFIAPI efi_snp_wait_for_packet ( EFI_EVENT event __unused,
00844                                              VOID *context ) {
00845         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
00846         struct efi_snp_device *snpdev = context;
00847         EFI_TPL saved_tpl;
00848 
00849         DBGCP ( snpdev, "SNPDEV %p WAIT_FOR_PACKET\n", snpdev );
00850 
00851         /* Do nothing unless the net device is open */
00852         if ( ! netdev_is_open ( snpdev->netdev ) )
00853                 return;
00854 
00855         /* Do nothing if net device is currently claimed for use by iPXE */
00856         if ( efi_snp_claimed )
00857                 return;
00858 
00859         /* Raise TPL */
00860         saved_tpl = bs->RaiseTPL ( TPL_CALLBACK );
00861 
00862         /* Poll the network device */
00863         efi_snp_poll ( snpdev );
00864 
00865         /* Restore TPL */
00866         bs->RestoreTPL ( saved_tpl );
00867 }
00868 
00869 /** SNP interface */
00870 static EFI_SIMPLE_NETWORK_PROTOCOL efi_snp_device_snp = {
00871         .Revision       = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION,
00872         .Start          = efi_snp_start,
00873         .Stop           = efi_snp_stop,
00874         .Initialize     = efi_snp_initialize,
00875         .Reset          = efi_snp_reset,
00876         .Shutdown       = efi_snp_shutdown,
00877         .ReceiveFilters = efi_snp_receive_filters,
00878         .StationAddress = efi_snp_station_address,
00879         .Statistics     = efi_snp_statistics,
00880         .MCastIpToMac   = efi_snp_mcast_ip_to_mac,
00881         .NvData         = efi_snp_nvdata,
00882         .GetStatus      = efi_snp_get_status,
00883         .Transmit       = efi_snp_transmit,
00884         .Receive        = efi_snp_receive,
00885 };
00886 
00887 /******************************************************************************
00888  *
00889  * UNDI protocol
00890  *
00891  ******************************************************************************
00892  */
00893 
00894 /** Union type for command parameter blocks */
00895 typedef union {
00896         PXE_CPB_STATION_ADDRESS station_address;
00897         PXE_CPB_FILL_HEADER fill_header;
00898         PXE_CPB_FILL_HEADER_FRAGMENTED fill_header_fragmented;
00899         PXE_CPB_TRANSMIT transmit;
00900         PXE_CPB_RECEIVE receive;
00901 } PXE_CPB_ANY;
00902 
00903 /** Union type for data blocks */
00904 typedef union {
00905         PXE_DB_GET_INIT_INFO get_init_info;
00906         PXE_DB_STATION_ADDRESS station_address;
00907         PXE_DB_GET_STATUS get_status;
00908         PXE_DB_RECEIVE receive;
00909 } PXE_DB_ANY;
00910 
00911 /**
00912  * Calculate UNDI byte checksum
00913  *
00914  * @v data              Data
00915  * @v len               Length of data
00916  * @ret sum             Checksum
00917  */
00918 static uint8_t efi_undi_checksum ( void *data, size_t len ) {
00919         uint8_t *bytes = data;
00920         uint8_t sum = 0;
00921 
00922         while ( len-- )
00923                 sum += *bytes++;
00924         return sum;
00925 }
00926 
00927 /**
00928  * Get UNDI SNP device interface number
00929  *
00930  * @v snpdev            SNP device
00931  * @ret ifnum           UNDI interface number
00932  */
00933 static unsigned int efi_undi_ifnum ( struct efi_snp_device *snpdev ) {
00934 
00935         /* iPXE network device indexes are one-based (leaving zero
00936          * meaning "unspecified").  UNDI interface numbers are
00937          * zero-based.
00938          */
00939         return ( snpdev->netdev->index - 1 );
00940 }
00941 
00942 /**
00943  * Identify UNDI SNP device
00944  *
00945  * @v ifnum             Interface number
00946  * @ret snpdev          SNP device, or NULL if not found
00947  */
00948 static struct efi_snp_device * efi_undi_snpdev ( unsigned int ifnum ) {
00949         struct efi_snp_device *snpdev;
00950 
00951         list_for_each_entry ( snpdev, &efi_snp_devices, list ) {
00952                 if ( efi_undi_ifnum ( snpdev ) == ifnum )
00953                         return snpdev;
00954         }
00955         return NULL;
00956 }
00957 
00958 /**
00959  * Convert EFI status code to UNDI status code
00960  *
00961  * @v efirc             EFI status code
00962  * @ret statcode        UNDI status code
00963  */
00964 static PXE_STATCODE efi_undi_statcode ( EFI_STATUS efirc ) {
00965 
00966         switch ( efirc ) {
00967         case EFI_INVALID_PARAMETER:     return PXE_STATCODE_INVALID_PARAMETER;
00968         case EFI_UNSUPPORTED:           return PXE_STATCODE_UNSUPPORTED;
00969         case EFI_OUT_OF_RESOURCES:      return PXE_STATCODE_BUFFER_FULL;
00970         case EFI_PROTOCOL_ERROR:        return PXE_STATCODE_DEVICE_FAILURE;
00971         case EFI_NOT_READY:             return PXE_STATCODE_NO_DATA;
00972         default:
00973                 return PXE_STATCODE_INVALID_CDB;
00974         }
00975 }
00976 
00977 /**
00978  * Get state
00979  *
00980  * @v snpdev            SNP device
00981  * @v cdb               Command description block
00982  * @ret efirc           EFI status code
00983  */
00984 static EFI_STATUS efi_undi_get_state ( struct efi_snp_device *snpdev,
00985                                        PXE_CDB *cdb ) {
00986         EFI_SIMPLE_NETWORK_MODE *mode = &snpdev->mode;
00987 
00988         DBGC ( snpdev, "UNDI %p GET STATE\n", snpdev );
00989 
00990         /* Return current state */
00991         if ( mode->State == EfiSimpleNetworkInitialized ) {
00992                 cdb->StatFlags |= PXE_STATFLAGS_GET_STATE_INITIALIZED;
00993         } else if ( mode->State == EfiSimpleNetworkStarted ) {
00994                 cdb->StatFlags |= PXE_STATFLAGS_GET_STATE_STARTED;
00995         } else {
00996                 cdb->StatFlags |= PXE_STATFLAGS_GET_STATE_STOPPED;
00997         }
00998 
00999         return 0;
01000 }
01001 
01002 /**
01003  * Start
01004  *
01005  * @v snpdev            SNP device
01006  * @ret efirc           EFI status code
01007  */
01008 static EFI_STATUS efi_undi_start ( struct efi_snp_device *snpdev ) {
01009         EFI_STATUS efirc;
01010 
01011         DBGC ( snpdev, "UNDI %p START\n", snpdev );
01012 
01013         /* Start SNP device */
01014         if ( ( efirc = efi_snp_start ( &snpdev->snp ) ) != 0 )
01015                 return efirc;
01016 
01017         return 0;
01018 }
01019 
01020 /**
01021  * Stop
01022  *
01023  * @v snpdev            SNP device
01024  * @ret efirc           EFI status code
01025  */
01026 static EFI_STATUS efi_undi_stop ( struct efi_snp_device *snpdev ) {
01027         EFI_STATUS efirc;
01028 
01029         DBGC ( snpdev, "UNDI %p STOP\n", snpdev );
01030 
01031         /* Stop SNP device */
01032         if ( ( efirc = efi_snp_stop ( &snpdev->snp ) ) != 0 )
01033                 return efirc;
01034 
01035         return 0;
01036 }
01037 
01038 /**
01039  * Get initialisation information
01040  *
01041  * @v snpdev            SNP device
01042  * @v cdb               Command description block
01043  * @v db                Data block
01044  * @ret efirc           EFI status code
01045  */
01046 static EFI_STATUS efi_undi_get_init_info ( struct efi_snp_device *snpdev,
01047                                            PXE_CDB *cdb,
01048                                            PXE_DB_GET_INIT_INFO *db ) {
01049         struct net_device *netdev = snpdev->netdev;
01050         struct ll_protocol *ll_protocol = netdev->ll_protocol;
01051 
01052         DBGC ( snpdev, "UNDI %p GET INIT INFO\n", snpdev );
01053 
01054         /* Populate structure */
01055         memset ( db, 0, sizeof ( *db ) );
01056         db->FrameDataLen = ( netdev->max_pkt_len - ll_protocol->ll_header_len );
01057         db->MediaHeaderLen = ll_protocol->ll_header_len;
01058         db->HWaddrLen = ll_protocol->ll_addr_len;
01059         db->IFtype = ntohs ( ll_protocol->ll_proto );
01060         cdb->StatFlags |= ( PXE_STATFLAGS_CABLE_DETECT_SUPPORTED |
01061                             PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED );
01062 
01063         return 0;
01064 }
01065 
01066 /**
01067  * Initialise
01068  *
01069  * @v snpdev            SNP device
01070  * @v cdb               Command description block
01071  * @v efirc             EFI status code
01072  */
01073 static EFI_STATUS efi_undi_initialize ( struct efi_snp_device *snpdev,
01074                                         PXE_CDB *cdb ) {
01075         struct net_device *netdev = snpdev->netdev;
01076         EFI_STATUS efirc;
01077 
01078         DBGC ( snpdev, "UNDI %p INITIALIZE\n", snpdev );
01079 
01080         /* Reset SNP device */
01081         if ( ( efirc = efi_snp_initialize ( &snpdev->snp, 0, 0 ) ) != 0 )
01082                 return efirc;
01083 
01084         /* Report link state */
01085         if ( ! netdev_link_ok ( netdev ) )
01086                 cdb->StatFlags |= PXE_STATFLAGS_INITIALIZED_NO_MEDIA;
01087 
01088         return 0;
01089 }
01090 
01091 /**
01092  * Reset
01093  *
01094  * @v snpdev            SNP device
01095  * @v efirc             EFI status code
01096  */
01097 static EFI_STATUS efi_undi_reset ( struct efi_snp_device *snpdev ) {
01098         EFI_STATUS efirc;
01099 
01100         DBGC ( snpdev, "UNDI %p RESET\n", snpdev );
01101 
01102         /* Reset SNP device */
01103         if ( ( efirc = efi_snp_reset ( &snpdev->snp, 0 ) ) != 0 )
01104                 return efirc;
01105 
01106         return 0;
01107 }
01108 
01109 /**
01110  * Shutdown
01111  *
01112  * @v snpdev            SNP device
01113  * @v efirc             EFI status code
01114  */
01115 static EFI_STATUS efi_undi_shutdown ( struct efi_snp_device *snpdev ) {
01116         EFI_STATUS efirc;
01117 
01118         DBGC ( snpdev, "UNDI %p SHUTDOWN\n", snpdev );
01119 
01120         /* Reset SNP device */
01121         if ( ( efirc = efi_snp_shutdown ( &snpdev->snp ) ) != 0 )
01122                 return efirc;
01123 
01124         return 0;
01125 }
01126 
01127 /**
01128  * Get/set receive filters
01129  *
01130  * @v snpdev            SNP device
01131  * @v cdb               Command description block
01132  * @v efirc             EFI status code
01133  */
01134 static EFI_STATUS efi_undi_receive_filters ( struct efi_snp_device *snpdev,
01135                                              PXE_CDB *cdb ) {
01136 
01137         DBGC ( snpdev, "UNDI %p RECEIVE FILTERS\n", snpdev );
01138 
01139         /* Mark everything as supported */
01140         cdb->StatFlags |= ( PXE_STATFLAGS_RECEIVE_FILTER_UNICAST |
01141                             PXE_STATFLAGS_RECEIVE_FILTER_BROADCAST |
01142                             PXE_STATFLAGS_RECEIVE_FILTER_PROMISCUOUS |
01143                             PXE_STATFLAGS_RECEIVE_FILTER_ALL_MULTICAST );
01144 
01145         return 0;
01146 }
01147 
01148 /**
01149  * Get/set station address
01150  *
01151  * @v snpdev            SNP device
01152  * @v cdb               Command description block
01153  * @v cpb               Command parameter block
01154  * @v efirc             EFI status code
01155  */
01156 static EFI_STATUS efi_undi_station_address ( struct efi_snp_device *snpdev,
01157                                              PXE_CDB *cdb,
01158                                              PXE_CPB_STATION_ADDRESS *cpb,
01159                                              PXE_DB_STATION_ADDRESS *db ) {
01160         struct net_device *netdev = snpdev->netdev;
01161         struct ll_protocol *ll_protocol = netdev->ll_protocol;
01162         void *mac;
01163         int reset;
01164         EFI_STATUS efirc;
01165 
01166         DBGC ( snpdev, "UNDI %p STATION ADDRESS\n", snpdev );
01167 
01168         /* Update address if applicable */
01169         reset = ( cdb->OpFlags & PXE_OPFLAGS_STATION_ADDRESS_RESET );
01170         mac = ( cpb ? &cpb->StationAddr : NULL );
01171         if ( ( reset || mac ) &&
01172              ( ( efirc = efi_snp_station_address ( &snpdev->snp, reset,
01173                                                    mac ) ) != 0 ) )
01174                 return efirc;
01175 
01176         /* Fill in current addresses, if applicable */
01177         if ( db ) {
01178                 memset ( db, 0, sizeof ( *db ) );
01179                 memcpy ( &db->StationAddr, netdev->ll_addr,
01180                          ll_protocol->ll_addr_len );
01181                 memcpy ( &db->BroadcastAddr, netdev->ll_broadcast,
01182                          ll_protocol->ll_addr_len );
01183                 memcpy ( &db->PermanentAddr, netdev->hw_addr,
01184                          ll_protocol->hw_addr_len );
01185         }
01186 
01187         return 0;
01188 }
01189 
01190 /**
01191  * Get interrupt status
01192  *
01193  * @v snpdev            SNP device
01194  * @v cdb               Command description block
01195  * @v db                Data block
01196  * @v efirc             EFI status code
01197  */
01198 static EFI_STATUS efi_undi_get_status ( struct efi_snp_device *snpdev,
01199                                         PXE_CDB *cdb, PXE_DB_GET_STATUS *db ) {
01200         UINT32 interrupts;
01201         VOID *txbuf;
01202         struct io_buffer *rxbuf;
01203         EFI_STATUS efirc;
01204 
01205         DBGC2 ( snpdev, "UNDI %p GET STATUS\n", snpdev );
01206 
01207         /* Get status */
01208         if ( ( efirc = efi_snp_get_status ( &snpdev->snp, &interrupts,
01209                                             &txbuf ) ) != 0 )
01210                 return efirc;
01211 
01212         /* Report status */
01213         memset ( db, 0, sizeof ( *db ) );
01214         if ( interrupts & EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT )
01215                 cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_RECEIVE;
01216         if ( interrupts & EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT )
01217                 cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_TRANSMIT;
01218         if ( txbuf ) {
01219                 db->TxBuffer[0] = ( ( intptr_t ) txbuf );
01220         } else {
01221                 cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN;
01222                 /* The specification states clearly that UNDI drivers
01223                  * should set TXBUF_QUEUE_EMPTY if all completed
01224                  * buffer addresses are written into the returned data
01225                  * block.  However, SnpDxe chooses to interpret
01226                  * TXBUF_QUEUE_EMPTY as a synonym for
01227                  * NO_TXBUFS_WRITTEN, thereby rendering it entirely
01228                  * pointless.  Work around this UEFI stupidity, as per
01229                  * usual.
01230                  */
01231                 if ( snpdev->tx_prod == snpdev->tx_cons )
01232                         cdb->StatFlags |=
01233                                 PXE_STATFLAGS_GET_STATUS_TXBUF_QUEUE_EMPTY;
01234         }
01235         rxbuf = list_first_entry ( &snpdev->rx, struct io_buffer, list );
01236         if ( rxbuf )
01237                 db->RxFrameLen = iob_len ( rxbuf );
01238         if ( ! netdev_link_ok ( snpdev->netdev ) )
01239                 cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_NO_MEDIA;
01240 
01241         return 0;
01242 }
01243 
01244 /**
01245  * Fill header
01246  *
01247  * @v snpdev            SNP device
01248  * @v cdb               Command description block
01249  * @v cpb               Command parameter block
01250  * @v efirc             EFI status code
01251  */
01252 static EFI_STATUS efi_undi_fill_header ( struct efi_snp_device *snpdev,
01253                                          PXE_CDB *cdb, PXE_CPB_ANY *cpb ) {
01254         struct net_device *netdev = snpdev->netdev;
01255         struct ll_protocol *ll_protocol = netdev->ll_protocol;
01256         PXE_CPB_FILL_HEADER *whole = &cpb->fill_header;
01257         PXE_CPB_FILL_HEADER_FRAGMENTED *fragged = &cpb->fill_header_fragmented;
01258         VOID *data;
01259         void *dest;
01260         void *src;
01261         uint16_t proto;
01262         struct io_buffer iobuf;
01263         int rc;
01264 
01265         /* SnpDxe will (pointlessly) use PXE_CPB_FILL_HEADER_FRAGMENTED
01266          * even though we choose to explicitly not claim support for
01267          * fragments via PXE_ROMID_IMP_FRAG_SUPPORTED.
01268          */
01269         if ( cdb->OpFlags & PXE_OPFLAGS_FILL_HEADER_FRAGMENTED ) {
01270                 data = ( ( void * ) ( intptr_t ) fragged->FragDesc[0].FragAddr);
01271                 dest = &fragged->DestAddr;
01272                 src = &fragged->SrcAddr;
01273                 proto = fragged->Protocol;
01274         } else {
01275                 data = ( ( void * ) ( intptr_t ) whole->MediaHeader );
01276                 dest = &whole->DestAddr;
01277                 src = &whole->SrcAddr;
01278                 proto = whole->Protocol;
01279         }
01280 
01281         /* Construct link-layer header */
01282         iob_populate ( &iobuf, data, 0, ll_protocol->ll_header_len );
01283         iob_reserve ( &iobuf, ll_protocol->ll_header_len );
01284         if ( ( rc = ll_protocol->push ( netdev, &iobuf, dest, src,
01285                                         proto ) ) != 0 )
01286                 return EFIRC ( rc );
01287 
01288         return 0;
01289 }
01290 
01291 /**
01292  * Transmit
01293  *
01294  * @v snpdev            SNP device
01295  * @v cpb               Command parameter block
01296  * @v efirc             EFI status code
01297  */
01298 static EFI_STATUS efi_undi_transmit ( struct efi_snp_device *snpdev,
01299                                       PXE_CPB_TRANSMIT *cpb ) {
01300         VOID *data = ( ( void * ) ( intptr_t ) cpb->FrameAddr );
01301         EFI_STATUS efirc;
01302 
01303         DBGC2 ( snpdev, "UNDI %p TRANSMIT\n", snpdev );
01304 
01305         /* Transmit packet */
01306         if ( ( efirc = efi_snp_transmit ( &snpdev->snp, 0, cpb->DataLen,
01307                                           data, NULL, NULL, NULL ) ) != 0 )
01308                 return efirc;
01309 
01310         return 0;
01311 }
01312 
01313 /**
01314  * Receive
01315  *
01316  * @v snpdev            SNP device
01317  * @v cpb               Command parameter block
01318  * @v efirc             EFI status code
01319  */
01320 static EFI_STATUS efi_undi_receive ( struct efi_snp_device *snpdev,
01321                                      PXE_CPB_RECEIVE *cpb,
01322                                      PXE_DB_RECEIVE *db ) {
01323         struct net_device *netdev = snpdev->netdev;
01324         struct ll_protocol *ll_protocol = netdev->ll_protocol;
01325         VOID *data = ( ( void * ) ( intptr_t ) cpb->BufferAddr );
01326         UINTN hdr_len;
01327         UINTN len = cpb->BufferLen;
01328         EFI_MAC_ADDRESS src;
01329         EFI_MAC_ADDRESS dest;
01330         UINT16 proto;
01331         EFI_STATUS efirc;
01332 
01333         DBGC2 ( snpdev, "UNDI %p RECEIVE\n", snpdev );
01334 
01335         /* Receive packet */
01336         if ( ( efirc = efi_snp_receive ( &snpdev->snp, &hdr_len, &len, data,
01337                                          &src, &dest, &proto ) ) != 0 )
01338                 return efirc;
01339 
01340         /* Describe frame */
01341         memset ( db, 0, sizeof ( *db ) );
01342         memcpy ( &db->SrcAddr, &src, ll_protocol->ll_addr_len );
01343         memcpy ( &db->DestAddr, &dest, ll_protocol->ll_addr_len );
01344         db->FrameLen = len;
01345         db->Protocol = proto;
01346         db->MediaHeaderLen = ll_protocol->ll_header_len;
01347         db->Type = PXE_FRAME_TYPE_PROMISCUOUS;
01348 
01349         return 0;
01350 }
01351 
01352 /** UNDI entry point */
01353 static EFIAPI VOID efi_undi_issue ( UINT64 cdb_phys ) {
01354         PXE_CDB *cdb = ( ( void * ) ( intptr_t ) cdb_phys );
01355         PXE_CPB_ANY *cpb = ( ( void * ) ( intptr_t ) cdb->CPBaddr );
01356         PXE_DB_ANY *db = ( ( void * ) ( intptr_t ) cdb->DBaddr );
01357         struct efi_snp_device *snpdev;
01358         EFI_STATUS efirc;
01359 
01360         /* Identify device */
01361         snpdev = efi_undi_snpdev ( cdb->IFnum );
01362         if ( ! snpdev ) {
01363                 DBGC ( cdb, "UNDI invalid interface number %d\n", cdb->IFnum );
01364                 cdb->StatCode = PXE_STATCODE_INVALID_CDB;
01365                 cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
01366                 return;
01367         }
01368 
01369         /* Fail if net device is currently claimed for use by iPXE */
01370         if ( efi_snp_claimed ) {
01371                 cdb->StatCode = PXE_STATCODE_BUSY;
01372                 cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
01373                 return;
01374         }
01375 
01376         /* Handle opcode */
01377         cdb->StatCode = PXE_STATCODE_SUCCESS;
01378         cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
01379         switch ( cdb->OpCode ) {
01380 
01381         case PXE_OPCODE_GET_STATE:
01382                 efirc = efi_undi_get_state ( snpdev, cdb );
01383                 break;
01384 
01385         case PXE_OPCODE_START:
01386                 efirc = efi_undi_start ( snpdev );
01387                 break;
01388 
01389         case PXE_OPCODE_STOP:
01390                 efirc = efi_undi_stop ( snpdev );
01391                 break;
01392 
01393         case PXE_OPCODE_GET_INIT_INFO:
01394                 efirc = efi_undi_get_init_info ( snpdev, cdb,
01395                                                  &db->get_init_info );
01396                 break;
01397 
01398         case PXE_OPCODE_INITIALIZE:
01399                 efirc = efi_undi_initialize ( snpdev, cdb );
01400                 break;
01401 
01402         case PXE_OPCODE_RESET:
01403                 efirc = efi_undi_reset ( snpdev );
01404                 break;
01405 
01406         case PXE_OPCODE_SHUTDOWN:
01407                 efirc = efi_undi_shutdown ( snpdev );
01408                 break;
01409 
01410         case PXE_OPCODE_RECEIVE_FILTERS:
01411                 efirc = efi_undi_receive_filters ( snpdev, cdb );
01412                 break;
01413 
01414         case PXE_OPCODE_STATION_ADDRESS:
01415                 efirc = efi_undi_station_address ( snpdev, cdb,
01416                                                    &cpb->station_address,
01417                                                    &db->station_address );
01418                 break;
01419 
01420         case PXE_OPCODE_GET_STATUS:
01421                 efirc = efi_undi_get_status ( snpdev, cdb, &db->get_status );
01422                 break;
01423 
01424         case PXE_OPCODE_FILL_HEADER:
01425                 efirc = efi_undi_fill_header ( snpdev, cdb, cpb );
01426                 break;
01427 
01428         case PXE_OPCODE_TRANSMIT:
01429                 efirc = efi_undi_transmit ( snpdev, &cpb->transmit );
01430                 break;
01431 
01432         case PXE_OPCODE_RECEIVE:
01433                 efirc = efi_undi_receive ( snpdev, &cpb->receive,
01434                                            &db->receive );
01435                 break;
01436 
01437         default:
01438                 DBGC ( snpdev, "UNDI %p unsupported opcode %#04x\n",
01439                        snpdev, cdb->OpCode );
01440                 efirc = EFI_UNSUPPORTED;
01441                 break;
01442         }
01443 
01444         /* Convert EFI status code to UNDI status code */
01445         if ( efirc != 0 ) {
01446                 cdb->StatFlags &= ~PXE_STATFLAGS_STATUS_MASK;
01447                 cdb->StatFlags |= PXE_STATFLAGS_COMMAND_FAILED;
01448                 cdb->StatCode = efi_undi_statcode ( efirc );
01449         }
01450 }
01451 
01452 /** UNDI interface
01453  *
01454  * Must be aligned on a 16-byte boundary, for no particularly good
01455  * reason.
01456  */
01457 static PXE_SW_UNDI efi_snp_undi __attribute__ (( aligned ( 16 ) )) = {
01458         .Signature      = PXE_ROMID_SIGNATURE,
01459         .Len            = sizeof ( efi_snp_undi ),
01460         .Rev            = PXE_ROMID_REV,
01461         .MajorVer       = PXE_ROMID_MAJORVER,
01462         .MinorVer       = PXE_ROMID_MINORVER,
01463         .Implementation = ( PXE_ROMID_IMP_SW_VIRT_ADDR |
01464                             PXE_ROMID_IMP_STATION_ADDR_SETTABLE |
01465                             PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED |
01466                             PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED |
01467                             PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED |
01468                             PXE_ROMID_IMP_TX_COMPLETE_INT_SUPPORTED |
01469                             PXE_ROMID_IMP_PACKET_RX_INT_SUPPORTED ),
01470         /* SnpDxe checks that BusCnt is non-zero.  It makes no further
01471          * use of BusCnt, and never looks as BusType[].  As with much
01472          * of the EDK2 code, this check seems to serve no purpose
01473          * whatsoever but must nonetheless be humoured.
01474          */
01475         .BusCnt         = 1,
01476         .BusType[0]     = PXE_BUSTYPE ( 'i', 'P', 'X', 'E' ),
01477 };
01478 
01479 /** Network Identification Interface (NII) */
01480 static EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL efi_snp_device_nii = {
01481         .Revision       = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION,
01482         .StringId       = "UNDI",
01483         .Type           = EfiNetworkInterfaceUndi,
01484         .MajorVer       = 3,
01485         .MinorVer       = 1,
01486         .Ipv6Supported  = TRUE, /* This is a raw packet interface, FFS! */
01487 };
01488 
01489 /******************************************************************************
01490  *
01491  * Component name protocol
01492  *
01493  ******************************************************************************
01494  */
01495 
01496 /**
01497  * Look up driver name
01498  *
01499  * @v name2             Component name protocol
01500  * @v language          Language to use
01501  * @v driver_name       Driver name to fill in
01502  * @ret efirc           EFI status code
01503  */
01504 static EFI_STATUS EFIAPI
01505 efi_snp_get_driver_name ( EFI_COMPONENT_NAME2_PROTOCOL *name2,
01506                           CHAR8 *language __unused, CHAR16 **driver_name ) {
01507         struct efi_snp_device *snpdev =
01508                 container_of ( name2, struct efi_snp_device, name2 );
01509 
01510         *driver_name = snpdev->driver_name;
01511         return 0;
01512 }
01513 
01514 /**
01515  * Look up controller name
01516  *
01517  * @v name2                     Component name protocol
01518  * @v device            Device
01519  * @v child             Child device, or NULL
01520  * @v language          Language to use
01521  * @v driver_name       Device name to fill in
01522  * @ret efirc           EFI status code
01523  */
01524 static EFI_STATUS EFIAPI
01525 efi_snp_get_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *name2,
01526                               EFI_HANDLE device __unused,
01527                               EFI_HANDLE child __unused,
01528                               CHAR8 *language __unused,
01529                               CHAR16 **controller_name ) {
01530         struct efi_snp_device *snpdev =
01531                 container_of ( name2, struct efi_snp_device, name2 );
01532 
01533         *controller_name = snpdev->controller_name;
01534         return 0;
01535 }
01536 
01537 /******************************************************************************
01538  *
01539  * Load file protocol
01540  *
01541  ******************************************************************************
01542  */
01543 
01544 /**
01545  * Load file
01546  *
01547  * @v loadfile          Load file protocol
01548  * @v path              File path
01549  * @v booting           Loading as part of a boot attempt
01550  * @ret efirc           EFI status code
01551  */
01552 static EFI_STATUS EFIAPI
01553 efi_snp_load_file ( EFI_LOAD_FILE_PROTOCOL *load_file,
01554                     EFI_DEVICE_PATH_PROTOCOL *path __unused,
01555                     BOOLEAN booting, UINTN *len __unused,
01556                     VOID *data __unused ) {
01557         struct efi_snp_device *snpdev =
01558                 container_of ( load_file, struct efi_snp_device, load_file );
01559         struct net_device *netdev = snpdev->netdev;
01560         int rc;
01561 
01562         /* Fail unless this is a boot attempt */
01563         if ( ! booting ) {
01564                 DBGC ( snpdev, "SNPDEV %p cannot load non-boot file\n",
01565                        snpdev );
01566                 return EFI_UNSUPPORTED;
01567         }
01568 
01569         /* Claim network devices for use by iPXE */
01570         efi_snp_claim();
01571 
01572         /* Start watchdog holdoff timer */
01573         efi_watchdog_start();
01574 
01575         /* Boot from network device */
01576         if ( ( rc = ipxe ( netdev ) ) != 0 )
01577                 goto err_ipxe;
01578 
01579         /* Reset console */
01580         console_reset();
01581 
01582  err_ipxe:
01583         efi_watchdog_stop();
01584         efi_snp_release();
01585         return EFIRC ( rc );
01586 }
01587 
01588 /** Load file protocol */
01589 static EFI_LOAD_FILE_PROTOCOL efi_snp_load_file_protocol = {
01590         .LoadFile       = efi_snp_load_file,
01591 };
01592 
01593 /******************************************************************************
01594  *
01595  * iPXE network driver
01596  *
01597  ******************************************************************************
01598  */
01599 
01600 /**
01601  * Locate SNP device corresponding to network device
01602  *
01603  * @v netdev            Network device
01604  * @ret snp             SNP device, or NULL if not found
01605  */
01606 static struct efi_snp_device * efi_snp_demux ( struct net_device *netdev ) {
01607         struct efi_snp_device *snpdev;
01608 
01609         list_for_each_entry ( snpdev, &efi_snp_devices, list ) {
01610                 if ( snpdev->netdev == netdev )
01611                         return snpdev;
01612         }
01613         return NULL;
01614 }
01615 
01616 /**
01617  * Create SNP device
01618  *
01619  * @v netdev            Network device
01620  * @ret rc              Return status code
01621  */
01622 static int efi_snp_probe ( struct net_device *netdev ) {
01623         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
01624         struct efi_device *efidev;
01625         struct efi_snp_device *snpdev;
01626         EFI_DEVICE_PATH_PROTOCOL *path_end;
01627         MAC_ADDR_DEVICE_PATH *macpath;
01628         VLAN_DEVICE_PATH *vlanpath;
01629         size_t path_prefix_len = 0;
01630         unsigned int ifcnt;
01631         unsigned int tag;
01632         void *interface;
01633         EFI_STATUS efirc;
01634         int rc;
01635 
01636         /* Find parent EFI device */
01637         efidev = efidev_parent ( netdev->dev );
01638         if ( ! efidev ) {
01639                 DBG ( "SNP skipping non-EFI device %s\n", netdev->name );
01640                 rc = 0;
01641                 goto err_no_efidev;
01642         }
01643 
01644         /* Allocate the SNP device */
01645         snpdev = zalloc ( sizeof ( *snpdev ) );
01646         if ( ! snpdev ) {
01647                 rc = -ENOMEM;
01648                 goto err_alloc_snp;
01649         }
01650         snpdev->netdev = netdev_get ( netdev );
01651         snpdev->efidev = efidev;
01652         INIT_LIST_HEAD ( &snpdev->rx );
01653 
01654         /* Sanity check */
01655         if ( netdev->ll_protocol->ll_addr_len > sizeof ( EFI_MAC_ADDRESS ) ) {
01656                 DBGC ( snpdev, "SNPDEV %p cannot support link-layer address "
01657                        "length %d for %s\n", snpdev,
01658                        netdev->ll_protocol->ll_addr_len, netdev->name );
01659                 rc = -ENOTSUP;
01660                 goto err_ll_addr_len;
01661         }
01662 
01663         /* Populate the SNP structure */
01664         memcpy ( &snpdev->snp, &efi_snp_device_snp, sizeof ( snpdev->snp ) );
01665         snpdev->snp.Mode = &snpdev->mode;
01666         if ( ( efirc = bs->CreateEvent ( EVT_NOTIFY_WAIT, TPL_NOTIFY,
01667                                          efi_snp_wait_for_packet, snpdev,
01668                                          &snpdev->snp.WaitForPacket ) ) != 0 ){
01669                 rc = -EEFI ( efirc );
01670                 DBGC ( snpdev, "SNPDEV %p could not create event: %s\n",
01671                        snpdev, strerror ( rc ) );
01672                 goto err_create_event;
01673         }
01674 
01675         /* Populate the SNP mode structure */
01676         snpdev->mode.State = EfiSimpleNetworkStopped;
01677         efi_snp_set_mode ( snpdev );
01678 
01679         /* Populate the NII structure */
01680         memcpy ( &snpdev->nii, &efi_snp_device_nii, sizeof ( snpdev->nii ) );
01681         snpdev->nii.Id = ( ( intptr_t ) &efi_snp_undi );
01682         snpdev->nii.IfNum = efi_undi_ifnum ( snpdev );
01683         efi_snp_undi.EntryPoint = ( ( intptr_t ) efi_undi_issue );
01684         ifcnt = ( ( efi_snp_undi.IFcntExt << 8 ) | efi_snp_undi.IFcnt );
01685         if ( ifcnt < snpdev->nii.IfNum )
01686                 ifcnt = snpdev->nii.IfNum;
01687         efi_snp_undi.IFcnt = ( ifcnt & 0xff );
01688         efi_snp_undi.IFcntExt = ( ifcnt >> 8 );
01689         efi_snp_undi.Fudge -= efi_undi_checksum ( &efi_snp_undi,
01690                                                   sizeof ( efi_snp_undi ) );
01691 
01692         /* Populate the component name structure */
01693         efi_snprintf ( snpdev->driver_name,
01694                        ( sizeof ( snpdev->driver_name ) /
01695                          sizeof ( snpdev->driver_name[0] ) ),
01696                        "%s %s", product_short_name, netdev->dev->driver_name );
01697         efi_snprintf ( snpdev->controller_name,
01698                        ( sizeof ( snpdev->controller_name ) /
01699                          sizeof ( snpdev->controller_name[0] ) ),
01700                        "%s %s (%s, %s)", product_short_name,
01701                        netdev->dev->driver_name, netdev->dev->name,
01702                        netdev_addr ( netdev ) );
01703         snpdev->name2.GetDriverName = efi_snp_get_driver_name;
01704         snpdev->name2.GetControllerName = efi_snp_get_controller_name;
01705         snpdev->name2.SupportedLanguages = "en";
01706 
01707         /* Populate the load file protocol structure */
01708         memcpy ( &snpdev->load_file, &efi_snp_load_file_protocol,
01709                  sizeof ( snpdev->load_file ) );
01710 
01711         /* Populate the device name */
01712         efi_snprintf ( snpdev->name, ( sizeof ( snpdev->name ) /
01713                                        sizeof ( snpdev->name[0] ) ),
01714                        "%s", netdev->name );
01715 
01716         /* Allocate the new device path */
01717         path_prefix_len = efi_devpath_len ( efidev->path );
01718         snpdev->path = zalloc ( path_prefix_len + sizeof ( *macpath ) +
01719                                 sizeof ( *vlanpath ) + sizeof ( *path_end ) );
01720         if ( ! snpdev->path ) {
01721                 rc = -ENOMEM;
01722                 goto err_alloc_device_path;
01723         }
01724 
01725         /* Populate the device path */
01726         memcpy ( snpdev->path, efidev->path, path_prefix_len );
01727         macpath = ( ( ( void * ) snpdev->path ) + path_prefix_len );
01728         memset ( macpath, 0, sizeof ( *macpath ) );
01729         macpath->Header.Type = MESSAGING_DEVICE_PATH;
01730         macpath->Header.SubType = MSG_MAC_ADDR_DP;
01731         macpath->Header.Length[0] = sizeof ( *macpath );
01732         memcpy ( &macpath->MacAddress, netdev->ll_addr,
01733                  netdev->ll_protocol->ll_addr_len );
01734         macpath->IfType = ntohs ( netdev->ll_protocol->ll_proto );
01735         if ( ( tag = vlan_tag ( netdev ) ) ) {
01736                 vlanpath = ( ( ( void * ) macpath ) + sizeof ( *macpath ) );
01737                 memset ( vlanpath, 0, sizeof ( *vlanpath ) );
01738                 vlanpath->Header.Type = MESSAGING_DEVICE_PATH;
01739                 vlanpath->Header.SubType = MSG_VLAN_DP;
01740                 vlanpath->Header.Length[0] = sizeof ( *vlanpath );
01741                 vlanpath->VlanId = tag;
01742                 path_end = ( ( ( void * ) vlanpath ) + sizeof ( *vlanpath ) );
01743         } else {
01744                 path_end = ( ( ( void * ) macpath ) + sizeof ( *macpath ) );
01745         }
01746         memset ( path_end, 0, sizeof ( *path_end ) );
01747         path_end->Type = END_DEVICE_PATH_TYPE;
01748         path_end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
01749         path_end->Length[0] = sizeof ( *path_end );
01750 
01751         /* Install the SNP */
01752         if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
01753                         &snpdev->handle,
01754                         &efi_simple_network_protocol_guid, &snpdev->snp,
01755                         &efi_device_path_protocol_guid, snpdev->path,
01756                         &efi_nii_protocol_guid, &snpdev->nii,
01757                         &efi_nii31_protocol_guid, &snpdev->nii,
01758                         &efi_component_name2_protocol_guid, &snpdev->name2,
01759                         &efi_load_file_protocol_guid, &snpdev->load_file,
01760                         NULL ) ) != 0 ) {
01761                 rc = -EEFI ( efirc );
01762                 DBGC ( snpdev, "SNPDEV %p could not install protocols: %s\n",
01763                        snpdev, strerror ( rc ) );
01764                 goto err_install_protocol_interface;
01765         }
01766 
01767         /* SnpDxe will repeatedly start up and shut down our NII/UNDI
01768          * interface (in order to obtain the MAC address) before
01769          * discovering that it cannot install another SNP on the same
01770          * handle.  This causes the underlying network device to be
01771          * unexpectedly closed.
01772          *
01773          * Prevent this by opening our own NII (and NII31) protocol
01774          * instances to prevent SnpDxe from attempting to bind to
01775          * them.
01776          */
01777         if ( ( efirc = bs->OpenProtocol ( snpdev->handle,
01778                                           &efi_nii_protocol_guid, &interface,
01779                                           efi_image_handle, snpdev->handle,
01780                                           ( EFI_OPEN_PROTOCOL_BY_DRIVER |
01781                                             EFI_OPEN_PROTOCOL_EXCLUSIVE )))!=0){
01782                 rc = -EEFI ( efirc );
01783                 DBGC ( snpdev, "SNPDEV %p could not open NII protocol: %s\n",
01784                        snpdev, strerror ( rc ) );
01785                 goto err_open_nii;
01786         }
01787         if ( ( efirc = bs->OpenProtocol ( snpdev->handle,
01788                                           &efi_nii31_protocol_guid, &interface,
01789                                           efi_image_handle, snpdev->handle,
01790                                           ( EFI_OPEN_PROTOCOL_BY_DRIVER |
01791                                             EFI_OPEN_PROTOCOL_EXCLUSIVE )))!=0){
01792                 rc = -EEFI ( efirc );
01793                 DBGC ( snpdev, "SNPDEV %p could not open NII31 protocol: %s\n",
01794                        snpdev, strerror ( rc ) );
01795                 goto err_open_nii31;
01796         }
01797 
01798         /* Add as child of EFI parent device */
01799         if ( ( rc = efi_child_add ( efidev->device, snpdev->handle ) ) != 0 ) {
01800                 DBGC ( snpdev, "SNPDEV %p could not become child of %s: %s\n",
01801                        snpdev, efi_handle_name ( efidev->device ),
01802                        strerror ( rc ) );
01803                 goto err_efi_child_add;
01804         }
01805 
01806         /* Install HII */
01807         if ( ( rc = efi_snp_hii_install ( snpdev ) ) != 0 ) {
01808                 DBGC ( snpdev, "SNPDEV %p could not install HII: %s\n",
01809                        snpdev, strerror ( rc ) );
01810                 /* HII fails on several platforms.  It's
01811                  * non-essential, so treat this as a non-fatal
01812                  * error.
01813                  */
01814         }
01815 
01816         /* Add to list of SNP devices */
01817         list_add ( &snpdev->list, &efi_snp_devices );
01818 
01819         /* Close device path */
01820         bs->CloseProtocol ( efidev->device, &efi_device_path_protocol_guid,
01821                             efi_image_handle, efidev->device );
01822 
01823         DBGC ( snpdev, "SNPDEV %p installed for %s as device %s\n",
01824                snpdev, netdev->name, efi_handle_name ( snpdev->handle ) );
01825         return 0;
01826 
01827         list_del ( &snpdev->list );
01828         if ( snpdev->package_list )
01829                 efi_snp_hii_uninstall ( snpdev );
01830         efi_child_del ( efidev->device, snpdev->handle );
01831  err_efi_child_add:
01832         bs->CloseProtocol ( snpdev->handle, &efi_nii_protocol_guid,
01833                             efi_image_handle, snpdev->handle );
01834  err_open_nii:
01835         bs->CloseProtocol ( snpdev->handle, &efi_nii31_protocol_guid,
01836                             efi_image_handle, snpdev->handle );
01837  err_open_nii31:
01838         bs->UninstallMultipleProtocolInterfaces (
01839                         snpdev->handle,
01840                         &efi_simple_network_protocol_guid, &snpdev->snp,
01841                         &efi_device_path_protocol_guid, snpdev->path,
01842                         &efi_nii_protocol_guid, &snpdev->nii,
01843                         &efi_nii31_protocol_guid, &snpdev->nii,
01844                         &efi_component_name2_protocol_guid, &snpdev->name2,
01845                         &efi_load_file_protocol_guid, &snpdev->load_file,
01846                         NULL );
01847  err_install_protocol_interface:
01848         free ( snpdev->path );
01849  err_alloc_device_path:
01850         bs->CloseEvent ( snpdev->snp.WaitForPacket );
01851  err_create_event:
01852  err_ll_addr_len:
01853         netdev_put ( netdev );
01854         free ( snpdev );
01855  err_alloc_snp:
01856  err_no_efidev:
01857         return rc;
01858 }
01859 
01860 /**
01861  * Handle SNP device or link state change
01862  *
01863  * @v netdev            Network device
01864  */
01865 static void efi_snp_notify ( struct net_device *netdev ) {
01866         struct efi_snp_device *snpdev;
01867 
01868         /* Locate SNP device */
01869         snpdev = efi_snp_demux ( netdev );
01870         if ( ! snpdev ) {
01871                 DBG ( "SNP skipping non-SNP device %s\n", netdev->name );
01872                 return;
01873         }
01874 
01875         /* Update link state */
01876         snpdev->mode.MediaPresent =
01877                 ( netdev_link_ok ( netdev ) ? TRUE : FALSE );
01878         DBGC ( snpdev, "SNPDEV %p link is %s\n", snpdev,
01879                ( snpdev->mode.MediaPresent ? "up" : "down" ) );
01880 
01881         /* Update mode state */
01882         efi_snp_set_state ( snpdev );
01883 }
01884 
01885 /**
01886  * Destroy SNP device
01887  *
01888  * @v netdev            Network device
01889  */
01890 static void efi_snp_remove ( struct net_device *netdev ) {
01891         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
01892         struct efi_snp_device *snpdev;
01893 
01894         /* Locate SNP device */
01895         snpdev = efi_snp_demux ( netdev );
01896         if ( ! snpdev ) {
01897                 DBG ( "SNP skipping non-SNP device %s\n", netdev->name );
01898                 return;
01899         }
01900 
01901         /* Uninstall the SNP */
01902         list_del ( &snpdev->list );
01903         if ( snpdev->package_list )
01904                 efi_snp_hii_uninstall ( snpdev );
01905         efi_child_del ( snpdev->efidev->device, snpdev->handle );
01906         bs->CloseProtocol ( snpdev->handle, &efi_nii_protocol_guid,
01907                             efi_image_handle, snpdev->handle );
01908         bs->CloseProtocol ( snpdev->handle, &efi_nii31_protocol_guid,
01909                             efi_image_handle, snpdev->handle );
01910         bs->UninstallMultipleProtocolInterfaces (
01911                         snpdev->handle,
01912                         &efi_simple_network_protocol_guid, &snpdev->snp,
01913                         &efi_device_path_protocol_guid, snpdev->path,
01914                         &efi_nii_protocol_guid, &snpdev->nii,
01915                         &efi_nii31_protocol_guid, &snpdev->nii,
01916                         &efi_component_name2_protocol_guid, &snpdev->name2,
01917                         &efi_load_file_protocol_guid, &snpdev->load_file,
01918                         NULL );
01919         free ( snpdev->path );
01920         bs->CloseEvent ( snpdev->snp.WaitForPacket );
01921         netdev_put ( snpdev->netdev );
01922         free ( snpdev );
01923 }
01924 
01925 /** SNP driver */
01926 struct net_driver efi_snp_driver __net_driver = {
01927         .name = "SNP",
01928         .probe = efi_snp_probe,
01929         .notify = efi_snp_notify,
01930         .remove = efi_snp_remove,
01931 };
01932 
01933 /**
01934  * Find SNP device by EFI device handle
01935  *
01936  * @v handle            EFI device handle
01937  * @ret snpdev          SNP device, or NULL
01938  */
01939 struct efi_snp_device * find_snpdev ( EFI_HANDLE handle ) {
01940         struct efi_snp_device *snpdev;
01941 
01942         list_for_each_entry ( snpdev, &efi_snp_devices, list ) {
01943                 if ( snpdev->handle == handle )
01944                         return snpdev;
01945         }
01946         return NULL;
01947 }
01948 
01949 /**
01950  * Get most recently opened SNP device
01951  *
01952  * @ret snpdev          Most recently opened SNP device, or NULL
01953  */
01954 struct efi_snp_device * last_opened_snpdev ( void ) {
01955         struct net_device *netdev;
01956 
01957         netdev = last_opened_netdev();
01958         if ( ! netdev )
01959                 return NULL;
01960 
01961         return efi_snp_demux ( netdev );
01962 }
01963 
01964 /**
01965  * Add to SNP claimed/released count
01966  *
01967  * @v delta             Claim count change
01968  */
01969 void efi_snp_add_claim ( int delta ) {
01970         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
01971         struct efi_snp_device *snpdev;
01972 
01973         /* Raise TPL if we are about to claim devices */
01974         if ( ! efi_snp_claimed )
01975                 efi_snp_old_tpl = bs->RaiseTPL ( TPL_CALLBACK );
01976 
01977         /* Claim SNP devices */
01978         efi_snp_claimed += delta;
01979         assert ( efi_snp_claimed >= 0 );
01980 
01981         /* Update SNP mode state for each interface */
01982         list_for_each_entry ( snpdev, &efi_snp_devices, list )
01983                 efi_snp_set_state ( snpdev );
01984 
01985         /* Restore TPL if we have released devices */
01986         if ( ! efi_snp_claimed )
01987                 bs->RestoreTPL ( efi_snp_old_tpl );
01988 }