iPXE
Data Structures | Functions | Variables
efi_pxe.c File Reference

EFI PXE base code protocol. More...

#include <string.h>
#include <errno.h>
#include <ipxe/refcnt.h>
#include <ipxe/list.h>
#include <ipxe/netdevice.h>
#include <ipxe/fakedhcp.h>
#include <ipxe/process.h>
#include <ipxe/uri.h>
#include <ipxe/in.h>
#include <ipxe/socket.h>
#include <ipxe/tcpip.h>
#include <ipxe/xferbuf.h>
#include <ipxe/open.h>
#include <ipxe/dhcppkt.h>
#include <ipxe/udp.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/efi_snp.h>
#include <ipxe/efi/efi_pxe.h>
#include <ipxe/efi/Protocol/PxeBaseCode.h>
#include <ipxe/efi/Protocol/AppleNetBoot.h>
#include <usr/ifmgmt.h>
#include <config/general.h>

Go to the source code of this file.

Data Structures

struct  efi_pxe
 A PXE base code. More...
struct  sockaddr_efi
 An EFI socket address. More...
struct  efi_pxe_udp_pseudo_header
 EFI UDP pseudo-header. More...

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static void efi_pxe_free (struct refcnt *refcnt)
 Free PXE base code.
static LIST_HEAD (efi_pxes)
 List of PXE base codes.
static struct efi_pxeefi_pxe_find (EFI_HANDLE handle)
 Locate PXE base code.
static void efi_pxe_ip_sockaddr (struct efi_pxe *pxe, EFI_IP_ADDRESS *ip, struct sockaddr *sa)
 Populate socket address from EFI IP address.
static const char * efi_pxe_ip_ntoa (struct efi_pxe *pxe, EFI_IP_ADDRESS *ip)
 Transcribe EFI IP address (for debugging)
static int efi_pxe_ip (struct efi_pxe *pxe)
 Populate local IP address.
static int efi_pxe_ip_filter (struct efi_pxe *pxe, EFI_IP_ADDRESS *ip)
 Check if IP address matches filter.
static int efi_pxe_buf_realloc (struct xfer_buffer *xferbuf __unused, size_t len __unused)
 Reallocate PXE data transfer buffer.
static void efi_pxe_buf_write (struct xfer_buffer *xferbuf, size_t offset, const void *data, size_t len)
 Write data to PXE data transfer buffer.
static void efi_pxe_tftp_close (struct efi_pxe *pxe, int rc)
 Close PXE (M)TFTP download interface.
static size_t efi_pxe_tftp_window (struct efi_pxe *pxe)
 Check PXE (M)TFTP download flow control window.
static int efi_pxe_tftp_deliver (struct efi_pxe *pxe, struct io_buffer *iobuf, struct xfer_metadata *meta)
 Receive new PXE (M)TFTP download data.
static int efi_pxe_tftp_open (struct efi_pxe *pxe, EFI_IP_ADDRESS *ip, const char *filename)
 Open (M)TFTP download interface.
static void efi_pxe_udp_close (struct efi_pxe *pxe, int rc)
 Close UDP interface.
static int efi_pxe_udp_deliver (struct efi_pxe *pxe, struct io_buffer *iobuf, struct xfer_metadata *meta)
 Receive UDP packet.
static int efi_pxe_udp_open (struct efi_pxe *pxe)
 Open UDP interface.
static void efi_pxe_udp_schedule_close (struct efi_pxe *pxe)
 Schedule close of UDP interface.
static void efi_pxe_udp_scheduled_close (struct efi_pxe *pxe)
 Scheduled close of UDP interface.
static const char * efi_pxe_fake_name (struct efi_pxe *pxe, EFI_PXE_BASE_CODE_PACKET *packet)
 Name fake DHCP packet.
static BOOLEAN efi_pxe_fake (struct efi_pxe *pxe, int(*fake)(struct net_device *netdev, void *data, size_t len), EFI_PXE_BASE_CODE_PACKET *packet)
 Construct fake DHCP packet and flag.
static void efi_pxe_fake_all (struct efi_pxe *pxe)
 Construct fake DHCP packets.
static EFI_STATUS EFIAPI efi_pxe_start (EFI_PXE_BASE_CODE_PROTOCOL *base, BOOLEAN use_ipv6)
 Start PXE base code.
static EFI_STATUS EFIAPI efi_pxe_stop (EFI_PXE_BASE_CODE_PROTOCOL *base)
 Stop PXE base code.
static EFI_STATUS EFIAPI efi_pxe_dhcp (EFI_PXE_BASE_CODE_PROTOCOL *base, BOOLEAN sort)
 Perform DHCP.
static EFI_STATUS EFIAPI efi_pxe_discover (EFI_PXE_BASE_CODE_PROTOCOL *base, UINT16 type, UINT16 *layer, BOOLEAN bis, EFI_PXE_BASE_CODE_DISCOVER_INFO *info)
 Perform boot server discovery.
static EFI_STATUS EFIAPI efi_pxe_mtftp (EFI_PXE_BASE_CODE_PROTOCOL *base, EFI_PXE_BASE_CODE_TFTP_OPCODE opcode, VOID *data, BOOLEAN overwrite, UINT64 *len, UINTN *blksize, EFI_IP_ADDRESS *ip, UINT8 *filename, EFI_PXE_BASE_CODE_MTFTP_INFO *info, BOOLEAN callback)
 Perform (M)TFTP.
static EFI_STATUS EFIAPI efi_pxe_udp_write (EFI_PXE_BASE_CODE_PROTOCOL *base, UINT16 flags, EFI_IP_ADDRESS *dest_ip, EFI_PXE_BASE_CODE_UDP_PORT *dest_port, EFI_IP_ADDRESS *gateway, EFI_IP_ADDRESS *src_ip, EFI_PXE_BASE_CODE_UDP_PORT *src_port, UINTN *hdr_len, VOID *hdr, UINTN *len, VOID *data)
 Transmit UDP packet.
static EFI_STATUS EFIAPI efi_pxe_udp_read (EFI_PXE_BASE_CODE_PROTOCOL *base, UINT16 flags, EFI_IP_ADDRESS *dest_ip, EFI_PXE_BASE_CODE_UDP_PORT *dest_port, EFI_IP_ADDRESS *src_ip, EFI_PXE_BASE_CODE_UDP_PORT *src_port, UINTN *hdr_len, VOID *hdr, UINTN *len, VOID *data)
 Receive UDP packet.
static EFI_STATUS EFIAPI efi_pxe_set_ip_filter (EFI_PXE_BASE_CODE_PROTOCOL *base, EFI_PXE_BASE_CODE_IP_FILTER *filter)
 Set receive filter.
static EFI_STATUS EFIAPI efi_pxe_arp (EFI_PXE_BASE_CODE_PROTOCOL *base, EFI_IP_ADDRESS *ip, EFI_MAC_ADDRESS *mac)
 Resolve MAC address.
static EFI_STATUS EFIAPI efi_pxe_set_parameters (EFI_PXE_BASE_CODE_PROTOCOL *base, BOOLEAN *autoarp, BOOLEAN *sendguid, UINT8 *ttl, UINT8 *tos, BOOLEAN *callback)
 Set parameters.
static EFI_STATUS EFIAPI efi_pxe_set_station_ip (EFI_PXE_BASE_CODE_PROTOCOL *base, EFI_IP_ADDRESS *ip, EFI_IP_ADDRESS *netmask)
 Set IP address.
static EFI_STATUS EFIAPI efi_pxe_set_packets (EFI_PXE_BASE_CODE_PROTOCOL *base, BOOLEAN *dhcpdisc_ok, BOOLEAN *dhcpack_ok, BOOLEAN *proxyoffer_ok, BOOLEAN *pxebsdisc_ok, BOOLEAN *pxebsack_ok, BOOLEAN *pxebsbis_ok, EFI_PXE_BASE_CODE_PACKET *dhcpdisc, EFI_PXE_BASE_CODE_PACKET *dhcpack, EFI_PXE_BASE_CODE_PACKET *proxyoffer, EFI_PXE_BASE_CODE_PACKET *pxebsdisc, EFI_PXE_BASE_CODE_PACKET *pxebsack, EFI_PXE_BASE_CODE_PACKET *pxebsbis)
 Update cached DHCP packets.
static EFI_STATUS EFIAPI efi_apple_get_response (EFI_PXE_BASE_CODE_PACKET *packet, UINTN *len, VOID *data)
 Get DHCP/BSDP response.
static EFI_STATUS EFIAPI efi_apple_get_dhcp_response (EFI_APPLE_NET_BOOT_PROTOCOL *apple, UINTN *len, VOID *data)
 Get DHCP response.
static EFI_STATUS EFIAPI efi_apple_get_bsdp_response (EFI_APPLE_NET_BOOT_PROTOCOL *apple, UINTN *len, VOID *data)
 Get BSDP response.
int efi_pxe_install (EFI_HANDLE handle, struct net_device *netdev)
 Install PXE base code protocol.
void efi_pxe_uninstall (EFI_HANDLE handle)
 Uninstall PXE base code protocol.

Variables

static struct
xfer_buffer_operations 
efi_pxe_buf_operations
 PXE data transfer buffer operations.
static struct interface_operation efi_pxe_tftp_operations []
 PXE file data transfer interface operations.
static struct interface_descriptor efi_pxe_tftp_desc
 PXE file data transfer interface descriptor.
static struct interface_operation efi_pxe_udp_operations []
 PXE UDP interface operations.
static struct interface_descriptor efi_pxe_udp_desc
 PXE UDP interface descriptor.
static struct process_descriptor efi_pxe_process_desc
 UDP close process descriptor.
static EFI_PXE_BASE_CODE_PROTOCOL efi_pxe_base_code_protocol
 PXE base code protocol.
static EFI_APPLE_NET_BOOT_PROTOCOL efi_apple_net_boot_protocol
 Apple NetBoot protocol.

Detailed Description

EFI PXE base code protocol.

Definition in file efi_pxe.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
static void efi_pxe_free ( struct refcnt refcnt) [static]

Free PXE base code.

Parameters:
refcntReference count

Definition at line 115 of file efi_pxe.c.

References container_of, free, efi_pxe::netdev, and netdev_put().

Referenced by efi_pxe_install().

                                                   {
        struct efi_pxe *pxe = container_of ( refcnt, struct efi_pxe, refcnt );

        netdev_put ( pxe->netdev );
        free ( pxe );
}
static LIST_HEAD ( efi_pxes  ) [static]

List of PXE base codes.

static struct efi_pxe* efi_pxe_find ( EFI_HANDLE  handle) [static, read]

Locate PXE base code.

Parameters:
handleEFI handle
Return values:
pxePXE base code, or NULL

Definition at line 131 of file efi_pxe.c.

References efi_pxe::handle, efi_pxe::list, list_for_each_entry, and NULL.

Referenced by efi_pxe_uninstall().

                                                           {
        struct efi_pxe *pxe;

        /* Locate base code */
        list_for_each_entry ( pxe, &efi_pxes, list ) {
                if ( pxe->handle == handle )
                        return pxe;
        }

        return NULL;
}
static void efi_pxe_ip_sockaddr ( struct efi_pxe pxe,
EFI_IP_ADDRESS ip,
struct sockaddr sa 
) [static]

Populate socket address from EFI IP address.

Parameters:
pxePXE base code
ipEFI IP address
saSocket address to fill in

Definition at line 190 of file efi_pxe.c.

References container_of, net_device::index, memcpy(), memset(), efi_pxe::net, net_protocol::net_addr_len, efi_pxe::netdev, sockaddr::sa_family, tcpip_net_protocol::sa_family, and efi_pxe::tcpip.

Referenced by efi_pxe_tftp_open(), and efi_pxe_udp_write().

                                                        {
        union {
                struct sockaddr sa;
                struct sockaddr_efi se;
        } *sockaddr = container_of ( sa, typeof ( *sockaddr ), sa );

        /* Initialise socket address */
        memset ( sockaddr, 0, sizeof ( *sockaddr ) );
        sockaddr->sa.sa_family = pxe->tcpip->sa_family;
        memcpy ( &sockaddr->se.se_addr, ip, pxe->net->net_addr_len );
        sockaddr->se.se_scope_id = pxe->netdev->index;
}
static const char* efi_pxe_ip_ntoa ( struct efi_pxe pxe,
EFI_IP_ADDRESS ip 
) [static]

Transcribe EFI IP address (for debugging)

Parameters:
pxePXE base code
ipEFI IP address
Return values:
textTranscribed IP address

Definition at line 211 of file efi_pxe.c.

References efi_pxe::net, and net_protocol::ntoa.

Referenced by efi_pxe_arp(), efi_pxe_discover(), efi_pxe_mtftp(), efi_pxe_set_ip_filter(), efi_pxe_set_station_ip(), efi_pxe_tftp_open(), efi_pxe_udp_read(), and efi_pxe_udp_write().

                                                           {

        return pxe->net->ntoa ( ip );
}
static int efi_pxe_ip ( struct efi_pxe pxe) [static]

Populate local IP address.

Parameters:
pxePXE base code
Return values:
rcReturn status code

Definition at line 223 of file efi_pxe.c.

References ENOTSUP, fetch_ipv4_setting(), memcpy(), memset(), efi_pxe::mode, efi_pxe::netdev, netdev_settings(), EFI_PXE_BASE_CODE_MODE::StationIp, EFI_PXE_BASE_CODE_MODE::SubnetMask, and EFI_PXE_BASE_CODE_MODE::UsingIpv6.

Referenced by efi_pxe_dhcp(), and efi_pxe_start().

                                              {
        EFI_PXE_BASE_CODE_MODE *mode = &pxe->mode;
        struct in_addr address;
        struct in_addr netmask;

        /* It's unclear which of the potentially many IPv6 addresses
         * is supposed to be used.
         */
        if ( mode->UsingIpv6 )
                return -ENOTSUP;

        /* Fetch IP address and subnet mask */
        fetch_ipv4_setting ( netdev_settings ( pxe->netdev ), &ip_setting,
                             &address );
        fetch_ipv4_setting ( netdev_settings ( pxe->netdev ), &netmask_setting,
                             &netmask );

        /* Populate IP address and subnet mask */
        memset ( &mode->StationIp, 0, sizeof ( mode->StationIp ) );
        memcpy ( &mode->StationIp, &address, sizeof ( address ) );
        memset ( &mode->SubnetMask, 0, sizeof ( mode->SubnetMask ) );
        memcpy ( &mode->SubnetMask, &netmask, sizeof ( netmask ) );

        return 0;
}
static int efi_pxe_ip_filter ( struct efi_pxe pxe,
EFI_IP_ADDRESS ip 
) [static]

Check if IP address matches filter.

Parameters:
pxePXE base code
ipEFI IP address
Return values:
is_matchIP address matches filter

Definition at line 256 of file efi_pxe.c.

References container_of, EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST, EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS, EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST, EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP, filter, EFI_PXE_BASE_CODE_IP_FILTER::Filters, IN6_IS_ADDR_MULTICAST, IN_IS_MULTICAST, INADDR_BROADCAST, ip, EFI_PXE_BASE_CODE_IP_FILTER::IpCnt, EFI_PXE_BASE_CODE_MODE::IpFilter, EFI_PXE_BASE_CODE_IP_FILTER::IpList, memcmp(), efi_pxe::mode, efi_pxe::net, net_protocol::net_addr_len, EFI_PXE_BASE_CODE_MODE::StationIp, u, and EFI_PXE_BASE_CODE_MODE::UsingIpv6.

Referenced by efi_pxe_udp_read().

                                                                         {
        EFI_PXE_BASE_CODE_MODE *mode = &pxe->mode;
        EFI_PXE_BASE_CODE_IP_FILTER *filter = &mode->IpFilter;
        uint8_t filters = filter->Filters;
        union {
                EFI_IP_ADDRESS ip;
                struct in_addr in;
                struct in6_addr in6;
        } *u = container_of ( ip, typeof ( *u ), ip );
        size_t addr_len = pxe->net->net_addr_len;
        unsigned int i;

        /* Match everything, if applicable */
        if ( filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS )
                return 1;

        /* Match all multicasts, if applicable */
        if ( filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST ) {
                if ( mode->UsingIpv6 ) {
                        if ( IN6_IS_ADDR_MULTICAST ( &u->in6 ) )
                                return 1;
                } else {
                        if ( IN_IS_MULTICAST ( u->in.s_addr ) )
                                return 1;
                }
        }

        /* Match IPv4 broadcasts, if applicable */
        if ( filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST ) {
                if ( ( ! mode->UsingIpv6 ) &&
                     ( u->in.s_addr == INADDR_BROADCAST ) )
                        return 1;
        }

        /* Match station address, if applicable */
        if ( filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP ) {
                if ( memcmp ( ip, &mode->StationIp, addr_len ) == 0 )
                        return 1;
        }

        /* Match explicit addresses, if applicable */
        for ( i = 0 ; i < filter->IpCnt ; i++ ) {
                if ( memcmp ( ip, &filter->IpList[i], addr_len ) == 0 )
                        return 1;
        }

        return 0;
}
static int efi_pxe_buf_realloc ( struct xfer_buffer *xferbuf  __unused,
size_t len  __unused 
) [static]

Reallocate PXE data transfer buffer.

Parameters:
xferbufData transfer buffer
lenNew length (or zero to free buffer)
Return values:
rcReturn status code

Definition at line 319 of file efi_pxe.c.

References ERANGE.

                                                       {

        /* Can never reallocate: return EFI_BUFFER_TOO_SMALL */
        return -ERANGE;
}
static void efi_pxe_buf_write ( struct xfer_buffer xferbuf,
size_t  offset,
const void *  data,
size_t  len 
) [static]

Write data to PXE data transfer buffer.

Parameters:
xferbufData transfer buffer
offsetStarting offset
dataData to copy
lenLength of data

Definition at line 334 of file efi_pxe.c.

References xfer_buffer::data, and memcpy().

                                                               {

        /* Copy data to buffer */
        memcpy ( ( xferbuf->data + offset ), data, len );
}
static void efi_pxe_tftp_close ( struct efi_pxe pxe,
int  rc 
) [static]

Close PXE (M)TFTP download interface.

Parameters:
pxePXE base code
rcReason for close

Definition at line 360 of file efi_pxe.c.

References intf_restart(), efi_pxe::rc, rc, and efi_pxe::tftp.

Referenced by efi_pxe_mtftp(), efi_pxe_stop(), and efi_pxe_tftp_deliver().

                                                               {

        /* Restart interface */
        intf_restart ( &pxe->tftp, rc );

        /* Record overall status */
        pxe->rc = rc;
}
static size_t efi_pxe_tftp_window ( struct efi_pxe pxe) [static]

Check PXE (M)TFTP download flow control window.

Parameters:
pxePXE base code
Return values:
lenLength of window

Definition at line 375 of file efi_pxe.c.

References efi_pxe::blksize.

                                                          {

        /* Return requested blocksize */
        return pxe->blksize;
}
static int efi_pxe_tftp_deliver ( struct efi_pxe pxe,
struct io_buffer iobuf,
struct xfer_metadata meta 
) [static]

Receive new PXE (M)TFTP download data.

Parameters:
pxePXE base code
iobufI/O buffer
metaTransfer metadata
Return values:
rcReturn status code

Definition at line 389 of file efi_pxe.c.

References efi_pxe::buf, efi_pxe_tftp_close(), iob_disown, rc, and xferbuf_deliver().

                                                               {
        int rc;

        /* Deliver to data transfer buffer */
        if ( ( rc = xferbuf_deliver ( &pxe->buf, iob_disown ( iobuf ),
                                      meta ) ) != 0 )
                goto err_deliver;

        return 0;

 err_deliver:
        efi_pxe_tftp_close ( pxe, rc );
        return rc;
}
static int efi_pxe_tftp_open ( struct efi_pxe pxe,
EFI_IP_ADDRESS ip,
const char *  filename 
) [static]

Open (M)TFTP download interface.

Parameters:
pxePXE base code
ipEFI IP address
filenameFilename
Return values:
rcReturn status code

Definition at line 425 of file efi_pxe.c.

References DBGC, efi_pxe_ip_ntoa(), efi_pxe_ip_sockaddr(), ENOTSUP, efi_pxe::name, pxe_uri(), rc, strerror(), efi_pxe::tftp, uri_put(), and xfer_open_uri().

Referenced by efi_pxe_mtftp().

                                                      {
        struct sockaddr server;
        struct uri *uri;
        int rc;

        /* Parse server address and filename */
        efi_pxe_ip_sockaddr ( pxe, ip, &server );
        uri = pxe_uri ( &server, filename );
        if ( ! uri ) {
                DBGC ( pxe, "PXE %s could not parse %s:%s\n", pxe->name,
                       efi_pxe_ip_ntoa ( pxe, ip ), filename );
                rc = -ENOTSUP;
                goto err_parse;
        }

        /* Open URI */
        if ( ( rc = xfer_open_uri ( &pxe->tftp, uri ) ) != 0 ) {
                DBGC ( pxe, "PXE %s could not open: %s\n",
                       pxe->name, strerror ( rc ) );
                goto err_open;
        }

 err_open:
        uri_put ( uri );
 err_parse:
        return rc;
}
static void efi_pxe_udp_close ( struct efi_pxe pxe,
int  rc 
) [static]

Close UDP interface.

Parameters:
pxePXE base code
rcReason for close

Definition at line 477 of file efi_pxe.c.

References efi_snp_release(), free_iob(), intf_restart(), io_buffer::list, list_del, list_for_each_entry_safe, efi_pxe::process, process_del(), process_running(), efi_pxe::queue, and efi_pxe::udp.

Referenced by efi_pxe_stop(), and efi_pxe_udp_scheduled_close().

                                                              {
        struct io_buffer *iobuf;
        struct io_buffer *tmp;

        /* Release our claim on SNP devices, if applicable */
        if ( process_running ( &pxe->process ) )
                efi_snp_release();

        /* Stop process */
        process_del ( &pxe->process );

        /* Restart UDP interface */
        intf_restart ( &pxe->udp, rc );

        /* Flush any received UDP packets */
        list_for_each_entry_safe ( iobuf, tmp, &pxe->queue, list ) {
                list_del ( &iobuf->list );
                free_iob ( iobuf );
        }
}
static int efi_pxe_udp_deliver ( struct efi_pxe pxe,
struct io_buffer iobuf,
struct xfer_metadata meta 
) [static]

Receive UDP packet.

Parameters:
pxePXE base code
iobufI/O buffer
metaData transfer metadata
Return values:
rcReturn status code

Definition at line 506 of file efi_pxe.c.

References assert, xfer_metadata::dest, efi_pxe_udp_pseudo_header::dest_port, ENOTSUP, free_iob(), iob_ensure_headroom(), iob_push, io_buffer::list, list_add_tail, memcpy(), efi_pxe_udp_pseudo_header::net, net_protocol::net_addr_len, tcpip_net_protocol::net_protocol, ntohs, NULL, efi_pxe::queue, rc, sockaddr_efi::se_addr, sockaddr_efi::se_family, sockaddr_efi::se_port, xfer_metadata::src, efi_pxe_udp_pseudo_header::src_port, and tcpip_net_protocol().

                                                              {
        struct sockaddr_efi *se_src;
        struct sockaddr_efi *se_dest;
        struct tcpip_net_protocol *tcpip;
        struct net_protocol *net;
        struct efi_pxe_udp_pseudo_header *pshdr;
        size_t addr_len;
        size_t pshdr_len;
        int rc;

        /* Sanity checks */
        assert ( meta != NULL );
        se_src = ( ( struct sockaddr_efi * ) meta->src );
        assert ( se_src != NULL );
        se_dest = ( ( struct sockaddr_efi * ) meta->dest );
        assert ( se_dest != NULL );
        assert ( se_src->se_family == se_dest->se_family );

        /* Determine protocol */
        tcpip = tcpip_net_protocol ( se_src->se_family );
        if ( ! tcpip ) {
                rc = -ENOTSUP;
                goto err_unsupported;
        }
        net = tcpip->net_protocol;
        addr_len = net->net_addr_len;

        /* Construct pseudo-header */
        pshdr_len = ( sizeof ( *pshdr ) + ( 2 * addr_len ) );
        if ( ( rc = iob_ensure_headroom ( iobuf, pshdr_len ) ) != 0 )
                goto err_headroom;
        memcpy ( iob_push ( iobuf, addr_len ), &se_src->se_addr, addr_len );
        memcpy ( iob_push ( iobuf, addr_len ), &se_dest->se_addr, addr_len );
        pshdr = iob_push ( iobuf, sizeof ( *pshdr ) );
        pshdr->net = net;
        pshdr->dest_port = ntohs ( se_dest->se_port );
        pshdr->src_port = ntohs ( se_src->se_port );

        /* Add to queue */
        list_add_tail ( &iobuf->list, &pxe->queue );

        return 0;

 err_unsupported:
 err_headroom:
        free_iob ( iobuf );
        return rc;
}
static int efi_pxe_udp_open ( struct efi_pxe pxe) [static]

Open UDP interface.

Parameters:
pxePXE base code
Return values:
rcReturn status code

Definition at line 572 of file efi_pxe.c.

References DBGC, efi_snp_claim(), efi_pxe::name, efi_pxe::process, process_del(), process_running(), rc, strerror(), efi_pxe::udp, and udp_open_promisc().

Referenced by efi_pxe_udp_read(), and efi_pxe_udp_write().

                                                    {
        int rc;

        /* If interface is already open, then cancel the scheduled close */
        if ( process_running ( &pxe->process ) ) {
                process_del ( &pxe->process );
                return 0;
        }

        /* Open promiscuous UDP interface */
        if ( ( rc = udp_open_promisc ( &pxe->udp ) ) != 0 ) {
                DBGC ( pxe, "PXE %s could not open UDP connection: %s\n",
                       pxe->name, strerror ( rc ) );
                return rc;
        }

        /* Claim network devices */
        efi_snp_claim();

        return 0;
}
static void efi_pxe_udp_schedule_close ( struct efi_pxe pxe) [static]

Schedule close of UDP interface.

Parameters:
pxePXE base code

Definition at line 599 of file efi_pxe.c.

References efi_pxe::process, and process_add().

Referenced by efi_pxe_udp_read(), and efi_pxe_udp_write().

                                                               {

        /* The EFI PXE base code protocol does not provide any
         * explicit UDP open/close methods.  To avoid the overhead of
         * reopening a socket for each read/write operation, we start
         * a process which will close the socket immediately if the
         * next call into iPXE is anything other than a UDP
         * read/write.
         */
        process_add ( &pxe->process );
}
static void efi_pxe_udp_scheduled_close ( struct efi_pxe pxe) [static]

Scheduled close of UDP interface.

Parameters:
pxePXE base code

Definition at line 616 of file efi_pxe.c.

References efi_pxe_udp_close().

                                                                {

        /* Close UDP interface */
        efi_pxe_udp_close ( pxe, 0 );
}
static const char* efi_pxe_fake_name ( struct efi_pxe pxe,
EFI_PXE_BASE_CODE_PACKET packet 
) [static]

Name fake DHCP packet.

Parameters:
pxePXE base code
packetPacket
Return values:
nameName of packet

Definition at line 640 of file efi_pxe.c.

References EFI_PXE_BASE_CODE_MODE::DhcpAck, EFI_PXE_BASE_CODE_MODE::DhcpDiscover, efi_pxe::mode, EFI_PXE_BASE_CODE_MODE::ProxyOffer, EFI_PXE_BASE_CODE_MODE::PxeBisReply, EFI_PXE_BASE_CODE_MODE::PxeDiscover, and EFI_PXE_BASE_CODE_MODE::PxeReply.

Referenced by efi_pxe_fake().

                                                                           {
        EFI_PXE_BASE_CODE_MODE *mode = &pxe->mode;

        if ( packet == &mode->DhcpDiscover ) {
                return "DhcpDiscover";
        } else if ( packet == &mode->DhcpAck ) {
                return "DhcpAck";
        } else if ( packet == &mode->ProxyOffer ) {
                return "ProxyOffer";
        } else if ( packet == &mode->PxeDiscover ) {
                return "PxeDiscover";
        } else if ( packet == &mode->PxeReply ) {
                return "PxeReply";
        } else if ( packet == &mode->PxeBisReply ) {
                return "PxeBisReply";
        } else {
                return "<UNKNOWN>";
        }
}
static BOOLEAN efi_pxe_fake ( struct efi_pxe pxe,
int(*)(struct net_device *netdev, void *data, size_t len fake,
EFI_PXE_BASE_CODE_PACKET packet 
) [static]

Construct fake DHCP packet and flag.

Parameters:
pxePXE base code
fakeFake packet constructor
packetPacket to fill in
Return values:
existsPacket existence flag

Definition at line 669 of file efi_pxe.c.

References EFI_PXE_BASE_CODE_DHCPV4_PACKET::BootpOpcode, container_of, DBGC, DHCP_END, dhcppkt_init(), dhcppkt_len(), EFI_PXE_BASE_CODE_PACKET::Dhcpv4, efi_pxe_fake_name(), FALSE, len, efi_pxe::mode, efi_pxe::name, efi_pxe::netdev, op, EFI_PXE_BASE_CODE_PACKET::Raw, rc, strerror(), TRUE, and EFI_PXE_BASE_CODE_MODE::UsingIpv6.

Referenced by efi_pxe_fake_all().

                                                                 {
        EFI_PXE_BASE_CODE_MODE *mode = &pxe->mode;
        struct dhcp_packet dhcppkt;
        struct dhcphdr *dhcphdr;
        unsigned int len;
        int rc;

        /* The fake packet constructors do not support IPv6 */
        if ( mode->UsingIpv6 )
                return FALSE;

        /* Attempt to construct packet */
        if ( ( rc = fake ( pxe->netdev, packet, sizeof ( *packet ) ) != 0 ) ) {
                DBGC ( pxe, "PXE %s could not fake %s: %s\n", pxe->name,
                       efi_pxe_fake_name ( pxe, packet ), strerror ( rc ) );
                return FALSE;
        }

        /* The WDS bootstrap wdsmgfw.efi has a buggy DHCPv4 packet
         * parser which does not correctly handle DHCP padding bytes.
         * Specifically, if a padding byte (i.e. a zero) is
         * encountered, the parse will first increment the pointer by
         * one to skip over the padding byte but will then drop into
         * the code path for handling normal options, which increments
         * the pointer by two to skip over the (already-skipped) type
         * field and the (non-existent) length field.
         *
         * The upshot of this bug in WDS is that the parser will fail
         * with an error 0xc0000023 if the number of spare bytes after
         * the end of the options is not an exact multiple of three.
         *
         * Work around this buggy parser by adding an explicit
         * DHCP_END tag.
         */
        dhcphdr = container_of ( &packet->Dhcpv4.BootpOpcode,
                                 struct dhcphdr, op );
        dhcppkt_init ( &dhcppkt, dhcphdr, sizeof ( *packet ) );
        len = dhcppkt_len ( &dhcppkt );
        if ( len < sizeof ( *packet ) )
                packet->Raw[len] = DHCP_END;

        return TRUE;
}
static void efi_pxe_fake_all ( struct efi_pxe pxe) [static]
static EFI_STATUS EFIAPI efi_pxe_start ( EFI_PXE_BASE_CODE_PROTOCOL base,
BOOLEAN  use_ipv6 
) [static]

Start PXE base code.

Parameters:
basePXE base code protocol
use_ipv6Use IPv6
Return values:
efircEFI status code

Definition at line 750 of file efi_pxe.c.

References AF_INET, AF_INET6, EFI_PXE_BASE_CODE_MODE::AutoArp, container_of, DBGC, DEFAULT_ToS, DEFAULT_TTL, EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST, EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS, EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST, EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP, efi_pxe_fake_all(), efi_pxe_ip(), EFI_UNSUPPORTED, EFI_PXE_BASE_CODE_IP_FILTER::Filters, EFI_PXE_BASE_CODE_MODE::IpFilter, EFI_PXE_BASE_CODE_MODE::Ipv6Available, EFI_PXE_BASE_CODE_MODE::Ipv6Supported, memset(), efi_pxe::mode, efi_pxe::name, efi_pxe::net, tcpip_net_protocol::net_protocol, net_protocol::ntoa, NULL, rc, socket_family_name(), EFI_PXE_BASE_CODE_MODE::Started, EFI_PXE_BASE_CODE_MODE::StationIp, efi_pxe::tcpip, tcpip_net_protocol(), EFI_PXE_BASE_CODE_MODE::ToS, TRUE, EFI_PXE_BASE_CODE_MODE::TTL, and EFI_PXE_BASE_CODE_MODE::UsingIpv6.

Referenced by efi_pxe_install().

                                                            {
        struct efi_pxe *pxe = container_of ( base, struct efi_pxe, base );
        EFI_PXE_BASE_CODE_MODE *mode = &pxe->mode;
        struct tcpip_net_protocol *ipv6 = tcpip_net_protocol ( AF_INET6 );
        sa_family_t family = ( use_ipv6 ? AF_INET6 : AF_INET );
        int rc;

        DBGC ( pxe, "PXE %s START %s\n", pxe->name, ( ipv6 ? "IPv6" : "IPv4" ));

        /* Initialise mode structure */
        memset ( mode, 0, sizeof ( *mode ) );
        mode->AutoArp = TRUE;
        mode->TTL = DEFAULT_TTL;
        mode->ToS = DEFAULT_ToS;
        mode->IpFilter.Filters =
                ( EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP |
                  EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST |
                  EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS |
                  EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST );

        /* Check for IPv4/IPv6 support */
        mode->Ipv6Supported = ( ipv6 != NULL );
        mode->Ipv6Available = ( ipv6 != NULL );
        pxe->tcpip = tcpip_net_protocol ( family );
        if ( ! pxe->tcpip ) {
                DBGC ( pxe, "PXE %s has no support for %s\n",
                       pxe->name, socket_family_name ( family ) );
                return EFI_UNSUPPORTED;
        }
        pxe->net = pxe->tcpip->net_protocol;
        mode->UsingIpv6 = use_ipv6;

        /* Populate station IP address */
        if ( ( rc = efi_pxe_ip ( pxe ) ) != 0 )
                return rc;

        /* Construct fake DHCP packets */
        efi_pxe_fake_all ( pxe );

        /* Record that base code is started */
        mode->Started = TRUE;
        DBGC ( pxe, "PXE %s using %s\n",
               pxe->name, pxe->net->ntoa ( &mode->StationIp ) );

        return 0;
}

Stop PXE base code.

Parameters:
basePXE base code protocol
Return values:
efircEFI status code

Definition at line 804 of file efi_pxe.c.

References container_of, DBGC, efi_pxe_tftp_close(), efi_pxe_udp_close(), FALSE, efi_pxe::mode, efi_pxe::name, and EFI_PXE_BASE_CODE_MODE::Started.

Referenced by efi_pxe_uninstall().

                                                                           {
        struct efi_pxe *pxe = container_of ( base, struct efi_pxe, base );
        EFI_PXE_BASE_CODE_MODE *mode = &pxe->mode;

        DBGC ( pxe, "PXE %s STOP\n", pxe->name );

        /* Record that base code is stopped */
        mode->Started = FALSE;

        /* Close TFTP */
        efi_pxe_tftp_close ( pxe, 0 );

        /* Close UDP */
        efi_pxe_udp_close ( pxe, 0 );

        return 0;
}
static EFI_STATUS EFIAPI efi_pxe_dhcp ( EFI_PXE_BASE_CODE_PROTOCOL base,
BOOLEAN  sort 
) [static]

Perform DHCP.

Parameters:
basePXE base code protocol
sortOffers should be sorted
Return values:
efircEFI status code

Definition at line 829 of file efi_pxe.c.

References container_of, DBGC, efi_pxe_fake_all(), efi_pxe_ip(), efi_snp_claim(), efi_snp_release(), EFIRC, ETIMEDOUT, efi_pxe::name, netdev, efi_pxe::netdev, netdev_configuration_in_progress(), netdev_configuration_ok(), netdev_configure_all(), rc, step(), and strerror().

                                                       {
        struct efi_pxe *pxe = container_of ( base, struct efi_pxe, base );
        struct net_device *netdev = pxe->netdev;
        int rc;

        DBGC ( pxe, "PXE %s DHCP %s\n",
               pxe->name, ( sort ? "sorted" : "unsorted" ) );

        /* Claim network devices */
        efi_snp_claim();

        /* Initiate configuration */
        if ( ( rc = netdev_configure_all ( netdev ) ) != 0 ) {
                DBGC ( pxe, "PXE %s could not initiate configuration: %s\n",
                       pxe->name, strerror ( rc ) );
                goto err_configure;
        }

        /* Wait for configuration to complete (or time out) */
        while ( netdev_configuration_in_progress ( netdev ) )
                step();

        /* Report timeout if configuration failed */
        if ( ! netdev_configuration_ok ( netdev ) ) {
                rc = -ETIMEDOUT;
                goto err_timeout;
        }

        /* Update station IP address */
        if ( ( rc = efi_pxe_ip ( pxe ) ) != 0 )
                goto err_ip;

        /* Update faked DHCP packets */
        efi_pxe_fake_all ( pxe );

 err_ip:
 err_timeout:
 err_configure:
        efi_snp_release();
        return EFIRC ( rc );
}
static EFI_STATUS EFIAPI efi_pxe_discover ( EFI_PXE_BASE_CODE_PROTOCOL base,
UINT16  type,
UINT16 layer,
BOOLEAN  bis,
EFI_PXE_BASE_CODE_DISCOVER_INFO info 
) [static]

Perform boot server discovery.

Parameters:
basePXE base code protocol
typeBoot server type
layerBoot server layer
bisUse boot integrity services
infoAdditional information
Return values:
efircEFI status code

Definition at line 883 of file efi_pxe.c.

References EFI_PXE_BASE_CODE_SRVLIST::AcceptAnyResponse, container_of, DBGC, efi_pxe_ip_ntoa(), EFI_UNSUPPORTED, ip, EFI_PXE_BASE_CODE_SRVLIST::IpAddr, EFI_PXE_BASE_CODE_DISCOVER_INFO::IpCnt, EFI_PXE_BASE_CODE_DISCOVER_INFO::MustUseList, efi_pxe::name, EFI_PXE_BASE_CODE_DISCOVER_INFO::ServerMCastIp, EFI_PXE_BASE_CODE_DISCOVER_INFO::SrvList, EFI_PXE_BASE_CODE_SRVLIST::Type, EFI_PXE_BASE_CODE_DISCOVER_INFO::UseBCast, EFI_PXE_BASE_CODE_DISCOVER_INFO::UseMCast, and EFI_PXE_BASE_CODE_DISCOVER_INFO::UseUCast.

                                                                        {
        struct efi_pxe *pxe = container_of ( base, struct efi_pxe, base );
        EFI_IP_ADDRESS *ip;
        unsigned int i;

        DBGC ( pxe, "PXE %s DISCOVER type %d layer %d%s\n",
               pxe->name, type, *layer, ( bis ? " bis" : "" ) );
        if ( info ) {
                DBGC ( pxe, "%s%s%s%s %s",
                       ( info->UseMCast ? " mcast" : "" ),
                       ( info->UseBCast ? " bcast" : "" ),
                       ( info->UseUCast ? " ucast" : "" ),
                       ( info->MustUseList ? " list" : "" ),
                       efi_pxe_ip_ntoa ( pxe, &info->ServerMCastIp ) );
                for ( i = 0 ; i < info->IpCnt ; i++ ) {
                        ip = &info->SrvList[i].IpAddr;
                        DBGC ( pxe, " %d%s:%s", info->SrvList[i].Type,
                               ( info->SrvList[i].AcceptAnyResponse ?
                                 ":any" : "" ), efi_pxe_ip_ntoa ( pxe, ip ) );
                }
        }
        DBGC ( pxe, "\n" );

        /* Not used by any bootstrap I can find to test with */
        return EFI_UNSUPPORTED;
}
static EFI_STATUS EFIAPI efi_pxe_mtftp ( EFI_PXE_BASE_CODE_PROTOCOL base,
EFI_PXE_BASE_CODE_TFTP_OPCODE  opcode,
VOID data,
BOOLEAN  overwrite,
UINT64 len,
UINTN blksize,
EFI_IP_ADDRESS ip,
UINT8 filename,
EFI_PXE_BASE_CODE_MTFTP_INFO info,
BOOLEAN  callback 
) [static]

Perform (M)TFTP.

Parameters:
basePXE base code protocol
opcodeTFTP opcode
dataData buffer
overwriteOverwrite file
lenLength of data buffer
blksizeBlock size
ipServer address
filenameFilename
infoAdditional information
callbackPass packets to callback instead of data buffer
Return values:
efircEFI status code

Definition at line 927 of file efi_pxe.c.

References efi_pxe::blksize, blksize, efi_pxe::buf, container_of, EFI_PXE_BASE_CODE_MTFTP_INFO::CPort, xfer_buffer::data, data, DBGC, EFI_PXE_BASE_CODE_MTFTP_READ_FILE, EFI_PXE_BASE_CODE_TFTP_READ_FILE, efi_pxe_ip_ntoa(), efi_pxe_tftp_close(), efi_pxe_tftp_open(), efi_snp_claim(), efi_snp_release(), EFIRC, EINPROGRESS, ENOTSUP, xfer_buffer::len, len, EFI_PXE_BASE_CODE_MTFTP_INFO::ListenTimeout, EFI_PXE_BASE_CODE_MTFTP_INFO::MCastIp, efi_pxe::name, efi_pxe::rc, rc, EFI_PXE_BASE_CODE_MTFTP_INFO::SPort, step(), strerror(), and EFI_PXE_BASE_CODE_MTFTP_INFO::TransmitTimeout.

                                                                       {
        struct efi_pxe *pxe = container_of ( base, struct efi_pxe, base );
        int rc;

        DBGC ( pxe, "PXE %s MTFTP %d%s %p+%llx", pxe->name, opcode,
               ( overwrite ? " overwrite" : "" ), data, *len );
        if ( blksize )
                DBGC ( pxe, " blksize %zd", ( ( size_t ) *blksize ) );
        DBGC ( pxe, " %s:%s", efi_pxe_ip_ntoa ( pxe, ip ), filename );
        if ( info ) {
                DBGC ( pxe, " %s:%d:%d:%d:%d",
                       efi_pxe_ip_ntoa ( pxe, &info->MCastIp ),
                       info->CPort, info->SPort, info->ListenTimeout,
                       info->TransmitTimeout );
        }
        DBGC ( pxe, "%s\n", ( callback ? " callback" : "" ) );

        /* Fail unless operation is supported */
        if ( ! ( ( opcode == EFI_PXE_BASE_CODE_TFTP_READ_FILE ) ||
                 ( opcode == EFI_PXE_BASE_CODE_MTFTP_READ_FILE ) ) ) {
                DBGC ( pxe, "PXE %s unsupported MTFTP opcode %d\n",
                       pxe->name, opcode );
                rc = -ENOTSUP;
                goto err_opcode;
        }

        /* Claim network devices */
        efi_snp_claim();

        /* Determine block size.  Ignore the requested block size
         * unless we are using callbacks, since limiting HTTP to a
         * 512-byte TCP window is not sensible.
         */
        pxe->blksize = ( ( callback && blksize ) ? *blksize : -1UL );

        /* Initialise data transfer buffer */
        pxe->buf.data = data;
        pxe->buf.len = *len;

        /* Open download */
        if ( ( rc = efi_pxe_tftp_open ( pxe, ip,
                                        ( ( const char * ) filename ) ) ) != 0 )
                goto err_open;

        /* Wait for download to complete */
        pxe->rc = -EINPROGRESS;
        while ( pxe->rc == -EINPROGRESS )
                step();
        if ( ( rc = pxe->rc ) != 0 ) {
                DBGC ( pxe, "PXE %s download failed: %s\n",
                       pxe->name, strerror ( rc ) );
                goto err_download;
        }

 err_download:
        efi_pxe_tftp_close ( pxe, rc );
 err_open:
        efi_snp_release();
 err_opcode:
        return EFIRC ( rc );
}
static EFI_STATUS EFIAPI efi_pxe_udp_write ( EFI_PXE_BASE_CODE_PROTOCOL base,
UINT16  flags,
EFI_IP_ADDRESS dest_ip,
EFI_PXE_BASE_CODE_UDP_PORT dest_port,
EFI_IP_ADDRESS gateway,
EFI_IP_ADDRESS src_ip,
EFI_PXE_BASE_CODE_UDP_PORT src_port,
UINTN hdr_len,
VOID hdr,
UINTN len,
VOID data 
) [static]

Transmit UDP packet.

Parameters:
basePXE base code protocol
flagsOperation flags
dest_ipDestination address
dest_portDestination port
gatewayGateway address
src_ipSource address
src_portSource port
hdr_lenHeader length
hdrHeader data
lenLength
dataData
Return values:
efircEFI status code

Definition at line 1010 of file efi_pxe.c.

References container_of, DBGC, DBGC2, xfer_metadata::dest, dest, EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT, EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT, efi_pxe_ip_ntoa(), efi_pxe_ip_sockaddr(), efi_pxe_udp_open(), efi_pxe_udp_schedule_close(), EFIRC, ENOMEM, free_iob(), htons, iob_disown, iob_put, memcpy(), memset(), efi_pxe::mode, efi_pxe::name, xfer_metadata::netdev, efi_pxe::netdev, ntohs, random(), rc, xfer_metadata::src, src, EFI_PXE_BASE_CODE_MODE::StationIp, strerror(), efi_pxe::udp, xfer_alloc_iob(), and xfer_deliver().

                                                                        {
        struct efi_pxe *pxe = container_of ( base, struct efi_pxe, base );
        EFI_PXE_BASE_CODE_MODE *mode = &pxe->mode;
        struct io_buffer *iobuf;
        struct xfer_metadata meta;
        union {
                struct sockaddr_tcpip st;
                struct sockaddr sa;
        } dest;
        union {
                struct sockaddr_tcpip st;
                struct sockaddr sa;
        } src;
        int rc;

        DBGC2 ( pxe, "PXE %s UDP WRITE ", pxe->name );
        if ( src_ip )
                DBGC2 ( pxe, "%s", efi_pxe_ip_ntoa ( pxe, src_ip ) );
        DBGC2 ( pxe, ":" );
        if ( src_port &&
             ( ! ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT ) ) ) {
                DBGC2 ( pxe, "%d", *src_port );
        } else {
                DBGC2 ( pxe, "*" );
        }
        DBGC2 ( pxe, "->%s:%d", efi_pxe_ip_ntoa ( pxe, dest_ip ), *dest_port );
        if ( gateway )
                DBGC2 ( pxe, " via %s", efi_pxe_ip_ntoa ( pxe, gateway ) );
        if ( hdr_len )
                DBGC2 ( pxe, " %p+%zx", hdr, ( ( size_t ) *hdr_len ) );
        DBGC2 ( pxe, " %p+%zx", data, ( ( size_t ) *len ) );
        if ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT )
                DBGC2 ( pxe, " frag" );
        DBGC2 ( pxe, "\n" );

        /* Open UDP connection (if applicable) */
        if ( ( rc = efi_pxe_udp_open ( pxe ) ) != 0 )
                goto err_open;

        /* Construct destination address */
        efi_pxe_ip_sockaddr ( pxe, dest_ip, &dest.sa );
        dest.st.st_port = htons ( *dest_port );

        /* Construct source address */
        efi_pxe_ip_sockaddr ( pxe, ( src_ip ? src_ip : &mode->StationIp ),
                              &src.sa );
        if ( src_port &&
             ( ! ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT ) ) ) {
                src.st.st_port = htons ( *src_port );
        } else {
                /* The API does not allow for a sensible concept of
                 * binding to a local port, so just use a random value.
                 */
                src.st.st_port = ( random() | htons ( 1024 ) );
                if ( src_port )
                        *src_port = ntohs ( src.st.st_port );
        }

        /* Allocate I/O buffer */
        iobuf = xfer_alloc_iob ( &pxe->udp,
                                 ( *len + ( hdr_len ? *hdr_len : 0 ) ) );
        if ( ! iobuf ) {
                rc = -ENOMEM;
                goto err_alloc;
        }

        /* Populate I/O buffer */
        if ( hdr_len )
                memcpy ( iob_put ( iobuf, *hdr_len ), hdr, *hdr_len );
        memcpy ( iob_put ( iobuf, *len ), data, *len );

        /* Construct metadata */
        memset ( &meta, 0, sizeof ( meta ) );
        meta.src = &src.sa;
        meta.dest = &dest.sa;
        meta.netdev = pxe->netdev;

        /* Deliver I/O buffer */
        if ( ( rc = xfer_deliver ( &pxe->udp, iob_disown ( iobuf ),
                                   &meta ) ) != 0 ) {
                DBGC ( pxe, "PXE %s could not transmit: %s\n",
                       pxe->name, strerror ( rc ) );
                goto err_deliver;
        }

 err_deliver:
        free_iob ( iobuf );
 err_alloc:
        efi_pxe_udp_schedule_close ( pxe );
 err_open:
        return EFIRC ( rc );
}
static EFI_STATUS EFIAPI efi_pxe_udp_read ( EFI_PXE_BASE_CODE_PROTOCOL base,
UINT16  flags,
EFI_IP_ADDRESS dest_ip,
EFI_PXE_BASE_CODE_UDP_PORT dest_port,
EFI_IP_ADDRESS src_ip,
EFI_PXE_BASE_CODE_UDP_PORT src_port,
UINTN hdr_len,
VOID hdr,
UINTN len,
VOID data 
) [static]

Receive UDP packet.

Parameters:
basePXE base code protocol
flagsOperation flags
dest_ipDestination address
dest_portDestination port
src_ipSource address
src_portSource port
hdr_lenHeader length
hdrHeader data
lenLength
dataData
Return values:
efircEFI status code

Definition at line 1124 of file efi_pxe.c.

References container_of, io_buffer::data, DBGC2, efi_pxe_udp_pseudo_header::dest_port, EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP, EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT, EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP, EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT, EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER, efi_pxe_ip_filter(), efi_pxe_ip_ntoa(), efi_pxe_udp_open(), efi_pxe_udp_schedule_close(), EFIRC, ERANGE, ETIMEDOUT, free_iob(), iob_len(), iob_pull, len, io_buffer::list, list_del, list_empty, list_first_entry, memcmp(), memcpy(), net_protocol::name, efi_pxe::name, efi_pxe::net, efi_pxe_udp_pseudo_header::net, net_protocol::net_addr_len, net_protocol::ntoa, efi_pxe::queue, rc, efi_pxe_udp_pseudo_header::src_port, and step().

                                                                       {
        struct efi_pxe *pxe = container_of ( base, struct efi_pxe, base );
        struct io_buffer *iobuf;
        struct efi_pxe_udp_pseudo_header *pshdr;
        EFI_IP_ADDRESS *actual_dest_ip;
        EFI_IP_ADDRESS *actual_src_ip;
        size_t addr_len;
        size_t frag_len;
        int rc;

        DBGC2 ( pxe, "PXE %s UDP READ ", pxe->name );
        if ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER ) {
                DBGC2 ( pxe, "(filter)" );
        } else if ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP ) {
                DBGC2 ( pxe, "*" );
        } else if ( dest_ip ) {
                DBGC2 ( pxe, "%s", efi_pxe_ip_ntoa ( pxe, dest_ip ) );
        }
        DBGC2 ( pxe, ":" );
        if ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT ) {
                DBGC2 ( pxe, "*" );
        } else if ( dest_port ) {
                DBGC2 ( pxe, "%d", *dest_port );
        } else {
                DBGC2 ( pxe, "<NULL>" );
        }
        DBGC2 ( pxe, "<-" );
        if ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP ) {
                DBGC2 ( pxe, "*" );
        } else if ( src_ip ) {
                DBGC2 ( pxe, "%s", efi_pxe_ip_ntoa ( pxe, src_ip ) );
        } else {
                DBGC2 ( pxe, "<NULL>" );
        }
        DBGC2 ( pxe, ":" );
        if ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT ) {
                DBGC2 ( pxe, "*" );
        } else if ( src_port ) {
                DBGC2 ( pxe, "%d", *src_port );
        } else {
                DBGC2 ( pxe, "<NULL>" );
        }
        if ( hdr_len )
                DBGC2 ( pxe, " %p+%zx", hdr, ( ( size_t ) *hdr_len ) );
        DBGC2 ( pxe, " %p+%zx\n", data, ( ( size_t ) *len ) );

        /* Open UDP connection (if applicable) */
        if ( ( rc = efi_pxe_udp_open ( pxe ) ) != 0 )
                goto err_open;

        /* Try receiving a packet, if the queue is empty */
        if ( list_empty ( &pxe->queue ) )
                step();

        /* Remove first packet from the queue */
        iobuf = list_first_entry ( &pxe->queue, struct io_buffer, list );
        if ( ! iobuf ) {
                rc = -ETIMEDOUT; /* "no packet" */
                goto err_empty;
        }
        list_del ( &iobuf->list );

        /* Strip pseudo-header */
        pshdr = iobuf->data;
        addr_len = ( pshdr->net->net_addr_len );
        iob_pull ( iobuf, sizeof ( *pshdr ) );
        actual_dest_ip = iobuf->data;
        iob_pull ( iobuf, addr_len );
        actual_src_ip = iobuf->data;
        iob_pull ( iobuf, addr_len );
        DBGC2 ( pxe, "PXE %s UDP RX %s:%d", pxe->name,
                pshdr->net->ntoa ( actual_dest_ip ), pshdr->dest_port );
        DBGC2 ( pxe, "<-%s:%d len %#zx\n", pshdr->net->ntoa ( actual_src_ip ),
                pshdr->src_port, iob_len ( iobuf ) );

        /* Filter based on network-layer protocol */
        if ( pshdr->net != pxe->net ) {
                DBGC2 ( pxe, "PXE %s filtered out %s packet\n",
                        pxe->name, pshdr->net->name );
                rc = -ETIMEDOUT; /* "no packet" */
                goto err_filter;
        }

        /* Filter based on port numbers */
        if ( ! ( ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT ) ||
                 ( dest_port && ( *dest_port == pshdr->dest_port ) ) ) ) {
                DBGC2 ( pxe, "PXE %s filtered out destination port %d\n",
                        pxe->name, pshdr->dest_port );
                rc = -ETIMEDOUT; /* "no packet" */
                goto err_filter;
        }
        if ( ! ( ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT ) ||
                 ( src_port && ( *src_port == pshdr->src_port ) ) ) ) {
                DBGC2 ( pxe, "PXE %s filtered out source port %d\n",
                        pxe->name, pshdr->src_port );
                rc = -ETIMEDOUT; /* "no packet" */
                goto err_filter;
        }

        /* Filter based on source IP address */
        if ( ! ( ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP ) ||
                 ( src_ip &&
                   ( memcmp ( src_ip, actual_src_ip, addr_len ) == 0 ) ) ) ) {
                DBGC2 ( pxe, "PXE %s filtered out source IP %s\n",
                        pxe->name, pshdr->net->ntoa ( actual_src_ip ) );
                rc = -ETIMEDOUT; /* "no packet" */
                goto err_filter;
        }

        /* Filter based on destination IP address */
        if ( ! ( ( ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER ) &&
                   efi_pxe_ip_filter ( pxe, actual_dest_ip ) ) ||
                 ( ( ! ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER ) ) &&
                   ( ( flags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP ) ||
                        ( dest_ip && ( memcmp ( dest_ip, actual_dest_ip,
                                                addr_len ) == 0 ) ) ) ) ) ) {
                DBGC2 ( pxe, "PXE %s filtered out destination IP %s\n",
                        pxe->name, pshdr->net->ntoa ( actual_dest_ip ) );
                rc = -ETIMEDOUT; /* "no packet" */
                goto err_filter;
        }

        /* Fill in addresses and port numbers */
        if ( dest_ip )
                memcpy ( dest_ip, actual_dest_ip, addr_len );
        if ( dest_port )
                *dest_port = pshdr->dest_port;
        if ( src_ip )
                memcpy ( src_ip, actual_src_ip, addr_len );
        if ( src_port )
                *src_port = pshdr->src_port;

        /* Fill in header, if applicable */
        if ( hdr_len ) {
                frag_len = iob_len ( iobuf );
                if ( frag_len > *hdr_len )
                        frag_len = *hdr_len;
                memcpy ( hdr, iobuf->data, frag_len );
                iob_pull ( iobuf, frag_len );
                *hdr_len = frag_len;
        }

        /* Fill in data buffer */
        frag_len = iob_len ( iobuf );
        if ( frag_len > *len )
                frag_len = *len;
        memcpy ( data, iobuf->data, frag_len );
        iob_pull ( iobuf, frag_len );
        *len = frag_len;

        /* Check for overflow */
        if ( iob_len ( iobuf ) ) {
                rc = -ERANGE;
                goto err_too_short;
        }

        /* Success */
        rc = 0;

 err_too_short:
 err_filter:
        free_iob ( iobuf );
 err_empty:
        efi_pxe_udp_schedule_close ( pxe );
 err_open:
        return EFIRC ( rc );
}

Set receive filter.

Parameters:
basePXE base code protocol
filterReceive filter
Return values:
efircEFI status code

Definition at line 1305 of file efi_pxe.c.

References container_of, DBGC, efi_pxe_ip_ntoa(), EFI_PXE_BASE_CODE_IP_FILTER::Filters, EFI_PXE_BASE_CODE_IP_FILTER::IpCnt, EFI_PXE_BASE_CODE_MODE::IpFilter, EFI_PXE_BASE_CODE_IP_FILTER::IpList, memcpy(), efi_pxe::mode, and efi_pxe::name.

                                                              {
        struct efi_pxe *pxe = container_of ( base, struct efi_pxe, base );
        EFI_PXE_BASE_CODE_MODE *mode = &pxe->mode;
        unsigned int i;

        DBGC ( pxe, "PXE %s SET IP FILTER %02x",
               pxe->name, filter->Filters );
        for ( i = 0 ; i < filter->IpCnt ; i++ ) {
                DBGC ( pxe, " %s",
                       efi_pxe_ip_ntoa ( pxe, &filter->IpList[i] ) );
        }
        DBGC ( pxe, "\n" );

        /* Update filter */
        memcpy ( &mode->IpFilter, filter, sizeof ( mode->IpFilter ) );

        return 0;
}
static EFI_STATUS EFIAPI efi_pxe_arp ( EFI_PXE_BASE_CODE_PROTOCOL base,
EFI_IP_ADDRESS ip,
EFI_MAC_ADDRESS mac 
) [static]

Resolve MAC address.

Parameters:
basePXE base code protocol
ipIP address
macMAC address to fill in
Return values:
efircEFI status code

Definition at line 1333 of file efi_pxe.c.

References container_of, DBGC, efi_pxe_ip_ntoa(), EFI_UNSUPPORTED, and efi_pxe::name.

                                                              {
        struct efi_pxe *pxe = container_of ( base, struct efi_pxe, base );

        DBGC ( pxe, "PXE %s ARP %s %p\n",
               pxe->name, efi_pxe_ip_ntoa ( pxe, ip ), mac );

        /* Not used by any bootstrap I can find to test with */
        return EFI_UNSUPPORTED;
}
static EFI_STATUS EFIAPI efi_pxe_set_parameters ( EFI_PXE_BASE_CODE_PROTOCOL base,
BOOLEAN autoarp,
BOOLEAN sendguid,
UINT8 ttl,
UINT8 tos,
BOOLEAN callback 
) [static]

Set parameters.

Parameters:
basePXE base code protocol
autoarpAutomatic ARP packet generation
sendguidSend GUID as client hardware address
ttlIP time to live
tosIP type of service
callbackMake callbacks
Return values:
efircEFI status code

Definition at line 1357 of file efi_pxe.c.

References EFI_PXE_BASE_CODE_MODE::AutoArp, container_of, DBGC, EFI_PXE_BASE_CODE_MODE::MakeCallbacks, efi_pxe::mode, efi_pxe::name, EFI_PXE_BASE_CODE_MODE::SendGUID, EFI_PXE_BASE_CODE_MODE::ToS, and EFI_PXE_BASE_CODE_MODE::TTL.

                                                         {
        struct efi_pxe *pxe = container_of ( base, struct efi_pxe, base );
        EFI_PXE_BASE_CODE_MODE *mode = &pxe->mode;

        DBGC ( pxe, "PXE %s SET PARAMETERS", pxe->name );
        if ( autoarp )
                DBGC ( pxe, " %s", ( *autoarp ? "autoarp" : "noautoarp" ) );
        if ( sendguid )
                DBGC ( pxe, " %s", ( *sendguid ? "sendguid" : "sendmac" ) );
        if ( ttl )
                DBGC ( pxe, " ttl %d", *ttl );
        if ( tos )
                DBGC ( pxe, " tos %d", *tos );
        if ( callback ) {
                DBGC ( pxe, " %s",
                       ( *callback ? "callback" : "nocallback" ) );
        }
        DBGC ( pxe, "\n" );

        /* Update parameters */
        if ( autoarp )
                mode->AutoArp = *autoarp;
        if ( sendguid )
                mode->SendGUID = *sendguid;
        if ( ttl )
                mode->TTL = *ttl;
        if ( tos )
                mode->ToS = *tos;
        if ( callback )
                mode->MakeCallbacks = *callback;

        return 0;
}

Set IP address.

Parameters:
basePXE base code protocol
ipIP address
netmaskSubnet mask
Return values:
efircEFI status code

Definition at line 1402 of file efi_pxe.c.

References container_of, DBGC, efi_pxe_ip_ntoa(), memcpy(), efi_pxe::mode, efi_pxe::name, EFI_PXE_BASE_CODE_MODE::StationIp, and EFI_PXE_BASE_CODE_MODE::SubnetMask.

                                                                       {
        struct efi_pxe *pxe = container_of ( base, struct efi_pxe, base );
        EFI_PXE_BASE_CODE_MODE *mode = &pxe->mode;

        DBGC ( pxe, "PXE %s SET STATION IP ", pxe->name );
        if ( ip )
                DBGC ( pxe, "%s", efi_pxe_ip_ntoa ( pxe, ip ) );
        if ( netmask )
                DBGC ( pxe, "/%s", efi_pxe_ip_ntoa ( pxe, netmask ) );
        DBGC ( pxe, "\n" );

        /* Update IP address and netmask */
        if ( ip )
                memcpy ( &mode->StationIp, ip, sizeof ( mode->StationIp ) );
        if ( netmask )
                memcpy ( &mode->SubnetMask, netmask, sizeof (mode->SubnetMask));

        return 0;
}
static EFI_STATUS EFIAPI efi_pxe_set_packets ( EFI_PXE_BASE_CODE_PROTOCOL base,
BOOLEAN dhcpdisc_ok,
BOOLEAN dhcpack_ok,
BOOLEAN proxyoffer_ok,
BOOLEAN pxebsdisc_ok,
BOOLEAN pxebsack_ok,
BOOLEAN pxebsbis_ok,
EFI_PXE_BASE_CODE_PACKET dhcpdisc,
EFI_PXE_BASE_CODE_PACKET dhcpack,
EFI_PXE_BASE_CODE_PACKET proxyoffer,
EFI_PXE_BASE_CODE_PACKET pxebsdisc,
EFI_PXE_BASE_CODE_PACKET pxebsack,
EFI_PXE_BASE_CODE_PACKET pxebsbis 
) [static]

Update cached DHCP packets.

Parameters:
basePXE base code protocol
dhcpdisc_okDHCPDISCOVER is valid
dhcpack_okDHCPACK received
proxyoffer_okProxyDHCPOFFER received
pxebsdisc_okPxeBsDISCOVER valid
pxebsack_okPxeBsACK received
pxebsbis_okPxeBsBIS received
dhcpdiscDHCPDISCOVER packet
dhcpackDHCPACK packet
proxyofferProxyDHCPOFFER packet
pxebsdiscPxeBsDISCOVER packet
pxebsackPxeBsACK packet
pxebsbisPxeBsBIS packet
Return values:
efircEFI status code

Definition at line 1442 of file efi_pxe.c.

References container_of, DBGC, EFI_PXE_BASE_CODE_MODE::DhcpAck, EFI_PXE_BASE_CODE_MODE::DhcpAckReceived, EFI_PXE_BASE_CODE_MODE::DhcpDiscover, EFI_PXE_BASE_CODE_MODE::DhcpDiscoverValid, memcpy(), efi_pxe::mode, efi_pxe::name, EFI_PXE_BASE_CODE_MODE::ProxyOffer, EFI_PXE_BASE_CODE_MODE::ProxyOfferReceived, EFI_PXE_BASE_CODE_MODE::PxeBisReply, EFI_PXE_BASE_CODE_MODE::PxeBisReplyReceived, EFI_PXE_BASE_CODE_MODE::PxeDiscover, EFI_PXE_BASE_CODE_MODE::PxeDiscoverValid, EFI_PXE_BASE_CODE_MODE::PxeReply, and EFI_PXE_BASE_CODE_MODE::PxeReplyReceived.

                                                           {
        struct efi_pxe *pxe = container_of ( base, struct efi_pxe, base );
        EFI_PXE_BASE_CODE_MODE *mode = &pxe->mode;

        DBGC ( pxe, "PXE %s SET PACKETS\n", pxe->name );

        /* Update fake packet flags */
        if ( dhcpdisc_ok )
                mode->DhcpDiscoverValid = *dhcpdisc_ok;
        if ( dhcpack_ok )
                mode->DhcpAckReceived = *dhcpack_ok;
        if ( proxyoffer_ok )
                mode->ProxyOfferReceived = *proxyoffer_ok;
        if ( pxebsdisc_ok )
                mode->PxeDiscoverValid = *pxebsdisc_ok;
        if ( pxebsack_ok )
                mode->PxeReplyReceived = *pxebsack_ok;
        if ( pxebsbis_ok )
                mode->PxeBisReplyReceived = *pxebsbis_ok;

        /* Update fake packet contents */
        if ( dhcpdisc )
                memcpy ( &mode->DhcpDiscover, dhcpdisc, sizeof ( *dhcpdisc ) );
        if ( dhcpack )
                memcpy ( &mode->DhcpAck, dhcpack, sizeof ( *dhcpack ) );
        if ( proxyoffer )
                memcpy ( &mode->ProxyOffer, proxyoffer, sizeof ( *proxyoffer ));
        if ( pxebsdisc )
                memcpy ( &mode->PxeDiscover, pxebsdisc, sizeof ( *pxebsdisc ) );
        if ( pxebsack )
                memcpy ( &mode->PxeReply, pxebsack, sizeof ( *pxebsack ) );
        if ( pxebsbis )
                memcpy ( &mode->PxeBisReply, pxebsbis, sizeof ( *pxebsbis ) );

        return 0;
}
static EFI_STATUS EFIAPI efi_apple_get_response ( EFI_PXE_BASE_CODE_PACKET packet,
UINTN len,
VOID data 
) [static]

Get DHCP/BSDP response.

Parameters:
packetPacket
lenLength of data buffer
dataData buffer
Return values:
efircEFI status code

Definition at line 1520 of file efi_pxe.c.

References EFI_BUFFER_TOO_SMALL, EFI_SUCCESS, and memcpy().

Referenced by efi_apple_get_bsdp_response(), and efi_apple_get_dhcp_response().

                                      {

        /* Check length */
        if ( *len < sizeof ( *packet ) ) {
                *len = sizeof ( *packet );
                return EFI_BUFFER_TOO_SMALL;
        }

        /* Copy packet */
        memcpy ( data, packet, sizeof ( *packet ) );
        *len = sizeof ( *packet );

        return EFI_SUCCESS;
}
static EFI_STATUS EFIAPI efi_apple_get_dhcp_response ( EFI_APPLE_NET_BOOT_PROTOCOL apple,
UINTN len,
VOID data 
) [static]

Get DHCP response.

Parameters:
appleApple NetBoot protocol
lenLength of data buffer
dataData buffer
Return values:
efircEFI status code

Definition at line 1545 of file efi_pxe.c.

References container_of, EFI_PXE_BASE_CODE_MODE::DhcpAck, efi_apple_get_response(), and efi_pxe::mode.

                                                       {
        struct efi_pxe *pxe = container_of ( apple, struct efi_pxe, apple );

        return efi_apple_get_response ( &pxe->mode.DhcpAck, len, data );
}
static EFI_STATUS EFIAPI efi_apple_get_bsdp_response ( EFI_APPLE_NET_BOOT_PROTOCOL apple,
UINTN len,
VOID data 
) [static]

Get BSDP response.

Parameters:
appleApple NetBoot protocol
lenLength of data buffer
dataData buffer
Return values:
efircEFI status code

Definition at line 1561 of file efi_pxe.c.

References container_of, efi_apple_get_response(), efi_pxe::mode, and EFI_PXE_BASE_CODE_MODE::PxeReply.

                                                       {
        struct efi_pxe *pxe = container_of ( apple, struct efi_pxe, apple );

        return efi_apple_get_response ( &pxe->mode.PxeReply, len, data );
}
int efi_pxe_install ( EFI_HANDLE  handle,
struct net_device netdev 
)

Install PXE base code protocol.

Parameters:
handleEFI handle
netdevUnderlying network device
Return values:
rcReturn status code

Definition at line 1588 of file efi_pxe.c.

References AF_INET6, efi_pxe::apple, efi_pxe::base, EFI_SYSTEM_TABLE::BootServices, efi_pxe::buf, DBGC, EEFI, efi_apple_net_boot_protocol_guid, efi_handle_name(), efi_pxe_base_code_protocol_guid, efi_pxe_buf_operations, efi_pxe_free(), efi_pxe_start(), efi_systab, ENOMEM, FALSE, fetch_ipv4_setting(), efi_pxe::handle, handle, INIT_LIST_HEAD, EFI_BOOT_SERVICES::InstallMultipleProtocolInterfaces, intf_init(), efi_pxe::list, list_add_tail, memcpy(), efi_pxe::mode, _EFI_PXE_BASE_CODE_PROTOCOL::Mode, efi_pxe::name, net_device::name, efi_pxe::netdev, netdev_get(), netdev_settings(), NULL, xfer_buffer::op, efi_pxe::process, process_init_stopped(), efi_pxe::queue, rc, ref_init, ref_put, efi_pxe::refcnt, in_addr::s_addr, strerror(), tcpip_net_protocol(), efi_pxe::tftp, efi_pxe::udp, EFI_BOOT_SERVICES::UninstallMultipleProtocolInterfaces, and zalloc().

Referenced by efi_image_exec().

                                                                     {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        struct tcpip_net_protocol *ipv6 = tcpip_net_protocol ( AF_INET6 );
        struct efi_pxe *pxe;
        struct in_addr ip;
        BOOLEAN use_ipv6;
        EFI_STATUS efirc;
        int rc;

        /* Allocate and initialise structure */
        pxe = zalloc ( sizeof ( *pxe ) );
        if ( ! pxe ) {
                rc = -ENOMEM;
                goto err_alloc;
        }
        ref_init ( &pxe->refcnt, efi_pxe_free );
        pxe->netdev = netdev_get ( netdev );
        pxe->name = netdev->name;
        pxe->handle = handle;
        memcpy ( &pxe->base, &efi_pxe_base_code_protocol, sizeof ( pxe->base ));
        pxe->base.Mode = &pxe->mode;
        memcpy ( &pxe->apple, &efi_apple_net_boot_protocol,
                 sizeof ( pxe->apple ) );
        pxe->buf.op = &efi_pxe_buf_operations;
        intf_init ( &pxe->tftp, &efi_pxe_tftp_desc, &pxe->refcnt );
        intf_init ( &pxe->udp, &efi_pxe_udp_desc, &pxe->refcnt );
        INIT_LIST_HEAD ( &pxe->queue );
        process_init_stopped ( &pxe->process, &efi_pxe_process_desc,
                               &pxe->refcnt );

        /* Crude heuristic: assume that we prefer to use IPv4 if we
         * have an IPv4 address for the network device, otherwise
         * prefer IPv6 (if available).
         */
        fetch_ipv4_setting ( netdev_settings ( netdev ), &ip_setting, &ip );
        use_ipv6 = ( ip.s_addr ? FALSE : ( ipv6 != NULL ) );

        /* Start base code */
        efi_pxe_start ( &pxe->base, use_ipv6 );

        /* Install PXE base code protocol */
        if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
                        &handle,
                        &efi_pxe_base_code_protocol_guid, &pxe->base,
                        &efi_apple_net_boot_protocol_guid, &pxe->apple,
                        NULL ) ) != 0 ) {
                rc = -EEFI ( efirc );
                DBGC ( pxe, "PXE %s could not install base code protocol: %s\n",
                       pxe->name, strerror ( rc ) );
                goto err_install_protocol;
        }

        /* Transfer reference to list and return */
        list_add_tail ( &pxe->list, &efi_pxes );
        DBGC ( pxe, "PXE %s installed for %s\n",
               pxe->name, efi_handle_name ( handle ) );
        return 0;

        bs->UninstallMultipleProtocolInterfaces (
                        handle,
                        &efi_pxe_base_code_protocol_guid, &pxe->base,
                        &efi_apple_net_boot_protocol_guid, &pxe->apple,
                        NULL );
 err_install_protocol:
        ref_put ( &pxe->refcnt );
 err_alloc:
        return rc;
}
void efi_pxe_uninstall ( EFI_HANDLE  handle)

Uninstall PXE base code protocol.

Parameters:
handleEFI handle

Definition at line 1662 of file efi_pxe.c.

References efi_pxe::apple, efi_pxe::base, EFI_SYSTEM_TABLE::BootServices, DBG, efi_apple_net_boot_protocol_guid, efi_handle_name(), efi_pxe_base_code_protocol_guid, efi_pxe_find(), efi_pxe_stop(), efi_systab, efi_pxe::list, list_del, NULL, ref_put, efi_pxe::refcnt, and EFI_BOOT_SERVICES::UninstallMultipleProtocolInterfaces.

Referenced by efi_image_exec().

                                             {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        struct efi_pxe *pxe;

        /* Locate PXE base code */
        pxe = efi_pxe_find ( handle );
        if ( ! handle ) {
                DBG ( "PXE could not find base code for %s\n",
                      efi_handle_name ( handle ) );
                return;
        }

        /* Stop base code */
        efi_pxe_stop ( &pxe->base );

        /* Uninstall PXE base code protocol */
        bs->UninstallMultipleProtocolInterfaces (
                        handle,
                        &efi_pxe_base_code_protocol_guid, &pxe->base,
                        &efi_apple_net_boot_protocol_guid, &pxe->apple,
                        NULL );

        /* Remove from list and drop list's reference */
        list_del ( &pxe->list );
        ref_put ( &pxe->refcnt );
}

Variable Documentation

Initial value:
 {
        .realloc = efi_pxe_buf_realloc,
        .write = efi_pxe_buf_write,
}

PXE data transfer buffer operations.

Definition at line 342 of file efi_pxe.c.

Referenced by efi_pxe_install().

Initial value:

PXE file data transfer interface operations.

Definition at line 407 of file efi_pxe.c.

Initial value:

PXE file data transfer interface descriptor.

Definition at line 414 of file efi_pxe.c.

Initial value:

PXE UDP interface operations.

Definition at line 557 of file efi_pxe.c.

Initial value:

PXE UDP interface descriptor.

Definition at line 563 of file efi_pxe.c.

Initial value:

UDP close process descriptor.

Definition at line 623 of file efi_pxe.c.

Initial value:
 {
        .Revision       = EFI_PXE_BASE_CODE_PROTOCOL_REVISION,
        .Start          = efi_pxe_start,
        .Stop           = efi_pxe_stop,
        .Dhcp           = efi_pxe_dhcp,
        .Discover       = efi_pxe_discover,
        .Mtftp          = efi_pxe_mtftp,
        .UdpWrite       = efi_pxe_udp_write,
        .UdpRead        = efi_pxe_udp_read,
        .SetIpFilter    = efi_pxe_set_ip_filter,
        .Arp            = efi_pxe_arp,
        .SetParameters  = efi_pxe_set_parameters,
        .SetStationIp   = efi_pxe_set_station_ip,
        .SetPackets     = efi_pxe_set_packets,
}

PXE base code protocol.

Definition at line 1488 of file efi_pxe.c.

Initial value:
 {
        .GetDhcpResponse = efi_apple_get_dhcp_response,
        .GetBsdpResponse = efi_apple_get_bsdp_response,
}

Apple NetBoot protocol.

Definition at line 1569 of file efi_pxe.c.