iPXE
Data Structures | Defines | Enumerations | Functions | Variables
pxe_preboot.c File Reference

PXE Preboot API. More...

#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <ipxe/uaccess.h>
#include <ipxe/dhcp.h>
#include <ipxe/fakedhcp.h>
#include <ipxe/device.h>
#include <ipxe/netdevice.h>
#include <ipxe/isapnp.h>
#include <ipxe/init.h>
#include <ipxe/if_ether.h>
#include <basemem_packet.h>
#include <biosint.h>
#include <rmsetjmp.h>
#include "pxe.h"
#include "pxe_call.h"

Go to the source code of this file.

Data Structures

union  pxe_cached_info
 A cached DHCP packet. More...
struct  pxe_dhcp_packet_creator
 A PXE DHCP packet creator. More...

Defines

#define cached_info   __use_data16 ( cached_info )

Enumerations

enum  pxe_cached_info_indices { CACHED_INFO_DHCPDISCOVER = ( PXENV_PACKET_TYPE_DHCP_DISCOVER - 1 ), CACHED_INFO_DHCPACK = ( PXENV_PACKET_TYPE_DHCP_ACK - 1 ), CACHED_INFO_BINL = ( PXENV_PACKET_TYPE_CACHED_REPLY - 1 ), NUM_CACHED_INFOS }
 Zero-based versions of PXENV_GET_CACHED_INFO::PacketType. More...

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static const char * pxenv_get_cached_info_name (int packet_type)
 Name PXENV_GET_CACHED_INFO packet type.
static union pxe_cached_info __bss16_array (cached_info,[NUM_CACHED_INFOS])
void pxe_fake_cached_info (void)
 Construct cached DHCP packets.
static PXENV_EXIT_t pxenv_unload_stack (struct s_PXENV_UNLOAD_STACK *unload_stack)
 UNLOAD BASE CODE STACK.
static PXENV_EXIT_t pxenv_get_cached_info (struct s_PXENV_GET_CACHED_INFO *get_cached_info)
static PXENV_EXIT_t pxenv_restart_tftp (struct s_PXENV_TFTP_READ_FILE *restart_tftp)
static PXENV_EXIT_t pxenv_start_undi (struct s_PXENV_START_UNDI *start_undi)
static PXENV_EXIT_t pxenv_stop_undi (struct s_PXENV_STOP_UNDI *stop_undi)
static PXENV_EXIT_t pxenv_start_base (struct s_PXENV_START_BASE *start_base)
static PXENV_EXIT_t pxenv_stop_base (struct s_PXENV_STOP_BASE *stop_base)

Variables

uint16_t isapnp_read_port
static struct
pxe_dhcp_packet_creator 
pxe_dhcp_packet_creators []
 PXE DHCP packet creators.
struct pxe_api_call
pxe_preboot_api[] 
__pxe_api_call
 PXE preboot API.

Detailed Description

PXE Preboot API.

Definition in file pxe_preboot.c.


Define Documentation

Definition at line 129 of file pxe_preboot.c.

Referenced by pxe_fake_cached_info(), and pxenv_get_cached_info().


Enumeration Type Documentation

Zero-based versions of PXENV_GET_CACHED_INFO::PacketType.

Enumerator:
CACHED_INFO_DHCPDISCOVER 
CACHED_INFO_DHCPACK 
CACHED_INFO_BINL 
NUM_CACHED_INFOS 

Definition at line 54 of file pxe_preboot.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
static const char* pxenv_get_cached_info_name ( int  packet_type) [inline, static]

Name PXENV_GET_CACHED_INFO packet type.

Parameters:
packet_typePacket type
Return values:
nameName of packet type

Definition at line 104 of file pxe_preboot.c.

References PXENV_PACKET_TYPE_CACHED_REPLY, PXENV_PACKET_TYPE_DHCP_ACK, and PXENV_PACKET_TYPE_DHCP_DISCOVER.

Referenced by pxenv_get_cached_info().

                                               {
        switch ( packet_type ) {
        case PXENV_PACKET_TYPE_DHCP_DISCOVER:
                return "DHCPDISCOVER";
        case PXENV_PACKET_TYPE_DHCP_ACK:
                return "DHCPACK";
        case PXENV_PACKET_TYPE_CACHED_REPLY:
                return "BINL";
        default:
                return "<INVALID>";
        }
}
static union pxe_cached_info __bss16_array ( cached_info  ) [static, write]
void pxe_fake_cached_info ( void  )

Construct cached DHCP packets.

Definition at line 135 of file pxe_preboot.c.

References assert, cached_info, pxe_dhcp_packet_creator::create, DBGC, info, memset(), NULL, pxe_dhcp_packet_creators, pxe_netdev, rc, and strerror().

Referenced by pxe_exec().

                                   {
        struct pxe_dhcp_packet_creator *creator;
        union pxe_cached_info *info;
        unsigned int i;
        int rc;

        /* Sanity check */
        assert ( pxe_netdev != NULL );

        /* Erase any stale packets */
        memset ( cached_info, 0, sizeof ( cached_info ) );

        /* Construct all DHCP packets */
        for ( i = 0 ; i < ( sizeof ( pxe_dhcp_packet_creators ) /
                            sizeof ( pxe_dhcp_packet_creators[0] ) ) ; i++ ) {

                /* Construct DHCP packet */
                creator = &pxe_dhcp_packet_creators[i];
                info = &cached_info[i];
                if ( ( rc = creator->create ( pxe_netdev, info,
                                              sizeof ( *info ) ) ) != 0 ) {
                        DBGC ( &pxe_netdev, " failed to build packet: %s\n",
                               strerror ( rc ) );
                        /* Continue constructing remaining packets */
                }
        }
}
static PXENV_EXIT_t pxenv_unload_stack ( struct s_PXENV_UNLOAD_STACK unload_stack) [static]

UNLOAD BASE CODE STACK.

Parameters:
None-
Return values:
...

Definition at line 171 of file pxe_preboot.c.

References DBGC, pxe_netdev, PXENV_EXIT_SUCCESS, PXENV_STATUS_SUCCESS, and s_PXENV_UNLOAD_STACK::Status.

                                                                 {
        DBGC ( &pxe_netdev, "PXENV_UNLOAD_STACK\n" );

        unload_stack->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
}
static PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO get_cached_info) [static]

Definition at line 183 of file pxe_preboot.c.

References __from_data16, s_PXENV_GET_CACHED_INFO::Buffer, buffer, s_PXENV_GET_CACHED_INFO::BufferLimit, s_PXENV_GET_CACHED_INFO::BufferSize, cached_info, copy_to_user(), DBGC, info, len, NUM_CACHED_INFOS, s_PXENV_GET_CACHED_INFO::PacketType, pxe_netdev, PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, pxenv_get_cached_info_name(), PXENV_STATUS_SUCCESS, PXENV_STATUS_UNSUPPORTED, real_to_user(), rm_ds, and s_PXENV_GET_CACHED_INFO::Status.

                                                                          {
        union pxe_cached_info *info;
        unsigned int idx;
        size_t len;
        userptr_t buffer;

        DBGC ( &pxe_netdev, "PXENV_GET_CACHED_INFO %s to %04x:%04x+%x",
               pxenv_get_cached_info_name ( get_cached_info->PacketType ),
               get_cached_info->Buffer.segment,
               get_cached_info->Buffer.offset, get_cached_info->BufferSize );

        /* Sanity check */
        idx = ( get_cached_info->PacketType - 1 );
        if ( idx >= NUM_CACHED_INFOS ) {
                DBGC ( &pxe_netdev, " bad PacketType %d\n",
                       get_cached_info->PacketType );
                get_cached_info->Status = PXENV_STATUS_UNSUPPORTED;
                return PXENV_EXIT_FAILURE;
        }
        info = &cached_info[idx];

        /* Copy packet (if applicable) */
        len = get_cached_info->BufferSize;
        if ( len == 0 ) {
                /* Point client at our cached buffer.
                 *
                 * To add to the fun, Intel decided at some point in
                 * the evolution of the PXE specification to add the
                 * BufferLimit field, which we are meant to fill in
                 * with the length of our packet buffer, so that the
                 * caller can safely modify the boot server reply
                 * packet stored therein.  However, this field was not
                 * present in earlier versions of the PXE spec, and
                 * there is at least one PXE NBP (Altiris) which
                 * allocates only exactly enough space for this
                 * earlier, shorter version of the structure.  If we
                 * actually fill in the BufferLimit field, we
                 * therefore risk trashing random areas of the
                 * caller's memory.  If we *don't* fill it in, then
                 * the caller is at liberty to assume that whatever
                 * random value happened to be in that location
                 * represents the length of the buffer we've just
                 * passed back to it.
                 *
                 * Since older PXE stacks won't fill this field in
                 * anyway, it's probably safe to assume that no
                 * callers actually rely on it, so we choose to not
                 * fill it in.
                 */
                get_cached_info->Buffer.segment = rm_ds;
                get_cached_info->Buffer.offset = __from_data16 ( info );
                get_cached_info->BufferSize = sizeof ( *info );
                DBGC ( &pxe_netdev, " using %04x:%04x+%04x['%x']",
                       get_cached_info->Buffer.segment,
                       get_cached_info->Buffer.offset,
                       get_cached_info->BufferSize,
                       get_cached_info->BufferLimit );
        } else {
                /* Copy packet to client buffer */
                if ( len > sizeof ( *info ) )
                        len = sizeof ( *info );
                if ( len < sizeof ( *info ) )
                        DBGC ( &pxe_netdev, " buffer may be too short" );
                buffer = real_to_user ( get_cached_info->Buffer.segment,
                                        get_cached_info->Buffer.offset );
                copy_to_user ( buffer, 0, info, len );
                get_cached_info->BufferSize = len;
        }

        DBGC ( &pxe_netdev, "\n" );
        get_cached_info->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
}
static PXENV_EXIT_t pxenv_restart_tftp ( struct s_PXENV_TFTP_READ_FILE restart_tftp) [static]

Definition at line 262 of file pxe_preboot.c.

References s_PXENV_TFTP_READ_FILE::Buffer, s_PXENV_TFTP_READ_FILE::BufferSize, DBGC, PXE_LOAD_PHYS, pxe_netdev, pxe_restart_nbp, PXENV_EXIT_SUCCESS, PXENV_RESTART_TFTP, pxenv_tftp_read_file(), and rmlongjmp.

                                                                   {
        PXENV_EXIT_t tftp_exit;

        DBGC ( &pxe_netdev, "PXENV_RESTART_TFTP\n" );

        /* Words cannot describe the complete mismatch between the PXE
         * specification and any possible version of reality...
         */
        restart_tftp->Buffer = PXE_LOAD_PHYS; /* Fixed by spec, apparently */
        restart_tftp->BufferSize = ( 0xa0000 - PXE_LOAD_PHYS ); /* Near enough */
        tftp_exit = pxenv_tftp_read_file ( restart_tftp );
        if ( tftp_exit != PXENV_EXIT_SUCCESS )
                return tftp_exit;

        /* Restart NBP */
        rmlongjmp ( pxe_restart_nbp, PXENV_RESTART_TFTP );
}
static PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI start_undi) [static]

Definition at line 284 of file pxe_preboot.c.

References s_PXENV_START_UNDI::AX, BUS_TYPE_ISAPNP, BUS_TYPE_PCI, s_PXENV_START_UNDI::BX, DBGC, s_PXENV_START_UNDI::DX, find_netdev_by_location(), isapnp_read_port, net_device::name, netdev, pxe_activate(), pxe_netdev, PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, PXENV_STATUS_SUCCESS, PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC, startup(), and s_PXENV_START_UNDI::Status.

                                                                               {
        unsigned int bus_type;
        unsigned int location;
        struct net_device *netdev;

        DBGC ( &pxe_netdev, "PXENV_START_UNDI %04x:%04x:%04x\n",
               start_undi->AX, start_undi->BX, start_undi->DX );

        /* Determine bus type and location.  Use a heuristic to decide
         * whether we are PCI or ISAPnP
         */
        if ( ( start_undi->DX >= ISAPNP_READ_PORT_MIN ) &&
             ( start_undi->DX <= ISAPNP_READ_PORT_MAX ) &&
             ( start_undi->BX >= ISAPNP_CSN_MIN ) &&
             ( start_undi->BX <= ISAPNP_CSN_MAX ) ) {
                bus_type = BUS_TYPE_ISAPNP;
                location = start_undi->BX;
                /* Record ISAPnP read port for use by isapnp.c */
                isapnp_read_port = start_undi->DX;
        } else {
                bus_type = BUS_TYPE_PCI;
                location = start_undi->AX;
        }

        /* Probe for devices, etc. */
        startup();

        /* Look for a matching net device */
        netdev = find_netdev_by_location ( bus_type, location );
        if ( ! netdev ) {
                DBGC ( &pxe_netdev, "PXENV_START_UNDI could not find matching "
                       "net device\n" );
                start_undi->Status = PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC;
                return PXENV_EXIT_FAILURE;
        }
        DBGC ( &pxe_netdev, "PXENV_START_UNDI found net device %s\n",
               netdev->name );

        /* Activate PXE */
        pxe_activate ( netdev );

        start_undi->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
}
static PXENV_EXIT_t pxenv_stop_undi ( struct s_PXENV_STOP_UNDI stop_undi) [static]

Definition at line 333 of file pxe_preboot.c.

References DBGC, hooked_bios_interrupts, pxe_deactivate(), pxe_netdev, PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, PXENV_STATUS_KEEP_UNDI, PXENV_STATUS_SUCCESS, shutdown_boot(), and s_PXENV_STOP_UNDI::Status.

                                                                            {
        DBGC ( &pxe_netdev, "PXENV_STOP_UNDI\n" );

        /* Deactivate PXE */
        pxe_deactivate();

        /* Prepare for unload */
        shutdown_boot();

        /* Check to see if we still have any hooked interrupts */
        if ( hooked_bios_interrupts != 0 ) {
                DBGC ( &pxe_netdev, "PXENV_STOP_UNDI failed: %d interrupts "
                       "still hooked\n", hooked_bios_interrupts );
                stop_undi->Status = PXENV_STATUS_KEEP_UNDI;
                return PXENV_EXIT_FAILURE;
        }

        stop_undi->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
}
static PXENV_EXIT_t pxenv_start_base ( struct s_PXENV_START_BASE start_base) [static]

Definition at line 358 of file pxe_preboot.c.

References DBGC, pxe_netdev, PXENV_EXIT_FAILURE, PXENV_STATUS_UNSUPPORTED, and s_PXENV_START_BASE::Status.

                                                                               {
        DBGC ( &pxe_netdev, "PXENV_START_BASE\n" );

        start_base->Status = PXENV_STATUS_UNSUPPORTED;
        return PXENV_EXIT_FAILURE;
}
static PXENV_EXIT_t pxenv_stop_base ( struct s_PXENV_STOP_BASE stop_base) [static]

Definition at line 369 of file pxe_preboot.c.

References DBGC, pxe_netdev, PXENV_EXIT_SUCCESS, PXENV_STATUS_SUCCESS, and s_PXENV_STOP_BASE::Status.

                                                                            {
        DBGC ( &pxe_netdev, "PXENV_STOP_BASE\n" );

        /* The only time we will be called is when the NBP is trying
         * to shut down the PXE stack.  There's nothing we need to do
         * in this call.
         */

        stop_base->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
}

Variable Documentation

Definition at line 51 of file pxe_preboot.c.

Initial value:

PXE DHCP packet creators.

Definition at line 91 of file pxe_preboot.c.

Referenced by pxe_fake_cached_info().

struct pxe_api_call pxe_preboot_api [] __pxe_api_call