From 446b6d5fddb95901e8874475597c75ed3cacfdde Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 18 Nov 2008 22:27:02 +0000 Subject: [pxe] Move all PXE files to arch/i386 The initial PXE implementation in Etherboot had the goal of being architecture-agnostic, but this goal has not been realised. --- src/arch/i386/include/pxe.h | 151 +++ src/arch/i386/include/pxe_api.h | 1841 +++++++++++++++++++++++++++++ src/arch/i386/include/pxe_types.h | 125 ++ src/arch/i386/interface/pxe/pxe_errors.c | 103 ++ src/arch/i386/interface/pxe/pxe_file.c | 264 +++++ src/arch/i386/interface/pxe/pxe_loader.c | 51 + src/arch/i386/interface/pxe/pxe_preboot.c | 352 ++++++ src/arch/i386/interface/pxe/pxe_tftp.c | 584 +++++++++ src/arch/i386/interface/pxe/pxe_udp.c | 403 +++++++ src/arch/i386/interface/pxe/pxe_undi.c | 684 +++++++++++ src/include/pxe.h | 151 --- src/include/pxe_api.h | 1841 ----------------------------- src/include/pxe_types.h | 125 -- src/interface/pxe/pxe_errors.c | 103 -- src/interface/pxe/pxe_file.c | 264 ----- src/interface/pxe/pxe_loader.c | 51 - src/interface/pxe/pxe_preboot.c | 352 ------ src/interface/pxe/pxe_tftp.c | 584 --------- src/interface/pxe/pxe_udp.c | 403 ------- src/interface/pxe/pxe_undi.c | 684 ----------- 20 files changed, 4558 insertions(+), 4558 deletions(-) create mode 100644 src/arch/i386/include/pxe.h create mode 100644 src/arch/i386/include/pxe_api.h create mode 100644 src/arch/i386/include/pxe_types.h create mode 100644 src/arch/i386/interface/pxe/pxe_errors.c create mode 100644 src/arch/i386/interface/pxe/pxe_file.c create mode 100644 src/arch/i386/interface/pxe/pxe_loader.c create mode 100644 src/arch/i386/interface/pxe/pxe_preboot.c create mode 100644 src/arch/i386/interface/pxe/pxe_tftp.c create mode 100644 src/arch/i386/interface/pxe/pxe_udp.c create mode 100644 src/arch/i386/interface/pxe/pxe_undi.c delete mode 100644 src/include/pxe.h delete mode 100644 src/include/pxe_api.h delete mode 100644 src/include/pxe_types.h delete mode 100644 src/interface/pxe/pxe_errors.c delete mode 100644 src/interface/pxe/pxe_file.c delete mode 100644 src/interface/pxe/pxe_loader.c delete mode 100644 src/interface/pxe/pxe_preboot.c delete mode 100644 src/interface/pxe/pxe_tftp.c delete mode 100644 src/interface/pxe/pxe_udp.c delete mode 100644 src/interface/pxe/pxe_undi.c diff --git a/src/arch/i386/include/pxe.h b/src/arch/i386/include/pxe.h new file mode 100644 index 00000000..6d332ac7 --- /dev/null +++ b/src/arch/i386/include/pxe.h @@ -0,0 +1,151 @@ +#ifndef PXE_H +#define PXE_H + +#include "pxe_types.h" +#include "pxe_api.h" +#include + +/* Parameter block for pxenv_unknown() */ +struct s_PXENV_UNKNOWN { + PXENV_STATUS_t Status; /**< PXE status code */ +} PACKED; + +typedef struct s_PXENV_UNKNOWN PXENV_UNKNOWN_t; + +/* Union used for PXE API calls; we don't know the type of the + * structure until we interpret the opcode. Also, Status is available + * in the same location for any opcode, and it's convenient to have + * non-specific access to it. + */ +union u_PXENV_ANY { + /* Make it easy to read status for any operation */ + PXENV_STATUS_t Status; + struct s_PXENV_UNKNOWN unknown; + struct s_PXENV_UNLOAD_STACK unload_stack; + struct s_PXENV_GET_CACHED_INFO get_cached_info; + struct s_PXENV_TFTP_READ_FILE restart_tftp; + struct s_PXENV_START_UNDI start_undi; + struct s_PXENV_STOP_UNDI stop_undi; + struct s_PXENV_START_BASE start_base; + struct s_PXENV_STOP_BASE stop_base; + struct s_PXENV_TFTP_OPEN tftp_open; + struct s_PXENV_TFTP_CLOSE tftp_close; + struct s_PXENV_TFTP_READ tftp_read; + struct s_PXENV_TFTP_READ_FILE tftp_read_file; + struct s_PXENV_TFTP_GET_FSIZE tftp_get_fsize; + struct s_PXENV_UDP_OPEN udp_open; + struct s_PXENV_UDP_CLOSE udp_close; + struct s_PXENV_UDP_WRITE udp_write; + struct s_PXENV_UDP_READ udp_read; + struct s_PXENV_UNDI_STARTUP undi_startup; + struct s_PXENV_UNDI_CLEANUP undi_cleanup; + struct s_PXENV_UNDI_INITIALIZE undi_initialize; + struct s_PXENV_UNDI_RESET undi_reset_adapter; + struct s_PXENV_UNDI_SHUTDOWN undi_shutdown; + struct s_PXENV_UNDI_OPEN undi_open; + struct s_PXENV_UNDI_CLOSE undi_close; + struct s_PXENV_UNDI_TRANSMIT undi_transmit; + struct s_PXENV_UNDI_SET_MCAST_ADDRESS undi_set_mcast_address; + struct s_PXENV_UNDI_SET_STATION_ADDRESS undi_set_station_address; + struct s_PXENV_UNDI_SET_PACKET_FILTER undi_set_packet_filter; + struct s_PXENV_UNDI_GET_INFORMATION undi_get_information; + struct s_PXENV_UNDI_GET_STATISTICS undi_get_statistics; + struct s_PXENV_UNDI_CLEAR_STATISTICS undi_clear_statistics; + struct s_PXENV_UNDI_INITIATE_DIAGS undi_initiate_diags; + struct s_PXENV_UNDI_FORCE_INTERRUPT undi_force_interrupt; + struct s_PXENV_UNDI_GET_MCAST_ADDRESS undi_get_mcast_address; + struct s_PXENV_UNDI_GET_NIC_TYPE undi_get_nic_type; + struct s_PXENV_UNDI_GET_IFACE_INFO undi_get_iface_info; + struct s_PXENV_UNDI_GET_STATE undi_get_state; + struct s_PXENV_UNDI_ISR undi_isr; + struct s_PXENV_FILE_OPEN file_open; + struct s_PXENV_FILE_CLOSE file_close; + struct s_PXENV_FILE_SELECT file_select; + struct s_PXENV_FILE_READ file_read; + struct s_PXENV_GET_FILE_SIZE get_file_size; + struct s_PXENV_FILE_EXEC file_exec; + struct s_PXENV_FILE_API_CHECK file_api_check; +}; + +typedef union u_PXENV_ANY PXENV_ANY_t; + +/** An UNDI expansion ROM header */ +struct undi_rom_header { + /** Signature + * + * Must be equal to @c ROM_SIGNATURE + */ + UINT16_t Signature; + /** ROM length in 512-byte blocks */ + UINT8_t ROMLength; + /** Unused */ + UINT8_t unused[0x13]; + /** Offset of the PXE ROM ID structure */ + UINT16_t PXEROMID; + /** Offset of the PCI ROM structure */ + UINT16_t PCIRHeader; +} PACKED; + +/** Signature for an expansion ROM */ +#define ROM_SIGNATURE 0xaa55 + +/** An UNDI ROM ID structure */ +struct undi_rom_id { + /** Signature + * + * Must be equal to @c UNDI_ROM_ID_SIGNATURE + */ + UINT32_t Signature; + /** Length of structure */ + UINT8_t StructLength; + /** Checksum */ + UINT8_t StructCksum; + /** Structure revision + * + * Must be zero. + */ + UINT8_t StructRev; + /** UNDI revision + * + * Version 2.1.0 is encoded as the byte sequence 0x00, 0x01, 0x02. + */ + UINT8_t UNDIRev[3]; + /** Offset to UNDI loader */ + UINT16_t UNDILoader; + /** Minimum required stack segment size */ + UINT16_t StackSize; + /** Minimum required data segment size */ + UINT16_t DataSize; + /** Minimum required code segment size */ + UINT16_t CodeSize; +} PACKED; + +/** Signature for an UNDI ROM ID structure */ +#define UNDI_ROM_ID_SIGNATURE \ + ( ( 'U' << 0 ) + ( 'N' << 8 ) + ( 'D' << 16 ) + ( 'I' << 24 ) ) + +/** A PCI expansion header */ +struct pcir_header { + /** Signature + * + * Must be equal to @c PCIR_SIGNATURE + */ + uint32_t signature; + /** PCI vendor ID */ + uint16_t vendor_id; + /** PCI device ID */ + uint16_t device_id; +} PACKED; + +/** Signature for an UNDI ROM ID structure */ +#define PCIR_SIGNATURE \ + ( ( 'P' << 0 ) + ( 'C' << 8 ) + ( 'I' << 16 ) + ( 'R' << 24 ) ) + + +extern struct net_device *pxe_netdev; + +extern void pxe_set_netdev ( struct net_device *netdev ); + +extern void pxe_set_cached_filename ( const unsigned char *filename ); + +#endif /* PXE_H */ diff --git a/src/arch/i386/include/pxe_api.h b/src/arch/i386/include/pxe_api.h new file mode 100644 index 00000000..b3d4bca8 --- /dev/null +++ b/src/arch/i386/include/pxe_api.h @@ -0,0 +1,1841 @@ +#ifndef PXE_API_H +#define PXE_API_H + +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/** @file + * + * Preboot eXecution Environment (PXE) API + * + */ + +#include "pxe_types.h" + +/** @addtogroup pxe Preboot eXecution Environment (PXE) API + * @{ + */ + +/** @defgroup pxe_api_call PXE entry points + * + * PXE entry points and calling conventions + * + * @{ + */ + +/** The PXENV+ structure */ +struct s_PXENV { + /** Signature + * + * Contains the bytes 'P', 'X', 'E', 'N', 'V', '+'. + */ + UINT8_t Signature[6]; + /** PXE API version + * + * MSB is major version number, LSB is minor version number. + * If the API version number is 0x0201 or greater, the !PXE + * structure pointed to by #PXEPtr should be used instead of + * this data structure. + */ + UINT16_t Version; + UINT8_t Length; /**< Length of this structure */ + /** Checksum + * + * The byte checksum of this structure (using the length in + * #Length) must be zero. + */ + UINT8_t Checksum; + SEGOFF16_t RMEntry; /**< Real-mode PXENV+ entry point */ + /** Protected-mode PXENV+ entry point offset + * + * PXE 2.1 deprecates this entry point. For protected-mode + * API calls, use the !PXE structure pointed to by #PXEPtr + * instead. + */ + UINT32_t PMOffset; + /** Protected-mode PXENV+ entry point segment selector + * + * PXE 2.1 deprecates this entry point. For protected-mode + * API calls, use the !PXE structure pointed to by #PXEPtr + * instead. + */ + SEGSEL_t PMSelector; + SEGSEL_t StackSeg; /**< Stack segment selector */ + UINT16_t StackSize; /**< Stack segment size */ + SEGSEL_t BC_CodeSeg; /**< Base-code code segment selector */ + UINT16_t BC_CodeSize; /**< Base-code code segment size */ + SEGSEL_t BC_DataSeg; /**< Base-code data segment selector */ + UINT16_t BC_DataSize; /**< Base-code data segment size */ + SEGSEL_t UNDIDataSeg; /**< UNDI data segment selector */ + UINT16_t UNDIDataSize; /**< UNDI data segment size */ + SEGSEL_t UNDICodeSeg; /**< UNDI code segment selector */ + UINT16_t UNDICodeSize; /**< UNDI code segment size */ + /** Address of the !PXE structure + * + * This field is present only if #Version is 0x0201 or + * greater. If present, it points to a struct s_PXE. + */ + SEGOFF16_t PXEPtr; +} PACKED; + +typedef struct s_PXENV PXENV_t; + +/** The !PXE structure */ +struct s_PXE { + /** Signature + * + * Contains the bytes '!', 'P', 'X', 'E'. + */ + UINT8_t Signature[4]; + UINT8_t StructLength; /**< Length of this structure */ + /** Checksum + * + * The byte checksum of this structure (using the length in + * #StructLength) must be zero. + */ + UINT8_t StructCksum; + /** Revision of this structure + * + * For PXE version 2.1, this field must be zero. + */ + UINT8_t StructRev; + UINT8_t reserved_1; /**< Must be zero */ + /** Address of the UNDI ROM ID structure + * + * This is a pointer to a struct s_UNDI_ROM_ID. + */ + SEGOFF16_t UNDIROMID; + /** Address of the Base Code ROM ID structure + * + * This is a pointer to a struct s_BC_ROM_ID. + */ + SEGOFF16_t BaseROMID; + /** 16-bit !PXE entry point + * + * This is the entry point for either real mode, or protected + * mode with a 16-bit stack segment. + */ + SEGOFF16_t EntryPointSP; + /** 32-bit !PXE entry point + * + * This is the entry point for protected mode with a 32-bit + * stack segment. + */ + SEGOFF16_t EntryPointESP; + /** Status call-out function + * + * @v 0 (if in a time-out loop) + * @v n Number of a received TFTP packet + * @ret 0 Continue operation + * @ret 1 Cancel operation + * + * This function will be called whenever the PXE stack is in + * protected mode, is waiting for an event (e.g. a DHCP reply) + * and wishes to allow the user to cancel the operation. + * Parameters are passed in register %ax; the return value + * must also be placed in register %ax. All other registers + * and flags @b must be preserved. + * + * In real mode, an internal function (that checks for a + * keypress) will be used. + * + * If this field is set to -1, no status call-out function + * will be used and consequently the user will not be allowed + * to interrupt operations. + * + * @note The PXE specification version 2.1 defines the + * StatusCallout field, mentions it 11 times, but nowhere + * defines what it actually does or how it gets called. + * Fortunately, the WfM specification version 1.1a deigns to + * inform us of such petty details. + */ + SEGOFF16_t StatusCallout; + UINT8_t reserved_2; /**< Must be zero */ + /** Number of segment descriptors + * + * If this number is greater than 7, the remaining descriptors + * follow immediately after #BC_CodeWrite. + */ + UINT8_t SegDescCnt; + /** First protected-mode selector + * + * This is the segment selector value for the first segment + * assigned to PXE. Protected-mode selectors must be + * consecutive, according to the PXE 2.1 specification, though + * no reason is given. Each #SEGDESC_t includes a field for + * the segment selector, so this information is entirely + * redundant. + */ + SEGSEL_t FirstSelector; + /** Stack segment descriptor */ + SEGDESC_t Stack; + /** UNDI data segment descriptor */ + SEGDESC_t UNDIData; + /** UNDI code segment descriptor */ + SEGDESC_t UNDICode; + /** UNDI writable code segment descriptor */ + SEGDESC_t UNDICodeWrite; + /** Base-code data segment descriptor */ + SEGDESC_t BC_Data; + /** Base-code code segment descriptor */ + SEGDESC_t BC_Code; + /** Base-code writable code segment descriptor */ + SEGDESC_t BC_CodeWrite; +} PACKED; + +typedef struct s_PXE PXE_t; + +/** @} */ /* pxe_api_call */ + +/** @defgroup pxe_preboot_api PXE Preboot API + * + * General high-level functions: #PXENV_UNLOAD_STACK, #PXENV_START_UNDI etc. + * + * @{ + */ + +/** @defgroup pxenv_unload_stack PXENV_UNLOAD_STACK + * + * UNLOAD BASE CODE STACK + * + * @{ + */ + +/** PXE API function code for pxenv_unload_stack() */ +#define PXENV_UNLOAD_STACK 0x0070 + +/** Parameter block for pxenv_unload_stack() */ +struct s_PXENV_UNLOAD_STACK { + PXENV_STATUS_t Status; /**< PXE status code */ + UINT8_t reserved[10]; /**< Must be zero */ +} PACKED; + +typedef struct s_PXENV_UNLOAD_STACK PXENV_UNLOAD_STACK_t; + +extern PXENV_EXIT_t pxenv_unload_stack ( struct s_PXENV_UNLOAD_STACK + *unload_stack ); + +/** @} */ /* pxenv_unload_stack */ + +/** @defgroup pxenv_get_cached_info PXENV_GET_CACHED_INFO + * + * GET CACHED INFO + * + * @{ + */ + +/** PXE API function code for pxenv_get_cached_info() */ +#define PXENV_GET_CACHED_INFO 0x0071 + +/** The client's DHCPDISCOVER packet */ +#define PXENV_PACKET_TYPE_DHCP_DISCOVER 1 + +/** The DHCP server's DHCPACK packet */ +#define PXENV_PACKET_TYPE_DHCP_ACK 2 + +/** The Boot Server's Discover Reply packet + * + * This packet contains DHCP option 60 set to "PXEClient", a valid + * boot file name, and may or may not contain MTFTP options. + */ +#define PXENV_PACKET_TYPE_CACHED_REPLY 3 + +/** Parameter block for pxenv_get_cached_info() */ +struct s_PXENV_GET_CACHED_INFO { + PXENV_STATUS_t Status; /**< PXE status code */ + /** Packet type. + * + * Valid values are #PXENV_PACKET_TYPE_DHCP_DISCOVER, + * #PXENV_PACKET_TYPE_DHCP_ACK or #PXENV_PACKET_TYPE_CACHED_REPLY + */ + UINT16_t PacketType; + UINT16_t BufferSize; /**< Buffer size */ + SEGOFF16_t Buffer; /**< Buffer address */ + UINT16_t BufferLimit; /**< Maximum buffer size */ +} PACKED; + +typedef struct s_PXENV_GET_CACHED_INFO PXENV_GET_CACHED_INFO_t; + +#define BOOTP_REQ 1 /**< A BOOTP request packet */ +#define BOOTP_REP 2 /**< A BOOTP reply packet */ + +/** DHCP broadcast flag + * + * Request a broadcast response (DHCPOFFER or DHCPACK) from the DHCP + * server. + */ +#define BOOTP_BCAST 0x8000 + +#define VM_RFC1048 0x63825363L /**< DHCP magic cookie */ + +/** Maximum length of DHCP options */ +#define BOOTP_DHCPVEND 1024 + +/** Format of buffer filled in by pxenv_get_cached_info() + * + * This somewhat convoluted data structure simply describes the layout + * of a DHCP packet. Refer to RFC2131 section 2 for a full + * description. + */ +struct bootph { + /** Message opcode. + * + * Valid values are #BOOTP_REQ and #BOOTP_REP. + */ + UINT8_t opcode; + /** NIC hardware type. + * + * Valid values are as for s_PXENV_UNDI_GET_INFORMATION::HwType. + */ + UINT8_t Hardware; + UINT8_t Hardlen; /**< MAC address length */ + /** Gateway hops + * + * Zero in packets sent by the client. May be non-zero in + * replies from the DHCP server, if the reply comes via a DHCP + * relay agent. + */ + UINT8_t Gatehops; + UINT32_t ident; /**< DHCP transaction id (xid) */ + /** Elapsed time + * + * Number of seconds since the client began the DHCP + * transaction. + */ + UINT16_t seconds; + /** Flags + * + * This is the bitwise-OR of any of the following values: + * #BOOTP_BCAST. + */ + UINT16_t Flags; + /** Client IP address + * + * Set only if the client already has an IP address. + */ + IP4_t cip; + /** Your IP address + * + * This is the IP address that the server assigns to the + * client. + */ + IP4_t yip; + /** Server IP address + * + * This is the IP address of the BOOTP/DHCP server. + */ + IP4_t sip; + /** Gateway IP address + * + * This is the IP address of the BOOTP/DHCP relay agent, if + * any. It is @b not (necessarily) the address of the default + * gateway for routing purposes. + */ + IP4_t gip; + MAC_ADDR_t CAddr; /**< Client MAC address */ + UINT8_t Sname[64]; /**< Server host name */ + UINT8_t bootfile[128]; /**< Boot file name */ + /** DHCP options + * + * Don't ask. Just laugh. Then burn a copy of the PXE + * specification and send Intel an e-mail asking them if + * they've figured out what a "union" does in C yet. + */ + union bootph_vendor { + UINT8_t d[BOOTP_DHCPVEND]; /**< DHCP options */ + /** DHCP options */ + struct bootph_vendor_v { + /** DHCP magic cookie + * + * Should have the value #VM_RFC1048. + */ + UINT8_t magic[4]; + UINT32_t flags; /**< BOOTP flags/opcodes */ + /** "End of BOOTP vendor extensions" + * + * Abandon hope, all ye who consider the + * purpose of this field. + */ + UINT8_t pad[56]; + } v; + } vendor; +} PACKED; + +typedef struct bootph BOOTPLAYER_t; + +extern PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO + *get_cached_info ); + +/** @} */ /* pxenv_get_cached_info */ + +/** @defgroup pxenv_restart_tftp PXENV_RESTART_TFTP + * + * RESTART TFTP + * + * @{ + */ + +/** PXE API function code for pxenv_restart_tftp() */ +#define PXENV_RESTART_TFTP 0x0073 + +/** Parameter block for pxenv_restart_tftp() */ +struct s_PXENV_TFTP_READ_FILE; + +typedef struct s_PXENV_RESTART_TFTP PXENV_RESTART_TFTP_t; + +extern PXENV_EXIT_t pxenv_restart_tftp ( struct s_PXENV_TFTP_READ_FILE + *restart_tftp ); + +/** @} */ /* pxenv_restart_tftp */ + +/** @defgroup pxenv_start_undi PXENV_START_UNDI + * + * START UNDI + * + * @{ + */ + +/** PXE API function code for pxenv_start_undi() */ +#define PXENV_START_UNDI 0x0000 + +/** Parameter block for pxenv_start_undi() */ +struct s_PXENV_START_UNDI { + PXENV_STATUS_t Status; /**< PXE status code */ + /** %ax register as passed to the Option ROM initialisation routine. + * + * For a PCI device, this should contain the bus:dev:fn value + * that uniquely identifies the PCI device in the system. For + * a non-PCI device, this field is not defined. + */ + UINT16_t AX; + /** %bx register as passed to the Option ROM initialisation routine. + * + * For an ISAPnP device, this should contain the Card Select + * Number assigned to the ISAPnP card. For non-ISAPnP + * devices, this should contain 0xffff. + */ + UINT16_t BX; + /** %dx register as passed to the Option ROM initialisation routine. + * + * For an ISAPnP device, this should contain the ISAPnP Read + * Port address as currently set in all ISAPnP cards. If + * there are no ISAPnP cards, this should contain 0xffff. (If + * this is a non-ISAPnP device, but there are ISAPnP cards in + * the system, this value is not well defined.) + */ + UINT16_t DX; + /** %di register as passed to the Option ROM initialisation routine. + * + * This contains the #OFF16_t portion of a struct #s_SEGOFF16 + * that points to the System BIOS Plug and Play Installation + * Check Structure. (Refer to section 4.4 of the Plug and + * Play BIOS specification for a description of this + * structure.) + * + * @note The PXE specification defines the type of this field + * as #UINT16_t. For x86, #OFF16_t and #UINT16_t are + * equivalent anyway; for other architectures #OFF16_t makes + * more sense. + */ + OFF16_t DI; + /** %es register as passed to the Option ROM initialisation routine. + * + * This contains the #SEGSEL_t portion of a struct #s_SEGOFF16 + * that points to the System BIOS Plug and Play Installation + * Check Structure. (Refer to section 4.4 of the Plug and + * Play BIOS specification for a description of this + * structure.) + * + * @note The PXE specification defines the type of this field + * as #UINT16_t. For x86, #SEGSEL_t and #UINT16_t are + * equivalent anyway; for other architectures #SEGSEL_t makes + * more sense. + */ + SEGSEL_t ES; +} PACKED; + +typedef struct s_PXENV_START_UNDI PXENV_START_UNDI_t; + +extern PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi ); + +/** @} */ /* pxenv_start_undi */ + +/** @defgroup pxenv_stop_undi PXENV_STOP_UNDI + * + * STOP UNDI + * + * @{ + */ + +/** PXE API function code for pxenv_stop_undi() */ +#define PXENV_STOP_UNDI 0x0015 + +/** Parameter block for pxenv_stop_undi() */ +struct s_PXENV_STOP_UNDI { + PXENV_STATUS_t Status; /**< PXE status code */ +} PACKED; + +typedef struct s_PXENV_STOP_UNDI PXENV_STOP_UNDI_t; + +extern PXENV_EXIT_t pxenv_stop_undi ( struct s_PXENV_STOP_UNDI *stop_undi ); + +/** @} */ /* pxenv_stop_undi */ + +/** @defgroup pxenv_start_base PXENV_START_BASE + * + * START BASE + * + * @{ + */ + +/** PXE API function code for pxenv_start_base() */ +#define PXENV_START_BASE 0x0075 + +/** Parameter block for pxenv_start_base() */ +struct s_PXENV_START_BASE { + PXENV_STATUS_t Status; /**< PXE status code */ +} PACKED; + +typedef struct s_PXENV_START_BASE PXENV_START_BASE_t; + +extern PXENV_EXIT_t pxenv_start_base ( struct s_PXENV_START_BASE *start_base ); + +/** @} */ /* pxenv_start_base */ + +/** @defgroup pxenv_stop_base PXENV_STOP_BASE + * + * STOP BASE + * + * @{ + */ + +/** PXE API function code for pxenv_stop_base() */ +#define PXENV_STOP_BASE 0x0076 + +/** Parameter block for pxenv_stop_base() */ +struct s_PXENV_STOP_BASE { + PXENV_STATUS_t Status; /**< PXE status code */ +} PACKED; + +typedef struct s_PXENV_STOP_BASE PXENV_STOP_BASE_t; + +extern PXENV_EXIT_t pxenv_stop_base ( struct s_PXENV_STOP_BASE *stop_base ); + +/** @} */ /* pxenv_stop_base */ + +/** @} */ /* pxe_preboot_api */ + +/** @defgroup pxe_tftp_api PXE TFTP API + * + * Download files via TFTP or MTFTP + * + * @{ + */ + +/** @defgroup pxenv_tftp_open PXENV_TFTP_OPEN + * + * TFTP OPEN + * + * @{ + */ + +/** PXE API function code for pxenv_tftp_open() */ +#define PXENV_TFTP_OPEN 0x0020 + +/** Parameter block for pxenv_tftp_open() */ +struct s_PXENV_TFTP_OPEN { + PXENV_STATUS_t Status; /**< PXE status code */ + IP4_t ServerIPAddress; /**< TFTP server IP address */ + IP4_t GatewayIPAddress; /**< Relay agent IP address */ + UINT8_t FileName[128]; /**< File name */ + UDP_PORT_t TFTPPort; /**< TFTP server UDP port */ + /** Requested size of TFTP packets + * + * This is the TFTP "blksize" option. This must be at least + * 512, since servers that do not support TFTP options cannot + * negotiate blocksizes smaller than this. + */ + UINT16_t PacketSize; +} PACKED; + +typedef struct s_PXENV_TFTP_OPEN PXENV_TFTP_OPEN_t; + +extern PXENV_EXIT_t pxenv_tftp_open ( struct s_PXENV_TFTP_OPEN *tftp_open ); + +/** @} */ /* pxenv_tftp_open */ + +/** @defgroup pxenv_tftp_close PXENV_TFTP_CLOSE + * + * TFTP CLOSE + * + * @{ + */ + +/** PXE API function code for pxenv_tftp_close() */ +#define PXENV_TFTP_CLOSE 0x0021 + +/** Parameter block for pxenv_tftp_close() */ +struct s_PXENV_TFTP_CLOSE { + PXENV_STATUS_t Status; /**< PXE status code */ +} PACKED; + +typedef struct s_PXENV_TFTP_CLOSE PXENV_TFTP_CLOSE_t; + +extern PXENV_EXIT_t pxenv_tftp_close ( struct s_PXENV_TFTP_CLOSE *tftp_close ); + +/** @} */ /* pxenv_tftp_close */ + +/** @defgroup pxenv_tftp_read PXENV_TFTP_READ + * + * TFTP READ + * + * @{ + */ + +/** PXE API function code for pxenv_tftp_read() */ +#define PXENV_TFTP_READ 0x0022 + +/** Parameter block for pxenv_tftp_read() */ +struct s_PXENV_TFTP_READ { + PXENV_STATUS_t Status; /**< PXE status code */ + UINT16_t PacketNumber; /**< TFTP packet number */ + UINT16_t BufferSize; /**< Size of data buffer */ + SEGOFF16_t Buffer; /**< Address of data buffer */ +} PACKED; + +typedef struct s_PXENV_TFTP_READ PXENV_TFTP_READ_t; + +extern PXENV_EXIT_t pxenv_tftp_read ( struct s_PXENV_TFTP_READ *tftp_read ); + +/** @} */ /* pxenv_tftp_read */ + +/** @defgroup pxenv_tftp_read_file PXENV_TFTP_READ_FILE + * + * TFTP/MTFTP READ FILE + * + * @{ + */ + +/** PXE API function code for pxenv_tftp_read_file() */ +#define PXENV_TFTP_READ_FILE 0x0023 + +/** Parameter block for pxenv_tftp_read_file() */ +struct s_PXENV_TFTP_READ_FILE { + PXENV_STATUS_t Status; /**< PXE status code */ + UINT8_t FileName[128]; /**< File name */ + UINT32_t BufferSize; /**< Size of data buffer */ + ADDR32_t Buffer; /**< Address of data buffer */ + IP4_t ServerIPAddress; /**< TFTP server IP address */ + IP4_t GatewayIPAddress; /**< Relay agent IP address */ + /** File multicast IP address */ + IP4_t McastIPAddress; + /** Client multicast listening port */ + UDP_PORT_t TFTPClntPort; + /** Server multicast listening port */ + UDP_PORT_t TFTPSrvPort; + /** TFTP open timeout. + * + * This is the timeout for receiving the first DATA or ACK + * packets during the MTFTP Listen phase. + */ + UINT16_t TFTPOpenTimeOut; + /** TFTP reopen timeout. + * + * This is the timeout for receiving an ACK packet while in + * the MTFTP Listen phase (when at least one ACK packet has + * already been seen). + */ + UINT16_t TFTPReopenDelay; +} PACKED; + +typedef struct s_PXENV_TFTP_READ_FILE PXENV_TFTP_READ_FILE_t; + +extern PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE + *tftp_read_file ); + +/** @} */ /* pxenv_tftp_read_file */ + +/** @defgroup pxenv_tftp_get_fsize PXENV_TFTP_GET_FSIZE + * + * TFTP GET FILE SIZE + * + * @{ + */ + +/** PXE API function code for pxenv_tftp_get_fsize() */ +#define PXENV_TFTP_GET_FSIZE 0x0025 + +/** Parameter block for pxenv_tftp_get_fsize() */ +struct s_PXENV_TFTP_GET_FSIZE { + PXENV_STATUS_t Status; /**< PXE status code */ + IP4_t ServerIPAddress; /**< TFTP server IP address */ + IP4_t GatewayIPAddress; /**< Relay agent IP address */ + UINT8_t FileName[128]; /**< File name */ + UINT32_t FileSize; /**< Size of the file */ +} PACKED; + +typedef struct s_PXENV_TFTP_GET_FSIZE PXENV_TFTP_GET_FSIZE_t; + +extern PXENV_EXIT_t pxenv_tftp_get_fsize ( struct s_PXENV_TFTP_GET_FSIZE + *get_fsize ); + +/** @} */ /* pxenv_tftp_get_fsize */ + +/** @} */ /* pxe_tftp_api */ + +/** @defgroup pxe_udp_api PXE UDP API + * + * Transmit and receive UDP packets + * + * @{ + */ + +/** @defgroup pxenv_udp_open PXENV_UDP_OPEN + * + * UDP OPEN + * + * @{ + */ + +/** PXE API function code for pxenv_udp_open() */ +#define PXENV_UDP_OPEN 0x0030 + +/** Parameter block for pxenv_udp_open() */ +struct s_PXENV_UDP_OPEN { + PXENV_STATUS_t Status; /**< PXE status code */ + IP4_t src_ip; /**< IP address of this station */ +} PACKED; + +typedef struct s_PXENV_UDP_OPEN PXENV_UDP_OPEN_t; + +extern PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *udp_open ); + +/** @} */ /* pxenv_udp_open */ + +/** @defgroup pxenv_udp_close PXENV_UDP_CLOSE + * + * UDP CLOSE + * + * @{ + */ + +/** PXE API function code for pxenv_udp_close() */ +#define PXENV_UDP_CLOSE 0x0031 + +/** Parameter block for pxenv_udp_close() */ +struct s_PXENV_UDP_CLOSE { + PXENV_STATUS_t Status; /**< PXE status code */ +} PACKED; + +typedef struct s_PXENV_UDP_CLOSE PXENV_UDP_CLOSE_t; + +extern PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *udp_close ); + +/** @} */ /* pxenv_udp_close */ + +/** @defgroup pxenv_udp_write PXENV_UDP_WRITE + * + * UDP WRITE + * + * @{ + */ + +/** PXE API function code for pxenv_udp_write() */ +#define PXENV_UDP_WRITE 0x0033 + +/** Parameter block for pxenv_udp_write() */ +struct s_PXENV_UDP_WRITE { + PXENV_STATUS_t Status; /**< PXE status code */ + IP4_t ip; /**< Destination IP address */ + IP4_t gw; /**< Relay agent IP address */ + UDP_PORT_t src_port; /**< Source UDP port */ + UDP_PORT_t dst_port; /**< Destination UDP port */ + UINT16_t buffer_size; /**< UDP payload buffer size */ + SEGOFF16_t buffer; /**< UDP payload buffer address */ +} PACKED; + +typedef struct s_PXENV_UDP_WRITE PXENV_UDP_WRITE_t; + +extern PXENV_EXIT_t pxenv_udp_write ( struct s_PXENV_UDP_WRITE *udp_write ); + +/** @} */ /* pxenv_udp_write */ + +/** @defgroup pxenv_udp_read PXENV_UDP_READ + * + * UDP READ + * + * @{ + */ + +/** PXE API function code for pxenv_udp_read() */ +#define PXENV_UDP_READ 0x0032 + +/** Parameter block for pxenv_udp_read() */ +struct s_PXENV_UDP_READ { + PXENV_STATUS_t Status; /**< PXE status code */ + IP4_t src_ip; /**< Source IP address */ + IP4_t dest_ip; /**< Destination IP address */ + UDP_PORT_t s_port; /**< Source UDP port */ + UDP_PORT_t d_port; /**< Destination UDP port */ + UINT16_t buffer_size; /**< UDP payload buffer size */ + SEGOFF16_t buffer; /**< UDP payload buffer address */ +} PACKED; + +typedef struct s_PXENV_UDP_READ PXENV_UDP_READ_t; + +extern PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *udp_read ); + +/** @} */ /* pxenv_udp_read */ + +/** @} */ /* pxe_udp_api */ + +/** @defgroup pxe_undi_api PXE UNDI API + * + * Direct control of the network interface card + * + * @{ + */ + +/** @defgroup pxenv_undi_startup PXENV_UNDI_STARTUP + * + * UNDI STARTUP + * + * @{ + */ + +/** PXE API function code for pxenv_undi_startup() */ +#define PXENV_UNDI_STARTUP 0x0001 + +#define PXENV_BUS_ISA 0 /**< ISA bus type */ +#define PXENV_BUS_EISA 1 /**< EISA bus type */ +#define PXENV_BUS_MCA 2 /**< MCA bus type */ +#define PXENV_BUS_PCI 3 /**< PCI bus type */ +#define PXENV_BUS_VESA 4 /**< VESA bus type */ +#define PXENV_BUS_PCMCIA 5 /**< PCMCIA bus type */ + +/** Parameter block for pxenv_undi_startup() */ +struct s_PXENV_UNDI_STARTUP { + PXENV_STATUS_t Status; /**< PXE status code */ +} PACKED; + +typedef struct s_PXENV_UNDI_STARTUP PXENV_UNDI_STARTUP_t; + +extern PXENV_EXIT_t pxenv_undi_startup ( struct s_PXENV_UNDI_STARTUP + *undi_startup ); + +/** @} */ /* pxenv_undi_startup */ + +/** @defgroup pxenv_undi_cleanup PXENV_UNDI_CLEANUP + * + * UNDI CLEANUP + * + * @{ + */ + +/** PXE API function code for pxenv_undi_cleanup() */ +#define PXENV_UNDI_CLEANUP 0x0002 + +/** Parameter block for pxenv_undi_cleanup() */ +struct s_PXENV_UNDI_CLEANUP { + PXENV_STATUS_t Status; /**< PXE status code */ +} PACKED; + +typedef struct s_PXENV_UNDI_CLEANUP PXENV_UNDI_CLEANUP_t; + +extern PXENV_EXIT_t pxenv_undi_cleanup ( struct s_PXENV_UNDI_CLEANUP + *undi_cleanup ); + +/** @} */ /* pxenv_undi_cleanup */ + +/** @defgroup pxenv_undi_initialize PXENV_UNDI_INITIALIZE + * + * UNDI INITIALIZE + * + * @{ + */ + +/** PXE API function code for pxenv_undi_initialize() */ +#define PXENV_UNDI_INITIALIZE 0x0003 + +/** Parameter block for pxenv_undi_initialize() */ +struct s_PXENV_UNDI_INITIALIZE { + PXENV_STATUS_t Status; /**< PXE status code */ + /** NDIS 2.0 configuration information, or NULL + * + * This is a pointer to the data structure returned by the + * NDIS 2.0 GetProtocolManagerInfo() API call. The data + * structure is documented, in a rather haphazard way, in + * section 4-17 of the NDIS 2.0 specification. + */ + ADDR32_t ProtocolIni; + UINT8_t reserved[8]; /**< Must be zero */ +} PACKED; + +typedef struct s_PXENV_UNDI_INITIALIZE PXENV_UNDI_INITIALIZE_t; + +extern PXENV_EXIT_t pxenv_undi_initialize ( struct s_PXENV_UNDI_INITIALIZE + *undi_initialize ); + +/** @} */ /* pxenv_undi_initialize */ + +/** @defgroup pxenv_undi_reset_adapter PXENV_UNDI_RESET_ADAPTER + * + * UNDI RESET ADAPTER + * + * @{ + */ + +/** PXE API function code for pxenv_undi_reset_adapter() */ +#define PXENV_UNDI_RESET_ADAPTER 0x0004 + +/** Maximum number of multicast MAC addresses */ +#define MAXNUM_MCADDR 8 + +/** List of multicast MAC addresses */ +struct s_PXENV_UNDI_MCAST_ADDRESS { + /** Number of multicast MAC addresses */ + UINT16_t MCastAddrCount; + /** List of up to #MAXNUM_MCADDR multicast MAC addresses */ + MAC_ADDR_t McastAddr[MAXNUM_MCADDR]; +} PACKED; + +typedef struct s_PXENV_UNDI_MCAST_ADDRESS PXENV_UNDI_MCAST_ADDRESS_t; + +/** Parameter block for pxenv_undi_reset_adapter() */ +struct s_PXENV_UNDI_RESET { + PXENV_STATUS_t Status; /**< PXE status code */ + /** Multicast MAC addresses */ + struct s_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf; +} PACKED; + +typedef struct s_PXENV_UNDI_RESET PXENV_UNDI_RESET_t; + +extern PXENV_EXIT_t pxenv_undi_reset_adapter ( struct s_PXENV_UNDI_RESET + *undi_reset_adapter ); + +/** @} */ /* pxenv_undi_reset_adapter */ + +/** @defgroup pxenv_undi_shutdown PXENV_UNDI_SHUTDOWN + * + * UNDI SHUTDOWN + * + * @{ + */ + +/** PXE API function code for pxenv_undi_shutdown() */ +#define PXENV_UNDI_SHUTDOWN 0x0005 + +/** Parameter block for pxenv_undi_shutdown() */ +struct s_PXENV_UNDI_SHUTDOWN { + PXENV_STATUS_t Status; /**< PXE status code */ +} PACKED; + +typedef struct s_PXENV_UNDI_SHUTDOWN PXENV_UNDI_SHUTDOWN_t; + +extern PXENV_EXIT_t pxenv_undi_shutdown ( struct s_PXENV_UNDI_SHUTDOWN + *undi_shutdown ); + +/** @} */ /* pxenv_undi_shutdown */ + +/** @defgroup pxenv_undi_open PXENV_UNDI_OPEN + * + * UNDI OPEN + * + * @{ + */ + +/** PXE API function code for pxenv_undi_open() */ +#define PXENV_UNDI_OPEN 0x0006 + +/** Accept "directed" packets + * + * These are packets addresses to either this adapter's MAC address or + * to any of the configured multicast MAC addresses (see + * #s_PXENV_UNDI_MCAST_ADDRESS). + */ +#define FLTR_DIRECTED 0x0001 +/** Accept broadcast packets */ +#define FLTR_BRDCST 0x0002 +/** Accept all packets; listen in promiscuous mode */ +#define FLTR_PRMSCS 0x0004 +/** Accept source-routed packets */ +#define FLTR_SRC_RTG 0x0008 + +/** Parameter block for pxenv_undi_open() */ +struct s_PXENV_UNDI_OPEN { + PXENV_STATUS_t Status; /**< PXE status code */ + /** Open flags as defined in NDIS 2.0 + * + * This is the OpenOptions field as passed to the NDIS 2.0 + * OpenAdapter() API call. It is defined to be "adapter + * specific", though 0 is guaranteed to be a valid value. + */ + UINT16_t OpenFlag; + /** Receive packet filter + * + * This is the bitwise-OR of any of the following flags: + * #FLTR_DIRECTED, #FLTR_BRDCST, #FLTR_PRMSCS and + * #FLTR_SRC_RTG. + */ + UINT16_t PktFilter; + /** Multicast MAC addresses */ + struct s_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf; +} PACKED; + +typedef struct s_PXENV_UNDI_OPEN PXENV_UNDI_OPEN_t; + +extern PXENV_EXIT_t pxenv_undi_open ( struct s_PXENV_UNDI_OPEN *undi_open ); + +/** @} */ /* pxenv_undi_open */ + +/** @defgroup pxenv_undi_close PXENV_UNDI_CLOSE + * + * UNDI CLOSE + * + * @{ + */ + +/** PXE API function code for pxenv_undi_close() */ +#define PXENV_UNDI_CLOSE 0x0007 + +/** Parameter block for pxenv_undi_close() */ +struct s_PXENV_UNDI_CLOSE { + PXENV_STATUS_t Status; /**< PXE status code */ +} PACKED; + +typedef struct s_PXENV_UNDI_CLOSE PXENV_UNDI_CLOSE_t; + +extern PXENV_EXIT_t pxenv_undi_close ( struct s_PXENV_UNDI_CLOSE *undi_close ); + +/** @} */ /* pxenv_undi_close */ + +/** @defgroup pxenv_undi_transmit PXENV_UNDI_TRANSMIT + * + * UNDI TRANSMIT PACKET + * + * @{ + */ + +/** PXE API function code for pxenv_undi_transmit() */ +#define PXENV_UNDI_TRANSMIT 0x0008 + +#define P_UNKNOWN 0 /**< Media header already filled in */ +#define P_IP 1 /**< IP protocol */ +#define P_ARP 2 /**< ARP protocol */ +#define P_RARP 3 /**< RARP protocol */ +#define P_OTHER 4 /**< Other protocol */ + +#define XMT_DESTADDR 0x0000 /**< Unicast packet */ +#define XMT_BROADCAST 0x0001 /**< Broadcast packet */ + +/** Maximum number of data blocks in a transmit buffer descriptor */ +#define MAX_DATA_BLKS 8 + +/** A transmit buffer descriptor, as pointed to by s_PXENV_UNDI_TRANSMIT::TBD + */ +struct s_PXENV_UNDI_TBD { + UINT16_t ImmedLength; /**< Length of the transmit buffer */ + SEGOFF16_t Xmit; /**< Address of the transmit buffer */ + UINT16_t DataBlkCount; + /** Array of up to #MAX_DATA_BLKS additional transmit buffers */ + struct DataBlk { + /** Always 1 + * + * A value of 0 would indicate that #TDDataPtr were an + * #ADDR32_t rather than a #SEGOFF16_t. The PXE + * specification version 2.1 explicitly states that + * this is not supported; #TDDataPtr will always be a + * #SEGOFF16_t. + */ + UINT8_t TDPtrType; + UINT8_t TDRsvdByte; /**< Must be zero */ + UINT16_t TDDataLen; /**< Length of this transmit buffer */ + SEGOFF16_t TDDataPtr; /**< Address of this transmit buffer */ + } DataBlock[MAX_DATA_BLKS]; +} PACKED; + +typedef struct s_PXENV_UNDI_TBD PXENV_UNDI_TBD_t; + +/** Parameter block for pxenv_undi_transmit() */ +struct s_PXENV_UNDI_TRANSMIT { + PXENV_STATUS_t Status; /**< PXE status code */ + /** Protocol + * + * Valid values are #P_UNKNOWN, #P_IP, #P_ARP or #P_RARP. If + * the caller has already filled in the media header, this + * field must be set to #P_UNKNOWN. + */ + UINT8_t Protocol; + /** Unicast/broadcast flag + * + * Valid values are #XMT_DESTADDR or #XMT_BROADCAST. + */ + UINT8_t XmitFlag; + SEGOFF16_t DestAddr; /**< Destination MAC address */ + /** Address of the Transmit Buffer Descriptor + * + * This is a pointer to a struct s_PXENV_UNDI_TBD. + */ + SEGOFF16_t TBD; + UINT32_t Reserved[2]; /**< Must be zero */ +} PACKED; + +typedef struct s_PXENV_UNDI_TRANSMIT PXENV_UNDI_TRANSMIT_t; + +extern PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT + *undi_transmit ); + +/** @} */ /* pxenv_undi_transmit */ + +/** @defgroup pxenv_undi_set_mcast_address PXENV_UNDI_SET_MCAST_ADDRESS + * + * UNDI SET MULTICAST ADDRESS + * + * @{ + */ + +/** PXE API function code for pxenv_undi_set_mcast_address() */ +#define PXENV_UNDI_SET_MCAST_ADDRESS 0x0009 + +/** Parameter block for pxenv_undi_set_mcast_address() */ +struct s_PXENV_UNDI_SET_MCAST_ADDRESS { + PXENV_STATUS_t Status; /**< PXE status code */ + /** List of multicast addresses */ + struct s_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf; +} PACKED; + +typedef struct s_PXENV_UNDI_SET_MCAST_ADDRESS PXENV_UNDI_SET_MCAST_ADDRESS_t; + +extern PXENV_EXIT_t pxenv_undi_set_mcast_address ( + struct s_PXENV_UNDI_SET_MCAST_ADDRESS *undi_set_mcast_address ); + +/** @} */ /* pxenv_undi_set_mcast_address */ + +/** @defgroup pxenv_undi_set_station_address PXENV_UNDI_SET_STATION_ADDRESS + * + * UNDI SET STATION ADDRESS + * + * @{ + */ + +/** PXE API function code for pxenv_undi_set_station_address() */ +#define PXENV_UNDI_SET_STATION_ADDRESS 0x000a + +/** Parameter block for pxenv_undi_set_station_address() */ +struct s_PXENV_UNDI_SET_STATION_ADDRESS { + PXENV_STATUS_t Status; /**< PXE status code */ + MAC_ADDR_t StationAddress; /**< Station MAC address */ +} PACKED; + +typedef struct s_PXENV_UNDI_SET_STATION_ADDRESS PXENV_UNDI_SET_STATION_ADDRESS_t; + +extern PXENV_EXIT_t pxenv_undi_set_station_address ( + struct s_PXENV_UNDI_SET_STATION_ADDRESS *undi_set_station_address ); + +/** @} */ /* pxenv_undi_set_station_address */ + +/** @defgroup pxenv_undi_set_packet_filter PXENV_UNDI_SET_PACKET_FILTER + * + * UNDI SET PACKET FILTER + * + * @{ + */ + +/** PXE API function code for pxenv_undi_set_packet_filter() */ +#define PXENV_UNDI_SET_PACKET_FILTER 0x000b + +/** Parameter block for pxenv_undi_set_packet_filter() */ +struct s_PXENV_UNDI_SET_PACKET_FILTER { + PXENV_STATUS_t Status; /**< PXE status code */ + /** Receive packet filter + * + * This field takes the same values as + * s_PXENV_UNDI_OPEN::PktFilter. + * + * @note Yes, this field is a different size to + * s_PXENV_UNDI_OPEN::PktFilter. Blame "the managers at Intel + * who apparently let a consultant come up with the spec + * without any kind of adult supervision" (quote from hpa). + */ + UINT8_t filter; +} PACKED; + +typedef struct s_PXENV_UNDI_SET_PACKET_FILTER PXENV_UNDI_SET_PACKET_FILTER_t; + +extern PXENV_EXIT_t pxenv_undi_set_packet_filter ( + struct s_PXENV_UNDI_SET_PACKET_FILTER *undi_set_packet_filter ); + +/** @} */ /* pxenv_undi_set_packet_filter */ + +/** @defgroup pxenv_undi_get_information PXENV_UNDI_GET_INFORMATION + * + * UNDI GET INFORMATION + * + * @{ + */ + +/** PXE API function code for pxenv_undi_get_information() */ +#define PXENV_UNDI_GET_INFORMATION 0x000c + +#define ETHER_TYPE 1 /**< Ethernet (10Mb) */ +#define EXP_ETHER_TYPE 2 /**< Experimental Ethernet (3Mb) */ +#define AX25_TYPE 3 /**< Amateur Radio AX.25 */ +#define TOKEN_RING_TYPE 4 /**< Proteon ProNET Token Ring */ +#define CHAOS_TYPE 5 /**< Chaos */ +#define IEEE_TYPE 6 /**< IEEE 802 Networks */ +#define ARCNET_TYPE 7 /**< ARCNET */ + +/** Parameter block for pxenv_undi_get_information() */ +struct s_PXENV_UNDI_GET_INFORMATION { + PXENV_STATUS_t Status; /**< PXE status code */ + UINT16_t BaseIo; /**< I/O base address */ + UINT16_t IntNumber; /**< IRQ number */ + UINT16_t MaxTranUnit; /**< Adapter MTU */ + /** Hardware type + * + * Valid values are defined in RFC1010 ("Assigned numbers"), + * and are #ETHER_TYPE, #EXP_ETHER_TYPE, #AX25_TYPE, + * #TOKEN_RING_TYPE, #CHAOS_TYPE, #IEEE_TYPE or #ARCNET_TYPE. + */ + UINT16_t HwType; + UINT16_t HwAddrLen; /**< MAC address length */ + MAC_ADDR_t CurrentNodeAddress; /**< Current MAC address */ + MAC_ADDR_t PermNodeAddress; /**< Permanent (EEPROM) MAC address */ + SEGSEL_t ROMAddress; /**< Real-mode ROM segment address */ + UINT16_t RxBufCt; /**< Receive queue length */ + UINT16_t TxBufCt; /**< Transmit queue length */ +} PACKED; + +typedef struct s_PXENV_UNDI_GET_INFORMATION PXENV_UNDI_GET_INFORMATION_t; + +extern PXENV_EXIT_t pxenv_undi_get_information ( + struct s_PXENV_UNDI_GET_INFORMATION *undi_get_information ); + +/** @} */ /* pxenv_undi_get_information */ + +/** @defgroup pxenv_undi_get_statistics PXENV_UNDI_GET_STATISTICS + * + * UNDI GET STATISTICS + * + * @{ + */ + +/** PXE API function code for pxenv_undi_get_statistics() */ +#define PXENV_UNDI_GET_STATISTICS 0x000d + +/** Parameter block for pxenv_undi_get_statistics() */ +struct s_PXENV_UNDI_GET_STATISTICS { + PXENV_STATUS_t Status; /**< PXE status code */ + UINT32_t XmtGoodFrames; /**< Successful transmission count */ + UINT32_t RcvGoodFrames; /**< Successful reception count */ + UINT32_t RcvCRCErrors; /**< Receive CRC error count */ + UINT32_t RcvResourceErrors; /**< Receive queue overflow count */ +} PACKED; + +typedef struct s_PXENV_UNDI_GET_STATISTICS PXENV_UNDI_GET_STATISTICS_t; + +extern PXENV_EXIT_t pxenv_undi_get_statistics ( + struct s_PXENV_UNDI_GET_STATISTICS *undi_get_statistics ); + +/** @} */ /* pxenv_undi_get_statistics */ + +/** @defgroup pxenv_undi_clear_statistics PXENV_UNDI_CLEAR_STATISTICS + * + * UNDI CLEAR STATISTICS + * + * @{ + */ + +/** PXE API function code for pxenv_undi_clear_statistics() */ +#define PXENV_UNDI_CLEAR_STATISTICS 0x000e + +/** Parameter block for pxenv_undi_clear_statistics() */ +struct s_PXENV_UNDI_CLEAR_STATISTICS { + PXENV_STATUS_t Status; /**< PXE status code */ +} PACKED; + +typedef struct s_PXENV_UNDI_CLEAR_STATISTICS PXENV_UNDI_CLEAR_STATISTICS_t; + +extern PXENV_EXIT_t pxenv_undi_clear_statistics ( + struct s_PXENV_UNDI_CLEAR_STATISTICS *undi_clear_statistics ); + +/** @} */ /* pxenv_undi_clear_statistics */ + +/** @defgroup pxenv_undi_initiate_diags PXENV_UNDI_INITIATE_DIAGS + * + * UNDI INITIATE DIAGS + * + * @{ + */ + +/** PXE API function code for pxenv_undi_initiate_diags() */ +#define PXENV_UNDI_INITIATE_DIAGS 0x000f + +/** Parameter block for pxenv_undi_initiate_diags() */ +struct s_PXENV_UNDI_INITIATE_DIAGS { + PXENV_STATUS_t Status; /**< PXE status code */ +} PACKED; + +typedef struct s_PXENV_UNDI_INITIATE_DIAGS PXENV_UNDI_INITIATE_DIAGS_t; + +extern PXENV_EXIT_t pxenv_undi_initiate_diags ( + struct s_PXENV_UNDI_INITIATE_DIAGS *undi_initiate_diags ); + +/** @} */ /* pxenv_undi_initiate_diags */ + +/** @defgroup pxenv_undi_force_interrupt PXENV_UNDI_FORCE_INTERRUPT + * + * UNDI FORCE INTERRUPT + * + * @{ + */ + +/** PXE API function code for pxenv_undi_force_interrupt() */ +#define PXENV_UNDI_FORCE_INTERRUPT 0x0010 + +/** Parameter block for pxenv_undi_force_interrupt() */ +struct s_PXENV_UNDI_FORCE_INTERRUPT { + PXENV_STATUS_t Status; /**< PXE status code */ +} PACKED; + +typedef struct s_PXENV_UNDI_FORCE_INTERRUPT PXENV_UNDI_FORCE_INTERRUPT_t; + +extern PXENV_EXIT_t pxenv_undi_force_interrupt ( + struct s_PXENV_UNDI_FORCE_INTERRUPT *undi_force_interrupt ); + +/** @} */ /* pxenv_undi_force_interrupt */ + +/** @defgroup pxenv_undi_get_mcast_address PXENV_UNDI_GET_MCAST_ADDRESS + * + * UNDI GET MULTICAST ADDRESS + * + * @{ + */ + +/** PXE API function code for pxenv_undi_get_mcast_address() */ +#define PXENV_UNDI_GET_MCAST_ADDRESS 0x0011 + +/** Parameter block for pxenv_undi_get_mcast_address() */ +struct s_PXENV_UNDI_GET_MCAST_ADDRESS { + PXENV_STATUS_t Status; /**< PXE status code */ + IP4_t InetAddr; /**< Multicast IP address */ + MAC_ADDR_t MediaAddr; /**< Multicast MAC address */ +} PACKED; + +typedef struct s_PXENV_UNDI_GET_MCAST_ADDRESS PXENV_UNDI_GET_MCAST_ADDRESS_t; + +extern PXENV_EXIT_t pxenv_undi_get_mcast_address ( + struct s_PXENV_UNDI_GET_MCAST_ADDRESS *undi_get_mcast_address ); + +/** @} */ /* pxenv_undi_get_mcast_address */ + +/** @defgroup pxenv_undi_get_nic_type PXENV_UNDI_GET_NIC_TYPE + * + * UNDI GET NIC TYPE + * + * @{ + */ + +/** PXE API function code for pxenv_undi_get_nic_type() */ +#define PXENV_UNDI_GET_NIC_TYPE 0x0012 + +#define PCI_NIC 2 /**< PCI network card */ +#define PnP_NIC 3 /**< ISAPnP network card */ +#define CardBus_NIC 4 /**< CardBus network card */ + +/** Information for a PCI or equivalent NIC */ +struct pci_nic_info { + UINT16_t Vendor_ID; /**< PCI vendor ID */ + UINT16_t Dev_ID; /**< PCI device ID */ + UINT8_t Base_Class; /**< PCI base class */ + UINT8_t Sub_Class; /**< PCI sub class */ + UINT8_t Prog_Intf; /**< PCI programming interface */ + UINT8_t Rev; /**< PCI revision */ + UINT16_t BusDevFunc; /**< PCI bus:dev:fn address */ + UINT16_t SubVendor_ID; /**< PCI subvendor ID */ + UINT16_t SubDevice_ID; /**< PCI subdevice ID */ +} PACKED; + +/** Information for an ISAPnP or equivalent NIC */ +struct pnp_nic_info { + UINT32_t EISA_Dev_ID; /**< EISA device ID */ + UINT8_t Base_Class; /**< Base class */ + UINT8_t Sub_Class; /**< Sub class */ + UINT8_t Prog_Intf; /**< Programming interface */ + /** Card Select Number assigned to card */ + UINT16_t CardSelNum; +} PACKED; + +/** Parameter block for pxenv_undi_get_nic_type() */ +struct s_PXENV_UNDI_GET_NIC_TYPE { + PXENV_STATUS_t Status; /**< PXE status code */ + /** NIC type + * + * Valid values are #PCI_NIC, #PnP_NIC or #CardBus_NIC. + */ + UINT8_t NicType; + /** NIC information */ + union nic_type_info { + /** NIC information (if #NicType==#PCI_NIC) */ + struct pci_nic_info pci; + /** NIC information (if #NicType==#CardBus_NIC) */ + struct pci_nic_info cardbus; + /** NIC information (if #NicType==#PnP_NIC) */ + struct pnp_nic_info pnp; + } info; +} PACKED; + +typedef struct s_PXENV_UNDI_GET_NIC_TYPE PXENV_UNDI_GET_NIC_TYPE_t; + +extern PXENV_EXIT_t pxenv_undi_get_nic_type ( + struct s_PXENV_UNDI_GET_NIC_TYPE *undi_get_nic_type ); + +/** @} */ /* pxenv_undi_get_nic_type */ + +/** @defgroup pxenv_undi_get_iface_info PXENV_UNDI_GET_IFACE_INFO + * + * UNDI GET IFACE INFO + * + * @{ + */ + +/** PXE API function code for pxenv_undi_get_iface_info() */ +#define PXENV_UNDI_GET_IFACE_INFO 0x0013 + +/** Parameter block for pxenv_undi_get_iface_info() */ +struct s_PXENV_UNDI_GET_IFACE_INFO { + PXENV_STATUS_t Status; /**< PXE status code */ + /** Interface type + * + * This is defined in the NDIS 2.0 specification to be one of + * the strings "802.3", "802.4", "802.5", "802.6", "DIX", + * "DIX+802.3", "APPLETALK", "ARCNET", "FDDI", "SDLC", "BSC", + * "HDLC", or "ISDN". + * + * "Normal" Ethernet, for various historical reasons, is + * "DIX+802.3". + */ + UINT8_t IfaceType[16]; + UINT32_t LinkSpeed; /**< Link speed, in bits per second */ + /** Service flags + * + * These are the "service flags" defined in the "MAC + * Service-Specific Characteristics" table in the NDIS 2.0 + * specification. Almost all of them are irrelevant to PXE. + */ + UINT32_t ServiceFlags; + UINT32_t Reserved[4]; /**< Must be zero */ +} PACKED; + +typedef struct s_PXENV_UNDI_GET_IFACE_INFO PXENV_UNDI_GET_IFACE_INFO_t; + +extern PXENV_EXIT_t pxenv_undi_get_iface_info ( + struct s_PXENV_UNDI_GET_IFACE_INFO *undi_get_iface_info ); + +/** @} */ /* pxenv_undi_get_iface_info */ + +/** @defgroup pxenv_undi_get_state PXENV_UNDI_GET_STATE + * + * UNDI GET STATE + * + * @{ + */ + +/** PXE API function code for pxenv_undi_get_state() */ +#define PXENV_UNDI_GET_STATE 0x0015 + +/** pxenv_start_undi() has been called */ +#define PXE_UNDI_GET_STATE_STARTED 1 +/** pxenv_undi_initialize() has been called */ +#define PXE_UNDI_GET_STATE_INITIALIZED 2 +/** pxenv_undi_open() has been called */ +#define PXE_UNDI_GET_STATE_OPENED 3 + +/** Parameter block for pxenv_undi_get_state() */ +struct s_PXENV_UNDI_GET_STATE { + PXENV_STATUS_t Status; /**< PXE status code */ + /** Current state of the UNDI driver + * + * Valid values are #PXE_UNDI_GET_STATE_STARTED, + * #PXE_UNDI_GET_STATE_INITIALIZED or + * #PXE_UNDI_GET_STATE_OPENED. + */ + UINT8_t UNDIstate; +} PACKED; + +typedef struct s_PXENV_UNDI_GET_STATE PXENV_UNDI_GET_STATE_t; + +extern PXENV_EXIT_t pxenv_undi_get_state ( struct s_PXENV_UNDI_GET_STATE + *undi_get_state ); + +/** @} */ /* pxenv_undi_get_state */ + +/** @defgroup pxenv_undi_isr PXENV_UNDI_ISR + * + * UNDI ISR + * + * @{ + */ + +/** PXE API function code for pxenv_undi_isr() */ +#define PXENV_UNDI_ISR 0x0014 + +/** Determine whether or not this is our interrupt */ +#define PXENV_UNDI_ISR_IN_START 1 +/** Start processing interrupt */ +#define PXENV_UNDI_ISR_IN_PROCESS 2 +/** Continue processing interrupt */ +#define PXENV_UNDI_ISR_IN_GET_NEXT 3 +/** This interrupt was ours */ +#define PXENV_UNDI_ISR_OUT_OURS 0 +/** This interrupt was not ours */ +#define PXENV_UNDI_ISR_OUT_NOT_OURS 1 +/** Finished processing interrupt */ +#define PXENV_UNDI_ISR_OUT_DONE 0 +/** A packet transmission has completed */ +#define PXENV_UNDI_ISR_OUT_TRANSMIT 2 +/** A packet has been received */ +#define PXENV_UNDI_ISR_OUT_RECEIVE 3 +/** We are already in the middle of processing an interrupt */ +#define PXENV_UNDI_ISR_OUT_BUSY 4 + +/** Unicast packet (or packet captured in promiscuous mode) */ +#define P_DIRECTED 0 +/** Broadcast packet */ +#define P_BROADCAST 1 +/** Multicast packet */ +#define P_MULTICAST 2 + +/** Parameter block for pxenv_undi_isr() */ +struct s_PXENV_UNDI_ISR { + PXENV_STATUS_t Status; /**< PXE status code */ + /** Function flag + * + * Valid values are #PXENV_UNDI_ISR_IN_START, + * #PXENV_UNDI_ISR_IN_PROCESS, #PXENV_UNDI_ISR_IN_GET_NEXT, + * #PXENV_UNDI_ISR_OUT_OURS, #PXENV_UNDI_ISR_OUT_NOT_OURS, + * #PXENV_UNDI_ISR_OUT_DONE, #PXENV_UNDI_ISR_OUT_TRANSMIT, + * #PXENV_UNDI_ISR_OUT_RECEIVE or #PXENV_UNDI_ISR_OUT_BUSY. + */ + UINT16_t FuncFlag; + UINT16_t BufferLength; /**< Data buffer length */ + UINT16_t FrameLength; /**< Total frame length */ + UINT16_t FrameHeaderLength; /**< Frame header length */ + SEGOFF16_t Frame; /**< Data buffer address */ + /** Protocol type + * + * Valid values are #P_IP, #P_ARP, #P_RARP or #P_OTHER. + */ + UINT8_t ProtType; + /** Packet type + * + * Valid values are #P_DIRECTED, #P_BROADCAST or #P_MULTICAST. + */ + UINT8_t PktType; +} PACKED; + +typedef struct s_PXENV_UNDI_ISR PXENV_UNDI_ISR_t; + +extern PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ); + +/** @} */ /* pxenv_undi_isr */ + +/** @} */ /* pxe_undi_api */ + +/** @defgroup pxe_file_api PXE FILE API + * + * POSIX-like file operations + * + * @{ + */ + +/** @defgroup pxenv_file_open PXENV_FILE_OPEN + * + * FILE OPEN + * + * @{ + */ + +/** PXE API function code for pxenv_file_open() */ +#define PXENV_FILE_OPEN 0x00e0 + +/** Parameter block for pxenv_file_open() */ +struct s_PXENV_FILE_OPEN { + PXENV_STATUS_t Status; /**< PXE status code */ + UINT16_t FileHandle; /**< File handle */ + SEGOFF16_t FileName; /**< File URL */ + UINT32_t Reserved; /**< Reserved */ +} PACKED; + +typedef struct s_PXENV_FILE_OPEN PXENV_FILE_OPEN_t; + +extern PXENV_EXIT_t pxenv_file_open ( struct s_PXENV_FILE_OPEN *file_open ); + +/** @} */ /* pxenv_file_open */ + +/** @defgroup pxenv_file_close PXENV_FILE_CLOSE + * + * FILE CLOSE + * + * @{ + */ + +/** PXE API function code for pxenv_file_close() */ +#define PXENV_FILE_CLOSE 0x00e1 + +/** Parameter block for pxenv_file_close() */ +struct s_PXENV_FILE_CLOSE { + PXENV_STATUS_t Status; /**< PXE status code */ + UINT16_t FileHandle; /**< File handle */ +} PACKED; + +typedef struct s_PXENV_FILE_CLOSE PXENV_FILE_CLOSE_t; + +extern PXENV_EXIT_t pxenv_file_close ( struct s_PXENV_FILE_CLOSE + *file_close ); + +/** @} */ /* pxenv_file_close */ + +/** @defgroup pxenv_file_select PXENV_FILE_SELECT + * + * FILE SELECT + * + * @{ + */ + +/** PXE API function code for pxenv_file_select() */ +#define PXENV_FILE_SELECT 0x00e2 + +/** File is ready for reading */ +#define RDY_READ 0x0001 + +/** Parameter block for pxenv_file_select() */ +struct s_PXENV_FILE_SELECT { + PXENV_STATUS_t Status; /**< PXE status code */ + UINT16_t FileHandle; /**< File handle */ + UINT16_t Ready; /**< Indication of readiness */ +} PACKED; + +typedef struct s_PXENV_FILE_SELECT PXENV_FILE_SELECT_t; + +extern PXENV_EXIT_t pxenv_file_select ( struct s_PXENV_FILE_SELECT + *file_select ); + +/** @} */ /* pxenv_file_select */ + +/** @defgroup pxenv_file_read PXENV_FILE_READ + * + * FILE READ + * + * @{ + */ + +/** PXE API function code for pxenv_file_read() */ +#define PXENV_FILE_READ 0x00e3 + +/** Parameter block for pxenv_file_read() */ +struct s_PXENV_FILE_READ { + PXENV_STATUS_t Status; /**< PXE status code */ + UINT16_t FileHandle; /**< File handle */ + UINT16_t BufferSize; /**< Data buffer size */ + SEGOFF16_t Buffer; /**< Data buffer */ +} PACKED; + +typedef struct s_PXENV_FILE_READ PXENV_FILE_READ_t; + +extern PXENV_EXIT_t pxenv_file_read ( struct s_PXENV_FILE_READ *file_read ); + +/** @} */ /* pxenv_file_read */ + +/** @defgroup pxenv_get_file_size PXENV_GET_FILE_SIZE + * + * GET FILE SIZE + * + * @{ + */ + +/** PXE API function code for pxenv_get_file_size() */ +#define PXENV_GET_FILE_SIZE 0x00e4 + +/** Parameter block for pxenv_get_file_size() */ +struct s_PXENV_GET_FILE_SIZE { + PXENV_STATUS_t Status; /**< PXE status code */ + UINT16_t FileHandle; /**< File handle */ + UINT32_t FileSize; /**< File size */ +} PACKED; + +typedef struct s_PXENV_GET_FILE_SIZE PXENV_GET_FILE_SIZE_t; + +extern PXENV_EXIT_t pxenv_get_file_size ( struct s_PXENV_GET_FILE_SIZE + *get_file_size ); + +/** @} */ /* pxenv_get_file_size */ + +/** @defgroup pxenv_file_exec PXENV_FILE_EXEC + * + * FILE EXEC + * + * @{ + */ + +/** PXE API function code for pxenv_file_exec() */ +#define PXENV_FILE_EXEC 0x00e5 + +/** Parameter block for pxenv_file_exec() */ +struct s_PXENV_FILE_EXEC { + PXENV_STATUS_t Status; /**< PXE status code */ + SEGOFF16_t Command; /**< Command to execute */ +} PACKED; + +typedef struct s_PXENV_FILE_EXEC PXENV_FILE_EXEC_t; + +extern PXENV_EXIT_t pxenv_file_exec ( struct s_PXENV_FILE_EXEC *file_exec ); + +/** @} */ /* pxenv_file_exec */ + +/** @defgroup pxenv_file_api_check PXENV_FILE_API_CHECK + * + * FILE API CHECK + * + * @{ + */ + +/** PXE API function code for pxenv_file_api_check() */ +#define PXENV_FILE_API_CHECK 0x00e6 + +/** Parameter block for pxenv_file_api_check() */ +struct s_PXENV_FILE_API_CHECK { + PXENV_STATUS_t Status; /**< PXE status code */ + UINT16_t Size; /**< Size of structure */ + UINT32_t Magic; /**< Magic number */ + UINT32_t Provider; /**< Implementation identifier */ + UINT32_t APIMask; /**< Supported API functions */ + UINT32_t Flags; /**< Reserved for the future */ +} PACKED; + +typedef struct s_PXENV_FILE_API_CHECK PXENV_FILE_API_CHECK_t; + +extern PXENV_EXIT_t pxenv_file_api_check ( struct s_PXENV_FILE_API_CHECK *file_api_check ); + +/** @} */ /* pxenv_file_api_check */ + +/** @} */ /* pxe_file_api */ + +/** @defgroup pxe_loader_api PXE Loader API + * + * The UNDI ROM loader API + * + * @{ + */ + +/** Parameter block for undi_loader() */ +struct s_UNDI_LOADER { + /** PXE status code */ + PXENV_STATUS_t Status; + /** %ax register as for PXENV_START_UNDI */ + UINT16_t AX; + /** %bx register as for PXENV_START_UNDI */ + UINT16_t BX; + /** %dx register as for PXENV_START_UNDI */ + UINT16_t DX; + /** %di register as for PXENV_START_UNDI */ + OFF16_t DI; + /** %es register as for PXENV_START_UNDI */ + SEGSEL_t ES; + /** UNDI data segment + * + * @note The PXE specification defines the type of this field + * as #UINT16_t. For x86, #SEGSEL_t and #UINT16_t are + * equivalent anyway; for other architectures #SEGSEL_t makes + * more sense. + */ + SEGSEL_t UNDI_DS; + /** UNDI code segment + * + * @note The PXE specification defines the type of this field + * as #UINT16_t. For x86, #SEGSEL_t and #UINT16_t are + * equivalent anyway; for other architectures #SEGSEL_t makes + * more sense. + */ + SEGSEL_t UNDI_CS; + /** Address of the !PXE structure (a struct s_PXE) */ + SEGOFF16_t PXEptr; + /** Address of the PXENV+ structure (a struct s_PXENV) */ + SEGOFF16_t PXENVptr; +} PACKED; + +typedef struct s_UNDI_LOADER UNDI_LOADER_t; + +extern PXENV_EXIT_t undi_loader ( struct s_UNDI_LOADER *undi_loader ); + +/** @} */ /* pxe_loader_api */ + +/** @} */ /* pxe */ + +/** @page pxe_notes Etherboot PXE implementation notes + +@section pxe_routing IP routing + +Several PXE API calls (e.g. pxenv_tftp_open() and pxenv_udp_write()) +allow for the caller to specify a "relay agent IP address", often in a +field called "gateway" or similar. The PXE specification states that +"The IP layer should provide space for a minimum of four routing +entries obtained from the default router and static route DHCP option +tags in the DHCPACK message, plus any non-zero giaddr field from the +DHCPOFFER message(s) accepted by the client". + +The DHCP static route option ("option static-routes" in dhcpd.conf) +works only for classed IP routing (i.e. it provides no way to specify +a subnet mask). Since virtually everything now uses classless IP +routing, the DHCP static route option is almost totally useless, and +is (according to the dhcp-options man page) not implemented by any of +the popular DHCP clients. + +This leaves the caller-specified "relay agent IP address", the giaddr +field from the DHCPOFFER message(s) and the default gateway(s) +provided via the routers option ("option routers" in dhcpd.conf) in +the DHCPACK message. Each of these is a default gateway address. +It's a fair bet that the routers option should take priority over the +giaddr field, since the routers option has to be explicitly specified +by the DHCP server operator. Similarly, it's fair to assume that the +caller-specified "relay agent IP address", if present, should take +priority over any other routing table entries. + +@bug Etherboot currently ignores all potential sources of routing +information other than the first router provided to it by a DHCP +routers option. + +@section pxe_x86_modes x86 processor mode restrictions + +On the x86 platform, different PXE API calls have different +restrictions on the processor modes (real or protected) that can be +used. See the individual API call descriptions for the restrictions +that apply to any particular call. + +@subsection pxe_x86_pmode16 Real mode, or protected-mode with 16-bit stack + +The PXE specification states that the API function can be called in +protected mode only if the s_PXE::StatusCallout field is set to a +non-zero value, and that the API function cannot be called with a +32-bit stack segment. + +Etherboot does not enforce either of these restrictions; they seem (as +with so much of the PXE specification) to be artifacts of the Intel +implementation. + +*/ + +#endif /* PXE_API_H */ diff --git a/src/arch/i386/include/pxe_types.h b/src/arch/i386/include/pxe_types.h new file mode 100644 index 00000000..dd9092ef --- /dev/null +++ b/src/arch/i386/include/pxe_types.h @@ -0,0 +1,125 @@ +#ifndef PXE_TYPES_H +#define PXE_TYPES_H + +/** @file + * + * PXE data types + * + */ + +#include +#include /* PXE status codes */ + +/** @addtogroup pxe Preboot eXecution Environment (PXE) API + * @{ + */ + +/** @defgroup pxe_types PXE data types + * + * Basic PXE data types such as #UINT16_t, #ADDR32_t, #SEGSEL_t etc. + * + * These definitions are based on Table 1-1 ("Data Type Definitions") + * in the Intel PXE specification version 2.1. They have been + * generalised to non-x86 architectures where possible. + * + * @{ + */ + +/** An 8-bit unsigned integer */ +typedef uint8_t UINT8_t; + +/** A 16-bit unsigned integer */ +typedef uint16_t UINT16_t; + +/** A 32-bit unsigned integer */ +typedef uint32_t UINT32_t; + +/** A PXE exit code. + * + * Permitted values are #PXENV_EXIT_SUCCESS and #PXENV_EXIT_FAILURE. + * + */ +typedef UINT16_t PXENV_EXIT_t; +#define PXENV_EXIT_SUCCESS 0x0000 /**< No error occurred */ +#define PXENV_EXIT_FAILURE 0x0001 /**< An error occurred */ + +/** A PXE status code. + * + * Status codes are defined in errno.h. + * + */ +typedef UINT16_t PXENV_STATUS_t; + +/** An IPv4 address. + * + * @note This data type is in network (big-endian) byte order. + * + */ +typedef UINT32_t IP4_t; + +/** A UDP port. + * + * @note This data type is in network (big-endian) byte order. + * + */ +typedef UINT16_t UDP_PORT_t; + +/** Maximum length of a MAC address */ +#define MAC_ADDR_LEN 16 + +/** A MAC address */ +typedef UINT8_t MAC_ADDR_t[MAC_ADDR_LEN]; + +#ifndef HAVE_ARCH_ADDR32 +/** A physical address. + * + * For x86, this is a 32-bit physical address, and is therefore + * limited to the low 4GB. + * + */ +typedef UINT32_t ADDR32_t; +#endif + +#ifndef HAVE_ARCH_SEGSEL +/** A segment selector. + * + * For x86, this is a real mode segment (0x0000-0xffff), or a + * protected-mode segment selector, such as could be loaded into a + * segment register. + * + */ +typedef UINT16_t SEGSEL_t; +#endif + +#ifndef HAVE_ARCH_OFF16 +/** An offset within a segment identified by #SEGSEL + * + * For x86, this is a 16-bit offset. + * + */ +typedef UINT16_t OFF16_t; +#endif + +/** A segment:offset address + * + * For x86, this is a 16-bit real-mode or protected-mode + * segment:offset address. + * + */ +typedef struct s_SEGOFF16 { + OFF16_t offset; /**< Offset within the segment */ + SEGSEL_t segment; /**< Segment selector */ +} PACKED SEGOFF16_t; + +/** A segment descriptor */ +typedef struct s_SEGDESC { + SEGSEL_t segment_address; /**< Segment selector */ + ADDR32_t Physical_address; /**< Segment base address */ + OFF16_t Seg_size; /**< Size of the segment */ +} PACKED SEGDESC_t; + +/** @} */ /* pxe_types */ + +/** @} */ /* pxe */ + +#endif /* PXE_TYPES_H */ diff --git a/src/arch/i386/interface/pxe/pxe_errors.c b/src/arch/i386/interface/pxe/pxe_errors.c new file mode 100644 index 00000000..f884ef8a --- /dev/null +++ b/src/arch/i386/interface/pxe/pxe_errors.c @@ -0,0 +1,103 @@ +#include +#include + +/* + * This table was generated from the relevant section of errno.h using + * + * perl -ne 'if ( /(PXENV_STATUS_(\S+))/ ) { + * $code = $1; $msg = $2; + * $msg =~ s/_/ /g; $msg = ucfirst lc $msg; + * $msg =~ s/(tftp|udp|arp|undi|bis|binl|pxenv|pxe|dhcp)/uc $1/ieg; + * print "\t{ $code, \"$msg\" },\n"; + * }' + * + * followed by a little manual tweaking. + * + */ +struct errortab pxe_errortab[] __errortab = { + { PXENV_STATUS_SUCCESS, "Success" }, + { PXENV_STATUS_FAILURE, "Failure" }, + { PXENV_STATUS_BAD_FUNC, "Bad function" }, + { PXENV_STATUS_UNSUPPORTED, "Unsupported function" }, + { PXENV_STATUS_KEEP_UNDI, "Keep UNDI" }, + { PXENV_STATUS_KEEP_ALL, "Keep all" }, + { PXENV_STATUS_OUT_OF_RESOURCES, "Out of resources" }, + { PXENV_STATUS_ARP_TIMEOUT, "ARP timeout" }, + { PXENV_STATUS_UDP_CLOSED, "UDP closed" }, + { PXENV_STATUS_UDP_OPEN, "UDP open" }, + { PXENV_STATUS_TFTP_CLOSED, "TFTP closed" }, + { PXENV_STATUS_TFTP_OPEN, "TFTP open" }, + { PXENV_STATUS_MCOPY_PROBLEM, "Memory copy problem" }, + { PXENV_STATUS_BIS_INTEGRITY_FAILURE, "BIS integrity failure" }, + { PXENV_STATUS_BIS_VALIDATE_FAILURE, "BIS validation failure" }, + { PXENV_STATUS_BIS_INIT_FAILURE, "BIS init failure" }, + { PXENV_STATUS_BIS_SHUTDOWN_FAILURE, "BIS shutdown failure" }, + { PXENV_STATUS_BIS_GBOA_FAILURE, "BIS GBOA failure" }, + { PXENV_STATUS_BIS_FREE_FAILURE, "BIS free failure" }, + { PXENV_STATUS_BIS_GSI_FAILURE, "BIS GSI failure" }, + { PXENV_STATUS_BIS_BAD_CKSUM, "BIS bad checksum" }, + { PXENV_STATUS_TFTP_CANNOT_ARP_ADDRESS, "TFTP cannot ARP address" }, + { PXENV_STATUS_TFTP_OPEN_TIMEOUT, "TFTP open timeout" }, + { PXENV_STATUS_TFTP_UNKNOWN_OPCODE, "TFTP unknown opcode" }, + { PXENV_STATUS_TFTP_READ_TIMEOUT, "TFTP read timeout" }, + { PXENV_STATUS_TFTP_ERROR_OPCODE, "TFTP error opcode" }, + { PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION, + "TFTP cannot open connection" }, + { PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION, + "TFTP cannot read from connection" }, + { PXENV_STATUS_TFTP_TOO_MANY_PACKAGES, "TFTP too many packages" }, + { PXENV_STATUS_TFTP_FILE_NOT_FOUND, "TFTP file not found" }, + { PXENV_STATUS_TFTP_ACCESS_VIOLATION, "TFTP access violation" }, + { PXENV_STATUS_TFTP_NO_MCAST_ADDRESS, "TFTP no mcast address" }, + { PXENV_STATUS_TFTP_NO_FILESIZE, "TFTP no filesize" }, + { PXENV_STATUS_TFTP_INVALID_PACKET_SIZE, "TFTP invalid packet size" }, + { PXENV_STATUS_DHCP_TIMEOUT, "DHCP timeout" }, + { PXENV_STATUS_DHCP_NO_IP_ADDRESS, "DHCP no ip address" }, + { PXENV_STATUS_DHCP_NO_BOOTFILE_NAME, "DHCP no bootfile name" }, + { PXENV_STATUS_DHCP_BAD_IP_ADDRESS, "DHCP bad ip address" }, + { PXENV_STATUS_UNDI_INVALID_FUNCTION, "UNDI invalid function" }, + { PXENV_STATUS_UNDI_MEDIATEST_FAILED, "UNDI mediatest failed" }, + { PXENV_STATUS_UNDI_CANNOT_INIT_NIC_FOR_MCAST, + "UNDI cannot initialise NIC for multicast" }, + { PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC, + "UNDI cannot initialise NIC" }, + { PXENV_STATUS_UNDI_CANNOT_INITIALIZE_PHY, + "UNDI cannot initialise PHY" }, + { PXENV_STATUS_UNDI_CANNOT_READ_CONFIG_DATA, + "UNDI cannot read config data" }, + { PXENV_STATUS_UNDI_CANNOT_READ_INIT_DATA, + "UNDI cannot read init data" }, + { PXENV_STATUS_UNDI_BAD_MAC_ADDRESS, "UNDI bad MAC address" }, + { PXENV_STATUS_UNDI_BAD_EEPROM_CHECKSUM, "UNDI bad EEPROM checksum" }, + { PXENV_STATUS_UNDI_ERROR_SETTING_ISR, "UNDI error setting ISR" }, + { PXENV_STATUS_UNDI_INVALID_STATE, "UNDI invalid state" }, + { PXENV_STATUS_UNDI_TRANSMIT_ERROR, "UNDI transmit error" }, + { PXENV_STATUS_UNDI_INVALID_PARAMETER, "UNDI invalid parameter" }, + { PXENV_STATUS_BSTRAP_PROMPT_MENU, "Bootstrap prompt menu" }, + { PXENV_STATUS_BSTRAP_MCAST_ADDR, "Bootstrap mcast addr" }, + { PXENV_STATUS_BSTRAP_MISSING_LIST, "Bootstrap missing list" }, + { PXENV_STATUS_BSTRAP_NO_RESPONSE, "Bootstrap no response" }, + { PXENV_STATUS_BSTRAP_FILE_TOO_BIG, "Bootstrap file too big" }, + { PXENV_STATUS_BINL_CANCELED_BY_KEYSTROKE, + "BINL canceled by keystroke" }, + { PXENV_STATUS_BINL_NO_PXE_SERVER, "BINL no PXE server" }, + { PXENV_STATUS_NOT_AVAILABLE_IN_PMODE, + "Not available in protected mode" }, + { PXENV_STATUS_NOT_AVAILABLE_IN_RMODE, "Not available in real mode" }, + { PXENV_STATUS_BUSD_DEVICE_NOT_SUPPORTED, + "BUSD device not supported" }, + { PXENV_STATUS_LOADER_NO_FREE_BASE_MEMORY, + "Loader no free base memory" }, + { PXENV_STATUS_LOADER_NO_BC_ROMID, "Loader no Base Code ROM ID" }, + { PXENV_STATUS_LOADER_BAD_BC_ROMID, "Loader bad Base Code ROM ID" }, + { PXENV_STATUS_LOADER_BAD_BC_RUNTIME_IMAGE, + "Loader bad Base Code runtime image" }, + { PXENV_STATUS_LOADER_NO_UNDI_ROMID, "Loader no UNDI ROM ID" }, + { PXENV_STATUS_LOADER_BAD_UNDI_ROMID, "Loader bad UNDI ROM ID" }, + { PXENV_STATUS_LOADER_BAD_UNDI_DRIVER_IMAGE, + "Loader bad UNDI driver image" }, + { PXENV_STATUS_LOADER_NO_PXE_STRUCT, "Loader no !PXE struct" }, + { PXENV_STATUS_LOADER_NO_PXENV_STRUCT, "Loader no PXENV+ struct" }, + { PXENV_STATUS_LOADER_UNDI_START, "Loader UNDI start" }, + { PXENV_STATUS_LOADER_BC_START, "Loader Base Code start" }, +}; diff --git a/src/arch/i386/interface/pxe/pxe_file.c b/src/arch/i386/interface/pxe/pxe_file.c new file mode 100644 index 00000000..41674588 --- /dev/null +++ b/src/arch/i386/interface/pxe/pxe_file.c @@ -0,0 +1,264 @@ +/** @file + * + * PXE FILE API + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Copyright (C) 2007 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FEATURE ( FEATURE_MISC, "PXEXT", DHCP_EB_FEATURE_PXE_EXT, 2 ); + +/** + * FILE OPEN + * + * @v file_open Pointer to a struct s_PXENV_FILE_OPEN + * @v s_PXENV_FILE_OPEN::FileName URL of file to open + * @ret #PXENV_EXIT_SUCCESS File was opened + * @ret #PXENV_EXIT_FAILURE File was not opened + * @ret s_PXENV_FILE_OPEN::Status PXE status code + * @ret s_PXENV_FILE_OPEN::FileHandle Handle of opened file + * + */ +PXENV_EXIT_t pxenv_file_open ( struct s_PXENV_FILE_OPEN *file_open ) { + userptr_t filename; + size_t filename_len; + int fd; + + DBG ( "PXENV_FILE_OPEN" ); + + /* Copy name from external program, and open it */ + filename = real_to_user ( file_open->FileName.segment, + file_open->FileName.offset ); + filename_len = strlen_user ( filename, 0 ); + { + char uri_string[ filename_len + 1 ]; + + copy_from_user ( uri_string, filename, 0, + sizeof ( uri_string ) ); + DBG ( " %s", uri_string ); + fd = open ( uri_string ); + } + + if ( fd < 0 ) { + file_open->Status = PXENV_STATUS ( fd ); + return PXENV_EXIT_FAILURE; + } + + DBG ( " as file %d", fd ); + + file_open->FileHandle = fd; + file_open->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/** + * FILE CLOSE + * + * @v file_close Pointer to a struct s_PXENV_FILE_CLOSE + * @v s_PXENV_FILE_CLOSE::FileHandle File handle + * @ret #PXENV_EXIT_SUCCESS File was closed + * @ret #PXENV_EXIT_FAILURE File was not closed + * @ret s_PXENV_FILE_CLOSE::Status PXE status code + * + */ +PXENV_EXIT_t pxenv_file_close ( struct s_PXENV_FILE_CLOSE *file_close ) { + + DBG ( "PXENV_FILE_CLOSE %d", file_close->FileHandle ); + + close ( file_close->FileHandle ); + file_close->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/** + * FILE SELECT + * + * @v file_select Pointer to a struct s_PXENV_FILE_SELECT + * @v s_PXENV_FILE_SELECT::FileHandle File handle + * @ret #PXENV_EXIT_SUCCESS File has been checked for readiness + * @ret #PXENV_EXIT_FAILURE File has not been checked for readiness + * @ret s_PXENV_FILE_SELECT::Status PXE status code + * @ret s_PXENV_FILE_SELECT::Ready Indication of readiness + * + */ +PXENV_EXIT_t pxenv_file_select ( struct s_PXENV_FILE_SELECT *file_select ) { + fd_set fdset; + int ready; + + DBG ( "PXENV_FILE_SELECT %d", file_select->FileHandle ); + + FD_ZERO ( &fdset ); + FD_SET ( file_select->FileHandle, &fdset ); + if ( ( ready = select ( &fdset, 0 ) ) < 0 ) { + file_select->Status = PXENV_STATUS ( ready ); + return PXENV_EXIT_FAILURE; + } + + file_select->Ready = ( ready ? RDY_READ : 0 ); + file_select->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/** + * FILE READ + * + * @v file_read Pointer to a struct s_PXENV_FILE_READ + * @v s_PXENV_FILE_READ::FileHandle File handle + * @v s_PXENV_FILE_READ::BufferSize Size of data buffer + * @v s_PXENV_FILE_READ::Buffer Data buffer + * @ret #PXENV_EXIT_SUCCESS Data has been read from file + * @ret #PXENV_EXIT_FAILURE Data has not been read from file + * @ret s_PXENV_FILE_READ::Status PXE status code + * @ret s_PXENV_FILE_READ::Ready Indication of readiness + * @ret s_PXENV_FILE_READ::BufferSize Length of data read + * + */ +PXENV_EXIT_t pxenv_file_read ( struct s_PXENV_FILE_READ *file_read ) { + userptr_t buffer; + ssize_t len; + + DBG ( "PXENV_FILE_READ %d to %04x:%04x+%04x", file_read->FileHandle, + file_read->Buffer.segment, file_read->Buffer.offset, + file_read->BufferSize ); + + buffer = real_to_user ( file_read->Buffer.segment, + file_read->Buffer.offset ); + if ( ( len = read_user ( file_read->FileHandle, buffer, 0, + file_read->BufferSize ) ) < 0 ) { + file_read->Status = PXENV_STATUS ( len ); + return PXENV_EXIT_FAILURE; + } + + DBG ( " read %04zx", ( ( size_t ) len ) ); + + file_read->BufferSize = len; + file_read->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/** + * GET FILE SIZE + * + * @v get_file_size Pointer to a struct s_PXENV_GET_FILE_SIZE + * @v s_PXENV_GET_FILE_SIZE::FileHandle File handle + * @ret #PXENV_EXIT_SUCCESS File size has been determined + * @ret #PXENV_EXIT_FAILURE File size has not been determined + * @ret s_PXENV_GET_FILE_SIZE::Status PXE status code + * @ret s_PXENV_GET_FILE_SIZE::FileSize Size of file + */ +PXENV_EXIT_t pxenv_get_file_size ( struct s_PXENV_GET_FILE_SIZE + *get_file_size ) { + ssize_t filesize; + + DBG ( "PXENV_GET_FILE_SIZE %d", get_file_size->FileHandle ); + + filesize = fsize ( get_file_size->FileHandle ); + if ( filesize < 0 ) { + get_file_size->Status = PXENV_STATUS ( filesize ); + return PXENV_EXIT_FAILURE; + } + + DBG ( " is %zd", ( ( size_t ) filesize ) ); + + get_file_size->FileSize = filesize; + get_file_size->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/** + * FILE EXEC + * + * @v file_exec Pointer to a struct s_PXENV_FILE_EXEC + * @v s_PXENV_FILE_EXEC::Command Command to execute + * @ret #PXENV_EXIT_SUCCESS Command was executed successfully + * @ret #PXENV_EXIT_FAILURE Command was not executed successfully + * @ret s_PXENV_FILE_EXEC::Status PXE status code + * + */ +PXENV_EXIT_t pxenv_file_exec ( struct s_PXENV_FILE_EXEC *file_exec ) { + userptr_t command; + size_t command_len; + int rc; + + DBG ( "PXENV_FILE_EXEC" ); + + /* Copy name from external program, and exec it */ + command = real_to_user ( file_exec->Command.segment, + file_exec->Command.offset ); + command_len = strlen_user ( command, 0 ); + { + char command_string[ command_len + 1 ]; + + copy_from_user ( command_string, command, 0, + sizeof ( command_string ) ); + DBG ( " %s", command_string ); + + if ( ( rc = system ( command_string ) ) != 0 ) { + file_exec->Status = PXENV_STATUS ( rc ); + return PXENV_EXIT_FAILURE; + } + } + + file_exec->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/** + * FILE API CHECK + * + * @v file_exec Pointer to a struct s_PXENV_FILE_API_CHECK + * @v s_PXENV_FILE_API_CHECK::Magic Inbound magic number (0x91d447b2) + * @ret #PXENV_EXIT_SUCCESS Command was executed successfully + * @ret #PXENV_EXIT_FAILURE Command was not executed successfully + * @ret s_PXENV_FILE_API_CHECK::Status PXE status code + * @ret s_PXENV_FILE_API_CHECK::Magic Outbound magic number (0xe9c17b20) + * @ret s_PXENV_FILE_API_CHECK::Provider "gPXE" (0x45585067) + * @ret s_PXENV_FILE_API_CHECK::APIMask API function bitmask + * @ret s_PXENV_FILE_API_CHECK::Flags Reserved + * + */ +PXENV_EXIT_t pxenv_file_api_check ( struct s_PXENV_FILE_API_CHECK *file_api_check ) { + DBG ( "PXENV_FILE_API_CHECK" ); + + if ( file_api_check->Magic != 0x91d447b2 ) { + file_api_check->Status = PXENV_STATUS_BAD_FUNC; + return PXENV_EXIT_FAILURE; + } else if ( file_api_check->Size < + sizeof(struct s_PXENV_FILE_API_CHECK) ) { + file_api_check->Status = PXENV_STATUS_OUT_OF_RESOURCES; + return PXENV_EXIT_FAILURE; + } else { + file_api_check->Status = PXENV_STATUS_SUCCESS; + file_api_check->Size = sizeof(struct s_PXENV_FILE_API_CHECK); + file_api_check->Magic = 0xe9c17b20; + file_api_check->Provider = 0x45585067; /* "gPXE" */ + file_api_check->APIMask = 0x0000007f; /* Functions e0-e6 */ + file_api_check->Flags = 0; /* None defined */ + return PXENV_EXIT_SUCCESS; + } +} diff --git a/src/arch/i386/interface/pxe/pxe_loader.c b/src/arch/i386/interface/pxe/pxe_loader.c new file mode 100644 index 00000000..d228a36d --- /dev/null +++ b/src/arch/i386/interface/pxe/pxe_loader.c @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2007 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include "pxe.h" +#include "pxe_call.h" + +/** @file + * + * PXE UNDI loader + * + */ + +/* PXENV_UNDI_LOADER + * + */ +PXENV_EXIT_t undi_loader ( struct s_UNDI_LOADER *undi_loader ) { + + /* Perform one-time initialisation (e.g. heap) */ + initialise(); + + DBG ( "[PXENV_UNDI_LOADER to CS %04x DS %04x]", + undi_loader->UNDI_CS, undi_loader->UNDI_DS ); + + /* Set up PXE data structures */ + pxe_init_structures(); + + /* Fill in UNDI loader structure */ + undi_loader->PXEptr.segment = rm_cs; + undi_loader->PXEptr.offset = __from_text16 ( &ppxe ); + undi_loader->PXENVptr.segment = rm_cs; + undi_loader->PXENVptr.offset = __from_text16 ( &pxenv ); + + undi_loader->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} diff --git a/src/arch/i386/interface/pxe/pxe_preboot.c b/src/arch/i386/interface/pxe/pxe_preboot.c new file mode 100644 index 00000000..8220d1f2 --- /dev/null +++ b/src/arch/i386/interface/pxe/pxe_preboot.c @@ -0,0 +1,352 @@ +/** @file + * + * PXE Preboot API + * + */ + +/* PXE API interface for Etherboot. + * + * Copyright (C) 2004 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pxe.h" +#include "pxe_call.h" + +/* Avoid dragging in isapnp.o unnecessarily */ +uint16_t isapnp_read_port; + +/** Zero-based versions of PXENV_GET_CACHED_INFO::PacketType */ +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 +}; + +/** A cached DHCP packet */ +union pxe_cached_info { + struct dhcphdr dhcphdr; + /* This buffer must be *exactly* the size of a BOOTPLAYER_t + * structure, otherwise WinPE will die horribly. It takes the + * size of *our* buffer and feeds it in to us as the size of + * one of *its* buffers. If our buffer is larger than it + * expects, we therefore end up overwriting part of its data + * segment, since it tells us to do so. (D'oh!) + * + * Note that a BOOTPLAYER_t is not necessarily large enough to + * hold a DHCP packet; this is a flaw in the PXE spec. + */ + BOOTPLAYER_t packet; +} __attribute__ (( packed )); + +/** A PXE DHCP packet creator */ +struct pxe_dhcp_packet_creator { + /** Create DHCP packet + * + * @v netdev Network device + * @v data Buffer for DHCP packet + * @v max_len Size of DHCP packet buffer + * @ret rc Return status code + */ + int ( * create ) ( struct net_device *netdev, void *data, + size_t max_len ); +}; + +/** PXE DHCP packet creators */ +static struct pxe_dhcp_packet_creator pxe_dhcp_packet_creators[] = { + [CACHED_INFO_DHCPDISCOVER] = { create_fakedhcpdiscover }, + [CACHED_INFO_DHCPACK] = { create_fakedhcpack }, + [CACHED_INFO_BINL] = { create_fakeproxydhcpack }, +}; + +/* The case in which the caller doesn't supply a buffer is really + * awkward to support given that we have multiple sources of options, + * and that we don't actually store the DHCP packets. (We may not + * even have performed DHCP; we may have obtained all configuration + * from non-volatile stored options or from the command line.) + * + * Some NBPs rely on the buffers we provide being persistent, so we + * can't just use the temporary packet buffer. 4.5kB of base memory + * always wasted just because some clients are too lazy to provide + * their own buffers... + */ +static union pxe_cached_info __bss16_array ( cached_info, [NUM_CACHED_INFOS] ); +#define cached_info __use_data16 ( cached_info ) + +/** + * Set PXE cached TFTP filename + * + * @v filename TFTP filename + * + * This is a bug-for-bug compatibility hack needed in order to work + * with Microsoft Remote Installation Services (RIS). The filename + * used in a call to PXENV_RESTART_TFTP or PXENV_TFTP_READ_FILE must + * be returned as the DHCP filename in subsequent calls to + * PXENV_GET_CACHED_INFO. + */ +void pxe_set_cached_filename ( const unsigned char *filename ) { + memcpy ( cached_info[CACHED_INFO_DHCPACK].dhcphdr.file, filename, + sizeof ( cached_info[CACHED_INFO_DHCPACK].dhcphdr.file ) ); + memcpy ( cached_info[CACHED_INFO_BINL].dhcphdr.file, filename, + sizeof ( cached_info[CACHED_INFO_BINL].dhcphdr.file ) ); +} + +/** + * UNLOAD BASE CODE STACK + * + * @v None - + * @ret ... + * + */ +PXENV_EXIT_t pxenv_unload_stack ( struct s_PXENV_UNLOAD_STACK *unload_stack ) { + DBG ( "PXENV_UNLOAD_STACK" ); + + unload_stack->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/* PXENV_GET_CACHED_INFO + * + * Status: working + */ +PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO + *get_cached_info ) { + struct pxe_dhcp_packet_creator *creator; + union pxe_cached_info *info; + unsigned int idx; + size_t len; + userptr_t buffer; + int rc; + + DBG ( "PXENV_GET_CACHED_INFO %d", get_cached_info->PacketType ); + + DBG ( " to %04x:%04x+%x", 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 ) { + DBG ( " bad PacketType" ); + goto err; + } + info = &cached_info[idx]; + + /* Construct cached version of packet, if not already constructed. */ + if ( ! info->dhcphdr.op ) { + /* Construct DHCP packet */ + creator = &pxe_dhcp_packet_creators[idx]; + if ( ( rc = creator->create ( pxe_netdev, info, + sizeof ( *info ) ) ) != 0 ) { + DBG ( " failed to build packet" ); + goto err; + } + } + + 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 ); + DBG ( " returning %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 ) ) + DBG ( " 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; + } + + get_cached_info->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; + + err: + get_cached_info->Status = PXENV_STATUS_OUT_OF_RESOURCES; + return PXENV_EXIT_FAILURE; +} + +/* PXENV_RESTART_TFTP + * + * Status: working + */ +PXENV_EXIT_t pxenv_restart_tftp ( struct s_PXENV_TFTP_READ_FILE + *restart_tftp ) { + PXENV_EXIT_t tftp_exit; + + DBG ( "PXENV_RESTART_TFTP " ); + + /* Intel bug-for-bug hack */ + pxe_set_cached_filename ( restart_tftp->FileName ); + + /* 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; + + /* Fire up the new NBP */ + restart_tftp->Status = pxe_start_nbp(); + + /* Not sure what "SUCCESS" actually means, since we can only + * return if the new NBP failed to boot... + */ + return PXENV_EXIT_SUCCESS; +} + +/* PXENV_START_UNDI + * + * Status: working + */ +PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi ) { + unsigned int bus_type; + unsigned int location; + struct net_device *netdev; + + DBG ( "PXENV_START_UNDI %04x:%04x:%04x", + 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 ) { + DBG ( " no net device found" ); + start_undi->Status = PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC; + return PXENV_EXIT_FAILURE; + } + DBG ( " using netdev %s", netdev->name ); + + /* Save as PXE net device */ + pxe_set_netdev ( netdev ); + + /* Hook INT 1A */ + pxe_hook_int1a(); + + start_undi->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/* PXENV_STOP_UNDI + * + * Status: working + */ +PXENV_EXIT_t pxenv_stop_undi ( struct s_PXENV_STOP_UNDI *stop_undi ) { + DBG ( "PXENV_STOP_UNDI" ); + + /* Unhook INT 1A */ + pxe_unhook_int1a(); + + /* Clear PXE net device */ + pxe_set_netdev ( NULL ); + + /* Prepare for unload */ + shutdown ( SHUTDOWN_BOOT ); + + stop_undi->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/* PXENV_START_BASE + * + * Status: won't implement (requires major structural changes) + */ +PXENV_EXIT_t pxenv_start_base ( struct s_PXENV_START_BASE *start_base ) { + DBG ( "PXENV_START_BASE" ); + + start_base->Status = PXENV_STATUS_UNSUPPORTED; + return PXENV_EXIT_FAILURE; +} + +/* PXENV_STOP_BASE + * + * Status: working + */ +PXENV_EXIT_t pxenv_stop_base ( struct s_PXENV_STOP_BASE *stop_base ) { + DBG ( "PXENV_STOP_BASE" ); + + /* 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; +} diff --git a/src/arch/i386/interface/pxe/pxe_tftp.c b/src/arch/i386/interface/pxe/pxe_tftp.c new file mode 100644 index 00000000..f5e76206 --- /dev/null +++ b/src/arch/i386/interface/pxe/pxe_tftp.c @@ -0,0 +1,584 @@ +/** @file + * + * PXE TFTP API + * + */ + +/* + * Copyright (C) 2004 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** A PXE TFTP connection */ +struct pxe_tftp_connection { + /** Data transfer interface */ + struct xfer_interface xfer; + /** Data buffer */ + userptr_t buffer; + /** Size of data buffer */ + size_t size; + /** Starting offset of data buffer */ + size_t start; + /** File position */ + size_t offset; + /** Maximum file position */ + size_t max_offset; + /** Block size */ + size_t blksize; + /** Block index */ + unsigned int blkidx; + /** Overall return status code */ + int rc; +}; + +/** The PXE TFTP connection */ +static struct pxe_tftp_connection pxe_tftp = { + .xfer = XFER_INIT ( &null_xfer_ops ), +}; + +/** + * Close PXE TFTP connection + * + * @v rc Final status code + */ +static void pxe_tftp_close ( int rc ) { + xfer_nullify ( &pxe_tftp.xfer ); + xfer_close ( &pxe_tftp.xfer, rc ); + pxe_tftp.rc = rc; +} + +/** + * Receive new data + * + * @v xfer Data transfer interface + * @v iobuf I/O buffer + * @v meta Transfer metadata + * @ret rc Return status code + */ +static int pxe_tftp_xfer_deliver_iob ( struct xfer_interface *xfer __unused, + struct io_buffer *iobuf, + struct xfer_metadata *meta ) { + size_t len = iob_len ( iobuf ); + int rc = 0; + + /* Calculate new buffer position */ + if ( meta->whence != SEEK_CUR ) + pxe_tftp.offset = 0; + pxe_tftp.offset += meta->offset; + + /* Copy data block to buffer */ + if ( len == 0 ) { + /* No data (pure seek); treat as success */ + } else if ( pxe_tftp.offset < pxe_tftp.start ) { + DBG ( " buffer underrun at %zx (min %zx)", + pxe_tftp.offset, pxe_tftp.start ); + rc = -ENOBUFS; + } else if ( ( pxe_tftp.offset + len ) > + ( pxe_tftp.start + pxe_tftp.size ) ) { + DBG ( " buffer overrun at %zx (max %zx)", + ( pxe_tftp.offset + len ), + ( pxe_tftp.start + pxe_tftp.size ) ); + rc = -ENOBUFS; + } else { + copy_to_user ( pxe_tftp.buffer, + ( pxe_tftp.offset - pxe_tftp.start ), + iobuf->data, len ); + } + + /* Calculate new buffer position */ + pxe_tftp.offset += len; + + /* Mildly ugly hack; assume that the first non-zero seek + * indicates the block size. + */ + if ( pxe_tftp.blksize == 0 ) + pxe_tftp.blksize = pxe_tftp.offset; + + /* Record maximum offset as the file size */ + if ( pxe_tftp.max_offset < pxe_tftp.offset ) + pxe_tftp.max_offset = pxe_tftp.offset; + + /* Terminate transfer on error */ + if ( rc != 0 ) + pxe_tftp_close ( rc ); + + free_iob ( iobuf ); + return rc; +} + +/** + * Handle close() event + * + * @v xfer Data transfer interface + * @v rc Reason for close + */ +static void pxe_tftp_xfer_close ( struct xfer_interface *xfer __unused, + int rc ) { + pxe_tftp_close ( rc ); +} + +static struct xfer_interface_operations pxe_tftp_xfer_ops = { + .close = pxe_tftp_xfer_close, + .vredirect = xfer_vopen, + .window = unlimited_xfer_window, + .alloc_iob = default_xfer_alloc_iob, + .deliver_iob = pxe_tftp_xfer_deliver_iob, + .deliver_raw = xfer_deliver_as_iob, +}; + +/** + * Maximum length of a PXE TFTP URI + * + * The PXE TFTP API provides 128 characters for the filename; the + * extra 128 bytes allow for the remainder of the URI. + */ +#define PXE_TFTP_URI_LEN 256 + +/** + * Open PXE TFTP connection + * + * @v ipaddress IP address + * @v port TFTP server port + * @v filename File name + * @v blksize Requested block size + * @ret rc Return status code + */ +static int pxe_tftp_open ( uint32_t ipaddress, unsigned int port, + const unsigned char *filename, size_t blksize ) { + char uri_string[PXE_TFTP_URI_LEN]; + struct in_addr address; + int rc; + + /* Intel bug-for-bug hack */ + pxe_set_cached_filename ( filename ); + + /* Reset PXE TFTP connection structure */ + memset ( &pxe_tftp, 0, sizeof ( pxe_tftp ) ); + xfer_init ( &pxe_tftp.xfer, &pxe_tftp_xfer_ops, NULL ); + pxe_tftp.rc = -EINPROGRESS; + + /* Construct URI string */ + address.s_addr = ipaddress; + if ( ! port ) + port = htons ( TFTP_PORT ); + if ( blksize < TFTP_DEFAULT_BLKSIZE ) + blksize = TFTP_DEFAULT_BLKSIZE; + snprintf ( uri_string, sizeof ( uri_string ), + "tftp://%s:%d%s%s?blksize=%zd", + inet_ntoa ( address ), ntohs ( port ), + ( ( filename[0] == '/' ) ? "" : "/" ), filename, blksize ); + DBG ( " %s", uri_string ); + + /* Open PXE TFTP connection */ + if ( ( rc = xfer_open_uri_string ( &pxe_tftp.xfer, + uri_string ) ) != 0 ) { + DBG ( " could not open (%s)\n", strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * TFTP OPEN + * + * @v tftp_open Pointer to a struct s_PXENV_TFTP_OPEN + * @v s_PXENV_TFTP_OPEN::ServerIPAddress TFTP server IP address + * @v s_PXENV_TFTP_OPEN::GatewayIPAddress Relay agent IP address, or 0.0.0.0 + * @v s_PXENV_TFTP_OPEN::FileName Name of file to open + * @v s_PXENV_TFTP_OPEN::TFTPPort TFTP server UDP port + * @v s_PXENV_TFTP_OPEN::PacketSize TFTP blksize option to request + * @ret #PXENV_EXIT_SUCCESS File was opened + * @ret #PXENV_EXIT_FAILURE File was not opened + * @ret s_PXENV_TFTP_OPEN::Status PXE status code + * @ret s_PXENV_TFTP_OPEN::PacketSize Negotiated blksize + * @err #PXENV_STATUS_TFTP_INVALID_PACKET_SIZE Requested blksize too small + * + * Opens a TFTP connection for downloading a file a block at a time + * using pxenv_tftp_read(). + * + * If s_PXENV_TFTP_OPEN::GatewayIPAddress is 0.0.0.0, normal IP + * routing will take place. See the relevant + * @ref pxe_routing "implementation note" for more details. + * + * On x86, you must set the s_PXE::StatusCallout field to a nonzero + * value before calling this function in protected mode. You cannot + * call this function with a 32-bit stack segment. (See the relevant + * @ref pxe_x86_pmode16 "implementation note" for more details.) + * + * @note According to the PXE specification version 2.1, this call + * "opens a file for reading/writing", though how writing is to be + * achieved without the existence of an API call %pxenv_tftp_write() + * is not made clear. + * + * @note Despite the existence of the numerous statements within the + * PXE specification of the form "...if a TFTP/MTFTP or UDP connection + * is active...", you cannot use pxenv_tftp_open() and + * pxenv_tftp_read() to read a file via MTFTP; only via plain old + * TFTP. If you want to use MTFTP, use pxenv_tftp_read_file() + * instead. Astute readers will note that, since + * pxenv_tftp_read_file() is an atomic operation from the point of + * view of the PXE API, it is conceptually impossible to issue any + * other PXE API call "if an MTFTP connection is active". + */ +PXENV_EXIT_t pxenv_tftp_open ( struct s_PXENV_TFTP_OPEN *tftp_open ) { + int rc; + + DBG ( "PXENV_TFTP_OPEN" ); + + /* Guard against callers that fail to close before re-opening */ + pxe_tftp_close ( 0 ); + + /* Open connection */ + if ( ( rc = pxe_tftp_open ( tftp_open->ServerIPAddress, + tftp_open->TFTPPort, + tftp_open->FileName, + tftp_open->PacketSize ) ) != 0 ) { + tftp_open->Status = PXENV_STATUS ( rc ); + return PXENV_EXIT_FAILURE; + } + + /* Wait for OACK to arrive so that we have the block size */ + while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) && + ( pxe_tftp.blksize == 0 ) ) { + step(); + } + tftp_open->PacketSize = pxe_tftp.blksize; + + /* EINPROGRESS is normal; we don't wait for the whole transfer */ + if ( rc == -EINPROGRESS ) + rc = 0; + + tftp_open->Status = PXENV_STATUS ( rc ); + return ( rc ? PXENV_EXIT_FAILURE : PXENV_EXIT_SUCCESS ); +} + +/** + * TFTP CLOSE + * + * @v tftp_close Pointer to a struct s_PXENV_TFTP_CLOSE + * @ret #PXENV_EXIT_SUCCESS File was closed successfully + * @ret #PXENV_EXIT_FAILURE File was not closed + * @ret s_PXENV_TFTP_CLOSE::Status PXE status code + * @err None - + * + * Close a connection previously opened with pxenv_tftp_open(). You + * must have previously opened a connection with pxenv_tftp_open(). + * + * On x86, you must set the s_PXE::StatusCallout field to a nonzero + * value before calling this function in protected mode. You cannot + * call this function with a 32-bit stack segment. (See the relevant + * @ref pxe_x86_pmode16 "implementation note" for more details.) + */ +PXENV_EXIT_t pxenv_tftp_close ( struct s_PXENV_TFTP_CLOSE *tftp_close ) { + DBG ( "PXENV_TFTP_CLOSE" ); + + pxe_tftp_close ( 0 ); + tftp_close->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/** + * TFTP READ + * + * @v tftp_read Pointer to a struct s_PXENV_TFTP_READ + * @v s_PXENV_TFTP_READ::Buffer Address of data buffer + * @ret #PXENV_EXIT_SUCCESS Data was read successfully + * @ret #PXENV_EXIT_FAILURE Data was not read + * @ret s_PXENV_TFTP_READ::Status PXE status code + * @ret s_PXENV_TFTP_READ::PacketNumber TFTP packet number + * @ret s_PXENV_TFTP_READ::BufferSize Length of data written into buffer + * + * Reads a single packet from a connection previously opened with + * pxenv_tftp_open() into the data buffer pointed to by + * s_PXENV_TFTP_READ::Buffer. You must have previously opened a + * connection with pxenv_tftp_open(). The data written into + * s_PXENV_TFTP_READ::Buffer is just the file data; the various + * network headers have already been removed. + * + * The buffer must be large enough to contain a packet of the size + * negotiated via the s_PXENV_TFTP_OPEN::PacketSize field in the + * pxenv_tftp_open() call. It is worth noting that the PXE + * specification does @b not require the caller to fill in + * s_PXENV_TFTP_READ::BufferSize before calling pxenv_tftp_read(), so + * the PXE stack is free to ignore whatever value the caller might + * place there and just assume that the buffer is large enough. That + * said, it may be worth the caller always filling in + * s_PXENV_TFTP_READ::BufferSize to guard against PXE stacks that + * mistake it for an input parameter. + * + * The length of the TFTP data packet will be returned via + * s_PXENV_TFTP_READ::BufferSize. If this length is less than the + * blksize negotiated via s_PXENV_TFTP_OPEN::PacketSize in the call to + * pxenv_tftp_open(), this indicates that the block is the last block + * in the file. Note that zero is a valid length for + * s_PXENV_TFTP_READ::BufferSize, and will occur when the length of + * the file is a multiple of the blksize. + * + * The PXE specification doesn't actually state that calls to + * pxenv_tftp_read() will return the data packets in strict sequential + * order, though most PXE stacks will probably do so. The sequence + * number of the packet will be returned in + * s_PXENV_TFTP_READ::PacketNumber. The first packet in the file has + * a sequence number of one, not zero. + * + * To guard against flawed PXE stacks, the caller should probably set + * s_PXENV_TFTP_READ::PacketNumber to one less than the expected + * returned value (i.e. set it to zero for the first call to + * pxenv_tftp_read() and then re-use the returned s_PXENV_TFTP_READ + * parameter block for subsequent calls without modifying + * s_PXENV_TFTP_READ::PacketNumber between calls). The caller should + * also guard against potential problems caused by flawed + * implementations returning the occasional duplicate packet, by + * checking that the value returned in s_PXENV_TFTP_READ::PacketNumber + * is as expected (i.e. one greater than that returned from the + * previous call to pxenv_tftp_read()). + * + * On x86, you must set the s_PXE::StatusCallout field to a nonzero + * value before calling this function in protected mode. You cannot + * call this function with a 32-bit stack segment. (See the relevant + * @ref pxe_x86_pmode16 "implementation note" for more details.) + */ +PXENV_EXIT_t pxenv_tftp_read ( struct s_PXENV_TFTP_READ *tftp_read ) { + int rc; + + DBG ( "PXENV_TFTP_READ to %04x:%04x", + tftp_read->Buffer.segment, tftp_read->Buffer.offset ); + + /* Read single block into buffer */ + pxe_tftp.buffer = real_to_user ( tftp_read->Buffer.segment, + tftp_read->Buffer.offset ); + pxe_tftp.size = pxe_tftp.blksize; + pxe_tftp.start = pxe_tftp.offset; + while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) && + ( pxe_tftp.offset == pxe_tftp.start ) ) + step(); + pxe_tftp.buffer = UNULL; + tftp_read->BufferSize = ( pxe_tftp.offset - pxe_tftp.start ); + tftp_read->PacketNumber = ++pxe_tftp.blkidx; + + /* EINPROGRESS is normal if we haven't reached EOF yet */ + if ( rc == -EINPROGRESS ) + rc = 0; + + tftp_read->Status = PXENV_STATUS ( rc ); + return ( rc ? PXENV_EXIT_FAILURE : PXENV_EXIT_SUCCESS ); +} + +/** + * TFTP/MTFTP read file + * + * @v tftp_read_file Pointer to a struct s_PXENV_TFTP_READ_FILE + * @v s_PXENV_TFTP_READ_FILE::FileName File name + * @v s_PXENV_TFTP_READ_FILE::BufferSize Size of the receive buffer + * @v s_PXENV_TFTP_READ_FILE::Buffer Address of the receive buffer + * @v s_PXENV_TFTP_READ_FILE::ServerIPAddress TFTP server IP address + * @v s_PXENV_TFTP_READ_FILE::GatewayIPAddress Relay agent IP address + * @v s_PXENV_TFTP_READ_FILE::McastIPAddress File's multicast IP address + * @v s_PXENV_TFTP_READ_FILE::TFTPClntPort Client multicast UDP port + * @v s_PXENV_TFTP_READ_FILE::TFTPSrvPort Server multicast UDP port + * @v s_PXENV_TFTP_READ_FILE::TFTPOpenTimeOut Time to wait for first packet + * @v s_PXENV_TFTP_READ_FILE::TFTPReopenDelay MTFTP inactivity timeout + * @ret #PXENV_EXIT_SUCCESS File downloaded successfully + * @ret #PXENV_EXIT_FAILURE File not downloaded + * @ret s_PXENV_TFTP_READ_FILE::Status PXE status code + * @ret s_PXENV_TFTP_READ_FILE::BufferSize Length of downloaded file + * + * Downloads an entire file via either TFTP or MTFTP into the buffer + * pointed to by s_PXENV_TFTP_READ_FILE::Buffer. + * + * The PXE specification does not make it clear how the caller + * requests that MTFTP be used rather than TFTP (or vice versa). One + * reasonable guess is that setting + * s_PXENV_TFTP_READ_FILE::McastIPAddress to 0.0.0.0 would cause TFTP + * to be used instead of MTFTP, though it is conceivable that some PXE + * stacks would interpret that as "use the DHCP-provided multicast IP + * address" instead. Some PXE stacks will not implement MTFTP at all, + * and will always use TFTP. + * + * It is not specified whether or not + * s_PXENV_TFTP_READ_FILE::TFTPSrvPort will be used as the TFTP server + * port for TFTP (rather than MTFTP) downloads. Callers should assume + * that the only way to access a TFTP server on a non-standard port is + * to use pxenv_tftp_open() and pxenv_tftp_read(). + * + * If s_PXENV_TFTP_READ_FILE::GatewayIPAddress is 0.0.0.0, normal IP + * routing will take place. See the relevant + * @ref pxe_routing "implementation note" for more details. + * + * It is interesting to note that s_PXENV_TFTP_READ_FILE::Buffer is an + * #ADDR32_t type, i.e. nominally a flat physical address. Some PXE + * NBPs (e.g. NTLDR) are known to call pxenv_tftp_read_file() in real + * mode with s_PXENV_TFTP_READ_FILE::Buffer set to an address above + * 1MB. This means that PXE stacks must be prepared to write to areas + * outside base memory. Exactly how this is to be achieved is not + * specified, though using INT 15,87 is as close to a standard method + * as any, and should probably be used. Switching to protected-mode + * in order to access high memory will fail if pxenv_tftp_read_file() + * is called in V86 mode; it is reasonably to expect that a V86 + * monitor would intercept the relatively well-defined INT 15,87 if it + * wants the PXE stack to be able to write to high memory. + * + * Things get even more interesting if pxenv_tftp_read_file() is + * called in protected mode, because there is then absolutely no way + * for the PXE stack to write to an absolute physical address. You + * can't even get around the problem by creating a special "access + * everything" segment in the s_PXE data structure, because the + * #SEGDESC_t descriptors are limited to 64kB in size. + * + * Previous versions of the PXE specification (e.g. WfM 1.1a) provide + * a separate API call, %pxenv_tftp_read_file_pmode(), specifically to + * work around this problem. The s_PXENV_TFTP_READ_FILE_PMODE + * parameter block splits s_PXENV_TFTP_READ_FILE::Buffer into + * s_PXENV_TFTP_READ_FILE_PMODE::BufferSelector and + * s_PXENV_TFTP_READ_FILE_PMODE::BufferOffset, i.e. it provides a + * protected-mode segment:offset address for the data buffer. This + * API call is no longer present in version 2.1 of the PXE + * specification. + * + * Etherboot makes the assumption that s_PXENV_TFTP_READ_FILE::Buffer + * is an offset relative to the caller's data segment, when + * pxenv_tftp_read_file() is called in protected mode. + * + * On x86, you must set the s_PXE::StatusCallout field to a nonzero + * value before calling this function in protected mode. You cannot + * call this function with a 32-bit stack segment. (See the relevant + * @ref pxe_x86_pmode16 "implementation note" for more details.) + * + * @note Microsoft's NTLDR assumes that the filename passed in via + * s_PXENV_TFTP_READ_FILE::FileName will be stored in the "file" field + * of the stored DHCPACK packet, whence it will be returned via any + * subsequent calls to pxenv_get_cached_info(). Though this is + * essentially a bug in the Intel PXE implementation (not, for once, + * in the specification!), it is a bug that Microsoft relies upon, and + * so we implement this bug-for-bug compatibility by overwriting the + * filename stored DHCPACK packet with the filename passed in + * s_PXENV_TFTP_READ_FILE::FileName. + * + */ +PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE + *tftp_read_file ) { + int rc; + + DBG ( "PXENV_TFTP_READ_FILE to %08lx+%lx", tftp_read_file->Buffer, + tftp_read_file->BufferSize ); + + /* Open TFTP file */ + if ( ( rc = pxe_tftp_open ( tftp_read_file->ServerIPAddress, 0, + tftp_read_file->FileName, 0 ) ) != 0 ) { + tftp_read_file->Status = PXENV_STATUS ( rc ); + return PXENV_EXIT_FAILURE; + } + + /* Read entire file */ + pxe_tftp.buffer = phys_to_user ( tftp_read_file->Buffer ); + pxe_tftp.size = tftp_read_file->BufferSize; + while ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) + step(); + pxe_tftp.buffer = UNULL; + tftp_read_file->BufferSize = pxe_tftp.max_offset; + + /* Close TFTP file */ + pxe_tftp_close ( rc ); + + tftp_read_file->Status = PXENV_STATUS ( rc ); + return ( rc ? PXENV_EXIT_FAILURE : PXENV_EXIT_SUCCESS ); +} + +/** + * TFTP GET FILE SIZE + * + * @v tftp_get_fsize Pointer to a struct s_PXENV_TFTP_GET_FSIZE + * @v s_PXENV_TFTP_GET_FSIZE::ServerIPAddress TFTP server IP address + * @v s_PXENV_TFTP_GET_FSIZE::GatewayIPAddress Relay agent IP address + * @v s_PXENV_TFTP_GET_FSIZE::FileName File name + * @ret #PXENV_EXIT_SUCCESS File size was determined successfully + * @ret #PXENV_EXIT_FAILURE File size was not determined + * @ret s_PXENV_TFTP_GET_FSIZE::Status PXE status code + * @ret s_PXENV_TFTP_GET_FSIZE::FileSize File size + * + * Determine the size of a file on a TFTP server. This uses the + * "tsize" TFTP option, and so will not work with a TFTP server that + * does not support TFTP options, or that does not support the "tsize" + * option. + * + * The PXE specification states that this API call will @b not open a + * TFTP connection for subsequent use with pxenv_tftp_read(). (This + * is somewhat daft, since the only way to obtain the file size via + * the "tsize" option involves issuing a TFTP open request, but that's + * life.) + * + * You cannot call pxenv_tftp_get_fsize() while a TFTP or UDP + * connection is open. + * + * If s_PXENV_TFTP_GET_FSIZE::GatewayIPAddress is 0.0.0.0, normal IP + * routing will take place. See the relevant + * @ref pxe_routing "implementation note" for more details. + * + * On x86, you must set the s_PXE::StatusCallout field to a nonzero + * value before calling this function in protected mode. You cannot + * call this function with a 32-bit stack segment. (See the relevant + * @ref pxe_x86_pmode16 "implementation note" for more details.) + * + * @note There is no way to specify the TFTP server port with this API + * call. Though you can open a file using a non-standard TFTP server + * port (via s_PXENV_TFTP_OPEN::TFTPPort or, potentially, + * s_PXENV_TFTP_READ_FILE::TFTPSrvPort), you can only get the size of + * a file from a TFTP server listening on the standard TFTP port. + * "Consistency" is not a word in Intel's vocabulary. + */ +PXENV_EXIT_t pxenv_tftp_get_fsize ( struct s_PXENV_TFTP_GET_FSIZE + *tftp_get_fsize ) { + int rc; + + DBG ( "PXENV_TFTP_GET_FSIZE" ); + + /* Open TFTP file */ + if ( ( rc = pxe_tftp_open ( tftp_get_fsize->ServerIPAddress, 0, + tftp_get_fsize->FileName, 0 ) ) != 0 ) { + tftp_get_fsize->Status = PXENV_STATUS ( rc ); + return PXENV_EXIT_FAILURE; + } + + /* Wait for initial seek to arrive, and record size */ + while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) && + ( pxe_tftp.max_offset == 0 ) ) { + step(); + } + tftp_get_fsize->FileSize = pxe_tftp.max_offset; + + /* EINPROGRESS is normal; we don't wait for the whole transfer */ + if ( rc == -EINPROGRESS ) + rc = 0; + + /* Close TFTP file */ + pxe_tftp_close ( rc ); + + tftp_get_fsize->Status = PXENV_STATUS ( rc ); + return ( rc ? PXENV_EXIT_FAILURE : PXENV_EXIT_SUCCESS ); +} diff --git a/src/arch/i386/interface/pxe/pxe_udp.c b/src/arch/i386/interface/pxe/pxe_udp.c new file mode 100644 index 00000000..033b1ad9 --- /dev/null +++ b/src/arch/i386/interface/pxe/pxe_udp.c @@ -0,0 +1,403 @@ +/** @file + * + * PXE UDP API + * + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Copyright (C) 2004 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/** A PXE UDP connection */ +struct pxe_udp_connection { + /** Data transfer interface to UDP stack */ + struct xfer_interface xfer; + /** Local address */ + struct sockaddr_in local; + /** Current PXENV_UDP_READ parameter block */ + struct s_PXENV_UDP_READ *pxenv_udp_read; +}; + +/** + * Receive PXE UDP data + * + * @v xfer Data transfer interface + * @v iobuf I/O buffer + * @v meta Data transfer metadata + * @ret rc Return status code + * + * Receives a packet as part of the current pxenv_udp_read() + * operation. + */ +static int pxe_udp_deliver_iob ( struct xfer_interface *xfer, + struct io_buffer *iobuf, + struct xfer_metadata *meta ) { + struct pxe_udp_connection *pxe_udp = + container_of ( xfer, struct pxe_udp_connection, xfer ); + struct s_PXENV_UDP_READ *pxenv_udp_read = pxe_udp->pxenv_udp_read; + struct sockaddr_in *sin_src; + struct sockaddr_in *sin_dest; + userptr_t buffer; + size_t len; + int rc = 0; + + if ( ! pxenv_udp_read ) { + DBG ( "PXE discarded UDP packet\n" ); + rc = -ENOBUFS; + goto done; + } + + /* Copy packet to buffer and record length */ + buffer = real_to_user ( pxenv_udp_read->buffer.segment, + pxenv_udp_read->buffer.offset ); + len = iob_len ( iobuf ); + if ( len > pxenv_udp_read->buffer_size ) + len = pxenv_udp_read->buffer_size; + copy_to_user ( buffer, 0, iobuf->data, len ); + pxenv_udp_read->buffer_size = len; + + /* Fill in source/dest information */ + assert ( meta ); + sin_src = ( struct sockaddr_in * ) meta->src; + assert ( sin_src ); + assert ( sin_src->sin_family == AF_INET ); + pxenv_udp_read->src_ip = sin_src->sin_addr.s_addr; + pxenv_udp_read->s_port = sin_src->sin_port; + sin_dest = ( struct sockaddr_in * ) meta->dest; + assert ( sin_dest ); + assert ( sin_dest->sin_family == AF_INET ); + pxenv_udp_read->dest_ip = sin_dest->sin_addr.s_addr; + pxenv_udp_read->d_port = sin_dest->sin_port; + + /* Mark as received */ + pxe_udp->pxenv_udp_read = NULL; + + done: + free_iob ( iobuf ); + return rc; +} + +/** PXE UDP data transfer interface operations */ +static struct xfer_interface_operations pxe_udp_xfer_operations = { + .close = ignore_xfer_close, + .vredirect = ignore_xfer_vredirect, + .window = unlimited_xfer_window, + .alloc_iob = default_xfer_alloc_iob, + .deliver_iob = pxe_udp_deliver_iob, + .deliver_raw = xfer_deliver_as_iob, +}; + +/** The PXE UDP connection */ +static struct pxe_udp_connection pxe_udp = { + .xfer = XFER_INIT ( &pxe_udp_xfer_operations ), + .local = { + .sin_family = AF_INET, + }, +}; + +/** + * UDP OPEN + * + * @v pxenv_udp_open Pointer to a struct s_PXENV_UDP_OPEN + * @v s_PXENV_UDP_OPEN::src_ip IP address of this station, or 0.0.0.0 + * @ret #PXENV_EXIT_SUCCESS Always + * @ret s_PXENV_UDP_OPEN::Status PXE status code + * @err #PXENV_STATUS_UDP_OPEN UDP connection already open + * @err #PXENV_STATUS_OUT_OF_RESOURCES Could not open connection + * + * Prepares the PXE stack for communication using pxenv_udp_write() + * and pxenv_udp_read(). + * + * The IP address supplied in s_PXENV_UDP_OPEN::src_ip will be + * recorded and used as the local station's IP address for all further + * communication, including communication by means other than + * pxenv_udp_write() and pxenv_udp_read(). (If + * s_PXENV_UDP_OPEN::src_ip is 0.0.0.0, the local station's IP address + * will remain unchanged.) + * + * You can only have one open UDP connection at a time. This is not a + * meaningful restriction, since pxenv_udp_write() and + * pxenv_udp_read() allow you to specify arbitrary local and remote + * ports and an arbitrary remote address for each packet. According + * to the PXE specifiation, you cannot have a UDP connection open at + * the same time as a TFTP connection; this restriction does not apply + * to Etherboot. + * + * On x86, you must set the s_PXE::StatusCallout field to a nonzero + * value before calling this function in protected mode. You cannot + * call this function with a 32-bit stack segment. (See the relevant + * @ref pxe_x86_pmode16 "implementation note" for more details.) + * + * @note The PXE specification does not make it clear whether the IP + * address supplied in s_PXENV_UDP_OPEN::src_ip should be used only + * for this UDP connection, or retained for all future communication. + * The latter seems more consistent with typical PXE stack behaviour. + * + * @note Etherboot currently ignores the s_PXENV_UDP_OPEN::src_ip + * parameter. + * + */ +PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *pxenv_udp_open ) { + int rc; + + DBG ( "PXENV_UDP_OPEN" ); + + /* Record source IP address */ + pxe_udp.local.sin_addr.s_addr = pxenv_udp_open->src_ip; + DBG ( " %s", inet_ntoa ( pxe_udp.local.sin_addr ) ); + + /* Open promiscuous UDP connection */ + xfer_close ( &pxe_udp.xfer, 0 ); + if ( ( rc = udp_open_promisc ( &pxe_udp.xfer ) ) != 0 ) { + pxenv_udp_open->Status = PXENV_STATUS ( rc ); + return PXENV_EXIT_FAILURE; + } + + pxenv_udp_open->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/** + * UDP CLOSE + * + * @v pxenv_udp_close Pointer to a struct s_PXENV_UDP_CLOSE + * @ret #PXENV_EXIT_SUCCESS Always + * @ret s_PXENV_UDP_CLOSE::Status PXE status code + * @err None - + * + * Closes a UDP connection opened with pxenv_udp_open(). + * + * You can only have one open UDP connection at a time. You cannot + * have a UDP connection open at the same time as a TFTP connection. + * You cannot use pxenv_udp_close() to close a TFTP connection; use + * pxenv_tftp_close() instead. + * + * On x86, you must set the s_PXE::StatusCallout field to a nonzero + * value before calling this function in protected mode. You cannot + * call this function with a 32-bit stack segment. (See the relevant + * @ref pxe_x86_pmode16 "implementation note" for more details.) + * + */ +PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *pxenv_udp_close ) { + DBG ( "PXENV_UDP_CLOSE" ); + + /* Close UDP connection */ + xfer_close ( &pxe_udp.xfer, 0 ); + + pxenv_udp_close->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/** + * UDP WRITE + * + * @v pxenv_udp_write Pointer to a struct s_PXENV_UDP_WRITE + * @v s_PXENV_UDP_WRITE::ip Destination IP address + * @v s_PXENV_UDP_WRITE::gw Relay agent IP address, or 0.0.0.0 + * @v s_PXENV_UDP_WRITE::src_port Source UDP port, or 0 + * @v s_PXENV_UDP_WRITE::dst_port Destination UDP port + * @v s_PXENV_UDP_WRITE::buffer_size Length of the UDP payload + * @v s_PXENV_UDP_WRITE::buffer Address of the UDP payload + * @ret #PXENV_EXIT_SUCCESS Packet was transmitted successfully + * @ret #PXENV_EXIT_FAILURE Packet could not be transmitted + * @ret s_PXENV_UDP_WRITE::Status PXE status code + * @err #PXENV_STATUS_UDP_CLOSED UDP connection is not open + * @err #PXENV_STATUS_UNDI_TRANSMIT_ERROR Could not transmit packet + * + * Transmits a single UDP packet. A valid IP and UDP header will be + * prepended to the payload in s_PXENV_UDP_WRITE::buffer; the buffer + * should not contain precomputed IP and UDP headers, nor should it + * contain space allocated for these headers. The first byte of the + * buffer will be transmitted as the first byte following the UDP + * header. + * + * If s_PXENV_UDP_WRITE::gw is 0.0.0.0, normal IP routing will take + * place. See the relevant @ref pxe_routing "implementation note" for + * more details. + * + * If s_PXENV_UDP_WRITE::src_port is 0, port 2069 will be used. + * + * You must have opened a UDP connection with pxenv_udp_open() before + * calling pxenv_udp_write(). + * + * On x86, you must set the s_PXE::StatusCallout field to a nonzero + * value before calling this function in protected mode. You cannot + * call this function with a 32-bit stack segment. (See the relevant + * @ref pxe_x86_pmode16 "implementation note" for more details.) + * + * @note Etherboot currently ignores the s_PXENV_UDP_WRITE::gw + * parameter. + * + */ +PXENV_EXIT_t pxenv_udp_write ( struct s_PXENV_UDP_WRITE *pxenv_udp_write ) { + struct sockaddr_in dest; + struct xfer_metadata meta = { + .src = ( struct sockaddr * ) &pxe_udp.local, + .dest = ( struct sockaddr * ) &dest, + .netdev = pxe_netdev, + }; + size_t len; + struct io_buffer *iobuf; + userptr_t buffer; + int rc; + + DBG ( "PXENV_UDP_WRITE" ); + + /* Construct destination socket address */ + memset ( &dest, 0, sizeof ( dest ) ); + dest.sin_family = AF_INET; + dest.sin_addr.s_addr = pxenv_udp_write->ip; + dest.sin_port = pxenv_udp_write->dst_port; + + /* Set local (source) port. PXE spec says source port is 2069 + * if not specified. Really, this ought to be set at UDP open + * time but hey, we didn't design this API. + */ + pxe_udp.local.sin_port = pxenv_udp_write->src_port; + if ( ! pxe_udp.local.sin_port ) + pxe_udp.local.sin_port = htons ( 2069 ); + + /* FIXME: we ignore the gateway specified, since we're + * confident of being able to do our own routing. We should + * probably allow for multiple gateways. + */ + + /* Allocate and fill data buffer */ + len = pxenv_udp_write->buffer_size; + iobuf = xfer_alloc_iob ( &pxe_udp.xfer, len ); + if ( ! iobuf ) { + pxenv_udp_write->Status = PXENV_STATUS_OUT_OF_RESOURCES; + return PXENV_EXIT_FAILURE; + } + buffer = real_to_user ( pxenv_udp_write->buffer.segment, + pxenv_udp_write->buffer.offset ); + copy_from_user ( iob_put ( iobuf, len ), buffer, 0, len ); + + DBG ( " %04x:%04x+%x %d->%s:%d", pxenv_udp_write->buffer.segment, + pxenv_udp_write->buffer.offset, pxenv_udp_write->buffer_size, + ntohs ( pxenv_udp_write->src_port ), + inet_ntoa ( dest.sin_addr ), + ntohs ( pxenv_udp_write->dst_port ) ); + + /* Transmit packet */ + if ( ( rc = xfer_deliver_iob_meta ( &pxe_udp.xfer, iobuf, + &meta ) ) != 0 ) { + pxenv_udp_write->Status = PXENV_STATUS ( rc ); + return PXENV_EXIT_FAILURE; + } + + pxenv_udp_write->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/** + * UDP READ + * + * @v pxenv_udp_read Pointer to a struct s_PXENV_UDP_READ + * @v s_PXENV_UDP_READ::dest_ip Destination IP address, or 0.0.0.0 + * @v s_PXENV_UDP_READ::d_port Destination UDP port, or 0 + * @v s_PXENV_UDP_READ::buffer_size Size of the UDP payload buffer + * @v s_PXENV_UDP_READ::buffer Address of the UDP payload buffer + * @ret #PXENV_EXIT_SUCCESS A packet has been received + * @ret #PXENV_EXIT_FAILURE No packet has been received + * @ret s_PXENV_UDP_READ::Status PXE status code + * @ret s_PXENV_UDP_READ::src_ip Source IP address + * @ret s_PXENV_UDP_READ::dest_ip Destination IP address + * @ret s_PXENV_UDP_READ::s_port Source UDP port + * @ret s_PXENV_UDP_READ::d_port Destination UDP port + * @ret s_PXENV_UDP_READ::buffer_size Length of UDP payload + * @err #PXENV_STATUS_UDP_CLOSED UDP connection is not open + * @err #PXENV_STATUS_FAILURE No packet was ready to read + * + * Receive a single UDP packet. This is a non-blocking call; if no + * packet is ready to read, the call will return instantly with + * s_PXENV_UDP_READ::Status==PXENV_STATUS_FAILURE. + * + * If s_PXENV_UDP_READ::dest_ip is 0.0.0.0, UDP packets addressed to + * any IP address will be accepted and may be returned to the caller. + * + * If s_PXENV_UDP_READ::d_port is 0, UDP packets addressed to any UDP + * port will be accepted and may be returned to the caller. + * + * You must have opened a UDP connection with pxenv_udp_open() before + * calling pxenv_udp_read(). + * + * On x86, you must set the s_PXE::StatusCallout field to a nonzero + * value before calling this function in protected mode. You cannot + * call this function with a 32-bit stack segment. (See the relevant + * @ref pxe_x86_pmode16 "implementation note" for more details.) + * + * @note The PXE specification (version 2.1) does not state that we + * should fill in s_PXENV_UDP_READ::dest_ip and + * s_PXENV_UDP_READ::d_port, but Microsoft Windows' NTLDR program + * expects us to do so, and will fail if we don't. + * + */ +PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *pxenv_udp_read ) { + struct in_addr dest_ip_wanted = { .s_addr = pxenv_udp_read->dest_ip }; + struct in_addr dest_ip; + uint16_t d_port_wanted = pxenv_udp_read->d_port; + uint16_t d_port; + + DBG ( "PXENV_UDP_READ" ); + + /* Try receiving a packet */ + pxe_udp.pxenv_udp_read = pxenv_udp_read; + step(); + if ( pxe_udp.pxenv_udp_read ) { + /* No packet received */ + pxe_udp.pxenv_udp_read = NULL; + goto no_packet; + } + dest_ip.s_addr = pxenv_udp_read->dest_ip; + d_port = pxenv_udp_read->d_port; + + /* Filter on destination address and/or port */ + if ( dest_ip_wanted.s_addr && + ( dest_ip_wanted.s_addr != dest_ip.s_addr ) ) { + DBG ( " wrong IP %s", inet_ntoa ( dest_ip ) ); + DBG ( " (wanted %s)", inet_ntoa ( dest_ip_wanted ) ); + goto no_packet; + } + if ( d_port_wanted && ( d_port_wanted != d_port ) ) { + DBG ( " wrong port %d ", htons ( d_port ) ); + DBG ( " (wanted %d)", htons ( d_port_wanted ) ); + goto no_packet; + } + + DBG ( " %04x:%04x+%x %s:", pxenv_udp_read->buffer.segment, + pxenv_udp_read->buffer.offset, pxenv_udp_read->buffer_size, + inet_ntoa ( *( ( struct in_addr * ) &pxenv_udp_read->src_ip ) )); + DBG ( "%d<-%s:%d", ntohs ( pxenv_udp_read->s_port ), + inet_ntoa ( *( ( struct in_addr * ) &pxenv_udp_read->dest_ip ) ), + ntohs ( pxenv_udp_read->d_port ) ); + + pxenv_udp_read->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; + + no_packet: + pxenv_udp_read->Status = PXENV_STATUS_FAILURE; + return PXENV_EXIT_FAILURE; +} diff --git a/src/arch/i386/interface/pxe/pxe_undi.c b/src/arch/i386/interface/pxe/pxe_undi.c new file mode 100644 index 00000000..4e4a3da0 --- /dev/null +++ b/src/arch/i386/interface/pxe/pxe_undi.c @@ -0,0 +1,684 @@ +/** @file + * + * PXE UNDI API + * + */ + +/* + * Copyright (C) 2004 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pxe.h" + +/** + * Count of outstanding transmitted packets + * + * This is incremented each time PXENV_UNDI_TRANSMIT is called, and + * decremented each time that PXENV_UNDI_ISR is called with the TX + * queue empty, stopping when the count reaches zero. This allows us + * to provide a pessimistic approximation of TX completion events to + * the PXE NBP simply by monitoring the netdev's TX queue. + */ +static int undi_tx_count = 0; + +struct net_device *pxe_netdev = NULL; + +/** + * Set network device as current PXE network device + * + * @v netdev Network device, or NULL + */ +void pxe_set_netdev ( struct net_device *netdev ) { + if ( pxe_netdev ) + netdev_put ( pxe_netdev ); + pxe_netdev = NULL; + if ( netdev ) + pxe_netdev = netdev_get ( netdev ); +} + +/** + * Open PXE network device + * + * @ret rc Return status code + */ +static int pxe_netdev_open ( void ) { + int rc; + + if ( ( rc = netdev_open ( pxe_netdev ) ) != 0 ) + return rc; + + netdev_irq ( pxe_netdev, 1 ); + return 0; +} + +/** + * Close PXE network device + * + */ +static void pxe_netdev_close ( void ) { + netdev_irq ( pxe_netdev, 0 ); + netdev_close ( pxe_netdev ); + undi_tx_count = 0; +} + +/* PXENV_UNDI_STARTUP + * + * Status: working + */ +PXENV_EXIT_t pxenv_undi_startup ( struct s_PXENV_UNDI_STARTUP *undi_startup ) { + DBG ( "PXENV_UNDI_STARTUP" ); + + undi_startup->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/* PXENV_UNDI_CLEANUP + * + * Status: working + */ +PXENV_EXIT_t pxenv_undi_cleanup ( struct s_PXENV_UNDI_CLEANUP *undi_cleanup ) { + DBG ( "PXENV_UNDI_CLEANUP" ); + + pxe_netdev_close(); + + undi_cleanup->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/* PXENV_UNDI_INITIALIZE + * + * Status: working + */ +PXENV_EXIT_t pxenv_undi_initialize ( struct s_PXENV_UNDI_INITIALIZE + *undi_initialize ) { + DBG ( "PXENV_UNDI_INITIALIZE" ); + + undi_initialize->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/* PXENV_UNDI_RESET_ADAPTER + * + * Status: working + */ +PXENV_EXIT_t pxenv_undi_reset_adapter ( struct s_PXENV_UNDI_RESET + *undi_reset_adapter ) { + int rc; + + DBG ( "PXENV_UNDI_RESET_ADAPTER" ); + + pxe_netdev_close(); + if ( ( rc = pxe_netdev_open() ) != 0 ) { + undi_reset_adapter->Status = PXENV_STATUS ( rc ); + return PXENV_EXIT_FAILURE; + } + + undi_reset_adapter->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/* PXENV_UNDI_SHUTDOWN + * + * Status: working + */ +PXENV_EXIT_t pxenv_undi_shutdown ( struct s_PXENV_UNDI_SHUTDOWN + *undi_shutdown ) { + DBG ( "PXENV_UNDI_SHUTDOWN" ); + + pxe_netdev_close(); + + undi_shutdown->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/* PXENV_UNDI_OPEN + * + * Status: working + */ +PXENV_EXIT_t pxenv_undi_open ( struct s_PXENV_UNDI_OPEN *undi_open ) { + int rc; + + DBG ( "PXENV_UNDI_OPEN" ); + + if ( ( rc = pxe_netdev_open() ) != 0 ) { + undi_open->Status = PXENV_STATUS ( rc ); + return PXENV_EXIT_FAILURE; + } + + undi_open->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/* PXENV_UNDI_CLOSE + * + * Status: working + */ +PXENV_EXIT_t pxenv_undi_close ( struct s_PXENV_UNDI_CLOSE *undi_close ) { + DBG ( "PXENV_UNDI_CLOSE" ); + + pxe_netdev_close(); + + undi_close->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/* PXENV_UNDI_TRANSMIT + * + * Status: working + */ +PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT + *undi_transmit ) { + struct s_PXENV_UNDI_TBD tbd; + struct DataBlk *datablk; + struct io_buffer *iobuf; + struct net_protocol *net_protocol; + struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol; + char destaddr[MAX_LL_ADDR_LEN]; + const void *ll_dest; + size_t ll_hlen = ll_protocol->ll_header_len; + size_t len; + unsigned int i; + int rc; + + DBG ( "PXENV_UNDI_TRANSMIT" ); + + /* Identify network-layer protocol */ + switch ( undi_transmit->Protocol ) { + case P_IP: net_protocol = &ipv4_protocol; break; + case P_ARP: net_protocol = &arp_protocol; break; + case P_RARP: net_protocol = &rarp_protocol; break; + case P_UNKNOWN: + net_protocol = NULL; + ll_hlen = 0; + break; + default: + undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER; + return PXENV_EXIT_FAILURE; + } + DBG ( " %s", ( net_protocol ? net_protocol->name : "RAW" ) ); + + /* Calculate total packet length */ + copy_from_real ( &tbd, undi_transmit->TBD.segment, + undi_transmit->TBD.offset, sizeof ( tbd ) ); + len = tbd.ImmedLength; + DBG ( " %d", tbd.ImmedLength ); + for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) { + datablk = &tbd.DataBlock[i]; + len += datablk->TDDataLen; + DBG ( "+%d", datablk->TDDataLen ); + } + + /* Allocate and fill I/O buffer */ + iobuf = alloc_iob ( ll_hlen + len ); + if ( ! iobuf ) { + undi_transmit->Status = PXENV_STATUS_OUT_OF_RESOURCES; + return PXENV_EXIT_FAILURE; + } + iob_reserve ( iobuf, ll_hlen ); + copy_from_real ( iob_put ( iobuf, tbd.ImmedLength ), tbd.Xmit.segment, + tbd.Xmit.offset, tbd.ImmedLength ); + for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) { + datablk = &tbd.DataBlock[i]; + copy_from_real ( iob_put ( iobuf, datablk->TDDataLen ), + datablk->TDDataPtr.segment, + datablk->TDDataPtr.offset, + datablk->TDDataLen ); + } + + /* Add link-layer header, if required to do so */ + if ( net_protocol != NULL ) { + + /* Calculate destination address */ + if ( undi_transmit->XmitFlag == XMT_DESTADDR ) { + copy_from_real ( destaddr, + undi_transmit->DestAddr.segment, + undi_transmit->DestAddr.offset, + ll_protocol->ll_addr_len ); + ll_dest = destaddr; + } else { + DBG ( " BCAST" ); + ll_dest = ll_protocol->ll_broadcast; + } + + /* Add link-layer header */ + if ( ( rc = ll_protocol->push ( iobuf, ll_dest, + pxe_netdev->ll_addr, + net_protocol->net_proto ))!=0){ + free_iob ( iobuf ); + undi_transmit->Status = PXENV_STATUS ( rc ); + return PXENV_EXIT_FAILURE; + } + } + + /* Transmit packet */ + if ( ( rc = netdev_tx ( pxe_netdev, iobuf ) ) != 0 ) { + undi_transmit->Status = PXENV_STATUS ( rc ); + return PXENV_EXIT_FAILURE; + } + + /* Flag transmission as in-progress */ + undi_tx_count++; + + undi_transmit->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/* PXENV_UNDI_SET_MCAST_ADDRESS + * + * Status: stub (no PXE multicast support) + */ +PXENV_EXIT_t +pxenv_undi_set_mcast_address ( struct s_PXENV_UNDI_SET_MCAST_ADDRESS + *undi_set_mcast_address ) { + DBG ( "PXENV_UNDI_SET_MCAST_ADDRESS" ); + + undi_set_mcast_address->Status = PXENV_STATUS_UNSUPPORTED; + return PXENV_EXIT_FAILURE; +} + +/* PXENV_UNDI_SET_STATION_ADDRESS + * + * Status: working + */ +PXENV_EXIT_t +pxenv_undi_set_station_address ( struct s_PXENV_UNDI_SET_STATION_ADDRESS + *undi_set_station_address ) { + + DBG ( "PXENV_UNDI_SET_STATION_ADDRESS" ); + + /* If adapter is open, the change will have no effect; return + * an error + */ + if ( pxe_netdev->state & NETDEV_OPEN ) { + undi_set_station_address->Status = + PXENV_STATUS_UNDI_INVALID_STATE; + return PXENV_EXIT_FAILURE; + } + + /* Update MAC address */ + memcpy ( pxe_netdev->ll_addr, + &undi_set_station_address->StationAddress, + pxe_netdev->ll_protocol->ll_addr_len ); + + undi_set_station_address->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/* PXENV_UNDI_SET_PACKET_FILTER + * + * Status: won't implement (would require driver API changes for no + * real benefit) + */ +PXENV_EXIT_t +pxenv_undi_set_packet_filter ( struct s_PXENV_UNDI_SET_PACKET_FILTER + *undi_set_packet_filter ) { + DBG ( "PXENV_UNDI_SET_PACKET_FILTER" ); + + undi_set_packet_filter->Status = PXENV_STATUS_UNSUPPORTED; + return PXENV_EXIT_FAILURE; +} + +/* PXENV_UNDI_GET_INFORMATION + * + * Status: working + */ +PXENV_EXIT_t pxenv_undi_get_information ( struct s_PXENV_UNDI_GET_INFORMATION + *undi_get_information ) { + struct device *dev = pxe_netdev->dev; + struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol; + + DBG ( "PXENV_UNDI_GET_INFORMATION" ); + + undi_get_information->BaseIo = dev->desc.ioaddr; + undi_get_information->IntNumber = dev->desc.irq; + /* Cheat: assume all cards can cope with this */ + undi_get_information->MaxTranUnit = ETH_MAX_MTU; + undi_get_information->HwType = ntohs ( ll_protocol->ll_proto ); + undi_get_information->HwAddrLen = ll_protocol->ll_addr_len; + /* Cheat: assume card is always configured with its permanent + * node address. This is a valid assumption within Etherboot + * at the time of writing. + */ + memcpy ( &undi_get_information->CurrentNodeAddress, + pxe_netdev->ll_addr, + sizeof ( undi_get_information->CurrentNodeAddress ) ); + memcpy ( &undi_get_information->PermNodeAddress, + pxe_netdev->ll_addr, + sizeof ( undi_get_information->PermNodeAddress ) ); + undi_get_information->ROMAddress = 0; + /* nic.rom_info->rom_segment; */ + /* We only provide the ability to receive or transmit a single + * packet at a time. This is a bootloader, not an OS. + */ + undi_get_information->RxBufCt = 1; + undi_get_information->TxBufCt = 1; + + undi_get_information->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/* PXENV_UNDI_GET_STATISTICS + * + * Status: working + */ +PXENV_EXIT_t pxenv_undi_get_statistics ( struct s_PXENV_UNDI_GET_STATISTICS + *undi_get_statistics ) { + DBG ( "PXENV_UNDI_GET_STATISTICS" ); + + undi_get_statistics->XmtGoodFrames = pxe_netdev->tx_stats.good; + undi_get_statistics->RcvGoodFrames = pxe_netdev->rx_stats.good; + undi_get_statistics->RcvCRCErrors = pxe_netdev->rx_stats.bad; + undi_get_statistics->RcvResourceErrors = pxe_netdev->rx_stats.bad; + + undi_get_statistics->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/* PXENV_UNDI_CLEAR_STATISTICS + * + * Status: working + */ +PXENV_EXIT_t pxenv_undi_clear_statistics ( struct s_PXENV_UNDI_CLEAR_STATISTICS + *undi_clear_statistics ) { + DBG ( "PXENV_UNDI_CLEAR_STATISTICS" ); + + memset ( &pxe_netdev->tx_stats, 0, sizeof ( pxe_netdev->tx_stats ) ); + memset ( &pxe_netdev->rx_stats, 0, sizeof ( pxe_netdev->rx_stats ) ); + + undi_clear_statistics->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/* PXENV_UNDI_INITIATE_DIAGS + * + * Status: won't implement (would require driver API changes for no + * real benefit) + */ +PXENV_EXIT_t pxenv_undi_initiate_diags ( struct s_PXENV_UNDI_INITIATE_DIAGS + *undi_initiate_diags ) { + DBG ( "PXENV_UNDI_INITIATE_DIAGS" ); + + undi_initiate_diags->Status = PXENV_STATUS_UNSUPPORTED; + return PXENV_EXIT_FAILURE; +} + +/* PXENV_UNDI_FORCE_INTERRUPT + * + * Status: won't implement (would require driver API changes for no + * perceptible benefit) + */ +PXENV_EXIT_t pxenv_undi_force_interrupt ( struct s_PXENV_UNDI_FORCE_INTERRUPT + *undi_force_interrupt ) { + DBG ( "PXENV_UNDI_FORCE_INTERRUPT" ); + + undi_force_interrupt->Status = PXENV_STATUS_UNSUPPORTED; + return PXENV_EXIT_FAILURE; +} + +/* PXENV_UNDI_GET_MCAST_ADDRESS + * + * Status: stub (no PXE multicast support) + */ +PXENV_EXIT_t +pxenv_undi_get_mcast_address ( struct s_PXENV_UNDI_GET_MCAST_ADDRESS + *undi_get_mcast_address ) { + DBG ( "PXENV_UNDI_GET_MCAST_ADDRESS" ); + + undi_get_mcast_address->Status = PXENV_STATUS_UNSUPPORTED; + return PXENV_EXIT_FAILURE; +} + +/* PXENV_UNDI_GET_NIC_TYPE + * + * Status: working + */ +PXENV_EXIT_t pxenv_undi_get_nic_type ( struct s_PXENV_UNDI_GET_NIC_TYPE + *undi_get_nic_type ) { + struct device *dev = pxe_netdev->dev; + + DBG ( "PXENV_UNDI_GET_NIC_TYPE" ); + + memset ( &undi_get_nic_type->info, 0, + sizeof ( undi_get_nic_type->info ) ); + + switch ( dev->desc.bus_type ) { + case BUS_TYPE_PCI: { + struct pci_nic_info *info = &undi_get_nic_type->info.pci; + + undi_get_nic_type->NicType = PCI_NIC; + info->Vendor_ID = dev->desc.vendor; + info->Dev_ID = dev->desc.device; + info->Base_Class = PCI_BASE_CLASS ( dev->desc.class ); + info->Sub_Class = PCI_SUB_CLASS ( dev->desc.class ); + info->Prog_Intf = PCI_PROG_INTF ( dev->desc.class ); + info->BusDevFunc = dev->desc.location; + /* Cheat: remaining fields are probably unnecessary, + * and would require adding extra code to pci.c. + */ + undi_get_nic_type->info.pci.SubVendor_ID = 0xffff; + undi_get_nic_type->info.pci.SubDevice_ID = 0xffff; + break; } + case BUS_TYPE_ISAPNP: { + struct pnp_nic_info *info = &undi_get_nic_type->info.pnp; + + undi_get_nic_type->NicType = PnP_NIC; + info->EISA_Dev_ID = ( ( dev->desc.vendor << 16 ) | + dev->desc.device ); + info->CardSelNum = dev->desc.location; + /* Cheat: remaining fields are probably unnecessary, + * and would require adding extra code to isapnp.c. + */ + break; } + default: + undi_get_nic_type->Status = PXENV_STATUS_FAILURE; + return PXENV_EXIT_FAILURE; + } + + undi_get_nic_type->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/* PXENV_UNDI_GET_IFACE_INFO + * + * Status: working + */ +PXENV_EXIT_t pxenv_undi_get_iface_info ( struct s_PXENV_UNDI_GET_IFACE_INFO + *undi_get_iface_info ) { + DBG ( "PXENV_UNDI_GET_IFACE_INFO" ); + + /* Just hand back some info, doesn't really matter what it is. + * Most PXE stacks seem to take this approach. + */ + snprintf ( ( char * ) undi_get_iface_info->IfaceType, + sizeof ( undi_get_iface_info->IfaceType ), "gPXE" ); + undi_get_iface_info->LinkSpeed = 10000000; /* 10 Mbps */ + undi_get_iface_info->ServiceFlags = 0; + memset ( undi_get_iface_info->Reserved, 0, + sizeof(undi_get_iface_info->Reserved) ); + + undi_get_iface_info->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/* PXENV_UNDI_GET_STATE + * + * Status: impossible + */ +PXENV_EXIT_t pxenv_undi_get_state ( struct s_PXENV_UNDI_GET_STATE + *undi_get_state ) { + DBG ( "PXENV_UNDI_GET_STATE" ); + + undi_get_state->Status = PXENV_STATUS_UNSUPPORTED; + return PXENV_EXIT_FAILURE; +}; + +/* PXENV_UNDI_ISR + * + * Status: working + */ +PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { + struct io_buffer *iobuf; + size_t len; + struct ll_protocol *ll_protocol; + const void *ll_dest; + const void *ll_source; + uint16_t net_proto; + size_t ll_hlen; + struct net_protocol *net_protocol; + unsigned int prottype; + int rc; + + DBG ( "PXENV_UNDI_ISR" ); + + /* Just in case some idiot actually looks at these fields when + * we weren't meant to fill them in... + */ + undi_isr->BufferLength = 0; + undi_isr->FrameLength = 0; + undi_isr->FrameHeaderLength = 0; + undi_isr->ProtType = 0; + undi_isr->PktType = 0; + + switch ( undi_isr->FuncFlag ) { + case PXENV_UNDI_ISR_IN_START : + DBG ( " START" ); + + /* Call poll(). This should acknowledge the device + * interrupt and queue up any received packet. + */ + netdev_poll ( pxe_netdev ); + + /* Disable interrupts to avoid interrupt storm */ + netdev_irq ( pxe_netdev, 0 ); + + /* Always say it was ours for the sake of simplicity */ + undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS; + break; + case PXENV_UNDI_ISR_IN_PROCESS : + DBG ( " PROCESS" ); + /* Fall through */ + case PXENV_UNDI_ISR_IN_GET_NEXT : + DBG ( " GET_NEXT" ); + + /* Some dumb NBPs (e.g. emBoot's winBoot/i) never call + * PXENV_UNDI_ISR with FuncFlag=PXENV_UNDI_ISR_START; + * they just sit in a tight polling loop merrily + * violating the PXE spec with repeated calls to + * PXENV_UNDI_ISR_IN_PROCESS. Force extra polls to + * cope with these out-of-spec clients. + */ + netdev_poll ( pxe_netdev ); + + /* If we have not yet marked a TX as complete, and the + * netdev TX queue is empty, report the TX completion. + */ + if ( undi_tx_count && list_empty ( &pxe_netdev->tx_queue ) ) { + DBG ( " TXC" ); + undi_tx_count--; + undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_TRANSMIT; + break; + } + + /* Remove first packet from netdev RX queue */ + iobuf = netdev_rx_dequeue ( pxe_netdev ); + if ( ! iobuf ) { + DBG ( " DONE" ); + /* No more packets remaining */ + undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE; + /* Re-enable interrupts */ + netdev_irq ( pxe_netdev, 1 ); + break; + } + + /* Copy packet to base memory buffer */ + len = iob_len ( iobuf ); + DBG ( " RX %zd", len ); + if ( len > sizeof ( basemem_packet ) ) { + /* Should never happen */ + len = sizeof ( basemem_packet ); + } + memcpy ( basemem_packet, iobuf->data, len ); + + /* Strip link-layer header */ + ll_protocol = pxe_netdev->ll_protocol; + if ( ( rc = ll_protocol->pull ( iobuf, &ll_dest, &ll_source, + &net_proto ) ) != 0 ) { + /* Assume unknown net_proto and no ll_source */ + net_proto = 0; + ll_source = NULL; + } + ll_hlen = ( len - iob_len ( iobuf ) ); + + /* Determine network-layer protocol */ + switch ( net_proto ) { + case htons ( ETH_P_IP ): + net_protocol = &ipv4_protocol; + prottype = P_IP; + break; + case htons ( ETH_P_ARP ): + net_protocol = &arp_protocol; + prottype = P_ARP; + break; + case htons ( ETH_P_RARP ): + net_protocol = &rarp_protocol; + prottype = P_RARP; + break; + default: + net_protocol = NULL; + prottype = P_UNKNOWN; + break; + } + DBG ( " %s", ( net_protocol ? net_protocol->name : "RAW" ) ); + + /* Fill in UNDI_ISR structure */ + undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_RECEIVE; + undi_isr->BufferLength = len; + undi_isr->FrameLength = len; + undi_isr->FrameHeaderLength = ll_hlen; + undi_isr->Frame.segment = rm_ds; + undi_isr->Frame.offset = __from_data16 ( basemem_packet ); + undi_isr->ProtType = prottype; + undi_isr->PktType = XMT_DESTADDR; + + /* Free packet */ + free_iob ( iobuf ); + break; + default : + DBG ( " INVALID(%04x)", undi_isr->FuncFlag ); + + /* Should never happen */ + undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE; + undi_isr->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER; + return PXENV_EXIT_FAILURE; + } + + undi_isr->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} diff --git a/src/include/pxe.h b/src/include/pxe.h deleted file mode 100644 index 6d332ac7..00000000 --- a/src/include/pxe.h +++ /dev/null @@ -1,151 +0,0 @@ -#ifndef PXE_H -#define PXE_H - -#include "pxe_types.h" -#include "pxe_api.h" -#include - -/* Parameter block for pxenv_unknown() */ -struct s_PXENV_UNKNOWN { - PXENV_STATUS_t Status; /**< PXE status code */ -} PACKED; - -typedef struct s_PXENV_UNKNOWN PXENV_UNKNOWN_t; - -/* Union used for PXE API calls; we don't know the type of the - * structure until we interpret the opcode. Also, Status is available - * in the same location for any opcode, and it's convenient to have - * non-specific access to it. - */ -union u_PXENV_ANY { - /* Make it easy to read status for any operation */ - PXENV_STATUS_t Status; - struct s_PXENV_UNKNOWN unknown; - struct s_PXENV_UNLOAD_STACK unload_stack; - struct s_PXENV_GET_CACHED_INFO get_cached_info; - struct s_PXENV_TFTP_READ_FILE restart_tftp; - struct s_PXENV_START_UNDI start_undi; - struct s_PXENV_STOP_UNDI stop_undi; - struct s_PXENV_START_BASE start_base; - struct s_PXENV_STOP_BASE stop_base; - struct s_PXENV_TFTP_OPEN tftp_open; - struct s_PXENV_TFTP_CLOSE tftp_close; - struct s_PXENV_TFTP_READ tftp_read; - struct s_PXENV_TFTP_READ_FILE tftp_read_file; - struct s_PXENV_TFTP_GET_FSIZE tftp_get_fsize; - struct s_PXENV_UDP_OPEN udp_open; - struct s_PXENV_UDP_CLOSE udp_close; - struct s_PXENV_UDP_WRITE udp_write; - struct s_PXENV_UDP_READ udp_read; - struct s_PXENV_UNDI_STARTUP undi_startup; - struct s_PXENV_UNDI_CLEANUP undi_cleanup; - struct s_PXENV_UNDI_INITIALIZE undi_initialize; - struct s_PXENV_UNDI_RESET undi_reset_adapter; - struct s_PXENV_UNDI_SHUTDOWN undi_shutdown; - struct s_PXENV_UNDI_OPEN undi_open; - struct s_PXENV_UNDI_CLOSE undi_close; - struct s_PXENV_UNDI_TRANSMIT undi_transmit; - struct s_PXENV_UNDI_SET_MCAST_ADDRESS undi_set_mcast_address; - struct s_PXENV_UNDI_SET_STATION_ADDRESS undi_set_station_address; - struct s_PXENV_UNDI_SET_PACKET_FILTER undi_set_packet_filter; - struct s_PXENV_UNDI_GET_INFORMATION undi_get_information; - struct s_PXENV_UNDI_GET_STATISTICS undi_get_statistics; - struct s_PXENV_UNDI_CLEAR_STATISTICS undi_clear_statistics; - struct s_PXENV_UNDI_INITIATE_DIAGS undi_initiate_diags; - struct s_PXENV_UNDI_FORCE_INTERRUPT undi_force_interrupt; - struct s_PXENV_UNDI_GET_MCAST_ADDRESS undi_get_mcast_address; - struct s_PXENV_UNDI_GET_NIC_TYPE undi_get_nic_type; - struct s_PXENV_UNDI_GET_IFACE_INFO undi_get_iface_info; - struct s_PXENV_UNDI_GET_STATE undi_get_state; - struct s_PXENV_UNDI_ISR undi_isr; - struct s_PXENV_FILE_OPEN file_open; - struct s_PXENV_FILE_CLOSE file_close; - struct s_PXENV_FILE_SELECT file_select; - struct s_PXENV_FILE_READ file_read; - struct s_PXENV_GET_FILE_SIZE get_file_size; - struct s_PXENV_FILE_EXEC file_exec; - struct s_PXENV_FILE_API_CHECK file_api_check; -}; - -typedef union u_PXENV_ANY PXENV_ANY_t; - -/** An UNDI expansion ROM header */ -struct undi_rom_header { - /** Signature - * - * Must be equal to @c ROM_SIGNATURE - */ - UINT16_t Signature; - /** ROM length in 512-byte blocks */ - UINT8_t ROMLength; - /** Unused */ - UINT8_t unused[0x13]; - /** Offset of the PXE ROM ID structure */ - UINT16_t PXEROMID; - /** Offset of the PCI ROM structure */ - UINT16_t PCIRHeader; -} PACKED; - -/** Signature for an expansion ROM */ -#define ROM_SIGNATURE 0xaa55 - -/** An UNDI ROM ID structure */ -struct undi_rom_id { - /** Signature - * - * Must be equal to @c UNDI_ROM_ID_SIGNATURE - */ - UINT32_t Signature; - /** Length of structure */ - UINT8_t StructLength; - /** Checksum */ - UINT8_t StructCksum; - /** Structure revision - * - * Must be zero. - */ - UINT8_t StructRev; - /** UNDI revision - * - * Version 2.1.0 is encoded as the byte sequence 0x00, 0x01, 0x02. - */ - UINT8_t UNDIRev[3]; - /** Offset to UNDI loader */ - UINT16_t UNDILoader; - /** Minimum required stack segment size */ - UINT16_t StackSize; - /** Minimum required data segment size */ - UINT16_t DataSize; - /** Minimum required code segment size */ - UINT16_t CodeSize; -} PACKED; - -/** Signature for an UNDI ROM ID structure */ -#define UNDI_ROM_ID_SIGNATURE \ - ( ( 'U' << 0 ) + ( 'N' << 8 ) + ( 'D' << 16 ) + ( 'I' << 24 ) ) - -/** A PCI expansion header */ -struct pcir_header { - /** Signature - * - * Must be equal to @c PCIR_SIGNATURE - */ - uint32_t signature; - /** PCI vendor ID */ - uint16_t vendor_id; - /** PCI device ID */ - uint16_t device_id; -} PACKED; - -/** Signature for an UNDI ROM ID structure */ -#define PCIR_SIGNATURE \ - ( ( 'P' << 0 ) + ( 'C' << 8 ) + ( 'I' << 16 ) + ( 'R' << 24 ) ) - - -extern struct net_device *pxe_netdev; - -extern void pxe_set_netdev ( struct net_device *netdev ); - -extern void pxe_set_cached_filename ( const unsigned char *filename ); - -#endif /* PXE_H */ diff --git a/src/include/pxe_api.h b/src/include/pxe_api.h deleted file mode 100644 index b3d4bca8..00000000 --- a/src/include/pxe_api.h +++ /dev/null @@ -1,1841 +0,0 @@ -#ifndef PXE_API_H -#define PXE_API_H - -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/** @file - * - * Preboot eXecution Environment (PXE) API - * - */ - -#include "pxe_types.h" - -/** @addtogroup pxe Preboot eXecution Environment (PXE) API - * @{ - */ - -/** @defgroup pxe_api_call PXE entry points - * - * PXE entry points and calling conventions - * - * @{ - */ - -/** The PXENV+ structure */ -struct s_PXENV { - /** Signature - * - * Contains the bytes 'P', 'X', 'E', 'N', 'V', '+'. - */ - UINT8_t Signature[6]; - /** PXE API version - * - * MSB is major version number, LSB is minor version number. - * If the API version number is 0x0201 or greater, the !PXE - * structure pointed to by #PXEPtr should be used instead of - * this data structure. - */ - UINT16_t Version; - UINT8_t Length; /**< Length of this structure */ - /** Checksum - * - * The byte checksum of this structure (using the length in - * #Length) must be zero. - */ - UINT8_t Checksum; - SEGOFF16_t RMEntry; /**< Real-mode PXENV+ entry point */ - /** Protected-mode PXENV+ entry point offset - * - * PXE 2.1 deprecates this entry point. For protected-mode - * API calls, use the !PXE structure pointed to by #PXEPtr - * instead. - */ - UINT32_t PMOffset; - /** Protected-mode PXENV+ entry point segment selector - * - * PXE 2.1 deprecates this entry point. For protected-mode - * API calls, use the !PXE structure pointed to by #PXEPtr - * instead. - */ - SEGSEL_t PMSelector; - SEGSEL_t StackSeg; /**< Stack segment selector */ - UINT16_t StackSize; /**< Stack segment size */ - SEGSEL_t BC_CodeSeg; /**< Base-code code segment selector */ - UINT16_t BC_CodeSize; /**< Base-code code segment size */ - SEGSEL_t BC_DataSeg; /**< Base-code data segment selector */ - UINT16_t BC_DataSize; /**< Base-code data segment size */ - SEGSEL_t UNDIDataSeg; /**< UNDI data segment selector */ - UINT16_t UNDIDataSize; /**< UNDI data segment size */ - SEGSEL_t UNDICodeSeg; /**< UNDI code segment selector */ - UINT16_t UNDICodeSize; /**< UNDI code segment size */ - /** Address of the !PXE structure - * - * This field is present only if #Version is 0x0201 or - * greater. If present, it points to a struct s_PXE. - */ - SEGOFF16_t PXEPtr; -} PACKED; - -typedef struct s_PXENV PXENV_t; - -/** The !PXE structure */ -struct s_PXE { - /** Signature - * - * Contains the bytes '!', 'P', 'X', 'E'. - */ - UINT8_t Signature[4]; - UINT8_t StructLength; /**< Length of this structure */ - /** Checksum - * - * The byte checksum of this structure (using the length in - * #StructLength) must be zero. - */ - UINT8_t StructCksum; - /** Revision of this structure - * - * For PXE version 2.1, this field must be zero. - */ - UINT8_t StructRev; - UINT8_t reserved_1; /**< Must be zero */ - /** Address of the UNDI ROM ID structure - * - * This is a pointer to a struct s_UNDI_ROM_ID. - */ - SEGOFF16_t UNDIROMID; - /** Address of the Base Code ROM ID structure - * - * This is a pointer to a struct s_BC_ROM_ID. - */ - SEGOFF16_t BaseROMID; - /** 16-bit !PXE entry point - * - * This is the entry point for either real mode, or protected - * mode with a 16-bit stack segment. - */ - SEGOFF16_t EntryPointSP; - /** 32-bit !PXE entry point - * - * This is the entry point for protected mode with a 32-bit - * stack segment. - */ - SEGOFF16_t EntryPointESP; - /** Status call-out function - * - * @v 0 (if in a time-out loop) - * @v n Number of a received TFTP packet - * @ret 0 Continue operation - * @ret 1 Cancel operation - * - * This function will be called whenever the PXE stack is in - * protected mode, is waiting for an event (e.g. a DHCP reply) - * and wishes to allow the user to cancel the operation. - * Parameters are passed in register %ax; the return value - * must also be placed in register %ax. All other registers - * and flags @b must be preserved. - * - * In real mode, an internal function (that checks for a - * keypress) will be used. - * - * If this field is set to -1, no status call-out function - * will be used and consequently the user will not be allowed - * to interrupt operations. - * - * @note The PXE specification version 2.1 defines the - * StatusCallout field, mentions it 11 times, but nowhere - * defines what it actually does or how it gets called. - * Fortunately, the WfM specification version 1.1a deigns to - * inform us of such petty details. - */ - SEGOFF16_t StatusCallout; - UINT8_t reserved_2; /**< Must be zero */ - /** Number of segment descriptors - * - * If this number is greater than 7, the remaining descriptors - * follow immediately after #BC_CodeWrite. - */ - UINT8_t SegDescCnt; - /** First protected-mode selector - * - * This is the segment selector value for the first segment - * assigned to PXE. Protected-mode selectors must be - * consecutive, according to the PXE 2.1 specification, though - * no reason is given. Each #SEGDESC_t includes a field for - * the segment selector, so this information is entirely - * redundant. - */ - SEGSEL_t FirstSelector; - /** Stack segment descriptor */ - SEGDESC_t Stack; - /** UNDI data segment descriptor */ - SEGDESC_t UNDIData; - /** UNDI code segment descriptor */ - SEGDESC_t UNDICode; - /** UNDI writable code segment descriptor */ - SEGDESC_t UNDICodeWrite; - /** Base-code data segment descriptor */ - SEGDESC_t BC_Data; - /** Base-code code segment descriptor */ - SEGDESC_t BC_Code; - /** Base-code writable code segment descriptor */ - SEGDESC_t BC_CodeWrite; -} PACKED; - -typedef struct s_PXE PXE_t; - -/** @} */ /* pxe_api_call */ - -/** @defgroup pxe_preboot_api PXE Preboot API - * - * General high-level functions: #PXENV_UNLOAD_STACK, #PXENV_START_UNDI etc. - * - * @{ - */ - -/** @defgroup pxenv_unload_stack PXENV_UNLOAD_STACK - * - * UNLOAD BASE CODE STACK - * - * @{ - */ - -/** PXE API function code for pxenv_unload_stack() */ -#define PXENV_UNLOAD_STACK 0x0070 - -/** Parameter block for pxenv_unload_stack() */ -struct s_PXENV_UNLOAD_STACK { - PXENV_STATUS_t Status; /**< PXE status code */ - UINT8_t reserved[10]; /**< Must be zero */ -} PACKED; - -typedef struct s_PXENV_UNLOAD_STACK PXENV_UNLOAD_STACK_t; - -extern PXENV_EXIT_t pxenv_unload_stack ( struct s_PXENV_UNLOAD_STACK - *unload_stack ); - -/** @} */ /* pxenv_unload_stack */ - -/** @defgroup pxenv_get_cached_info PXENV_GET_CACHED_INFO - * - * GET CACHED INFO - * - * @{ - */ - -/** PXE API function code for pxenv_get_cached_info() */ -#define PXENV_GET_CACHED_INFO 0x0071 - -/** The client's DHCPDISCOVER packet */ -#define PXENV_PACKET_TYPE_DHCP_DISCOVER 1 - -/** The DHCP server's DHCPACK packet */ -#define PXENV_PACKET_TYPE_DHCP_ACK 2 - -/** The Boot Server's Discover Reply packet - * - * This packet contains DHCP option 60 set to "PXEClient", a valid - * boot file name, and may or may not contain MTFTP options. - */ -#define PXENV_PACKET_TYPE_CACHED_REPLY 3 - -/** Parameter block for pxenv_get_cached_info() */ -struct s_PXENV_GET_CACHED_INFO { - PXENV_STATUS_t Status; /**< PXE status code */ - /** Packet type. - * - * Valid values are #PXENV_PACKET_TYPE_DHCP_DISCOVER, - * #PXENV_PACKET_TYPE_DHCP_ACK or #PXENV_PACKET_TYPE_CACHED_REPLY - */ - UINT16_t PacketType; - UINT16_t BufferSize; /**< Buffer size */ - SEGOFF16_t Buffer; /**< Buffer address */ - UINT16_t BufferLimit; /**< Maximum buffer size */ -} PACKED; - -typedef struct s_PXENV_GET_CACHED_INFO PXENV_GET_CACHED_INFO_t; - -#define BOOTP_REQ 1 /**< A BOOTP request packet */ -#define BOOTP_REP 2 /**< A BOOTP reply packet */ - -/** DHCP broadcast flag - * - * Request a broadcast response (DHCPOFFER or DHCPACK) from the DHCP - * server. - */ -#define BOOTP_BCAST 0x8000 - -#define VM_RFC1048 0x63825363L /**< DHCP magic cookie */ - -/** Maximum length of DHCP options */ -#define BOOTP_DHCPVEND 1024 - -/** Format of buffer filled in by pxenv_get_cached_info() - * - * This somewhat convoluted data structure simply describes the layout - * of a DHCP packet. Refer to RFC2131 section 2 for a full - * description. - */ -struct bootph { - /** Message opcode. - * - * Valid values are #BOOTP_REQ and #BOOTP_REP. - */ - UINT8_t opcode; - /** NIC hardware type. - * - * Valid values are as for s_PXENV_UNDI_GET_INFORMATION::HwType. - */ - UINT8_t Hardware; - UINT8_t Hardlen; /**< MAC address length */ - /** Gateway hops - * - * Zero in packets sent by the client. May be non-zero in - * replies from the DHCP server, if the reply comes via a DHCP - * relay agent. - */ - UINT8_t Gatehops; - UINT32_t ident; /**< DHCP transaction id (xid) */ - /** Elapsed time - * - * Number of seconds since the client began the DHCP - * transaction. - */ - UINT16_t seconds; - /** Flags - * - * This is the bitwise-OR of any of the following values: - * #BOOTP_BCAST. - */ - UINT16_t Flags; - /** Client IP address - * - * Set only if the client already has an IP address. - */ - IP4_t cip; - /** Your IP address - * - * This is the IP address that the server assigns to the - * client. - */ - IP4_t yip; - /** Server IP address - * - * This is the IP address of the BOOTP/DHCP server. - */ - IP4_t sip; - /** Gateway IP address - * - * This is the IP address of the BOOTP/DHCP relay agent, if - * any. It is @b not (necessarily) the address of the default - * gateway for routing purposes. - */ - IP4_t gip; - MAC_ADDR_t CAddr; /**< Client MAC address */ - UINT8_t Sname[64]; /**< Server host name */ - UINT8_t bootfile[128]; /**< Boot file name */ - /** DHCP options - * - * Don't ask. Just laugh. Then burn a copy of the PXE - * specification and send Intel an e-mail asking them if - * they've figured out what a "union" does in C yet. - */ - union bootph_vendor { - UINT8_t d[BOOTP_DHCPVEND]; /**< DHCP options */ - /** DHCP options */ - struct bootph_vendor_v { - /** DHCP magic cookie - * - * Should have the value #VM_RFC1048. - */ - UINT8_t magic[4]; - UINT32_t flags; /**< BOOTP flags/opcodes */ - /** "End of BOOTP vendor extensions" - * - * Abandon hope, all ye who consider the - * purpose of this field. - */ - UINT8_t pad[56]; - } v; - } vendor; -} PACKED; - -typedef struct bootph BOOTPLAYER_t; - -extern PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO - *get_cached_info ); - -/** @} */ /* pxenv_get_cached_info */ - -/** @defgroup pxenv_restart_tftp PXENV_RESTART_TFTP - * - * RESTART TFTP - * - * @{ - */ - -/** PXE API function code for pxenv_restart_tftp() */ -#define PXENV_RESTART_TFTP 0x0073 - -/** Parameter block for pxenv_restart_tftp() */ -struct s_PXENV_TFTP_READ_FILE; - -typedef struct s_PXENV_RESTART_TFTP PXENV_RESTART_TFTP_t; - -extern PXENV_EXIT_t pxenv_restart_tftp ( struct s_PXENV_TFTP_READ_FILE - *restart_tftp ); - -/** @} */ /* pxenv_restart_tftp */ - -/** @defgroup pxenv_start_undi PXENV_START_UNDI - * - * START UNDI - * - * @{ - */ - -/** PXE API function code for pxenv_start_undi() */ -#define PXENV_START_UNDI 0x0000 - -/** Parameter block for pxenv_start_undi() */ -struct s_PXENV_START_UNDI { - PXENV_STATUS_t Status; /**< PXE status code */ - /** %ax register as passed to the Option ROM initialisation routine. - * - * For a PCI device, this should contain the bus:dev:fn value - * that uniquely identifies the PCI device in the system. For - * a non-PCI device, this field is not defined. - */ - UINT16_t AX; - /** %bx register as passed to the Option ROM initialisation routine. - * - * For an ISAPnP device, this should contain the Card Select - * Number assigned to the ISAPnP card. For non-ISAPnP - * devices, this should contain 0xffff. - */ - UINT16_t BX; - /** %dx register as passed to the Option ROM initialisation routine. - * - * For an ISAPnP device, this should contain the ISAPnP Read - * Port address as currently set in all ISAPnP cards. If - * there are no ISAPnP cards, this should contain 0xffff. (If - * this is a non-ISAPnP device, but there are ISAPnP cards in - * the system, this value is not well defined.) - */ - UINT16_t DX; - /** %di register as passed to the Option ROM initialisation routine. - * - * This contains the #OFF16_t portion of a struct #s_SEGOFF16 - * that points to the System BIOS Plug and Play Installation - * Check Structure. (Refer to section 4.4 of the Plug and - * Play BIOS specification for a description of this - * structure.) - * - * @note The PXE specification defines the type of this field - * as #UINT16_t. For x86, #OFF16_t and #UINT16_t are - * equivalent anyway; for other architectures #OFF16_t makes - * more sense. - */ - OFF16_t DI; - /** %es register as passed to the Option ROM initialisation routine. - * - * This contains the #SEGSEL_t portion of a struct #s_SEGOFF16 - * that points to the System BIOS Plug and Play Installation - * Check Structure. (Refer to section 4.4 of the Plug and - * Play BIOS specification for a description of this - * structure.) - * - * @note The PXE specification defines the type of this field - * as #UINT16_t. For x86, #SEGSEL_t and #UINT16_t are - * equivalent anyway; for other architectures #SEGSEL_t makes - * more sense. - */ - SEGSEL_t ES; -} PACKED; - -typedef struct s_PXENV_START_UNDI PXENV_START_UNDI_t; - -extern PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi ); - -/** @} */ /* pxenv_start_undi */ - -/** @defgroup pxenv_stop_undi PXENV_STOP_UNDI - * - * STOP UNDI - * - * @{ - */ - -/** PXE API function code for pxenv_stop_undi() */ -#define PXENV_STOP_UNDI 0x0015 - -/** Parameter block for pxenv_stop_undi() */ -struct s_PXENV_STOP_UNDI { - PXENV_STATUS_t Status; /**< PXE status code */ -} PACKED; - -typedef struct s_PXENV_STOP_UNDI PXENV_STOP_UNDI_t; - -extern PXENV_EXIT_t pxenv_stop_undi ( struct s_PXENV_STOP_UNDI *stop_undi ); - -/** @} */ /* pxenv_stop_undi */ - -/** @defgroup pxenv_start_base PXENV_START_BASE - * - * START BASE - * - * @{ - */ - -/** PXE API function code for pxenv_start_base() */ -#define PXENV_START_BASE 0x0075 - -/** Parameter block for pxenv_start_base() */ -struct s_PXENV_START_BASE { - PXENV_STATUS_t Status; /**< PXE status code */ -} PACKED; - -typedef struct s_PXENV_START_BASE PXENV_START_BASE_t; - -extern PXENV_EXIT_t pxenv_start_base ( struct s_PXENV_START_BASE *start_base ); - -/** @} */ /* pxenv_start_base */ - -/** @defgroup pxenv_stop_base PXENV_STOP_BASE - * - * STOP BASE - * - * @{ - */ - -/** PXE API function code for pxenv_stop_base() */ -#define PXENV_STOP_BASE 0x0076 - -/** Parameter block for pxenv_stop_base() */ -struct s_PXENV_STOP_BASE { - PXENV_STATUS_t Status; /**< PXE status code */ -} PACKED; - -typedef struct s_PXENV_STOP_BASE PXENV_STOP_BASE_t; - -extern PXENV_EXIT_t pxenv_stop_base ( struct s_PXENV_STOP_BASE *stop_base ); - -/** @} */ /* pxenv_stop_base */ - -/** @} */ /* pxe_preboot_api */ - -/** @defgroup pxe_tftp_api PXE TFTP API - * - * Download files via TFTP or MTFTP - * - * @{ - */ - -/** @defgroup pxenv_tftp_open PXENV_TFTP_OPEN - * - * TFTP OPEN - * - * @{ - */ - -/** PXE API function code for pxenv_tftp_open() */ -#define PXENV_TFTP_OPEN 0x0020 - -/** Parameter block for pxenv_tftp_open() */ -struct s_PXENV_TFTP_OPEN { - PXENV_STATUS_t Status; /**< PXE status code */ - IP4_t ServerIPAddress; /**< TFTP server IP address */ - IP4_t GatewayIPAddress; /**< Relay agent IP address */ - UINT8_t FileName[128]; /**< File name */ - UDP_PORT_t TFTPPort; /**< TFTP server UDP port */ - /** Requested size of TFTP packets - * - * This is the TFTP "blksize" option. This must be at least - * 512, since servers that do not support TFTP options cannot - * negotiate blocksizes smaller than this. - */ - UINT16_t PacketSize; -} PACKED; - -typedef struct s_PXENV_TFTP_OPEN PXENV_TFTP_OPEN_t; - -extern PXENV_EXIT_t pxenv_tftp_open ( struct s_PXENV_TFTP_OPEN *tftp_open ); - -/** @} */ /* pxenv_tftp_open */ - -/** @defgroup pxenv_tftp_close PXENV_TFTP_CLOSE - * - * TFTP CLOSE - * - * @{ - */ - -/** PXE API function code for pxenv_tftp_close() */ -#define PXENV_TFTP_CLOSE 0x0021 - -/** Parameter block for pxenv_tftp_close() */ -struct s_PXENV_TFTP_CLOSE { - PXENV_STATUS_t Status; /**< PXE status code */ -} PACKED; - -typedef struct s_PXENV_TFTP_CLOSE PXENV_TFTP_CLOSE_t; - -extern PXENV_EXIT_t pxenv_tftp_close ( struct s_PXENV_TFTP_CLOSE *tftp_close ); - -/** @} */ /* pxenv_tftp_close */ - -/** @defgroup pxenv_tftp_read PXENV_TFTP_READ - * - * TFTP READ - * - * @{ - */ - -/** PXE API function code for pxenv_tftp_read() */ -#define PXENV_TFTP_READ 0x0022 - -/** Parameter block for pxenv_tftp_read() */ -struct s_PXENV_TFTP_READ { - PXENV_STATUS_t Status; /**< PXE status code */ - UINT16_t PacketNumber; /**< TFTP packet number */ - UINT16_t BufferSize; /**< Size of data buffer */ - SEGOFF16_t Buffer; /**< Address of data buffer */ -} PACKED; - -typedef struct s_PXENV_TFTP_READ PXENV_TFTP_READ_t; - -extern PXENV_EXIT_t pxenv_tftp_read ( struct s_PXENV_TFTP_READ *tftp_read ); - -/** @} */ /* pxenv_tftp_read */ - -/** @defgroup pxenv_tftp_read_file PXENV_TFTP_READ_FILE - * - * TFTP/MTFTP READ FILE - * - * @{ - */ - -/** PXE API function code for pxenv_tftp_read_file() */ -#define PXENV_TFTP_READ_FILE 0x0023 - -/** Parameter block for pxenv_tftp_read_file() */ -struct s_PXENV_TFTP_READ_FILE { - PXENV_STATUS_t Status; /**< PXE status code */ - UINT8_t FileName[128]; /**< File name */ - UINT32_t BufferSize; /**< Size of data buffer */ - ADDR32_t Buffer; /**< Address of data buffer */ - IP4_t ServerIPAddress; /**< TFTP server IP address */ - IP4_t GatewayIPAddress; /**< Relay agent IP address */ - /** File multicast IP address */ - IP4_t McastIPAddress; - /** Client multicast listening port */ - UDP_PORT_t TFTPClntPort; - /** Server multicast listening port */ - UDP_PORT_t TFTPSrvPort; - /** TFTP open timeout. - * - * This is the timeout for receiving the first DATA or ACK - * packets during the MTFTP Listen phase. - */ - UINT16_t TFTPOpenTimeOut; - /** TFTP reopen timeout. - * - * This is the timeout for receiving an ACK packet while in - * the MTFTP Listen phase (when at least one ACK packet has - * already been seen). - */ - UINT16_t TFTPReopenDelay; -} PACKED; - -typedef struct s_PXENV_TFTP_READ_FILE PXENV_TFTP_READ_FILE_t; - -extern PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE - *tftp_read_file ); - -/** @} */ /* pxenv_tftp_read_file */ - -/** @defgroup pxenv_tftp_get_fsize PXENV_TFTP_GET_FSIZE - * - * TFTP GET FILE SIZE - * - * @{ - */ - -/** PXE API function code for pxenv_tftp_get_fsize() */ -#define PXENV_TFTP_GET_FSIZE 0x0025 - -/** Parameter block for pxenv_tftp_get_fsize() */ -struct s_PXENV_TFTP_GET_FSIZE { - PXENV_STATUS_t Status; /**< PXE status code */ - IP4_t ServerIPAddress; /**< TFTP server IP address */ - IP4_t GatewayIPAddress; /**< Relay agent IP address */ - UINT8_t FileName[128]; /**< File name */ - UINT32_t FileSize; /**< Size of the file */ -} PACKED; - -typedef struct s_PXENV_TFTP_GET_FSIZE PXENV_TFTP_GET_FSIZE_t; - -extern PXENV_EXIT_t pxenv_tftp_get_fsize ( struct s_PXENV_TFTP_GET_FSIZE - *get_fsize ); - -/** @} */ /* pxenv_tftp_get_fsize */ - -/** @} */ /* pxe_tftp_api */ - -/** @defgroup pxe_udp_api PXE UDP API - * - * Transmit and receive UDP packets - * - * @{ - */ - -/** @defgroup pxenv_udp_open PXENV_UDP_OPEN - * - * UDP OPEN - * - * @{ - */ - -/** PXE API function code for pxenv_udp_open() */ -#define PXENV_UDP_OPEN 0x0030 - -/** Parameter block for pxenv_udp_open() */ -struct s_PXENV_UDP_OPEN { - PXENV_STATUS_t Status; /**< PXE status code */ - IP4_t src_ip; /**< IP address of this station */ -} PACKED; - -typedef struct s_PXENV_UDP_OPEN PXENV_UDP_OPEN_t; - -extern PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *udp_open ); - -/** @} */ /* pxenv_udp_open */ - -/** @defgroup pxenv_udp_close PXENV_UDP_CLOSE - * - * UDP CLOSE - * - * @{ - */ - -/** PXE API function code for pxenv_udp_close() */ -#define PXENV_UDP_CLOSE 0x0031 - -/** Parameter block for pxenv_udp_close() */ -struct s_PXENV_UDP_CLOSE { - PXENV_STATUS_t Status; /**< PXE status code */ -} PACKED; - -typedef struct s_PXENV_UDP_CLOSE PXENV_UDP_CLOSE_t; - -extern PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *udp_close ); - -/** @} */ /* pxenv_udp_close */ - -/** @defgroup pxenv_udp_write PXENV_UDP_WRITE - * - * UDP WRITE - * - * @{ - */ - -/** PXE API function code for pxenv_udp_write() */ -#define PXENV_UDP_WRITE 0x0033 - -/** Parameter block for pxenv_udp_write() */ -struct s_PXENV_UDP_WRITE { - PXENV_STATUS_t Status; /**< PXE status code */ - IP4_t ip; /**< Destination IP address */ - IP4_t gw; /**< Relay agent IP address */ - UDP_PORT_t src_port; /**< Source UDP port */ - UDP_PORT_t dst_port; /**< Destination UDP port */ - UINT16_t buffer_size; /**< UDP payload buffer size */ - SEGOFF16_t buffer; /**< UDP payload buffer address */ -} PACKED; - -typedef struct s_PXENV_UDP_WRITE PXENV_UDP_WRITE_t; - -extern PXENV_EXIT_t pxenv_udp_write ( struct s_PXENV_UDP_WRITE *udp_write ); - -/** @} */ /* pxenv_udp_write */ - -/** @defgroup pxenv_udp_read PXENV_UDP_READ - * - * UDP READ - * - * @{ - */ - -/** PXE API function code for pxenv_udp_read() */ -#define PXENV_UDP_READ 0x0032 - -/** Parameter block for pxenv_udp_read() */ -struct s_PXENV_UDP_READ { - PXENV_STATUS_t Status; /**< PXE status code */ - IP4_t src_ip; /**< Source IP address */ - IP4_t dest_ip; /**< Destination IP address */ - UDP_PORT_t s_port; /**< Source UDP port */ - UDP_PORT_t d_port; /**< Destination UDP port */ - UINT16_t buffer_size; /**< UDP payload buffer size */ - SEGOFF16_t buffer; /**< UDP payload buffer address */ -} PACKED; - -typedef struct s_PXENV_UDP_READ PXENV_UDP_READ_t; - -extern PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *udp_read ); - -/** @} */ /* pxenv_udp_read */ - -/** @} */ /* pxe_udp_api */ - -/** @defgroup pxe_undi_api PXE UNDI API - * - * Direct control of the network interface card - * - * @{ - */ - -/** @defgroup pxenv_undi_startup PXENV_UNDI_STARTUP - * - * UNDI STARTUP - * - * @{ - */ - -/** PXE API function code for pxenv_undi_startup() */ -#define PXENV_UNDI_STARTUP 0x0001 - -#define PXENV_BUS_ISA 0 /**< ISA bus type */ -#define PXENV_BUS_EISA 1 /**< EISA bus type */ -#define PXENV_BUS_MCA 2 /**< MCA bus type */ -#define PXENV_BUS_PCI 3 /**< PCI bus type */ -#define PXENV_BUS_VESA 4 /**< VESA bus type */ -#define PXENV_BUS_PCMCIA 5 /**< PCMCIA bus type */ - -/** Parameter block for pxenv_undi_startup() */ -struct s_PXENV_UNDI_STARTUP { - PXENV_STATUS_t Status; /**< PXE status code */ -} PACKED; - -typedef struct s_PXENV_UNDI_STARTUP PXENV_UNDI_STARTUP_t; - -extern PXENV_EXIT_t pxenv_undi_startup ( struct s_PXENV_UNDI_STARTUP - *undi_startup ); - -/** @} */ /* pxenv_undi_startup */ - -/** @defgroup pxenv_undi_cleanup PXENV_UNDI_CLEANUP - * - * UNDI CLEANUP - * - * @{ - */ - -/** PXE API function code for pxenv_undi_cleanup() */ -#define PXENV_UNDI_CLEANUP 0x0002 - -/** Parameter block for pxenv_undi_cleanup() */ -struct s_PXENV_UNDI_CLEANUP { - PXENV_STATUS_t Status; /**< PXE status code */ -} PACKED; - -typedef struct s_PXENV_UNDI_CLEANUP PXENV_UNDI_CLEANUP_t; - -extern PXENV_EXIT_t pxenv_undi_cleanup ( struct s_PXENV_UNDI_CLEANUP - *undi_cleanup ); - -/** @} */ /* pxenv_undi_cleanup */ - -/** @defgroup pxenv_undi_initialize PXENV_UNDI_INITIALIZE - * - * UNDI INITIALIZE - * - * @{ - */ - -/** PXE API function code for pxenv_undi_initialize() */ -#define PXENV_UNDI_INITIALIZE 0x0003 - -/** Parameter block for pxenv_undi_initialize() */ -struct s_PXENV_UNDI_INITIALIZE { - PXENV_STATUS_t Status; /**< PXE status code */ - /** NDIS 2.0 configuration information, or NULL - * - * This is a pointer to the data structure returned by the - * NDIS 2.0 GetProtocolManagerInfo() API call. The data - * structure is documented, in a rather haphazard way, in - * section 4-17 of the NDIS 2.0 specification. - */ - ADDR32_t ProtocolIni; - UINT8_t reserved[8]; /**< Must be zero */ -} PACKED; - -typedef struct s_PXENV_UNDI_INITIALIZE PXENV_UNDI_INITIALIZE_t; - -extern PXENV_EXIT_t pxenv_undi_initialize ( struct s_PXENV_UNDI_INITIALIZE - *undi_initialize ); - -/** @} */ /* pxenv_undi_initialize */ - -/** @defgroup pxenv_undi_reset_adapter PXENV_UNDI_RESET_ADAPTER - * - * UNDI RESET ADAPTER - * - * @{ - */ - -/** PXE API function code for pxenv_undi_reset_adapter() */ -#define PXENV_UNDI_RESET_ADAPTER 0x0004 - -/** Maximum number of multicast MAC addresses */ -#define MAXNUM_MCADDR 8 - -/** List of multicast MAC addresses */ -struct s_PXENV_UNDI_MCAST_ADDRESS { - /** Number of multicast MAC addresses */ - UINT16_t MCastAddrCount; - /** List of up to #MAXNUM_MCADDR multicast MAC addresses */ - MAC_ADDR_t McastAddr[MAXNUM_MCADDR]; -} PACKED; - -typedef struct s_PXENV_UNDI_MCAST_ADDRESS PXENV_UNDI_MCAST_ADDRESS_t; - -/** Parameter block for pxenv_undi_reset_adapter() */ -struct s_PXENV_UNDI_RESET { - PXENV_STATUS_t Status; /**< PXE status code */ - /** Multicast MAC addresses */ - struct s_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf; -} PACKED; - -typedef struct s_PXENV_UNDI_RESET PXENV_UNDI_RESET_t; - -extern PXENV_EXIT_t pxenv_undi_reset_adapter ( struct s_PXENV_UNDI_RESET - *undi_reset_adapter ); - -/** @} */ /* pxenv_undi_reset_adapter */ - -/** @defgroup pxenv_undi_shutdown PXENV_UNDI_SHUTDOWN - * - * UNDI SHUTDOWN - * - * @{ - */ - -/** PXE API function code for pxenv_undi_shutdown() */ -#define PXENV_UNDI_SHUTDOWN 0x0005 - -/** Parameter block for pxenv_undi_shutdown() */ -struct s_PXENV_UNDI_SHUTDOWN { - PXENV_STATUS_t Status; /**< PXE status code */ -} PACKED; - -typedef struct s_PXENV_UNDI_SHUTDOWN PXENV_UNDI_SHUTDOWN_t; - -extern PXENV_EXIT_t pxenv_undi_shutdown ( struct s_PXENV_UNDI_SHUTDOWN - *undi_shutdown ); - -/** @} */ /* pxenv_undi_shutdown */ - -/** @defgroup pxenv_undi_open PXENV_UNDI_OPEN - * - * UNDI OPEN - * - * @{ - */ - -/** PXE API function code for pxenv_undi_open() */ -#define PXENV_UNDI_OPEN 0x0006 - -/** Accept "directed" packets - * - * These are packets addresses to either this adapter's MAC address or - * to any of the configured multicast MAC addresses (see - * #s_PXENV_UNDI_MCAST_ADDRESS). - */ -#define FLTR_DIRECTED 0x0001 -/** Accept broadcast packets */ -#define FLTR_BRDCST 0x0002 -/** Accept all packets; listen in promiscuous mode */ -#define FLTR_PRMSCS 0x0004 -/** Accept source-routed packets */ -#define FLTR_SRC_RTG 0x0008 - -/** Parameter block for pxenv_undi_open() */ -struct s_PXENV_UNDI_OPEN { - PXENV_STATUS_t Status; /**< PXE status code */ - /** Open flags as defined in NDIS 2.0 - * - * This is the OpenOptions field as passed to the NDIS 2.0 - * OpenAdapter() API call. It is defined to be "adapter - * specific", though 0 is guaranteed to be a valid value. - */ - UINT16_t OpenFlag; - /** Receive packet filter - * - * This is the bitwise-OR of any of the following flags: - * #FLTR_DIRECTED, #FLTR_BRDCST, #FLTR_PRMSCS and - * #FLTR_SRC_RTG. - */ - UINT16_t PktFilter; - /** Multicast MAC addresses */ - struct s_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf; -} PACKED; - -typedef struct s_PXENV_UNDI_OPEN PXENV_UNDI_OPEN_t; - -extern PXENV_EXIT_t pxenv_undi_open ( struct s_PXENV_UNDI_OPEN *undi_open ); - -/** @} */ /* pxenv_undi_open */ - -/** @defgroup pxenv_undi_close PXENV_UNDI_CLOSE - * - * UNDI CLOSE - * - * @{ - */ - -/** PXE API function code for pxenv_undi_close() */ -#define PXENV_UNDI_CLOSE 0x0007 - -/** Parameter block for pxenv_undi_close() */ -struct s_PXENV_UNDI_CLOSE { - PXENV_STATUS_t Status; /**< PXE status code */ -} PACKED; - -typedef struct s_PXENV_UNDI_CLOSE PXENV_UNDI_CLOSE_t; - -extern PXENV_EXIT_t pxenv_undi_close ( struct s_PXENV_UNDI_CLOSE *undi_close ); - -/** @} */ /* pxenv_undi_close */ - -/** @defgroup pxenv_undi_transmit PXENV_UNDI_TRANSMIT - * - * UNDI TRANSMIT PACKET - * - * @{ - */ - -/** PXE API function code for pxenv_undi_transmit() */ -#define PXENV_UNDI_TRANSMIT 0x0008 - -#define P_UNKNOWN 0 /**< Media header already filled in */ -#define P_IP 1 /**< IP protocol */ -#define P_ARP 2 /**< ARP protocol */ -#define P_RARP 3 /**< RARP protocol */ -#define P_OTHER 4 /**< Other protocol */ - -#define XMT_DESTADDR 0x0000 /**< Unicast packet */ -#define XMT_BROADCAST 0x0001 /**< Broadcast packet */ - -/** Maximum number of data blocks in a transmit buffer descriptor */ -#define MAX_DATA_BLKS 8 - -/** A transmit buffer descriptor, as pointed to by s_PXENV_UNDI_TRANSMIT::TBD - */ -struct s_PXENV_UNDI_TBD { - UINT16_t ImmedLength; /**< Length of the transmit buffer */ - SEGOFF16_t Xmit; /**< Address of the transmit buffer */ - UINT16_t DataBlkCount; - /** Array of up to #MAX_DATA_BLKS additional transmit buffers */ - struct DataBlk { - /** Always 1 - * - * A value of 0 would indicate that #TDDataPtr were an - * #ADDR32_t rather than a #SEGOFF16_t. The PXE - * specification version 2.1 explicitly states that - * this is not supported; #TDDataPtr will always be a - * #SEGOFF16_t. - */ - UINT8_t TDPtrType; - UINT8_t TDRsvdByte; /**< Must be zero */ - UINT16_t TDDataLen; /**< Length of this transmit buffer */ - SEGOFF16_t TDDataPtr; /**< Address of this transmit buffer */ - } DataBlock[MAX_DATA_BLKS]; -} PACKED; - -typedef struct s_PXENV_UNDI_TBD PXENV_UNDI_TBD_t; - -/** Parameter block for pxenv_undi_transmit() */ -struct s_PXENV_UNDI_TRANSMIT { - PXENV_STATUS_t Status; /**< PXE status code */ - /** Protocol - * - * Valid values are #P_UNKNOWN, #P_IP, #P_ARP or #P_RARP. If - * the caller has already filled in the media header, this - * field must be set to #P_UNKNOWN. - */ - UINT8_t Protocol; - /** Unicast/broadcast flag - * - * Valid values are #XMT_DESTADDR or #XMT_BROADCAST. - */ - UINT8_t XmitFlag; - SEGOFF16_t DestAddr; /**< Destination MAC address */ - /** Address of the Transmit Buffer Descriptor - * - * This is a pointer to a struct s_PXENV_UNDI_TBD. - */ - SEGOFF16_t TBD; - UINT32_t Reserved[2]; /**< Must be zero */ -} PACKED; - -typedef struct s_PXENV_UNDI_TRANSMIT PXENV_UNDI_TRANSMIT_t; - -extern PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT - *undi_transmit ); - -/** @} */ /* pxenv_undi_transmit */ - -/** @defgroup pxenv_undi_set_mcast_address PXENV_UNDI_SET_MCAST_ADDRESS - * - * UNDI SET MULTICAST ADDRESS - * - * @{ - */ - -/** PXE API function code for pxenv_undi_set_mcast_address() */ -#define PXENV_UNDI_SET_MCAST_ADDRESS 0x0009 - -/** Parameter block for pxenv_undi_set_mcast_address() */ -struct s_PXENV_UNDI_SET_MCAST_ADDRESS { - PXENV_STATUS_t Status; /**< PXE status code */ - /** List of multicast addresses */ - struct s_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf; -} PACKED; - -typedef struct s_PXENV_UNDI_SET_MCAST_ADDRESS PXENV_UNDI_SET_MCAST_ADDRESS_t; - -extern PXENV_EXIT_t pxenv_undi_set_mcast_address ( - struct s_PXENV_UNDI_SET_MCAST_ADDRESS *undi_set_mcast_address ); - -/** @} */ /* pxenv_undi_set_mcast_address */ - -/** @defgroup pxenv_undi_set_station_address PXENV_UNDI_SET_STATION_ADDRESS - * - * UNDI SET STATION ADDRESS - * - * @{ - */ - -/** PXE API function code for pxenv_undi_set_station_address() */ -#define PXENV_UNDI_SET_STATION_ADDRESS 0x000a - -/** Parameter block for pxenv_undi_set_station_address() */ -struct s_PXENV_UNDI_SET_STATION_ADDRESS { - PXENV_STATUS_t Status; /**< PXE status code */ - MAC_ADDR_t StationAddress; /**< Station MAC address */ -} PACKED; - -typedef struct s_PXENV_UNDI_SET_STATION_ADDRESS PXENV_UNDI_SET_STATION_ADDRESS_t; - -extern PXENV_EXIT_t pxenv_undi_set_station_address ( - struct s_PXENV_UNDI_SET_STATION_ADDRESS *undi_set_station_address ); - -/** @} */ /* pxenv_undi_set_station_address */ - -/** @defgroup pxenv_undi_set_packet_filter PXENV_UNDI_SET_PACKET_FILTER - * - * UNDI SET PACKET FILTER - * - * @{ - */ - -/** PXE API function code for pxenv_undi_set_packet_filter() */ -#define PXENV_UNDI_SET_PACKET_FILTER 0x000b - -/** Parameter block for pxenv_undi_set_packet_filter() */ -struct s_PXENV_UNDI_SET_PACKET_FILTER { - PXENV_STATUS_t Status; /**< PXE status code */ - /** Receive packet filter - * - * This field takes the same values as - * s_PXENV_UNDI_OPEN::PktFilter. - * - * @note Yes, this field is a different size to - * s_PXENV_UNDI_OPEN::PktFilter. Blame "the managers at Intel - * who apparently let a consultant come up with the spec - * without any kind of adult supervision" (quote from hpa). - */ - UINT8_t filter; -} PACKED; - -typedef struct s_PXENV_UNDI_SET_PACKET_FILTER PXENV_UNDI_SET_PACKET_FILTER_t; - -extern PXENV_EXIT_t pxenv_undi_set_packet_filter ( - struct s_PXENV_UNDI_SET_PACKET_FILTER *undi_set_packet_filter ); - -/** @} */ /* pxenv_undi_set_packet_filter */ - -/** @defgroup pxenv_undi_get_information PXENV_UNDI_GET_INFORMATION - * - * UNDI GET INFORMATION - * - * @{ - */ - -/** PXE API function code for pxenv_undi_get_information() */ -#define PXENV_UNDI_GET_INFORMATION 0x000c - -#define ETHER_TYPE 1 /**< Ethernet (10Mb) */ -#define EXP_ETHER_TYPE 2 /**< Experimental Ethernet (3Mb) */ -#define AX25_TYPE 3 /**< Amateur Radio AX.25 */ -#define TOKEN_RING_TYPE 4 /**< Proteon ProNET Token Ring */ -#define CHAOS_TYPE 5 /**< Chaos */ -#define IEEE_TYPE 6 /**< IEEE 802 Networks */ -#define ARCNET_TYPE 7 /**< ARCNET */ - -/** Parameter block for pxenv_undi_get_information() */ -struct s_PXENV_UNDI_GET_INFORMATION { - PXENV_STATUS_t Status; /**< PXE status code */ - UINT16_t BaseIo; /**< I/O base address */ - UINT16_t IntNumber; /**< IRQ number */ - UINT16_t MaxTranUnit; /**< Adapter MTU */ - /** Hardware type - * - * Valid values are defined in RFC1010 ("Assigned numbers"), - * and are #ETHER_TYPE, #EXP_ETHER_TYPE, #AX25_TYPE, - * #TOKEN_RING_TYPE, #CHAOS_TYPE, #IEEE_TYPE or #ARCNET_TYPE. - */ - UINT16_t HwType; - UINT16_t HwAddrLen; /**< MAC address length */ - MAC_ADDR_t CurrentNodeAddress; /**< Current MAC address */ - MAC_ADDR_t PermNodeAddress; /**< Permanent (EEPROM) MAC address */ - SEGSEL_t ROMAddress; /**< Real-mode ROM segment address */ - UINT16_t RxBufCt; /**< Receive queue length */ - UINT16_t TxBufCt; /**< Transmit queue length */ -} PACKED; - -typedef struct s_PXENV_UNDI_GET_INFORMATION PXENV_UNDI_GET_INFORMATION_t; - -extern PXENV_EXIT_t pxenv_undi_get_information ( - struct s_PXENV_UNDI_GET_INFORMATION *undi_get_information ); - -/** @} */ /* pxenv_undi_get_information */ - -/** @defgroup pxenv_undi_get_statistics PXENV_UNDI_GET_STATISTICS - * - * UNDI GET STATISTICS - * - * @{ - */ - -/** PXE API function code for pxenv_undi_get_statistics() */ -#define PXENV_UNDI_GET_STATISTICS 0x000d - -/** Parameter block for pxenv_undi_get_statistics() */ -struct s_PXENV_UNDI_GET_STATISTICS { - PXENV_STATUS_t Status; /**< PXE status code */ - UINT32_t XmtGoodFrames; /**< Successful transmission count */ - UINT32_t RcvGoodFrames; /**< Successful reception count */ - UINT32_t RcvCRCErrors; /**< Receive CRC error count */ - UINT32_t RcvResourceErrors; /**< Receive queue overflow count */ -} PACKED; - -typedef struct s_PXENV_UNDI_GET_STATISTICS PXENV_UNDI_GET_STATISTICS_t; - -extern PXENV_EXIT_t pxenv_undi_get_statistics ( - struct s_PXENV_UNDI_GET_STATISTICS *undi_get_statistics ); - -/** @} */ /* pxenv_undi_get_statistics */ - -/** @defgroup pxenv_undi_clear_statistics PXENV_UNDI_CLEAR_STATISTICS - * - * UNDI CLEAR STATISTICS - * - * @{ - */ - -/** PXE API function code for pxenv_undi_clear_statistics() */ -#define PXENV_UNDI_CLEAR_STATISTICS 0x000e - -/** Parameter block for pxenv_undi_clear_statistics() */ -struct s_PXENV_UNDI_CLEAR_STATISTICS { - PXENV_STATUS_t Status; /**< PXE status code */ -} PACKED; - -typedef struct s_PXENV_UNDI_CLEAR_STATISTICS PXENV_UNDI_CLEAR_STATISTICS_t; - -extern PXENV_EXIT_t pxenv_undi_clear_statistics ( - struct s_PXENV_UNDI_CLEAR_STATISTICS *undi_clear_statistics ); - -/** @} */ /* pxenv_undi_clear_statistics */ - -/** @defgroup pxenv_undi_initiate_diags PXENV_UNDI_INITIATE_DIAGS - * - * UNDI INITIATE DIAGS - * - * @{ - */ - -/** PXE API function code for pxenv_undi_initiate_diags() */ -#define PXENV_UNDI_INITIATE_DIAGS 0x000f - -/** Parameter block for pxenv_undi_initiate_diags() */ -struct s_PXENV_UNDI_INITIATE_DIAGS { - PXENV_STATUS_t Status; /**< PXE status code */ -} PACKED; - -typedef struct s_PXENV_UNDI_INITIATE_DIAGS PXENV_UNDI_INITIATE_DIAGS_t; - -extern PXENV_EXIT_t pxenv_undi_initiate_diags ( - struct s_PXENV_UNDI_INITIATE_DIAGS *undi_initiate_diags ); - -/** @} */ /* pxenv_undi_initiate_diags */ - -/** @defgroup pxenv_undi_force_interrupt PXENV_UNDI_FORCE_INTERRUPT - * - * UNDI FORCE INTERRUPT - * - * @{ - */ - -/** PXE API function code for pxenv_undi_force_interrupt() */ -#define PXENV_UNDI_FORCE_INTERRUPT 0x0010 - -/** Parameter block for pxenv_undi_force_interrupt() */ -struct s_PXENV_UNDI_FORCE_INTERRUPT { - PXENV_STATUS_t Status; /**< PXE status code */ -} PACKED; - -typedef struct s_PXENV_UNDI_FORCE_INTERRUPT PXENV_UNDI_FORCE_INTERRUPT_t; - -extern PXENV_EXIT_t pxenv_undi_force_interrupt ( - struct s_PXENV_UNDI_FORCE_INTERRUPT *undi_force_interrupt ); - -/** @} */ /* pxenv_undi_force_interrupt */ - -/** @defgroup pxenv_undi_get_mcast_address PXENV_UNDI_GET_MCAST_ADDRESS - * - * UNDI GET MULTICAST ADDRESS - * - * @{ - */ - -/** PXE API function code for pxenv_undi_get_mcast_address() */ -#define PXENV_UNDI_GET_MCAST_ADDRESS 0x0011 - -/** Parameter block for pxenv_undi_get_mcast_address() */ -struct s_PXENV_UNDI_GET_MCAST_ADDRESS { - PXENV_STATUS_t Status; /**< PXE status code */ - IP4_t InetAddr; /**< Multicast IP address */ - MAC_ADDR_t MediaAddr; /**< Multicast MAC address */ -} PACKED; - -typedef struct s_PXENV_UNDI_GET_MCAST_ADDRESS PXENV_UNDI_GET_MCAST_ADDRESS_t; - -extern PXENV_EXIT_t pxenv_undi_get_mcast_address ( - struct s_PXENV_UNDI_GET_MCAST_ADDRESS *undi_get_mcast_address ); - -/** @} */ /* pxenv_undi_get_mcast_address */ - -/** @defgroup pxenv_undi_get_nic_type PXENV_UNDI_GET_NIC_TYPE - * - * UNDI GET NIC TYPE - * - * @{ - */ - -/** PXE API function code for pxenv_undi_get_nic_type() */ -#define PXENV_UNDI_GET_NIC_TYPE 0x0012 - -#define PCI_NIC 2 /**< PCI network card */ -#define PnP_NIC 3 /**< ISAPnP network card */ -#define CardBus_NIC 4 /**< CardBus network card */ - -/** Information for a PCI or equivalent NIC */ -struct pci_nic_info { - UINT16_t Vendor_ID; /**< PCI vendor ID */ - UINT16_t Dev_ID; /**< PCI device ID */ - UINT8_t Base_Class; /**< PCI base class */ - UINT8_t Sub_Class; /**< PCI sub class */ - UINT8_t Prog_Intf; /**< PCI programming interface */ - UINT8_t Rev; /**< PCI revision */ - UINT16_t BusDevFunc; /**< PCI bus:dev:fn address */ - UINT16_t SubVendor_ID; /**< PCI subvendor ID */ - UINT16_t SubDevice_ID; /**< PCI subdevice ID */ -} PACKED; - -/** Information for an ISAPnP or equivalent NIC */ -struct pnp_nic_info { - UINT32_t EISA_Dev_ID; /**< EISA device ID */ - UINT8_t Base_Class; /**< Base class */ - UINT8_t Sub_Class; /**< Sub class */ - UINT8_t Prog_Intf; /**< Programming interface */ - /** Card Select Number assigned to card */ - UINT16_t CardSelNum; -} PACKED; - -/** Parameter block for pxenv_undi_get_nic_type() */ -struct s_PXENV_UNDI_GET_NIC_TYPE { - PXENV_STATUS_t Status; /**< PXE status code */ - /** NIC type - * - * Valid values are #PCI_NIC, #PnP_NIC or #CardBus_NIC. - */ - UINT8_t NicType; - /** NIC information */ - union nic_type_info { - /** NIC information (if #NicType==#PCI_NIC) */ - struct pci_nic_info pci; - /** NIC information (if #NicType==#CardBus_NIC) */ - struct pci_nic_info cardbus; - /** NIC information (if #NicType==#PnP_NIC) */ - struct pnp_nic_info pnp; - } info; -} PACKED; - -typedef struct s_PXENV_UNDI_GET_NIC_TYPE PXENV_UNDI_GET_NIC_TYPE_t; - -extern PXENV_EXIT_t pxenv_undi_get_nic_type ( - struct s_PXENV_UNDI_GET_NIC_TYPE *undi_get_nic_type ); - -/** @} */ /* pxenv_undi_get_nic_type */ - -/** @defgroup pxenv_undi_get_iface_info PXENV_UNDI_GET_IFACE_INFO - * - * UNDI GET IFACE INFO - * - * @{ - */ - -/** PXE API function code for pxenv_undi_get_iface_info() */ -#define PXENV_UNDI_GET_IFACE_INFO 0x0013 - -/** Parameter block for pxenv_undi_get_iface_info() */ -struct s_PXENV_UNDI_GET_IFACE_INFO { - PXENV_STATUS_t Status; /**< PXE status code */ - /** Interface type - * - * This is defined in the NDIS 2.0 specification to be one of - * the strings "802.3", "802.4", "802.5", "802.6", "DIX", - * "DIX+802.3", "APPLETALK", "ARCNET", "FDDI", "SDLC", "BSC", - * "HDLC", or "ISDN". - * - * "Normal" Ethernet, for various historical reasons, is - * "DIX+802.3". - */ - UINT8_t IfaceType[16]; - UINT32_t LinkSpeed; /**< Link speed, in bits per second */ - /** Service flags - * - * These are the "service flags" defined in the "MAC - * Service-Specific Characteristics" table in the NDIS 2.0 - * specification. Almost all of them are irrelevant to PXE. - */ - UINT32_t ServiceFlags; - UINT32_t Reserved[4]; /**< Must be zero */ -} PACKED; - -typedef struct s_PXENV_UNDI_GET_IFACE_INFO PXENV_UNDI_GET_IFACE_INFO_t; - -extern PXENV_EXIT_t pxenv_undi_get_iface_info ( - struct s_PXENV_UNDI_GET_IFACE_INFO *undi_get_iface_info ); - -/** @} */ /* pxenv_undi_get_iface_info */ - -/** @defgroup pxenv_undi_get_state PXENV_UNDI_GET_STATE - * - * UNDI GET STATE - * - * @{ - */ - -/** PXE API function code for pxenv_undi_get_state() */ -#define PXENV_UNDI_GET_STATE 0x0015 - -/** pxenv_start_undi() has been called */ -#define PXE_UNDI_GET_STATE_STARTED 1 -/** pxenv_undi_initialize() has been called */ -#define PXE_UNDI_GET_STATE_INITIALIZED 2 -/** pxenv_undi_open() has been called */ -#define PXE_UNDI_GET_STATE_OPENED 3 - -/** Parameter block for pxenv_undi_get_state() */ -struct s_PXENV_UNDI_GET_STATE { - PXENV_STATUS_t Status; /**< PXE status code */ - /** Current state of the UNDI driver - * - * Valid values are #PXE_UNDI_GET_STATE_STARTED, - * #PXE_UNDI_GET_STATE_INITIALIZED or - * #PXE_UNDI_GET_STATE_OPENED. - */ - UINT8_t UNDIstate; -} PACKED; - -typedef struct s_PXENV_UNDI_GET_STATE PXENV_UNDI_GET_STATE_t; - -extern PXENV_EXIT_t pxenv_undi_get_state ( struct s_PXENV_UNDI_GET_STATE - *undi_get_state ); - -/** @} */ /* pxenv_undi_get_state */ - -/** @defgroup pxenv_undi_isr PXENV_UNDI_ISR - * - * UNDI ISR - * - * @{ - */ - -/** PXE API function code for pxenv_undi_isr() */ -#define PXENV_UNDI_ISR 0x0014 - -/** Determine whether or not this is our interrupt */ -#define PXENV_UNDI_ISR_IN_START 1 -/** Start processing interrupt */ -#define PXENV_UNDI_ISR_IN_PROCESS 2 -/** Continue processing interrupt */ -#define PXENV_UNDI_ISR_IN_GET_NEXT 3 -/** This interrupt was ours */ -#define PXENV_UNDI_ISR_OUT_OURS 0 -/** This interrupt was not ours */ -#define PXENV_UNDI_ISR_OUT_NOT_OURS 1 -/** Finished processing interrupt */ -#define PXENV_UNDI_ISR_OUT_DONE 0 -/** A packet transmission has completed */ -#define PXENV_UNDI_ISR_OUT_TRANSMIT 2 -/** A packet has been received */ -#define PXENV_UNDI_ISR_OUT_RECEIVE 3 -/** We are already in the middle of processing an interrupt */ -#define PXENV_UNDI_ISR_OUT_BUSY 4 - -/** Unicast packet (or packet captured in promiscuous mode) */ -#define P_DIRECTED 0 -/** Broadcast packet */ -#define P_BROADCAST 1 -/** Multicast packet */ -#define P_MULTICAST 2 - -/** Parameter block for pxenv_undi_isr() */ -struct s_PXENV_UNDI_ISR { - PXENV_STATUS_t Status; /**< PXE status code */ - /** Function flag - * - * Valid values are #PXENV_UNDI_ISR_IN_START, - * #PXENV_UNDI_ISR_IN_PROCESS, #PXENV_UNDI_ISR_IN_GET_NEXT, - * #PXENV_UNDI_ISR_OUT_OURS, #PXENV_UNDI_ISR_OUT_NOT_OURS, - * #PXENV_UNDI_ISR_OUT_DONE, #PXENV_UNDI_ISR_OUT_TRANSMIT, - * #PXENV_UNDI_ISR_OUT_RECEIVE or #PXENV_UNDI_ISR_OUT_BUSY. - */ - UINT16_t FuncFlag; - UINT16_t BufferLength; /**< Data buffer length */ - UINT16_t FrameLength; /**< Total frame length */ - UINT16_t FrameHeaderLength; /**< Frame header length */ - SEGOFF16_t Frame; /**< Data buffer address */ - /** Protocol type - * - * Valid values are #P_IP, #P_ARP, #P_RARP or #P_OTHER. - */ - UINT8_t ProtType; - /** Packet type - * - * Valid values are #P_DIRECTED, #P_BROADCAST or #P_MULTICAST. - */ - UINT8_t PktType; -} PACKED; - -typedef struct s_PXENV_UNDI_ISR PXENV_UNDI_ISR_t; - -extern PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ); - -/** @} */ /* pxenv_undi_isr */ - -/** @} */ /* pxe_undi_api */ - -/** @defgroup pxe_file_api PXE FILE API - * - * POSIX-like file operations - * - * @{ - */ - -/** @defgroup pxenv_file_open PXENV_FILE_OPEN - * - * FILE OPEN - * - * @{ - */ - -/** PXE API function code for pxenv_file_open() */ -#define PXENV_FILE_OPEN 0x00e0 - -/** Parameter block for pxenv_file_open() */ -struct s_PXENV_FILE_OPEN { - PXENV_STATUS_t Status; /**< PXE status code */ - UINT16_t FileHandle; /**< File handle */ - SEGOFF16_t FileName; /**< File URL */ - UINT32_t Reserved; /**< Reserved */ -} PACKED; - -typedef struct s_PXENV_FILE_OPEN PXENV_FILE_OPEN_t; - -extern PXENV_EXIT_t pxenv_file_open ( struct s_PXENV_FILE_OPEN *file_open ); - -/** @} */ /* pxenv_file_open */ - -/** @defgroup pxenv_file_close PXENV_FILE_CLOSE - * - * FILE CLOSE - * - * @{ - */ - -/** PXE API function code for pxenv_file_close() */ -#define PXENV_FILE_CLOSE 0x00e1 - -/** Parameter block for pxenv_file_close() */ -struct s_PXENV_FILE_CLOSE { - PXENV_STATUS_t Status; /**< PXE status code */ - UINT16_t FileHandle; /**< File handle */ -} PACKED; - -typedef struct s_PXENV_FILE_CLOSE PXENV_FILE_CLOSE_t; - -extern PXENV_EXIT_t pxenv_file_close ( struct s_PXENV_FILE_CLOSE - *file_close ); - -/** @} */ /* pxenv_file_close */ - -/** @defgroup pxenv_file_select PXENV_FILE_SELECT - * - * FILE SELECT - * - * @{ - */ - -/** PXE API function code for pxenv_file_select() */ -#define PXENV_FILE_SELECT 0x00e2 - -/** File is ready for reading */ -#define RDY_READ 0x0001 - -/** Parameter block for pxenv_file_select() */ -struct s_PXENV_FILE_SELECT { - PXENV_STATUS_t Status; /**< PXE status code */ - UINT16_t FileHandle; /**< File handle */ - UINT16_t Ready; /**< Indication of readiness */ -} PACKED; - -typedef struct s_PXENV_FILE_SELECT PXENV_FILE_SELECT_t; - -extern PXENV_EXIT_t pxenv_file_select ( struct s_PXENV_FILE_SELECT - *file_select ); - -/** @} */ /* pxenv_file_select */ - -/** @defgroup pxenv_file_read PXENV_FILE_READ - * - * FILE READ - * - * @{ - */ - -/** PXE API function code for pxenv_file_read() */ -#define PXENV_FILE_READ 0x00e3 - -/** Parameter block for pxenv_file_read() */ -struct s_PXENV_FILE_READ { - PXENV_STATUS_t Status; /**< PXE status code */ - UINT16_t FileHandle; /**< File handle */ - UINT16_t BufferSize; /**< Data buffer size */ - SEGOFF16_t Buffer; /**< Data buffer */ -} PACKED; - -typedef struct s_PXENV_FILE_READ PXENV_FILE_READ_t; - -extern PXENV_EXIT_t pxenv_file_read ( struct s_PXENV_FILE_READ *file_read ); - -/** @} */ /* pxenv_file_read */ - -/** @defgroup pxenv_get_file_size PXENV_GET_FILE_SIZE - * - * GET FILE SIZE - * - * @{ - */ - -/** PXE API function code for pxenv_get_file_size() */ -#define PXENV_GET_FILE_SIZE 0x00e4 - -/** Parameter block for pxenv_get_file_size() */ -struct s_PXENV_GET_FILE_SIZE { - PXENV_STATUS_t Status; /**< PXE status code */ - UINT16_t FileHandle; /**< File handle */ - UINT32_t FileSize; /**< File size */ -} PACKED; - -typedef struct s_PXENV_GET_FILE_SIZE PXENV_GET_FILE_SIZE_t; - -extern PXENV_EXIT_t pxenv_get_file_size ( struct s_PXENV_GET_FILE_SIZE - *get_file_size ); - -/** @} */ /* pxenv_get_file_size */ - -/** @defgroup pxenv_file_exec PXENV_FILE_EXEC - * - * FILE EXEC - * - * @{ - */ - -/** PXE API function code for pxenv_file_exec() */ -#define PXENV_FILE_EXEC 0x00e5 - -/** Parameter block for pxenv_file_exec() */ -struct s_PXENV_FILE_EXEC { - PXENV_STATUS_t Status; /**< PXE status code */ - SEGOFF16_t Command; /**< Command to execute */ -} PACKED; - -typedef struct s_PXENV_FILE_EXEC PXENV_FILE_EXEC_t; - -extern PXENV_EXIT_t pxenv_file_exec ( struct s_PXENV_FILE_EXEC *file_exec ); - -/** @} */ /* pxenv_file_exec */ - -/** @defgroup pxenv_file_api_check PXENV_FILE_API_CHECK - * - * FILE API CHECK - * - * @{ - */ - -/** PXE API function code for pxenv_file_api_check() */ -#define PXENV_FILE_API_CHECK 0x00e6 - -/** Parameter block for pxenv_file_api_check() */ -struct s_PXENV_FILE_API_CHECK { - PXENV_STATUS_t Status; /**< PXE status code */ - UINT16_t Size; /**< Size of structure */ - UINT32_t Magic; /**< Magic number */ - UINT32_t Provider; /**< Implementation identifier */ - UINT32_t APIMask; /**< Supported API functions */ - UINT32_t Flags; /**< Reserved for the future */ -} PACKED; - -typedef struct s_PXENV_FILE_API_CHECK PXENV_FILE_API_CHECK_t; - -extern PXENV_EXIT_t pxenv_file_api_check ( struct s_PXENV_FILE_API_CHECK *file_api_check ); - -/** @} */ /* pxenv_file_api_check */ - -/** @} */ /* pxe_file_api */ - -/** @defgroup pxe_loader_api PXE Loader API - * - * The UNDI ROM loader API - * - * @{ - */ - -/** Parameter block for undi_loader() */ -struct s_UNDI_LOADER { - /** PXE status code */ - PXENV_STATUS_t Status; - /** %ax register as for PXENV_START_UNDI */ - UINT16_t AX; - /** %bx register as for PXENV_START_UNDI */ - UINT16_t BX; - /** %dx register as for PXENV_START_UNDI */ - UINT16_t DX; - /** %di register as for PXENV_START_UNDI */ - OFF16_t DI; - /** %es register as for PXENV_START_UNDI */ - SEGSEL_t ES; - /** UNDI data segment - * - * @note The PXE specification defines the type of this field - * as #UINT16_t. For x86, #SEGSEL_t and #UINT16_t are - * equivalent anyway; for other architectures #SEGSEL_t makes - * more sense. - */ - SEGSEL_t UNDI_DS; - /** UNDI code segment - * - * @note The PXE specification defines the type of this field - * as #UINT16_t. For x86, #SEGSEL_t and #UINT16_t are - * equivalent anyway; for other architectures #SEGSEL_t makes - * more sense. - */ - SEGSEL_t UNDI_CS; - /** Address of the !PXE structure (a struct s_PXE) */ - SEGOFF16_t PXEptr; - /** Address of the PXENV+ structure (a struct s_PXENV) */ - SEGOFF16_t PXENVptr; -} PACKED; - -typedef struct s_UNDI_LOADER UNDI_LOADER_t; - -extern PXENV_EXIT_t undi_loader ( struct s_UNDI_LOADER *undi_loader ); - -/** @} */ /* pxe_loader_api */ - -/** @} */ /* pxe */ - -/** @page pxe_notes Etherboot PXE implementation notes - -@section pxe_routing IP routing - -Several PXE API calls (e.g. pxenv_tftp_open() and pxenv_udp_write()) -allow for the caller to specify a "relay agent IP address", often in a -field called "gateway" or similar. The PXE specification states that -"The IP layer should provide space for a minimum of four routing -entries obtained from the default router and static route DHCP option -tags in the DHCPACK message, plus any non-zero giaddr field from the -DHCPOFFER message(s) accepted by the client". - -The DHCP static route option ("option static-routes" in dhcpd.conf) -works only for classed IP routing (i.e. it provides no way to specify -a subnet mask). Since virtually everything now uses classless IP -routing, the DHCP static route option is almost totally useless, and -is (according to the dhcp-options man page) not implemented by any of -the popular DHCP clients. - -This leaves the caller-specified "relay agent IP address", the giaddr -field from the DHCPOFFER message(s) and the default gateway(s) -provided via the routers option ("option routers" in dhcpd.conf) in -the DHCPACK message. Each of these is a default gateway address. -It's a fair bet that the routers option should take priority over the -giaddr field, since the routers option has to be explicitly specified -by the DHCP server operator. Similarly, it's fair to assume that the -caller-specified "relay agent IP address", if present, should take -priority over any other routing table entries. - -@bug Etherboot currently ignores all potential sources of routing -information other than the first router provided to it by a DHCP -routers option. - -@section pxe_x86_modes x86 processor mode restrictions - -On the x86 platform, different PXE API calls have different -restrictions on the processor modes (real or protected) that can be -used. See the individual API call descriptions for the restrictions -that apply to any particular call. - -@subsection pxe_x86_pmode16 Real mode, or protected-mode with 16-bit stack - -The PXE specification states that the API function can be called in -protected mode only if the s_PXE::StatusCallout field is set to a -non-zero value, and that the API function cannot be called with a -32-bit stack segment. - -Etherboot does not enforce either of these restrictions; they seem (as -with so much of the PXE specification) to be artifacts of the Intel -implementation. - -*/ - -#endif /* PXE_API_H */ diff --git a/src/include/pxe_types.h b/src/include/pxe_types.h deleted file mode 100644 index dd9092ef..00000000 --- a/src/include/pxe_types.h +++ /dev/null @@ -1,125 +0,0 @@ -#ifndef PXE_TYPES_H -#define PXE_TYPES_H - -/** @file - * - * PXE data types - * - */ - -#include -#include /* PXE status codes */ - -/** @addtogroup pxe Preboot eXecution Environment (PXE) API - * @{ - */ - -/** @defgroup pxe_types PXE data types - * - * Basic PXE data types such as #UINT16_t, #ADDR32_t, #SEGSEL_t etc. - * - * These definitions are based on Table 1-1 ("Data Type Definitions") - * in the Intel PXE specification version 2.1. They have been - * generalised to non-x86 architectures where possible. - * - * @{ - */ - -/** An 8-bit unsigned integer */ -typedef uint8_t UINT8_t; - -/** A 16-bit unsigned integer */ -typedef uint16_t UINT16_t; - -/** A 32-bit unsigned integer */ -typedef uint32_t UINT32_t; - -/** A PXE exit code. - * - * Permitted values are #PXENV_EXIT_SUCCESS and #PXENV_EXIT_FAILURE. - * - */ -typedef UINT16_t PXENV_EXIT_t; -#define PXENV_EXIT_SUCCESS 0x0000 /**< No error occurred */ -#define PXENV_EXIT_FAILURE 0x0001 /**< An error occurred */ - -/** A PXE status code. - * - * Status codes are defined in errno.h. - * - */ -typedef UINT16_t PXENV_STATUS_t; - -/** An IPv4 address. - * - * @note This data type is in network (big-endian) byte order. - * - */ -typedef UINT32_t IP4_t; - -/** A UDP port. - * - * @note This data type is in network (big-endian) byte order. - * - */ -typedef UINT16_t UDP_PORT_t; - -/** Maximum length of a MAC address */ -#define MAC_ADDR_LEN 16 - -/** A MAC address */ -typedef UINT8_t MAC_ADDR_t[MAC_ADDR_LEN]; - -#ifndef HAVE_ARCH_ADDR32 -/** A physical address. - * - * For x86, this is a 32-bit physical address, and is therefore - * limited to the low 4GB. - * - */ -typedef UINT32_t ADDR32_t; -#endif - -#ifndef HAVE_ARCH_SEGSEL -/** A segment selector. - * - * For x86, this is a real mode segment (0x0000-0xffff), or a - * protected-mode segment selector, such as could be loaded into a - * segment register. - * - */ -typedef UINT16_t SEGSEL_t; -#endif - -#ifndef HAVE_ARCH_OFF16 -/** An offset within a segment identified by #SEGSEL - * - * For x86, this is a 16-bit offset. - * - */ -typedef UINT16_t OFF16_t; -#endif - -/** A segment:offset address - * - * For x86, this is a 16-bit real-mode or protected-mode - * segment:offset address. - * - */ -typedef struct s_SEGOFF16 { - OFF16_t offset; /**< Offset within the segment */ - SEGSEL_t segment; /**< Segment selector */ -} PACKED SEGOFF16_t; - -/** A segment descriptor */ -typedef struct s_SEGDESC { - SEGSEL_t segment_address; /**< Segment selector */ - ADDR32_t Physical_address; /**< Segment base address */ - OFF16_t Seg_size; /**< Size of the segment */ -} PACKED SEGDESC_t; - -/** @} */ /* pxe_types */ - -/** @} */ /* pxe */ - -#endif /* PXE_TYPES_H */ diff --git a/src/interface/pxe/pxe_errors.c b/src/interface/pxe/pxe_errors.c deleted file mode 100644 index f884ef8a..00000000 --- a/src/interface/pxe/pxe_errors.c +++ /dev/null @@ -1,103 +0,0 @@ -#include -#include - -/* - * This table was generated from the relevant section of errno.h using - * - * perl -ne 'if ( /(PXENV_STATUS_(\S+))/ ) { - * $code = $1; $msg = $2; - * $msg =~ s/_/ /g; $msg = ucfirst lc $msg; - * $msg =~ s/(tftp|udp|arp|undi|bis|binl|pxenv|pxe|dhcp)/uc $1/ieg; - * print "\t{ $code, \"$msg\" },\n"; - * }' - * - * followed by a little manual tweaking. - * - */ -struct errortab pxe_errortab[] __errortab = { - { PXENV_STATUS_SUCCESS, "Success" }, - { PXENV_STATUS_FAILURE, "Failure" }, - { PXENV_STATUS_BAD_FUNC, "Bad function" }, - { PXENV_STATUS_UNSUPPORTED, "Unsupported function" }, - { PXENV_STATUS_KEEP_UNDI, "Keep UNDI" }, - { PXENV_STATUS_KEEP_ALL, "Keep all" }, - { PXENV_STATUS_OUT_OF_RESOURCES, "Out of resources" }, - { PXENV_STATUS_ARP_TIMEOUT, "ARP timeout" }, - { PXENV_STATUS_UDP_CLOSED, "UDP closed" }, - { PXENV_STATUS_UDP_OPEN, "UDP open" }, - { PXENV_STATUS_TFTP_CLOSED, "TFTP closed" }, - { PXENV_STATUS_TFTP_OPEN, "TFTP open" }, - { PXENV_STATUS_MCOPY_PROBLEM, "Memory copy problem" }, - { PXENV_STATUS_BIS_INTEGRITY_FAILURE, "BIS integrity failure" }, - { PXENV_STATUS_BIS_VALIDATE_FAILURE, "BIS validation failure" }, - { PXENV_STATUS_BIS_INIT_FAILURE, "BIS init failure" }, - { PXENV_STATUS_BIS_SHUTDOWN_FAILURE, "BIS shutdown failure" }, - { PXENV_STATUS_BIS_GBOA_FAILURE, "BIS GBOA failure" }, - { PXENV_STATUS_BIS_FREE_FAILURE, "BIS free failure" }, - { PXENV_STATUS_BIS_GSI_FAILURE, "BIS GSI failure" }, - { PXENV_STATUS_BIS_BAD_CKSUM, "BIS bad checksum" }, - { PXENV_STATUS_TFTP_CANNOT_ARP_ADDRESS, "TFTP cannot ARP address" }, - { PXENV_STATUS_TFTP_OPEN_TIMEOUT, "TFTP open timeout" }, - { PXENV_STATUS_TFTP_UNKNOWN_OPCODE, "TFTP unknown opcode" }, - { PXENV_STATUS_TFTP_READ_TIMEOUT, "TFTP read timeout" }, - { PXENV_STATUS_TFTP_ERROR_OPCODE, "TFTP error opcode" }, - { PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION, - "TFTP cannot open connection" }, - { PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION, - "TFTP cannot read from connection" }, - { PXENV_STATUS_TFTP_TOO_MANY_PACKAGES, "TFTP too many packages" }, - { PXENV_STATUS_TFTP_FILE_NOT_FOUND, "TFTP file not found" }, - { PXENV_STATUS_TFTP_ACCESS_VIOLATION, "TFTP access violation" }, - { PXENV_STATUS_TFTP_NO_MCAST_ADDRESS, "TFTP no mcast address" }, - { PXENV_STATUS_TFTP_NO_FILESIZE, "TFTP no filesize" }, - { PXENV_STATUS_TFTP_INVALID_PACKET_SIZE, "TFTP invalid packet size" }, - { PXENV_STATUS_DHCP_TIMEOUT, "DHCP timeout" }, - { PXENV_STATUS_DHCP_NO_IP_ADDRESS, "DHCP no ip address" }, - { PXENV_STATUS_DHCP_NO_BOOTFILE_NAME, "DHCP no bootfile name" }, - { PXENV_STATUS_DHCP_BAD_IP_ADDRESS, "DHCP bad ip address" }, - { PXENV_STATUS_UNDI_INVALID_FUNCTION, "UNDI invalid function" }, - { PXENV_STATUS_UNDI_MEDIATEST_FAILED, "UNDI mediatest failed" }, - { PXENV_STATUS_UNDI_CANNOT_INIT_NIC_FOR_MCAST, - "UNDI cannot initialise NIC for multicast" }, - { PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC, - "UNDI cannot initialise NIC" }, - { PXENV_STATUS_UNDI_CANNOT_INITIALIZE_PHY, - "UNDI cannot initialise PHY" }, - { PXENV_STATUS_UNDI_CANNOT_READ_CONFIG_DATA, - "UNDI cannot read config data" }, - { PXENV_STATUS_UNDI_CANNOT_READ_INIT_DATA, - "UNDI cannot read init data" }, - { PXENV_STATUS_UNDI_BAD_MAC_ADDRESS, "UNDI bad MAC address" }, - { PXENV_STATUS_UNDI_BAD_EEPROM_CHECKSUM, "UNDI bad EEPROM checksum" }, - { PXENV_STATUS_UNDI_ERROR_SETTING_ISR, "UNDI error setting ISR" }, - { PXENV_STATUS_UNDI_INVALID_STATE, "UNDI invalid state" }, - { PXENV_STATUS_UNDI_TRANSMIT_ERROR, "UNDI transmit error" }, - { PXENV_STATUS_UNDI_INVALID_PARAMETER, "UNDI invalid parameter" }, - { PXENV_STATUS_BSTRAP_PROMPT_MENU, "Bootstrap prompt menu" }, - { PXENV_STATUS_BSTRAP_MCAST_ADDR, "Bootstrap mcast addr" }, - { PXENV_STATUS_BSTRAP_MISSING_LIST, "Bootstrap missing list" }, - { PXENV_STATUS_BSTRAP_NO_RESPONSE, "Bootstrap no response" }, - { PXENV_STATUS_BSTRAP_FILE_TOO_BIG, "Bootstrap file too big" }, - { PXENV_STATUS_BINL_CANCELED_BY_KEYSTROKE, - "BINL canceled by keystroke" }, - { PXENV_STATUS_BINL_NO_PXE_SERVER, "BINL no PXE server" }, - { PXENV_STATUS_NOT_AVAILABLE_IN_PMODE, - "Not available in protected mode" }, - { PXENV_STATUS_NOT_AVAILABLE_IN_RMODE, "Not available in real mode" }, - { PXENV_STATUS_BUSD_DEVICE_NOT_SUPPORTED, - "BUSD device not supported" }, - { PXENV_STATUS_LOADER_NO_FREE_BASE_MEMORY, - "Loader no free base memory" }, - { PXENV_STATUS_LOADER_NO_BC_ROMID, "Loader no Base Code ROM ID" }, - { PXENV_STATUS_LOADER_BAD_BC_ROMID, "Loader bad Base Code ROM ID" }, - { PXENV_STATUS_LOADER_BAD_BC_RUNTIME_IMAGE, - "Loader bad Base Code runtime image" }, - { PXENV_STATUS_LOADER_NO_UNDI_ROMID, "Loader no UNDI ROM ID" }, - { PXENV_STATUS_LOADER_BAD_UNDI_ROMID, "Loader bad UNDI ROM ID" }, - { PXENV_STATUS_LOADER_BAD_UNDI_DRIVER_IMAGE, - "Loader bad UNDI driver image" }, - { PXENV_STATUS_LOADER_NO_PXE_STRUCT, "Loader no !PXE struct" }, - { PXENV_STATUS_LOADER_NO_PXENV_STRUCT, "Loader no PXENV+ struct" }, - { PXENV_STATUS_LOADER_UNDI_START, "Loader UNDI start" }, - { PXENV_STATUS_LOADER_BC_START, "Loader Base Code start" }, -}; diff --git a/src/interface/pxe/pxe_file.c b/src/interface/pxe/pxe_file.c deleted file mode 100644 index 41674588..00000000 --- a/src/interface/pxe/pxe_file.c +++ /dev/null @@ -1,264 +0,0 @@ -/** @file - * - * PXE FILE API - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Copyright (C) 2007 Michael Brown . - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -FEATURE ( FEATURE_MISC, "PXEXT", DHCP_EB_FEATURE_PXE_EXT, 2 ); - -/** - * FILE OPEN - * - * @v file_open Pointer to a struct s_PXENV_FILE_OPEN - * @v s_PXENV_FILE_OPEN::FileName URL of file to open - * @ret #PXENV_EXIT_SUCCESS File was opened - * @ret #PXENV_EXIT_FAILURE File was not opened - * @ret s_PXENV_FILE_OPEN::Status PXE status code - * @ret s_PXENV_FILE_OPEN::FileHandle Handle of opened file - * - */ -PXENV_EXIT_t pxenv_file_open ( struct s_PXENV_FILE_OPEN *file_open ) { - userptr_t filename; - size_t filename_len; - int fd; - - DBG ( "PXENV_FILE_OPEN" ); - - /* Copy name from external program, and open it */ - filename = real_to_user ( file_open->FileName.segment, - file_open->FileName.offset ); - filename_len = strlen_user ( filename, 0 ); - { - char uri_string[ filename_len + 1 ]; - - copy_from_user ( uri_string, filename, 0, - sizeof ( uri_string ) ); - DBG ( " %s", uri_string ); - fd = open ( uri_string ); - } - - if ( fd < 0 ) { - file_open->Status = PXENV_STATUS ( fd ); - return PXENV_EXIT_FAILURE; - } - - DBG ( " as file %d", fd ); - - file_open->FileHandle = fd; - file_open->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} - -/** - * FILE CLOSE - * - * @v file_close Pointer to a struct s_PXENV_FILE_CLOSE - * @v s_PXENV_FILE_CLOSE::FileHandle File handle - * @ret #PXENV_EXIT_SUCCESS File was closed - * @ret #PXENV_EXIT_FAILURE File was not closed - * @ret s_PXENV_FILE_CLOSE::Status PXE status code - * - */ -PXENV_EXIT_t pxenv_file_close ( struct s_PXENV_FILE_CLOSE *file_close ) { - - DBG ( "PXENV_FILE_CLOSE %d", file_close->FileHandle ); - - close ( file_close->FileHandle ); - file_close->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} - -/** - * FILE SELECT - * - * @v file_select Pointer to a struct s_PXENV_FILE_SELECT - * @v s_PXENV_FILE_SELECT::FileHandle File handle - * @ret #PXENV_EXIT_SUCCESS File has been checked for readiness - * @ret #PXENV_EXIT_FAILURE File has not been checked for readiness - * @ret s_PXENV_FILE_SELECT::Status PXE status code - * @ret s_PXENV_FILE_SELECT::Ready Indication of readiness - * - */ -PXENV_EXIT_t pxenv_file_select ( struct s_PXENV_FILE_SELECT *file_select ) { - fd_set fdset; - int ready; - - DBG ( "PXENV_FILE_SELECT %d", file_select->FileHandle ); - - FD_ZERO ( &fdset ); - FD_SET ( file_select->FileHandle, &fdset ); - if ( ( ready = select ( &fdset, 0 ) ) < 0 ) { - file_select->Status = PXENV_STATUS ( ready ); - return PXENV_EXIT_FAILURE; - } - - file_select->Ready = ( ready ? RDY_READ : 0 ); - file_select->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} - -/** - * FILE READ - * - * @v file_read Pointer to a struct s_PXENV_FILE_READ - * @v s_PXENV_FILE_READ::FileHandle File handle - * @v s_PXENV_FILE_READ::BufferSize Size of data buffer - * @v s_PXENV_FILE_READ::Buffer Data buffer - * @ret #PXENV_EXIT_SUCCESS Data has been read from file - * @ret #PXENV_EXIT_FAILURE Data has not been read from file - * @ret s_PXENV_FILE_READ::Status PXE status code - * @ret s_PXENV_FILE_READ::Ready Indication of readiness - * @ret s_PXENV_FILE_READ::BufferSize Length of data read - * - */ -PXENV_EXIT_t pxenv_file_read ( struct s_PXENV_FILE_READ *file_read ) { - userptr_t buffer; - ssize_t len; - - DBG ( "PXENV_FILE_READ %d to %04x:%04x+%04x", file_read->FileHandle, - file_read->Buffer.segment, file_read->Buffer.offset, - file_read->BufferSize ); - - buffer = real_to_user ( file_read->Buffer.segment, - file_read->Buffer.offset ); - if ( ( len = read_user ( file_read->FileHandle, buffer, 0, - file_read->BufferSize ) ) < 0 ) { - file_read->Status = PXENV_STATUS ( len ); - return PXENV_EXIT_FAILURE; - } - - DBG ( " read %04zx", ( ( size_t ) len ) ); - - file_read->BufferSize = len; - file_read->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} - -/** - * GET FILE SIZE - * - * @v get_file_size Pointer to a struct s_PXENV_GET_FILE_SIZE - * @v s_PXENV_GET_FILE_SIZE::FileHandle File handle - * @ret #PXENV_EXIT_SUCCESS File size has been determined - * @ret #PXENV_EXIT_FAILURE File size has not been determined - * @ret s_PXENV_GET_FILE_SIZE::Status PXE status code - * @ret s_PXENV_GET_FILE_SIZE::FileSize Size of file - */ -PXENV_EXIT_t pxenv_get_file_size ( struct s_PXENV_GET_FILE_SIZE - *get_file_size ) { - ssize_t filesize; - - DBG ( "PXENV_GET_FILE_SIZE %d", get_file_size->FileHandle ); - - filesize = fsize ( get_file_size->FileHandle ); - if ( filesize < 0 ) { - get_file_size->Status = PXENV_STATUS ( filesize ); - return PXENV_EXIT_FAILURE; - } - - DBG ( " is %zd", ( ( size_t ) filesize ) ); - - get_file_size->FileSize = filesize; - get_file_size->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} - -/** - * FILE EXEC - * - * @v file_exec Pointer to a struct s_PXENV_FILE_EXEC - * @v s_PXENV_FILE_EXEC::Command Command to execute - * @ret #PXENV_EXIT_SUCCESS Command was executed successfully - * @ret #PXENV_EXIT_FAILURE Command was not executed successfully - * @ret s_PXENV_FILE_EXEC::Status PXE status code - * - */ -PXENV_EXIT_t pxenv_file_exec ( struct s_PXENV_FILE_EXEC *file_exec ) { - userptr_t command; - size_t command_len; - int rc; - - DBG ( "PXENV_FILE_EXEC" ); - - /* Copy name from external program, and exec it */ - command = real_to_user ( file_exec->Command.segment, - file_exec->Command.offset ); - command_len = strlen_user ( command, 0 ); - { - char command_string[ command_len + 1 ]; - - copy_from_user ( command_string, command, 0, - sizeof ( command_string ) ); - DBG ( " %s", command_string ); - - if ( ( rc = system ( command_string ) ) != 0 ) { - file_exec->Status = PXENV_STATUS ( rc ); - return PXENV_EXIT_FAILURE; - } - } - - file_exec->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} - -/** - * FILE API CHECK - * - * @v file_exec Pointer to a struct s_PXENV_FILE_API_CHECK - * @v s_PXENV_FILE_API_CHECK::Magic Inbound magic number (0x91d447b2) - * @ret #PXENV_EXIT_SUCCESS Command was executed successfully - * @ret #PXENV_EXIT_FAILURE Command was not executed successfully - * @ret s_PXENV_FILE_API_CHECK::Status PXE status code - * @ret s_PXENV_FILE_API_CHECK::Magic Outbound magic number (0xe9c17b20) - * @ret s_PXENV_FILE_API_CHECK::Provider "gPXE" (0x45585067) - * @ret s_PXENV_FILE_API_CHECK::APIMask API function bitmask - * @ret s_PXENV_FILE_API_CHECK::Flags Reserved - * - */ -PXENV_EXIT_t pxenv_file_api_check ( struct s_PXENV_FILE_API_CHECK *file_api_check ) { - DBG ( "PXENV_FILE_API_CHECK" ); - - if ( file_api_check->Magic != 0x91d447b2 ) { - file_api_check->Status = PXENV_STATUS_BAD_FUNC; - return PXENV_EXIT_FAILURE; - } else if ( file_api_check->Size < - sizeof(struct s_PXENV_FILE_API_CHECK) ) { - file_api_check->Status = PXENV_STATUS_OUT_OF_RESOURCES; - return PXENV_EXIT_FAILURE; - } else { - file_api_check->Status = PXENV_STATUS_SUCCESS; - file_api_check->Size = sizeof(struct s_PXENV_FILE_API_CHECK); - file_api_check->Magic = 0xe9c17b20; - file_api_check->Provider = 0x45585067; /* "gPXE" */ - file_api_check->APIMask = 0x0000007f; /* Functions e0-e6 */ - file_api_check->Flags = 0; /* None defined */ - return PXENV_EXIT_SUCCESS; - } -} diff --git a/src/interface/pxe/pxe_loader.c b/src/interface/pxe/pxe_loader.c deleted file mode 100644 index d228a36d..00000000 --- a/src/interface/pxe/pxe_loader.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2007 Michael Brown . - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include "pxe.h" -#include "pxe_call.h" - -/** @file - * - * PXE UNDI loader - * - */ - -/* PXENV_UNDI_LOADER - * - */ -PXENV_EXIT_t undi_loader ( struct s_UNDI_LOADER *undi_loader ) { - - /* Perform one-time initialisation (e.g. heap) */ - initialise(); - - DBG ( "[PXENV_UNDI_LOADER to CS %04x DS %04x]", - undi_loader->UNDI_CS, undi_loader->UNDI_DS ); - - /* Set up PXE data structures */ - pxe_init_structures(); - - /* Fill in UNDI loader structure */ - undi_loader->PXEptr.segment = rm_cs; - undi_loader->PXEptr.offset = __from_text16 ( &ppxe ); - undi_loader->PXENVptr.segment = rm_cs; - undi_loader->PXENVptr.offset = __from_text16 ( &pxenv ); - - undi_loader->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} diff --git a/src/interface/pxe/pxe_preboot.c b/src/interface/pxe/pxe_preboot.c deleted file mode 100644 index 8220d1f2..00000000 --- a/src/interface/pxe/pxe_preboot.c +++ /dev/null @@ -1,352 +0,0 @@ -/** @file - * - * PXE Preboot API - * - */ - -/* PXE API interface for Etherboot. - * - * Copyright (C) 2004 Michael Brown . - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "pxe.h" -#include "pxe_call.h" - -/* Avoid dragging in isapnp.o unnecessarily */ -uint16_t isapnp_read_port; - -/** Zero-based versions of PXENV_GET_CACHED_INFO::PacketType */ -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 -}; - -/** A cached DHCP packet */ -union pxe_cached_info { - struct dhcphdr dhcphdr; - /* This buffer must be *exactly* the size of a BOOTPLAYER_t - * structure, otherwise WinPE will die horribly. It takes the - * size of *our* buffer and feeds it in to us as the size of - * one of *its* buffers. If our buffer is larger than it - * expects, we therefore end up overwriting part of its data - * segment, since it tells us to do so. (D'oh!) - * - * Note that a BOOTPLAYER_t is not necessarily large enough to - * hold a DHCP packet; this is a flaw in the PXE spec. - */ - BOOTPLAYER_t packet; -} __attribute__ (( packed )); - -/** A PXE DHCP packet creator */ -struct pxe_dhcp_packet_creator { - /** Create DHCP packet - * - * @v netdev Network device - * @v data Buffer for DHCP packet - * @v max_len Size of DHCP packet buffer - * @ret rc Return status code - */ - int ( * create ) ( struct net_device *netdev, void *data, - size_t max_len ); -}; - -/** PXE DHCP packet creators */ -static struct pxe_dhcp_packet_creator pxe_dhcp_packet_creators[] = { - [CACHED_INFO_DHCPDISCOVER] = { create_fakedhcpdiscover }, - [CACHED_INFO_DHCPACK] = { create_fakedhcpack }, - [CACHED_INFO_BINL] = { create_fakeproxydhcpack }, -}; - -/* The case in which the caller doesn't supply a buffer is really - * awkward to support given that we have multiple sources of options, - * and that we don't actually store the DHCP packets. (We may not - * even have performed DHCP; we may have obtained all configuration - * from non-volatile stored options or from the command line.) - * - * Some NBPs rely on the buffers we provide being persistent, so we - * can't just use the temporary packet buffer. 4.5kB of base memory - * always wasted just because some clients are too lazy to provide - * their own buffers... - */ -static union pxe_cached_info __bss16_array ( cached_info, [NUM_CACHED_INFOS] ); -#define cached_info __use_data16 ( cached_info ) - -/** - * Set PXE cached TFTP filename - * - * @v filename TFTP filename - * - * This is a bug-for-bug compatibility hack needed in order to work - * with Microsoft Remote Installation Services (RIS). The filename - * used in a call to PXENV_RESTART_TFTP or PXENV_TFTP_READ_FILE must - * be returned as the DHCP filename in subsequent calls to - * PXENV_GET_CACHED_INFO. - */ -void pxe_set_cached_filename ( const unsigned char *filename ) { - memcpy ( cached_info[CACHED_INFO_DHCPACK].dhcphdr.file, filename, - sizeof ( cached_info[CACHED_INFO_DHCPACK].dhcphdr.file ) ); - memcpy ( cached_info[CACHED_INFO_BINL].dhcphdr.file, filename, - sizeof ( cached_info[CACHED_INFO_BINL].dhcphdr.file ) ); -} - -/** - * UNLOAD BASE CODE STACK - * - * @v None - - * @ret ... - * - */ -PXENV_EXIT_t pxenv_unload_stack ( struct s_PXENV_UNLOAD_STACK *unload_stack ) { - DBG ( "PXENV_UNLOAD_STACK" ); - - unload_stack->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} - -/* PXENV_GET_CACHED_INFO - * - * Status: working - */ -PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO - *get_cached_info ) { - struct pxe_dhcp_packet_creator *creator; - union pxe_cached_info *info; - unsigned int idx; - size_t len; - userptr_t buffer; - int rc; - - DBG ( "PXENV_GET_CACHED_INFO %d", get_cached_info->PacketType ); - - DBG ( " to %04x:%04x+%x", 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 ) { - DBG ( " bad PacketType" ); - goto err; - } - info = &cached_info[idx]; - - /* Construct cached version of packet, if not already constructed. */ - if ( ! info->dhcphdr.op ) { - /* Construct DHCP packet */ - creator = &pxe_dhcp_packet_creators[idx]; - if ( ( rc = creator->create ( pxe_netdev, info, - sizeof ( *info ) ) ) != 0 ) { - DBG ( " failed to build packet" ); - goto err; - } - } - - 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 ); - DBG ( " returning %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 ) ) - DBG ( " 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; - } - - get_cached_info->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; - - err: - get_cached_info->Status = PXENV_STATUS_OUT_OF_RESOURCES; - return PXENV_EXIT_FAILURE; -} - -/* PXENV_RESTART_TFTP - * - * Status: working - */ -PXENV_EXIT_t pxenv_restart_tftp ( struct s_PXENV_TFTP_READ_FILE - *restart_tftp ) { - PXENV_EXIT_t tftp_exit; - - DBG ( "PXENV_RESTART_TFTP " ); - - /* Intel bug-for-bug hack */ - pxe_set_cached_filename ( restart_tftp->FileName ); - - /* 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; - - /* Fire up the new NBP */ - restart_tftp->Status = pxe_start_nbp(); - - /* Not sure what "SUCCESS" actually means, since we can only - * return if the new NBP failed to boot... - */ - return PXENV_EXIT_SUCCESS; -} - -/* PXENV_START_UNDI - * - * Status: working - */ -PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi ) { - unsigned int bus_type; - unsigned int location; - struct net_device *netdev; - - DBG ( "PXENV_START_UNDI %04x:%04x:%04x", - 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 ) { - DBG ( " no net device found" ); - start_undi->Status = PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC; - return PXENV_EXIT_FAILURE; - } - DBG ( " using netdev %s", netdev->name ); - - /* Save as PXE net device */ - pxe_set_netdev ( netdev ); - - /* Hook INT 1A */ - pxe_hook_int1a(); - - start_undi->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} - -/* PXENV_STOP_UNDI - * - * Status: working - */ -PXENV_EXIT_t pxenv_stop_undi ( struct s_PXENV_STOP_UNDI *stop_undi ) { - DBG ( "PXENV_STOP_UNDI" ); - - /* Unhook INT 1A */ - pxe_unhook_int1a(); - - /* Clear PXE net device */ - pxe_set_netdev ( NULL ); - - /* Prepare for unload */ - shutdown ( SHUTDOWN_BOOT ); - - stop_undi->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} - -/* PXENV_START_BASE - * - * Status: won't implement (requires major structural changes) - */ -PXENV_EXIT_t pxenv_start_base ( struct s_PXENV_START_BASE *start_base ) { - DBG ( "PXENV_START_BASE" ); - - start_base->Status = PXENV_STATUS_UNSUPPORTED; - return PXENV_EXIT_FAILURE; -} - -/* PXENV_STOP_BASE - * - * Status: working - */ -PXENV_EXIT_t pxenv_stop_base ( struct s_PXENV_STOP_BASE *stop_base ) { - DBG ( "PXENV_STOP_BASE" ); - - /* 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; -} diff --git a/src/interface/pxe/pxe_tftp.c b/src/interface/pxe/pxe_tftp.c deleted file mode 100644 index f5e76206..00000000 --- a/src/interface/pxe/pxe_tftp.c +++ /dev/null @@ -1,584 +0,0 @@ -/** @file - * - * PXE TFTP API - * - */ - -/* - * Copyright (C) 2004 Michael Brown . - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** A PXE TFTP connection */ -struct pxe_tftp_connection { - /** Data transfer interface */ - struct xfer_interface xfer; - /** Data buffer */ - userptr_t buffer; - /** Size of data buffer */ - size_t size; - /** Starting offset of data buffer */ - size_t start; - /** File position */ - size_t offset; - /** Maximum file position */ - size_t max_offset; - /** Block size */ - size_t blksize; - /** Block index */ - unsigned int blkidx; - /** Overall return status code */ - int rc; -}; - -/** The PXE TFTP connection */ -static struct pxe_tftp_connection pxe_tftp = { - .xfer = XFER_INIT ( &null_xfer_ops ), -}; - -/** - * Close PXE TFTP connection - * - * @v rc Final status code - */ -static void pxe_tftp_close ( int rc ) { - xfer_nullify ( &pxe_tftp.xfer ); - xfer_close ( &pxe_tftp.xfer, rc ); - pxe_tftp.rc = rc; -} - -/** - * Receive new data - * - * @v xfer Data transfer interface - * @v iobuf I/O buffer - * @v meta Transfer metadata - * @ret rc Return status code - */ -static int pxe_tftp_xfer_deliver_iob ( struct xfer_interface *xfer __unused, - struct io_buffer *iobuf, - struct xfer_metadata *meta ) { - size_t len = iob_len ( iobuf ); - int rc = 0; - - /* Calculate new buffer position */ - if ( meta->whence != SEEK_CUR ) - pxe_tftp.offset = 0; - pxe_tftp.offset += meta->offset; - - /* Copy data block to buffer */ - if ( len == 0 ) { - /* No data (pure seek); treat as success */ - } else if ( pxe_tftp.offset < pxe_tftp.start ) { - DBG ( " buffer underrun at %zx (min %zx)", - pxe_tftp.offset, pxe_tftp.start ); - rc = -ENOBUFS; - } else if ( ( pxe_tftp.offset + len ) > - ( pxe_tftp.start + pxe_tftp.size ) ) { - DBG ( " buffer overrun at %zx (max %zx)", - ( pxe_tftp.offset + len ), - ( pxe_tftp.start + pxe_tftp.size ) ); - rc = -ENOBUFS; - } else { - copy_to_user ( pxe_tftp.buffer, - ( pxe_tftp.offset - pxe_tftp.start ), - iobuf->data, len ); - } - - /* Calculate new buffer position */ - pxe_tftp.offset += len; - - /* Mildly ugly hack; assume that the first non-zero seek - * indicates the block size. - */ - if ( pxe_tftp.blksize == 0 ) - pxe_tftp.blksize = pxe_tftp.offset; - - /* Record maximum offset as the file size */ - if ( pxe_tftp.max_offset < pxe_tftp.offset ) - pxe_tftp.max_offset = pxe_tftp.offset; - - /* Terminate transfer on error */ - if ( rc != 0 ) - pxe_tftp_close ( rc ); - - free_iob ( iobuf ); - return rc; -} - -/** - * Handle close() event - * - * @v xfer Data transfer interface - * @v rc Reason for close - */ -static void pxe_tftp_xfer_close ( struct xfer_interface *xfer __unused, - int rc ) { - pxe_tftp_close ( rc ); -} - -static struct xfer_interface_operations pxe_tftp_xfer_ops = { - .close = pxe_tftp_xfer_close, - .vredirect = xfer_vopen, - .window = unlimited_xfer_window, - .alloc_iob = default_xfer_alloc_iob, - .deliver_iob = pxe_tftp_xfer_deliver_iob, - .deliver_raw = xfer_deliver_as_iob, -}; - -/** - * Maximum length of a PXE TFTP URI - * - * The PXE TFTP API provides 128 characters for the filename; the - * extra 128 bytes allow for the remainder of the URI. - */ -#define PXE_TFTP_URI_LEN 256 - -/** - * Open PXE TFTP connection - * - * @v ipaddress IP address - * @v port TFTP server port - * @v filename File name - * @v blksize Requested block size - * @ret rc Return status code - */ -static int pxe_tftp_open ( uint32_t ipaddress, unsigned int port, - const unsigned char *filename, size_t blksize ) { - char uri_string[PXE_TFTP_URI_LEN]; - struct in_addr address; - int rc; - - /* Intel bug-for-bug hack */ - pxe_set_cached_filename ( filename ); - - /* Reset PXE TFTP connection structure */ - memset ( &pxe_tftp, 0, sizeof ( pxe_tftp ) ); - xfer_init ( &pxe_tftp.xfer, &pxe_tftp_xfer_ops, NULL ); - pxe_tftp.rc = -EINPROGRESS; - - /* Construct URI string */ - address.s_addr = ipaddress; - if ( ! port ) - port = htons ( TFTP_PORT ); - if ( blksize < TFTP_DEFAULT_BLKSIZE ) - blksize = TFTP_DEFAULT_BLKSIZE; - snprintf ( uri_string, sizeof ( uri_string ), - "tftp://%s:%d%s%s?blksize=%zd", - inet_ntoa ( address ), ntohs ( port ), - ( ( filename[0] == '/' ) ? "" : "/" ), filename, blksize ); - DBG ( " %s", uri_string ); - - /* Open PXE TFTP connection */ - if ( ( rc = xfer_open_uri_string ( &pxe_tftp.xfer, - uri_string ) ) != 0 ) { - DBG ( " could not open (%s)\n", strerror ( rc ) ); - return rc; - } - - return 0; -} - -/** - * TFTP OPEN - * - * @v tftp_open Pointer to a struct s_PXENV_TFTP_OPEN - * @v s_PXENV_TFTP_OPEN::ServerIPAddress TFTP server IP address - * @v s_PXENV_TFTP_OPEN::GatewayIPAddress Relay agent IP address, or 0.0.0.0 - * @v s_PXENV_TFTP_OPEN::FileName Name of file to open - * @v s_PXENV_TFTP_OPEN::TFTPPort TFTP server UDP port - * @v s_PXENV_TFTP_OPEN::PacketSize TFTP blksize option to request - * @ret #PXENV_EXIT_SUCCESS File was opened - * @ret #PXENV_EXIT_FAILURE File was not opened - * @ret s_PXENV_TFTP_OPEN::Status PXE status code - * @ret s_PXENV_TFTP_OPEN::PacketSize Negotiated blksize - * @err #PXENV_STATUS_TFTP_INVALID_PACKET_SIZE Requested blksize too small - * - * Opens a TFTP connection for downloading a file a block at a time - * using pxenv_tftp_read(). - * - * If s_PXENV_TFTP_OPEN::GatewayIPAddress is 0.0.0.0, normal IP - * routing will take place. See the relevant - * @ref pxe_routing "implementation note" for more details. - * - * On x86, you must set the s_PXE::StatusCallout field to a nonzero - * value before calling this function in protected mode. You cannot - * call this function with a 32-bit stack segment. (See the relevant - * @ref pxe_x86_pmode16 "implementation note" for more details.) - * - * @note According to the PXE specification version 2.1, this call - * "opens a file for reading/writing", though how writing is to be - * achieved without the existence of an API call %pxenv_tftp_write() - * is not made clear. - * - * @note Despite the existence of the numerous statements within the - * PXE specification of the form "...if a TFTP/MTFTP or UDP connection - * is active...", you cannot use pxenv_tftp_open() and - * pxenv_tftp_read() to read a file via MTFTP; only via plain old - * TFTP. If you want to use MTFTP, use pxenv_tftp_read_file() - * instead. Astute readers will note that, since - * pxenv_tftp_read_file() is an atomic operation from the point of - * view of the PXE API, it is conceptually impossible to issue any - * other PXE API call "if an MTFTP connection is active". - */ -PXENV_EXIT_t pxenv_tftp_open ( struct s_PXENV_TFTP_OPEN *tftp_open ) { - int rc; - - DBG ( "PXENV_TFTP_OPEN" ); - - /* Guard against callers that fail to close before re-opening */ - pxe_tftp_close ( 0 ); - - /* Open connection */ - if ( ( rc = pxe_tftp_open ( tftp_open->ServerIPAddress, - tftp_open->TFTPPort, - tftp_open->FileName, - tftp_open->PacketSize ) ) != 0 ) { - tftp_open->Status = PXENV_STATUS ( rc ); - return PXENV_EXIT_FAILURE; - } - - /* Wait for OACK to arrive so that we have the block size */ - while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) && - ( pxe_tftp.blksize == 0 ) ) { - step(); - } - tftp_open->PacketSize = pxe_tftp.blksize; - - /* EINPROGRESS is normal; we don't wait for the whole transfer */ - if ( rc == -EINPROGRESS ) - rc = 0; - - tftp_open->Status = PXENV_STATUS ( rc ); - return ( rc ? PXENV_EXIT_FAILURE : PXENV_EXIT_SUCCESS ); -} - -/** - * TFTP CLOSE - * - * @v tftp_close Pointer to a struct s_PXENV_TFTP_CLOSE - * @ret #PXENV_EXIT_SUCCESS File was closed successfully - * @ret #PXENV_EXIT_FAILURE File was not closed - * @ret s_PXENV_TFTP_CLOSE::Status PXE status code - * @err None - - * - * Close a connection previously opened with pxenv_tftp_open(). You - * must have previously opened a connection with pxenv_tftp_open(). - * - * On x86, you must set the s_PXE::StatusCallout field to a nonzero - * value before calling this function in protected mode. You cannot - * call this function with a 32-bit stack segment. (See the relevant - * @ref pxe_x86_pmode16 "implementation note" for more details.) - */ -PXENV_EXIT_t pxenv_tftp_close ( struct s_PXENV_TFTP_CLOSE *tftp_close ) { - DBG ( "PXENV_TFTP_CLOSE" ); - - pxe_tftp_close ( 0 ); - tftp_close->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} - -/** - * TFTP READ - * - * @v tftp_read Pointer to a struct s_PXENV_TFTP_READ - * @v s_PXENV_TFTP_READ::Buffer Address of data buffer - * @ret #PXENV_EXIT_SUCCESS Data was read successfully - * @ret #PXENV_EXIT_FAILURE Data was not read - * @ret s_PXENV_TFTP_READ::Status PXE status code - * @ret s_PXENV_TFTP_READ::PacketNumber TFTP packet number - * @ret s_PXENV_TFTP_READ::BufferSize Length of data written into buffer - * - * Reads a single packet from a connection previously opened with - * pxenv_tftp_open() into the data buffer pointed to by - * s_PXENV_TFTP_READ::Buffer. You must have previously opened a - * connection with pxenv_tftp_open(). The data written into - * s_PXENV_TFTP_READ::Buffer is just the file data; the various - * network headers have already been removed. - * - * The buffer must be large enough to contain a packet of the size - * negotiated via the s_PXENV_TFTP_OPEN::PacketSize field in the - * pxenv_tftp_open() call. It is worth noting that the PXE - * specification does @b not require the caller to fill in - * s_PXENV_TFTP_READ::BufferSize before calling pxenv_tftp_read(), so - * the PXE stack is free to ignore whatever value the caller might - * place there and just assume that the buffer is large enough. That - * said, it may be worth the caller always filling in - * s_PXENV_TFTP_READ::BufferSize to guard against PXE stacks that - * mistake it for an input parameter. - * - * The length of the TFTP data packet will be returned via - * s_PXENV_TFTP_READ::BufferSize. If this length is less than the - * blksize negotiated via s_PXENV_TFTP_OPEN::PacketSize in the call to - * pxenv_tftp_open(), this indicates that the block is the last block - * in the file. Note that zero is a valid length for - * s_PXENV_TFTP_READ::BufferSize, and will occur when the length of - * the file is a multiple of the blksize. - * - * The PXE specification doesn't actually state that calls to - * pxenv_tftp_read() will return the data packets in strict sequential - * order, though most PXE stacks will probably do so. The sequence - * number of the packet will be returned in - * s_PXENV_TFTP_READ::PacketNumber. The first packet in the file has - * a sequence number of one, not zero. - * - * To guard against flawed PXE stacks, the caller should probably set - * s_PXENV_TFTP_READ::PacketNumber to one less than the expected - * returned value (i.e. set it to zero for the first call to - * pxenv_tftp_read() and then re-use the returned s_PXENV_TFTP_READ - * parameter block for subsequent calls without modifying - * s_PXENV_TFTP_READ::PacketNumber between calls). The caller should - * also guard against potential problems caused by flawed - * implementations returning the occasional duplicate packet, by - * checking that the value returned in s_PXENV_TFTP_READ::PacketNumber - * is as expected (i.e. one greater than that returned from the - * previous call to pxenv_tftp_read()). - * - * On x86, you must set the s_PXE::StatusCallout field to a nonzero - * value before calling this function in protected mode. You cannot - * call this function with a 32-bit stack segment. (See the relevant - * @ref pxe_x86_pmode16 "implementation note" for more details.) - */ -PXENV_EXIT_t pxenv_tftp_read ( struct s_PXENV_TFTP_READ *tftp_read ) { - int rc; - - DBG ( "PXENV_TFTP_READ to %04x:%04x", - tftp_read->Buffer.segment, tftp_read->Buffer.offset ); - - /* Read single block into buffer */ - pxe_tftp.buffer = real_to_user ( tftp_read->Buffer.segment, - tftp_read->Buffer.offset ); - pxe_tftp.size = pxe_tftp.blksize; - pxe_tftp.start = pxe_tftp.offset; - while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) && - ( pxe_tftp.offset == pxe_tftp.start ) ) - step(); - pxe_tftp.buffer = UNULL; - tftp_read->BufferSize = ( pxe_tftp.offset - pxe_tftp.start ); - tftp_read->PacketNumber = ++pxe_tftp.blkidx; - - /* EINPROGRESS is normal if we haven't reached EOF yet */ - if ( rc == -EINPROGRESS ) - rc = 0; - - tftp_read->Status = PXENV_STATUS ( rc ); - return ( rc ? PXENV_EXIT_FAILURE : PXENV_EXIT_SUCCESS ); -} - -/** - * TFTP/MTFTP read file - * - * @v tftp_read_file Pointer to a struct s_PXENV_TFTP_READ_FILE - * @v s_PXENV_TFTP_READ_FILE::FileName File name - * @v s_PXENV_TFTP_READ_FILE::BufferSize Size of the receive buffer - * @v s_PXENV_TFTP_READ_FILE::Buffer Address of the receive buffer - * @v s_PXENV_TFTP_READ_FILE::ServerIPAddress TFTP server IP address - * @v s_PXENV_TFTP_READ_FILE::GatewayIPAddress Relay agent IP address - * @v s_PXENV_TFTP_READ_FILE::McastIPAddress File's multicast IP address - * @v s_PXENV_TFTP_READ_FILE::TFTPClntPort Client multicast UDP port - * @v s_PXENV_TFTP_READ_FILE::TFTPSrvPort Server multicast UDP port - * @v s_PXENV_TFTP_READ_FILE::TFTPOpenTimeOut Time to wait for first packet - * @v s_PXENV_TFTP_READ_FILE::TFTPReopenDelay MTFTP inactivity timeout - * @ret #PXENV_EXIT_SUCCESS File downloaded successfully - * @ret #PXENV_EXIT_FAILURE File not downloaded - * @ret s_PXENV_TFTP_READ_FILE::Status PXE status code - * @ret s_PXENV_TFTP_READ_FILE::BufferSize Length of downloaded file - * - * Downloads an entire file via either TFTP or MTFTP into the buffer - * pointed to by s_PXENV_TFTP_READ_FILE::Buffer. - * - * The PXE specification does not make it clear how the caller - * requests that MTFTP be used rather than TFTP (or vice versa). One - * reasonable guess is that setting - * s_PXENV_TFTP_READ_FILE::McastIPAddress to 0.0.0.0 would cause TFTP - * to be used instead of MTFTP, though it is conceivable that some PXE - * stacks would interpret that as "use the DHCP-provided multicast IP - * address" instead. Some PXE stacks will not implement MTFTP at all, - * and will always use TFTP. - * - * It is not specified whether or not - * s_PXENV_TFTP_READ_FILE::TFTPSrvPort will be used as the TFTP server - * port for TFTP (rather than MTFTP) downloads. Callers should assume - * that the only way to access a TFTP server on a non-standard port is - * to use pxenv_tftp_open() and pxenv_tftp_read(). - * - * If s_PXENV_TFTP_READ_FILE::GatewayIPAddress is 0.0.0.0, normal IP - * routing will take place. See the relevant - * @ref pxe_routing "implementation note" for more details. - * - * It is interesting to note that s_PXENV_TFTP_READ_FILE::Buffer is an - * #ADDR32_t type, i.e. nominally a flat physical address. Some PXE - * NBPs (e.g. NTLDR) are known to call pxenv_tftp_read_file() in real - * mode with s_PXENV_TFTP_READ_FILE::Buffer set to an address above - * 1MB. This means that PXE stacks must be prepared to write to areas - * outside base memory. Exactly how this is to be achieved is not - * specified, though using INT 15,87 is as close to a standard method - * as any, and should probably be used. Switching to protected-mode - * in order to access high memory will fail if pxenv_tftp_read_file() - * is called in V86 mode; it is reasonably to expect that a V86 - * monitor would intercept the relatively well-defined INT 15,87 if it - * wants the PXE stack to be able to write to high memory. - * - * Things get even more interesting if pxenv_tftp_read_file() is - * called in protected mode, because there is then absolutely no way - * for the PXE stack to write to an absolute physical address. You - * can't even get around the problem by creating a special "access - * everything" segment in the s_PXE data structure, because the - * #SEGDESC_t descriptors are limited to 64kB in size. - * - * Previous versions of the PXE specification (e.g. WfM 1.1a) provide - * a separate API call, %pxenv_tftp_read_file_pmode(), specifically to - * work around this problem. The s_PXENV_TFTP_READ_FILE_PMODE - * parameter block splits s_PXENV_TFTP_READ_FILE::Buffer into - * s_PXENV_TFTP_READ_FILE_PMODE::BufferSelector and - * s_PXENV_TFTP_READ_FILE_PMODE::BufferOffset, i.e. it provides a - * protected-mode segment:offset address for the data buffer. This - * API call is no longer present in version 2.1 of the PXE - * specification. - * - * Etherboot makes the assumption that s_PXENV_TFTP_READ_FILE::Buffer - * is an offset relative to the caller's data segment, when - * pxenv_tftp_read_file() is called in protected mode. - * - * On x86, you must set the s_PXE::StatusCallout field to a nonzero - * value before calling this function in protected mode. You cannot - * call this function with a 32-bit stack segment. (See the relevant - * @ref pxe_x86_pmode16 "implementation note" for more details.) - * - * @note Microsoft's NTLDR assumes that the filename passed in via - * s_PXENV_TFTP_READ_FILE::FileName will be stored in the "file" field - * of the stored DHCPACK packet, whence it will be returned via any - * subsequent calls to pxenv_get_cached_info(). Though this is - * essentially a bug in the Intel PXE implementation (not, for once, - * in the specification!), it is a bug that Microsoft relies upon, and - * so we implement this bug-for-bug compatibility by overwriting the - * filename stored DHCPACK packet with the filename passed in - * s_PXENV_TFTP_READ_FILE::FileName. - * - */ -PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE - *tftp_read_file ) { - int rc; - - DBG ( "PXENV_TFTP_READ_FILE to %08lx+%lx", tftp_read_file->Buffer, - tftp_read_file->BufferSize ); - - /* Open TFTP file */ - if ( ( rc = pxe_tftp_open ( tftp_read_file->ServerIPAddress, 0, - tftp_read_file->FileName, 0 ) ) != 0 ) { - tftp_read_file->Status = PXENV_STATUS ( rc ); - return PXENV_EXIT_FAILURE; - } - - /* Read entire file */ - pxe_tftp.buffer = phys_to_user ( tftp_read_file->Buffer ); - pxe_tftp.size = tftp_read_file->BufferSize; - while ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) - step(); - pxe_tftp.buffer = UNULL; - tftp_read_file->BufferSize = pxe_tftp.max_offset; - - /* Close TFTP file */ - pxe_tftp_close ( rc ); - - tftp_read_file->Status = PXENV_STATUS ( rc ); - return ( rc ? PXENV_EXIT_FAILURE : PXENV_EXIT_SUCCESS ); -} - -/** - * TFTP GET FILE SIZE - * - * @v tftp_get_fsize Pointer to a struct s_PXENV_TFTP_GET_FSIZE - * @v s_PXENV_TFTP_GET_FSIZE::ServerIPAddress TFTP server IP address - * @v s_PXENV_TFTP_GET_FSIZE::GatewayIPAddress Relay agent IP address - * @v s_PXENV_TFTP_GET_FSIZE::FileName File name - * @ret #PXENV_EXIT_SUCCESS File size was determined successfully - * @ret #PXENV_EXIT_FAILURE File size was not determined - * @ret s_PXENV_TFTP_GET_FSIZE::Status PXE status code - * @ret s_PXENV_TFTP_GET_FSIZE::FileSize File size - * - * Determine the size of a file on a TFTP server. This uses the - * "tsize" TFTP option, and so will not work with a TFTP server that - * does not support TFTP options, or that does not support the "tsize" - * option. - * - * The PXE specification states that this API call will @b not open a - * TFTP connection for subsequent use with pxenv_tftp_read(). (This - * is somewhat daft, since the only way to obtain the file size via - * the "tsize" option involves issuing a TFTP open request, but that's - * life.) - * - * You cannot call pxenv_tftp_get_fsize() while a TFTP or UDP - * connection is open. - * - * If s_PXENV_TFTP_GET_FSIZE::GatewayIPAddress is 0.0.0.0, normal IP - * routing will take place. See the relevant - * @ref pxe_routing "implementation note" for more details. - * - * On x86, you must set the s_PXE::StatusCallout field to a nonzero - * value before calling this function in protected mode. You cannot - * call this function with a 32-bit stack segment. (See the relevant - * @ref pxe_x86_pmode16 "implementation note" for more details.) - * - * @note There is no way to specify the TFTP server port with this API - * call. Though you can open a file using a non-standard TFTP server - * port (via s_PXENV_TFTP_OPEN::TFTPPort or, potentially, - * s_PXENV_TFTP_READ_FILE::TFTPSrvPort), you can only get the size of - * a file from a TFTP server listening on the standard TFTP port. - * "Consistency" is not a word in Intel's vocabulary. - */ -PXENV_EXIT_t pxenv_tftp_get_fsize ( struct s_PXENV_TFTP_GET_FSIZE - *tftp_get_fsize ) { - int rc; - - DBG ( "PXENV_TFTP_GET_FSIZE" ); - - /* Open TFTP file */ - if ( ( rc = pxe_tftp_open ( tftp_get_fsize->ServerIPAddress, 0, - tftp_get_fsize->FileName, 0 ) ) != 0 ) { - tftp_get_fsize->Status = PXENV_STATUS ( rc ); - return PXENV_EXIT_FAILURE; - } - - /* Wait for initial seek to arrive, and record size */ - while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) && - ( pxe_tftp.max_offset == 0 ) ) { - step(); - } - tftp_get_fsize->FileSize = pxe_tftp.max_offset; - - /* EINPROGRESS is normal; we don't wait for the whole transfer */ - if ( rc == -EINPROGRESS ) - rc = 0; - - /* Close TFTP file */ - pxe_tftp_close ( rc ); - - tftp_get_fsize->Status = PXENV_STATUS ( rc ); - return ( rc ? PXENV_EXIT_FAILURE : PXENV_EXIT_SUCCESS ); -} diff --git a/src/interface/pxe/pxe_udp.c b/src/interface/pxe/pxe_udp.c deleted file mode 100644 index 033b1ad9..00000000 --- a/src/interface/pxe/pxe_udp.c +++ /dev/null @@ -1,403 +0,0 @@ -/** @file - * - * PXE UDP API - * - */ - -#include -#include -#include -#include -#include -#include -#include - -/* - * Copyright (C) 2004 Michael Brown . - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/** A PXE UDP connection */ -struct pxe_udp_connection { - /** Data transfer interface to UDP stack */ - struct xfer_interface xfer; - /** Local address */ - struct sockaddr_in local; - /** Current PXENV_UDP_READ parameter block */ - struct s_PXENV_UDP_READ *pxenv_udp_read; -}; - -/** - * Receive PXE UDP data - * - * @v xfer Data transfer interface - * @v iobuf I/O buffer - * @v meta Data transfer metadata - * @ret rc Return status code - * - * Receives a packet as part of the current pxenv_udp_read() - * operation. - */ -static int pxe_udp_deliver_iob ( struct xfer_interface *xfer, - struct io_buffer *iobuf, - struct xfer_metadata *meta ) { - struct pxe_udp_connection *pxe_udp = - container_of ( xfer, struct pxe_udp_connection, xfer ); - struct s_PXENV_UDP_READ *pxenv_udp_read = pxe_udp->pxenv_udp_read; - struct sockaddr_in *sin_src; - struct sockaddr_in *sin_dest; - userptr_t buffer; - size_t len; - int rc = 0; - - if ( ! pxenv_udp_read ) { - DBG ( "PXE discarded UDP packet\n" ); - rc = -ENOBUFS; - goto done; - } - - /* Copy packet to buffer and record length */ - buffer = real_to_user ( pxenv_udp_read->buffer.segment, - pxenv_udp_read->buffer.offset ); - len = iob_len ( iobuf ); - if ( len > pxenv_udp_read->buffer_size ) - len = pxenv_udp_read->buffer_size; - copy_to_user ( buffer, 0, iobuf->data, len ); - pxenv_udp_read->buffer_size = len; - - /* Fill in source/dest information */ - assert ( meta ); - sin_src = ( struct sockaddr_in * ) meta->src; - assert ( sin_src ); - assert ( sin_src->sin_family == AF_INET ); - pxenv_udp_read->src_ip = sin_src->sin_addr.s_addr; - pxenv_udp_read->s_port = sin_src->sin_port; - sin_dest = ( struct sockaddr_in * ) meta->dest; - assert ( sin_dest ); - assert ( sin_dest->sin_family == AF_INET ); - pxenv_udp_read->dest_ip = sin_dest->sin_addr.s_addr; - pxenv_udp_read->d_port = sin_dest->sin_port; - - /* Mark as received */ - pxe_udp->pxenv_udp_read = NULL; - - done: - free_iob ( iobuf ); - return rc; -} - -/** PXE UDP data transfer interface operations */ -static struct xfer_interface_operations pxe_udp_xfer_operations = { - .close = ignore_xfer_close, - .vredirect = ignore_xfer_vredirect, - .window = unlimited_xfer_window, - .alloc_iob = default_xfer_alloc_iob, - .deliver_iob = pxe_udp_deliver_iob, - .deliver_raw = xfer_deliver_as_iob, -}; - -/** The PXE UDP connection */ -static struct pxe_udp_connection pxe_udp = { - .xfer = XFER_INIT ( &pxe_udp_xfer_operations ), - .local = { - .sin_family = AF_INET, - }, -}; - -/** - * UDP OPEN - * - * @v pxenv_udp_open Pointer to a struct s_PXENV_UDP_OPEN - * @v s_PXENV_UDP_OPEN::src_ip IP address of this station, or 0.0.0.0 - * @ret #PXENV_EXIT_SUCCESS Always - * @ret s_PXENV_UDP_OPEN::Status PXE status code - * @err #PXENV_STATUS_UDP_OPEN UDP connection already open - * @err #PXENV_STATUS_OUT_OF_RESOURCES Could not open connection - * - * Prepares the PXE stack for communication using pxenv_udp_write() - * and pxenv_udp_read(). - * - * The IP address supplied in s_PXENV_UDP_OPEN::src_ip will be - * recorded and used as the local station's IP address for all further - * communication, including communication by means other than - * pxenv_udp_write() and pxenv_udp_read(). (If - * s_PXENV_UDP_OPEN::src_ip is 0.0.0.0, the local station's IP address - * will remain unchanged.) - * - * You can only have one open UDP connection at a time. This is not a - * meaningful restriction, since pxenv_udp_write() and - * pxenv_udp_read() allow you to specify arbitrary local and remote - * ports and an arbitrary remote address for each packet. According - * to the PXE specifiation, you cannot have a UDP connection open at - * the same time as a TFTP connection; this restriction does not apply - * to Etherboot. - * - * On x86, you must set the s_PXE::StatusCallout field to a nonzero - * value before calling this function in protected mode. You cannot - * call this function with a 32-bit stack segment. (See the relevant - * @ref pxe_x86_pmode16 "implementation note" for more details.) - * - * @note The PXE specification does not make it clear whether the IP - * address supplied in s_PXENV_UDP_OPEN::src_ip should be used only - * for this UDP connection, or retained for all future communication. - * The latter seems more consistent with typical PXE stack behaviour. - * - * @note Etherboot currently ignores the s_PXENV_UDP_OPEN::src_ip - * parameter. - * - */ -PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *pxenv_udp_open ) { - int rc; - - DBG ( "PXENV_UDP_OPEN" ); - - /* Record source IP address */ - pxe_udp.local.sin_addr.s_addr = pxenv_udp_open->src_ip; - DBG ( " %s", inet_ntoa ( pxe_udp.local.sin_addr ) ); - - /* Open promiscuous UDP connection */ - xfer_close ( &pxe_udp.xfer, 0 ); - if ( ( rc = udp_open_promisc ( &pxe_udp.xfer ) ) != 0 ) { - pxenv_udp_open->Status = PXENV_STATUS ( rc ); - return PXENV_EXIT_FAILURE; - } - - pxenv_udp_open->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} - -/** - * UDP CLOSE - * - * @v pxenv_udp_close Pointer to a struct s_PXENV_UDP_CLOSE - * @ret #PXENV_EXIT_SUCCESS Always - * @ret s_PXENV_UDP_CLOSE::Status PXE status code - * @err None - - * - * Closes a UDP connection opened with pxenv_udp_open(). - * - * You can only have one open UDP connection at a time. You cannot - * have a UDP connection open at the same time as a TFTP connection. - * You cannot use pxenv_udp_close() to close a TFTP connection; use - * pxenv_tftp_close() instead. - * - * On x86, you must set the s_PXE::StatusCallout field to a nonzero - * value before calling this function in protected mode. You cannot - * call this function with a 32-bit stack segment. (See the relevant - * @ref pxe_x86_pmode16 "implementation note" for more details.) - * - */ -PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *pxenv_udp_close ) { - DBG ( "PXENV_UDP_CLOSE" ); - - /* Close UDP connection */ - xfer_close ( &pxe_udp.xfer, 0 ); - - pxenv_udp_close->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} - -/** - * UDP WRITE - * - * @v pxenv_udp_write Pointer to a struct s_PXENV_UDP_WRITE - * @v s_PXENV_UDP_WRITE::ip Destination IP address - * @v s_PXENV_UDP_WRITE::gw Relay agent IP address, or 0.0.0.0 - * @v s_PXENV_UDP_WRITE::src_port Source UDP port, or 0 - * @v s_PXENV_UDP_WRITE::dst_port Destination UDP port - * @v s_PXENV_UDP_WRITE::buffer_size Length of the UDP payload - * @v s_PXENV_UDP_WRITE::buffer Address of the UDP payload - * @ret #PXENV_EXIT_SUCCESS Packet was transmitted successfully - * @ret #PXENV_EXIT_FAILURE Packet could not be transmitted - * @ret s_PXENV_UDP_WRITE::Status PXE status code - * @err #PXENV_STATUS_UDP_CLOSED UDP connection is not open - * @err #PXENV_STATUS_UNDI_TRANSMIT_ERROR Could not transmit packet - * - * Transmits a single UDP packet. A valid IP and UDP header will be - * prepended to the payload in s_PXENV_UDP_WRITE::buffer; the buffer - * should not contain precomputed IP and UDP headers, nor should it - * contain space allocated for these headers. The first byte of the - * buffer will be transmitted as the first byte following the UDP - * header. - * - * If s_PXENV_UDP_WRITE::gw is 0.0.0.0, normal IP routing will take - * place. See the relevant @ref pxe_routing "implementation note" for - * more details. - * - * If s_PXENV_UDP_WRITE::src_port is 0, port 2069 will be used. - * - * You must have opened a UDP connection with pxenv_udp_open() before - * calling pxenv_udp_write(). - * - * On x86, you must set the s_PXE::StatusCallout field to a nonzero - * value before calling this function in protected mode. You cannot - * call this function with a 32-bit stack segment. (See the relevant - * @ref pxe_x86_pmode16 "implementation note" for more details.) - * - * @note Etherboot currently ignores the s_PXENV_UDP_WRITE::gw - * parameter. - * - */ -PXENV_EXIT_t pxenv_udp_write ( struct s_PXENV_UDP_WRITE *pxenv_udp_write ) { - struct sockaddr_in dest; - struct xfer_metadata meta = { - .src = ( struct sockaddr * ) &pxe_udp.local, - .dest = ( struct sockaddr * ) &dest, - .netdev = pxe_netdev, - }; - size_t len; - struct io_buffer *iobuf; - userptr_t buffer; - int rc; - - DBG ( "PXENV_UDP_WRITE" ); - - /* Construct destination socket address */ - memset ( &dest, 0, sizeof ( dest ) ); - dest.sin_family = AF_INET; - dest.sin_addr.s_addr = pxenv_udp_write->ip; - dest.sin_port = pxenv_udp_write->dst_port; - - /* Set local (source) port. PXE spec says source port is 2069 - * if not specified. Really, this ought to be set at UDP open - * time but hey, we didn't design this API. - */ - pxe_udp.local.sin_port = pxenv_udp_write->src_port; - if ( ! pxe_udp.local.sin_port ) - pxe_udp.local.sin_port = htons ( 2069 ); - - /* FIXME: we ignore the gateway specified, since we're - * confident of being able to do our own routing. We should - * probably allow for multiple gateways. - */ - - /* Allocate and fill data buffer */ - len = pxenv_udp_write->buffer_size; - iobuf = xfer_alloc_iob ( &pxe_udp.xfer, len ); - if ( ! iobuf ) { - pxenv_udp_write->Status = PXENV_STATUS_OUT_OF_RESOURCES; - return PXENV_EXIT_FAILURE; - } - buffer = real_to_user ( pxenv_udp_write->buffer.segment, - pxenv_udp_write->buffer.offset ); - copy_from_user ( iob_put ( iobuf, len ), buffer, 0, len ); - - DBG ( " %04x:%04x+%x %d->%s:%d", pxenv_udp_write->buffer.segment, - pxenv_udp_write->buffer.offset, pxenv_udp_write->buffer_size, - ntohs ( pxenv_udp_write->src_port ), - inet_ntoa ( dest.sin_addr ), - ntohs ( pxenv_udp_write->dst_port ) ); - - /* Transmit packet */ - if ( ( rc = xfer_deliver_iob_meta ( &pxe_udp.xfer, iobuf, - &meta ) ) != 0 ) { - pxenv_udp_write->Status = PXENV_STATUS ( rc ); - return PXENV_EXIT_FAILURE; - } - - pxenv_udp_write->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} - -/** - * UDP READ - * - * @v pxenv_udp_read Pointer to a struct s_PXENV_UDP_READ - * @v s_PXENV_UDP_READ::dest_ip Destination IP address, or 0.0.0.0 - * @v s_PXENV_UDP_READ::d_port Destination UDP port, or 0 - * @v s_PXENV_UDP_READ::buffer_size Size of the UDP payload buffer - * @v s_PXENV_UDP_READ::buffer Address of the UDP payload buffer - * @ret #PXENV_EXIT_SUCCESS A packet has been received - * @ret #PXENV_EXIT_FAILURE No packet has been received - * @ret s_PXENV_UDP_READ::Status PXE status code - * @ret s_PXENV_UDP_READ::src_ip Source IP address - * @ret s_PXENV_UDP_READ::dest_ip Destination IP address - * @ret s_PXENV_UDP_READ::s_port Source UDP port - * @ret s_PXENV_UDP_READ::d_port Destination UDP port - * @ret s_PXENV_UDP_READ::buffer_size Length of UDP payload - * @err #PXENV_STATUS_UDP_CLOSED UDP connection is not open - * @err #PXENV_STATUS_FAILURE No packet was ready to read - * - * Receive a single UDP packet. This is a non-blocking call; if no - * packet is ready to read, the call will return instantly with - * s_PXENV_UDP_READ::Status==PXENV_STATUS_FAILURE. - * - * If s_PXENV_UDP_READ::dest_ip is 0.0.0.0, UDP packets addressed to - * any IP address will be accepted and may be returned to the caller. - * - * If s_PXENV_UDP_READ::d_port is 0, UDP packets addressed to any UDP - * port will be accepted and may be returned to the caller. - * - * You must have opened a UDP connection with pxenv_udp_open() before - * calling pxenv_udp_read(). - * - * On x86, you must set the s_PXE::StatusCallout field to a nonzero - * value before calling this function in protected mode. You cannot - * call this function with a 32-bit stack segment. (See the relevant - * @ref pxe_x86_pmode16 "implementation note" for more details.) - * - * @note The PXE specification (version 2.1) does not state that we - * should fill in s_PXENV_UDP_READ::dest_ip and - * s_PXENV_UDP_READ::d_port, but Microsoft Windows' NTLDR program - * expects us to do so, and will fail if we don't. - * - */ -PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *pxenv_udp_read ) { - struct in_addr dest_ip_wanted = { .s_addr = pxenv_udp_read->dest_ip }; - struct in_addr dest_ip; - uint16_t d_port_wanted = pxenv_udp_read->d_port; - uint16_t d_port; - - DBG ( "PXENV_UDP_READ" ); - - /* Try receiving a packet */ - pxe_udp.pxenv_udp_read = pxenv_udp_read; - step(); - if ( pxe_udp.pxenv_udp_read ) { - /* No packet received */ - pxe_udp.pxenv_udp_read = NULL; - goto no_packet; - } - dest_ip.s_addr = pxenv_udp_read->dest_ip; - d_port = pxenv_udp_read->d_port; - - /* Filter on destination address and/or port */ - if ( dest_ip_wanted.s_addr && - ( dest_ip_wanted.s_addr != dest_ip.s_addr ) ) { - DBG ( " wrong IP %s", inet_ntoa ( dest_ip ) ); - DBG ( " (wanted %s)", inet_ntoa ( dest_ip_wanted ) ); - goto no_packet; - } - if ( d_port_wanted && ( d_port_wanted != d_port ) ) { - DBG ( " wrong port %d ", htons ( d_port ) ); - DBG ( " (wanted %d)", htons ( d_port_wanted ) ); - goto no_packet; - } - - DBG ( " %04x:%04x+%x %s:", pxenv_udp_read->buffer.segment, - pxenv_udp_read->buffer.offset, pxenv_udp_read->buffer_size, - inet_ntoa ( *( ( struct in_addr * ) &pxenv_udp_read->src_ip ) )); - DBG ( "%d<-%s:%d", ntohs ( pxenv_udp_read->s_port ), - inet_ntoa ( *( ( struct in_addr * ) &pxenv_udp_read->dest_ip ) ), - ntohs ( pxenv_udp_read->d_port ) ); - - pxenv_udp_read->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; - - no_packet: - pxenv_udp_read->Status = PXENV_STATUS_FAILURE; - return PXENV_EXIT_FAILURE; -} diff --git a/src/interface/pxe/pxe_undi.c b/src/interface/pxe/pxe_undi.c deleted file mode 100644 index 4e4a3da0..00000000 --- a/src/interface/pxe/pxe_undi.c +++ /dev/null @@ -1,684 +0,0 @@ -/** @file - * - * PXE UNDI API - * - */ - -/* - * Copyright (C) 2004 Michael Brown . - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "pxe.h" - -/** - * Count of outstanding transmitted packets - * - * This is incremented each time PXENV_UNDI_TRANSMIT is called, and - * decremented each time that PXENV_UNDI_ISR is called with the TX - * queue empty, stopping when the count reaches zero. This allows us - * to provide a pessimistic approximation of TX completion events to - * the PXE NBP simply by monitoring the netdev's TX queue. - */ -static int undi_tx_count = 0; - -struct net_device *pxe_netdev = NULL; - -/** - * Set network device as current PXE network device - * - * @v netdev Network device, or NULL - */ -void pxe_set_netdev ( struct net_device *netdev ) { - if ( pxe_netdev ) - netdev_put ( pxe_netdev ); - pxe_netdev = NULL; - if ( netdev ) - pxe_netdev = netdev_get ( netdev ); -} - -/** - * Open PXE network device - * - * @ret rc Return status code - */ -static int pxe_netdev_open ( void ) { - int rc; - - if ( ( rc = netdev_open ( pxe_netdev ) ) != 0 ) - return rc; - - netdev_irq ( pxe_netdev, 1 ); - return 0; -} - -/** - * Close PXE network device - * - */ -static void pxe_netdev_close ( void ) { - netdev_irq ( pxe_netdev, 0 ); - netdev_close ( pxe_netdev ); - undi_tx_count = 0; -} - -/* PXENV_UNDI_STARTUP - * - * Status: working - */ -PXENV_EXIT_t pxenv_undi_startup ( struct s_PXENV_UNDI_STARTUP *undi_startup ) { - DBG ( "PXENV_UNDI_STARTUP" ); - - undi_startup->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} - -/* PXENV_UNDI_CLEANUP - * - * Status: working - */ -PXENV_EXIT_t pxenv_undi_cleanup ( struct s_PXENV_UNDI_CLEANUP *undi_cleanup ) { - DBG ( "PXENV_UNDI_CLEANUP" ); - - pxe_netdev_close(); - - undi_cleanup->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} - -/* PXENV_UNDI_INITIALIZE - * - * Status: working - */ -PXENV_EXIT_t pxenv_undi_initialize ( struct s_PXENV_UNDI_INITIALIZE - *undi_initialize ) { - DBG ( "PXENV_UNDI_INITIALIZE" ); - - undi_initialize->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} - -/* PXENV_UNDI_RESET_ADAPTER - * - * Status: working - */ -PXENV_EXIT_t pxenv_undi_reset_adapter ( struct s_PXENV_UNDI_RESET - *undi_reset_adapter ) { - int rc; - - DBG ( "PXENV_UNDI_RESET_ADAPTER" ); - - pxe_netdev_close(); - if ( ( rc = pxe_netdev_open() ) != 0 ) { - undi_reset_adapter->Status = PXENV_STATUS ( rc ); - return PXENV_EXIT_FAILURE; - } - - undi_reset_adapter->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} - -/* PXENV_UNDI_SHUTDOWN - * - * Status: working - */ -PXENV_EXIT_t pxenv_undi_shutdown ( struct s_PXENV_UNDI_SHUTDOWN - *undi_shutdown ) { - DBG ( "PXENV_UNDI_SHUTDOWN" ); - - pxe_netdev_close(); - - undi_shutdown->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} - -/* PXENV_UNDI_OPEN - * - * Status: working - */ -PXENV_EXIT_t pxenv_undi_open ( struct s_PXENV_UNDI_OPEN *undi_open ) { - int rc; - - DBG ( "PXENV_UNDI_OPEN" ); - - if ( ( rc = pxe_netdev_open() ) != 0 ) { - undi_open->Status = PXENV_STATUS ( rc ); - return PXENV_EXIT_FAILURE; - } - - undi_open->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} - -/* PXENV_UNDI_CLOSE - * - * Status: working - */ -PXENV_EXIT_t pxenv_undi_close ( struct s_PXENV_UNDI_CLOSE *undi_close ) { - DBG ( "PXENV_UNDI_CLOSE" ); - - pxe_netdev_close(); - - undi_close->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} - -/* PXENV_UNDI_TRANSMIT - * - * Status: working - */ -PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT - *undi_transmit ) { - struct s_PXENV_UNDI_TBD tbd; - struct DataBlk *datablk; - struct io_buffer *iobuf; - struct net_protocol *net_protocol; - struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol; - char destaddr[MAX_LL_ADDR_LEN]; - const void *ll_dest; - size_t ll_hlen = ll_protocol->ll_header_len; - size_t len; - unsigned int i; - int rc; - - DBG ( "PXENV_UNDI_TRANSMIT" ); - - /* Identify network-layer protocol */ - switch ( undi_transmit->Protocol ) { - case P_IP: net_protocol = &ipv4_protocol; break; - case P_ARP: net_protocol = &arp_protocol; break; - case P_RARP: net_protocol = &rarp_protocol; break; - case P_UNKNOWN: - net_protocol = NULL; - ll_hlen = 0; - break; - default: - undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER; - return PXENV_EXIT_FAILURE; - } - DBG ( " %s", ( net_protocol ? net_protocol->name : "RAW" ) ); - - /* Calculate total packet length */ - copy_from_real ( &tbd, undi_transmit->TBD.segment, - undi_transmit->TBD.offset, sizeof ( tbd ) ); - len = tbd.ImmedLength; - DBG ( " %d", tbd.ImmedLength ); - for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) { - datablk = &tbd.DataBlock[i]; - len += datablk->TDDataLen; - DBG ( "+%d", datablk->TDDataLen ); - } - - /* Allocate and fill I/O buffer */ - iobuf = alloc_iob ( ll_hlen + len ); - if ( ! iobuf ) { - undi_transmit->Status = PXENV_STATUS_OUT_OF_RESOURCES; - return PXENV_EXIT_FAILURE; - } - iob_reserve ( iobuf, ll_hlen ); - copy_from_real ( iob_put ( iobuf, tbd.ImmedLength ), tbd.Xmit.segment, - tbd.Xmit.offset, tbd.ImmedLength ); - for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) { - datablk = &tbd.DataBlock[i]; - copy_from_real ( iob_put ( iobuf, datablk->TDDataLen ), - datablk->TDDataPtr.segment, - datablk->TDDataPtr.offset, - datablk->TDDataLen ); - } - - /* Add link-layer header, if required to do so */ - if ( net_protocol != NULL ) { - - /* Calculate destination address */ - if ( undi_transmit->XmitFlag == XMT_DESTADDR ) { - copy_from_real ( destaddr, - undi_transmit->DestAddr.segment, - undi_transmit->DestAddr.offset, - ll_protocol->ll_addr_len ); - ll_dest = destaddr; - } else { - DBG ( " BCAST" ); - ll_dest = ll_protocol->ll_broadcast; - } - - /* Add link-layer header */ - if ( ( rc = ll_protocol->push ( iobuf, ll_dest, - pxe_netdev->ll_addr, - net_protocol->net_proto ))!=0){ - free_iob ( iobuf ); - undi_transmit->Status = PXENV_STATUS ( rc ); - return PXENV_EXIT_FAILURE; - } - } - - /* Transmit packet */ - if ( ( rc = netdev_tx ( pxe_netdev, iobuf ) ) != 0 ) { - undi_transmit->Status = PXENV_STATUS ( rc ); - return PXENV_EXIT_FAILURE; - } - - /* Flag transmission as in-progress */ - undi_tx_count++; - - undi_transmit->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} - -/* PXENV_UNDI_SET_MCAST_ADDRESS - * - * Status: stub (no PXE multicast support) - */ -PXENV_EXIT_t -pxenv_undi_set_mcast_address ( struct s_PXENV_UNDI_SET_MCAST_ADDRESS - *undi_set_mcast_address ) { - DBG ( "PXENV_UNDI_SET_MCAST_ADDRESS" ); - - undi_set_mcast_address->Status = PXENV_STATUS_UNSUPPORTED; - return PXENV_EXIT_FAILURE; -} - -/* PXENV_UNDI_SET_STATION_ADDRESS - * - * Status: working - */ -PXENV_EXIT_t -pxenv_undi_set_station_address ( struct s_PXENV_UNDI_SET_STATION_ADDRESS - *undi_set_station_address ) { - - DBG ( "PXENV_UNDI_SET_STATION_ADDRESS" ); - - /* If adapter is open, the change will have no effect; return - * an error - */ - if ( pxe_netdev->state & NETDEV_OPEN ) { - undi_set_station_address->Status = - PXENV_STATUS_UNDI_INVALID_STATE; - return PXENV_EXIT_FAILURE; - } - - /* Update MAC address */ - memcpy ( pxe_netdev->ll_addr, - &undi_set_station_address->StationAddress, - pxe_netdev->ll_protocol->ll_addr_len ); - - undi_set_station_address->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} - -/* PXENV_UNDI_SET_PACKET_FILTER - * - * Status: won't implement (would require driver API changes for no - * real benefit) - */ -PXENV_EXIT_t -pxenv_undi_set_packet_filter ( struct s_PXENV_UNDI_SET_PACKET_FILTER - *undi_set_packet_filter ) { - DBG ( "PXENV_UNDI_SET_PACKET_FILTER" ); - - undi_set_packet_filter->Status = PXENV_STATUS_UNSUPPORTED; - return PXENV_EXIT_FAILURE; -} - -/* PXENV_UNDI_GET_INFORMATION - * - * Status: working - */ -PXENV_EXIT_t pxenv_undi_get_information ( struct s_PXENV_UNDI_GET_INFORMATION - *undi_get_information ) { - struct device *dev = pxe_netdev->dev; - struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol; - - DBG ( "PXENV_UNDI_GET_INFORMATION" ); - - undi_get_information->BaseIo = dev->desc.ioaddr; - undi_get_information->IntNumber = dev->desc.irq; - /* Cheat: assume all cards can cope with this */ - undi_get_information->MaxTranUnit = ETH_MAX_MTU; - undi_get_information->HwType = ntohs ( ll_protocol->ll_proto ); - undi_get_information->HwAddrLen = ll_protocol->ll_addr_len; - /* Cheat: assume card is always configured with its permanent - * node address. This is a valid assumption within Etherboot - * at the time of writing. - */ - memcpy ( &undi_get_information->CurrentNodeAddress, - pxe_netdev->ll_addr, - sizeof ( undi_get_information->CurrentNodeAddress ) ); - memcpy ( &undi_get_information->PermNodeAddress, - pxe_netdev->ll_addr, - sizeof ( undi_get_information->PermNodeAddress ) ); - undi_get_information->ROMAddress = 0; - /* nic.rom_info->rom_segment; */ - /* We only provide the ability to receive or transmit a single - * packet at a time. This is a bootloader, not an OS. - */ - undi_get_information->RxBufCt = 1; - undi_get_information->TxBufCt = 1; - - undi_get_information->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} - -/* PXENV_UNDI_GET_STATISTICS - * - * Status: working - */ -PXENV_EXIT_t pxenv_undi_get_statistics ( struct s_PXENV_UNDI_GET_STATISTICS - *undi_get_statistics ) { - DBG ( "PXENV_UNDI_GET_STATISTICS" ); - - undi_get_statistics->XmtGoodFrames = pxe_netdev->tx_stats.good; - undi_get_statistics->RcvGoodFrames = pxe_netdev->rx_stats.good; - undi_get_statistics->RcvCRCErrors = pxe_netdev->rx_stats.bad; - undi_get_statistics->RcvResourceErrors = pxe_netdev->rx_stats.bad; - - undi_get_statistics->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} - -/* PXENV_UNDI_CLEAR_STATISTICS - * - * Status: working - */ -PXENV_EXIT_t pxenv_undi_clear_statistics ( struct s_PXENV_UNDI_CLEAR_STATISTICS - *undi_clear_statistics ) { - DBG ( "PXENV_UNDI_CLEAR_STATISTICS" ); - - memset ( &pxe_netdev->tx_stats, 0, sizeof ( pxe_netdev->tx_stats ) ); - memset ( &pxe_netdev->rx_stats, 0, sizeof ( pxe_netdev->rx_stats ) ); - - undi_clear_statistics->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} - -/* PXENV_UNDI_INITIATE_DIAGS - * - * Status: won't implement (would require driver API changes for no - * real benefit) - */ -PXENV_EXIT_t pxenv_undi_initiate_diags ( struct s_PXENV_UNDI_INITIATE_DIAGS - *undi_initiate_diags ) { - DBG ( "PXENV_UNDI_INITIATE_DIAGS" ); - - undi_initiate_diags->Status = PXENV_STATUS_UNSUPPORTED; - return PXENV_EXIT_FAILURE; -} - -/* PXENV_UNDI_FORCE_INTERRUPT - * - * Status: won't implement (would require driver API changes for no - * perceptible benefit) - */ -PXENV_EXIT_t pxenv_undi_force_interrupt ( struct s_PXENV_UNDI_FORCE_INTERRUPT - *undi_force_interrupt ) { - DBG ( "PXENV_UNDI_FORCE_INTERRUPT" ); - - undi_force_interrupt->Status = PXENV_STATUS_UNSUPPORTED; - return PXENV_EXIT_FAILURE; -} - -/* PXENV_UNDI_GET_MCAST_ADDRESS - * - * Status: stub (no PXE multicast support) - */ -PXENV_EXIT_t -pxenv_undi_get_mcast_address ( struct s_PXENV_UNDI_GET_MCAST_ADDRESS - *undi_get_mcast_address ) { - DBG ( "PXENV_UNDI_GET_MCAST_ADDRESS" ); - - undi_get_mcast_address->Status = PXENV_STATUS_UNSUPPORTED; - return PXENV_EXIT_FAILURE; -} - -/* PXENV_UNDI_GET_NIC_TYPE - * - * Status: working - */ -PXENV_EXIT_t pxenv_undi_get_nic_type ( struct s_PXENV_UNDI_GET_NIC_TYPE - *undi_get_nic_type ) { - struct device *dev = pxe_netdev->dev; - - DBG ( "PXENV_UNDI_GET_NIC_TYPE" ); - - memset ( &undi_get_nic_type->info, 0, - sizeof ( undi_get_nic_type->info ) ); - - switch ( dev->desc.bus_type ) { - case BUS_TYPE_PCI: { - struct pci_nic_info *info = &undi_get_nic_type->info.pci; - - undi_get_nic_type->NicType = PCI_NIC; - info->Vendor_ID = dev->desc.vendor; - info->Dev_ID = dev->desc.device; - info->Base_Class = PCI_BASE_CLASS ( dev->desc.class ); - info->Sub_Class = PCI_SUB_CLASS ( dev->desc.class ); - info->Prog_Intf = PCI_PROG_INTF ( dev->desc.class ); - info->BusDevFunc = dev->desc.location; - /* Cheat: remaining fields are probably unnecessary, - * and would require adding extra code to pci.c. - */ - undi_get_nic_type->info.pci.SubVendor_ID = 0xffff; - undi_get_nic_type->info.pci.SubDevice_ID = 0xffff; - break; } - case BUS_TYPE_ISAPNP: { - struct pnp_nic_info *info = &undi_get_nic_type->info.pnp; - - undi_get_nic_type->NicType = PnP_NIC; - info->EISA_Dev_ID = ( ( dev->desc.vendor << 16 ) | - dev->desc.device ); - info->CardSelNum = dev->desc.location; - /* Cheat: remaining fields are probably unnecessary, - * and would require adding extra code to isapnp.c. - */ - break; } - default: - undi_get_nic_type->Status = PXENV_STATUS_FAILURE; - return PXENV_EXIT_FAILURE; - } - - undi_get_nic_type->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} - -/* PXENV_UNDI_GET_IFACE_INFO - * - * Status: working - */ -PXENV_EXIT_t pxenv_undi_get_iface_info ( struct s_PXENV_UNDI_GET_IFACE_INFO - *undi_get_iface_info ) { - DBG ( "PXENV_UNDI_GET_IFACE_INFO" ); - - /* Just hand back some info, doesn't really matter what it is. - * Most PXE stacks seem to take this approach. - */ - snprintf ( ( char * ) undi_get_iface_info->IfaceType, - sizeof ( undi_get_iface_info->IfaceType ), "gPXE" ); - undi_get_iface_info->LinkSpeed = 10000000; /* 10 Mbps */ - undi_get_iface_info->ServiceFlags = 0; - memset ( undi_get_iface_info->Reserved, 0, - sizeof(undi_get_iface_info->Reserved) ); - - undi_get_iface_info->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} - -/* PXENV_UNDI_GET_STATE - * - * Status: impossible - */ -PXENV_EXIT_t pxenv_undi_get_state ( struct s_PXENV_UNDI_GET_STATE - *undi_get_state ) { - DBG ( "PXENV_UNDI_GET_STATE" ); - - undi_get_state->Status = PXENV_STATUS_UNSUPPORTED; - return PXENV_EXIT_FAILURE; -}; - -/* PXENV_UNDI_ISR - * - * Status: working - */ -PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { - struct io_buffer *iobuf; - size_t len; - struct ll_protocol *ll_protocol; - const void *ll_dest; - const void *ll_source; - uint16_t net_proto; - size_t ll_hlen; - struct net_protocol *net_protocol; - unsigned int prottype; - int rc; - - DBG ( "PXENV_UNDI_ISR" ); - - /* Just in case some idiot actually looks at these fields when - * we weren't meant to fill them in... - */ - undi_isr->BufferLength = 0; - undi_isr->FrameLength = 0; - undi_isr->FrameHeaderLength = 0; - undi_isr->ProtType = 0; - undi_isr->PktType = 0; - - switch ( undi_isr->FuncFlag ) { - case PXENV_UNDI_ISR_IN_START : - DBG ( " START" ); - - /* Call poll(). This should acknowledge the device - * interrupt and queue up any received packet. - */ - netdev_poll ( pxe_netdev ); - - /* Disable interrupts to avoid interrupt storm */ - netdev_irq ( pxe_netdev, 0 ); - - /* Always say it was ours for the sake of simplicity */ - undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS; - break; - case PXENV_UNDI_ISR_IN_PROCESS : - DBG ( " PROCESS" ); - /* Fall through */ - case PXENV_UNDI_ISR_IN_GET_NEXT : - DBG ( " GET_NEXT" ); - - /* Some dumb NBPs (e.g. emBoot's winBoot/i) never call - * PXENV_UNDI_ISR with FuncFlag=PXENV_UNDI_ISR_START; - * they just sit in a tight polling loop merrily - * violating the PXE spec with repeated calls to - * PXENV_UNDI_ISR_IN_PROCESS. Force extra polls to - * cope with these out-of-spec clients. - */ - netdev_poll ( pxe_netdev ); - - /* If we have not yet marked a TX as complete, and the - * netdev TX queue is empty, report the TX completion. - */ - if ( undi_tx_count && list_empty ( &pxe_netdev->tx_queue ) ) { - DBG ( " TXC" ); - undi_tx_count--; - undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_TRANSMIT; - break; - } - - /* Remove first packet from netdev RX queue */ - iobuf = netdev_rx_dequeue ( pxe_netdev ); - if ( ! iobuf ) { - DBG ( " DONE" ); - /* No more packets remaining */ - undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE; - /* Re-enable interrupts */ - netdev_irq ( pxe_netdev, 1 ); - break; - } - - /* Copy packet to base memory buffer */ - len = iob_len ( iobuf ); - DBG ( " RX %zd", len ); - if ( len > sizeof ( basemem_packet ) ) { - /* Should never happen */ - len = sizeof ( basemem_packet ); - } - memcpy ( basemem_packet, iobuf->data, len ); - - /* Strip link-layer header */ - ll_protocol = pxe_netdev->ll_protocol; - if ( ( rc = ll_protocol->pull ( iobuf, &ll_dest, &ll_source, - &net_proto ) ) != 0 ) { - /* Assume unknown net_proto and no ll_source */ - net_proto = 0; - ll_source = NULL; - } - ll_hlen = ( len - iob_len ( iobuf ) ); - - /* Determine network-layer protocol */ - switch ( net_proto ) { - case htons ( ETH_P_IP ): - net_protocol = &ipv4_protocol; - prottype = P_IP; - break; - case htons ( ETH_P_ARP ): - net_protocol = &arp_protocol; - prottype = P_ARP; - break; - case htons ( ETH_P_RARP ): - net_protocol = &rarp_protocol; - prottype = P_RARP; - break; - default: - net_protocol = NULL; - prottype = P_UNKNOWN; - break; - } - DBG ( " %s", ( net_protocol ? net_protocol->name : "RAW" ) ); - - /* Fill in UNDI_ISR structure */ - undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_RECEIVE; - undi_isr->BufferLength = len; - undi_isr->FrameLength = len; - undi_isr->FrameHeaderLength = ll_hlen; - undi_isr->Frame.segment = rm_ds; - undi_isr->Frame.offset = __from_data16 ( basemem_packet ); - undi_isr->ProtType = prottype; - undi_isr->PktType = XMT_DESTADDR; - - /* Free packet */ - free_iob ( iobuf ); - break; - default : - DBG ( " INVALID(%04x)", undi_isr->FuncFlag ); - - /* Should never happen */ - undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE; - undi_isr->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER; - return PXENV_EXIT_FAILURE; - } - - undi_isr->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; -} -- cgit v1.2.3-55-g7522