Updated PXE UDP implementation to use the new Etherboot UDP API.
authorMichael Brown <mcb30@etherboot.org>
Wed, 2 Aug 2006 23:08:10 +0000 (23:08 +0000)
committerMichael Brown <mcb30@etherboot.org>
Wed, 2 Aug 2006 23:08:10 +0000 (23:08 +0000)
Updated PXE API dispatcher to use copy_{to,from}_user, and moved to
arch/i386 since the implementation is quite architecture-dependent.
(The individual PXE API calls can be largely
architecture-independent.)

src/arch/i386/Makefile
src/arch/i386/interface/pxe/pxe_call.c [new file with mode: 0644]
src/include/gpxe/udp.h
src/include/pxe.h
src/interface/pxe/pxe.c
src/interface/pxe/pxe_preboot.c
src/interface/pxe/pxe_tftp.c
src/interface/pxe/pxe_udp.c
src/interface/pxe/pxe_undi.c
src/net/udp.c

index 33a2d63..dd63a42 100644 (file)
@@ -7,6 +7,7 @@ SRCDIRS         += arch/i386/drivers/bus
 SRCDIRS                += arch/i386/drivers/net
 SRCDIRS                += arch/i386/drivers/disk
 SRCDIRS                += arch/i386/interface/pcbios
+SRCDIRS                += arch/i386/interface/pxe
 
 # The various xxx_loader.c files are #included into core/loader.c and
 # should not be compiled directly.
diff --git a/src/arch/i386/interface/pxe/pxe_call.c b/src/arch/i386/interface/pxe/pxe_call.c
new file mode 100644 (file)
index 0000000..4d567bf
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * 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 <gpxe/uaccess.h>
+#include <registers.h>
+#include <pxe.h>
+
+/** @file
+ *
+ * PXE API entry point
+ */
+
+/** A function pointer to hold any PXE API call
+ *
+ * Used by pxe_api_call() to avoid large swathes of duplicated code.
+ */
+union pxenv_call {
+       PXENV_EXIT_t ( * any ) ( union u_PXENV_ANY * );
+       PXENV_EXIT_t ( * unknown ) ( struct s_PXENV_UNKNOWN * );
+       PXENV_EXIT_t ( * unload_stack ) ( struct s_PXENV_UNLOAD_STACK * );
+       PXENV_EXIT_t ( * get_cached_info )
+                       ( struct s_PXENV_GET_CACHED_INFO * );
+       PXENV_EXIT_t ( * restart_tftp ) ( struct s_PXENV_TFTP_READ_FILE * );
+       PXENV_EXIT_t ( * start_undi ) ( struct s_PXENV_START_UNDI * );
+       PXENV_EXIT_t ( * stop_undi ) ( struct s_PXENV_STOP_UNDI * );
+       PXENV_EXIT_t ( * start_base ) ( struct s_PXENV_START_BASE * );
+       PXENV_EXIT_t ( * stop_base ) ( struct s_PXENV_STOP_BASE * );
+       PXENV_EXIT_t ( * tftp_open ) ( struct s_PXENV_TFTP_OPEN * );
+       PXENV_EXIT_t ( * tftp_close ) ( struct s_PXENV_TFTP_CLOSE * );
+       PXENV_EXIT_t ( * tftp_read ) ( struct s_PXENV_TFTP_READ * );
+       PXENV_EXIT_t ( * tftp_read_file ) ( struct s_PXENV_TFTP_READ_FILE * );
+       PXENV_EXIT_t ( * tftp_get_fsize ) ( struct s_PXENV_TFTP_GET_FSIZE * );
+       PXENV_EXIT_t ( * udp_open ) ( struct s_PXENV_UDP_OPEN * );
+       PXENV_EXIT_t ( * udp_close ) ( struct s_PXENV_UDP_CLOSE * );
+       PXENV_EXIT_t ( * udp_write ) ( struct s_PXENV_UDP_WRITE * );
+       PXENV_EXIT_t ( * udp_read ) ( struct s_PXENV_UDP_READ * );
+       PXENV_EXIT_t ( * undi_startup ) ( struct s_PXENV_UNDI_STARTUP * );
+       PXENV_EXIT_t ( * undi_cleanup ) ( struct s_PXENV_UNDI_CLEANUP * );
+       PXENV_EXIT_t ( * undi_initialize )
+                       ( struct s_PXENV_UNDI_INITIALIZE * );
+       PXENV_EXIT_t ( * undi_reset_adapter ) ( struct s_PXENV_UNDI_RESET * );
+       PXENV_EXIT_t ( * undi_shutdown ) ( struct s_PXENV_UNDI_SHUTDOWN * );
+       PXENV_EXIT_t ( * undi_open ) ( struct s_PXENV_UNDI_OPEN * );
+       PXENV_EXIT_t ( * undi_close ) ( struct s_PXENV_UNDI_CLOSE * );
+       PXENV_EXIT_t ( * undi_transmit ) ( struct s_PXENV_UNDI_TRANSMIT * );
+       PXENV_EXIT_t ( * undi_set_mcast_address )
+                       ( struct s_PXENV_UNDI_SET_MCAST_ADDRESS * );
+       PXENV_EXIT_t ( * undi_set_station_address )
+                       ( struct s_PXENV_UNDI_SET_STATION_ADDRESS * );
+       PXENV_EXIT_t ( * undi_set_packet_filter )
+                       ( struct s_PXENV_UNDI_SET_PACKET_FILTER * );
+       PXENV_EXIT_t ( * undi_get_information )
+                       ( struct s_PXENV_UNDI_GET_INFORMATION * );
+       PXENV_EXIT_t ( * undi_get_statistics )
+                       ( struct s_PXENV_UNDI_GET_STATISTICS * );
+       PXENV_EXIT_t ( * undi_clear_statistics )
+                       ( struct s_PXENV_UNDI_CLEAR_STATISTICS * );
+       PXENV_EXIT_t ( * undi_initiate_diags )
+                       ( struct s_PXENV_UNDI_INITIATE_DIAGS * );
+       PXENV_EXIT_t ( * undi_force_interrupt )
+                       ( struct s_PXENV_UNDI_FORCE_INTERRUPT * );
+       PXENV_EXIT_t ( * undi_get_mcast_address )
+                       ( struct s_PXENV_UNDI_GET_MCAST_ADDRESS * );
+       PXENV_EXIT_t ( * undi_get_nic_type )
+                       ( struct s_PXENV_UNDI_GET_NIC_TYPE * );
+       PXENV_EXIT_t ( * undi_get_iface_info )
+                       ( struct s_PXENV_UNDI_GET_IFACE_INFO * );
+       PXENV_EXIT_t ( * undi_get_state ) ( struct s_PXENV_UNDI_GET_STATE * );
+       PXENV_EXIT_t ( * undi_isr ) ( struct s_PXENV_UNDI_ISR * );
+};
+
+/**
+ * Handle an unknown PXE API call
+ *
+ * @v pxenv_unknown                    Pointer to a struct s_PXENV_UNKNOWN
+ * @ret #PXENV_EXIT_FAILURE            Always
+ * @err #PXENV_STATUS_UNSUPPORTED      Always
+ */
+static PXENV_EXIT_t pxenv_unknown ( struct s_PXENV_UNKNOWN *pxenv_unknown ) {
+       pxenv_unknown->Status = PXENV_STATUS_UNSUPPORTED;
+       return PXENV_EXIT_FAILURE;
+}
+
+/**
+ * Dispatch PXE API call
+ *
+ * @v bx               PXE opcode
+ * @v es:di            Address of PXE parameter block
+ * @ret ax             PXE exit code
+ */
+void pxe_api_call ( struct i386_all_regs *ix86 ) {
+       int opcode = ix86->regs.bx;
+       userptr_t parameters = real_to_user ( ix86->segs.es, ix86->regs.di );
+       size_t param_len;
+       union u_PXENV_ANY pxenv_any;
+       union pxenv_call pxenv_call;
+       PXENV_EXIT_t ret;
+
+       switch ( opcode ) {
+       case PXENV_UNLOAD_STACK:
+               pxenv_call.unload_stack = pxenv_unload_stack;
+               param_len = sizeof ( pxenv_any.unload_stack );
+               break;
+       case PXENV_GET_CACHED_INFO:
+               pxenv_call.get_cached_info = pxenv_get_cached_info;
+               param_len = sizeof ( pxenv_any.get_cached_info );
+               break;
+       case PXENV_RESTART_TFTP:
+               pxenv_call.restart_tftp = pxenv_restart_tftp;
+               param_len = sizeof ( pxenv_any.restart_tftp );
+               break;
+       case PXENV_START_UNDI:
+               pxenv_call.start_undi = pxenv_start_undi;
+               param_len = sizeof ( pxenv_any.start_undi );
+               break;
+       case PXENV_STOP_UNDI:
+               pxenv_call.stop_undi = pxenv_stop_undi;
+               param_len = sizeof ( pxenv_any.stop_undi );
+               break;
+       case PXENV_START_BASE:
+               pxenv_call.start_base = pxenv_start_base;
+               param_len = sizeof ( pxenv_any.start_base );
+               break;
+       case PXENV_STOP_BASE:
+               pxenv_call.stop_base = pxenv_stop_base;
+               param_len = sizeof ( pxenv_any.stop_base );
+               break;
+       case PXENV_TFTP_OPEN:
+               pxenv_call.tftp_open = pxenv_tftp_open;
+               param_len = sizeof ( pxenv_any.tftp_open );
+               break;
+       case PXENV_TFTP_CLOSE:
+               pxenv_call.tftp_close = pxenv_tftp_close;
+               param_len = sizeof ( pxenv_any.tftp_close );
+               break;
+       case PXENV_TFTP_READ:
+               pxenv_call.tftp_read = pxenv_tftp_read;
+               param_len = sizeof ( pxenv_any.tftp_read );
+               break;
+       case PXENV_TFTP_READ_FILE:
+               pxenv_call.tftp_read_file = pxenv_tftp_read_file;
+               param_len = sizeof ( pxenv_any.tftp_read_file );
+               break;
+       case PXENV_TFTP_GET_FSIZE:
+               pxenv_call.tftp_get_fsize = pxenv_tftp_get_fsize;
+               param_len = sizeof ( pxenv_any.tftp_get_fsize );
+               break;
+       case PXENV_UDP_OPEN:
+               pxenv_call.udp_open = pxenv_udp_open;
+               param_len = sizeof ( pxenv_any.udp_open );
+               break;
+       case PXENV_UDP_CLOSE:
+               pxenv_call.udp_close = pxenv_udp_close;
+               param_len = sizeof ( pxenv_any.udp_close );
+               break;
+       case PXENV_UDP_WRITE:
+               pxenv_call.udp_write = pxenv_udp_write;
+               param_len = sizeof ( pxenv_any.udp_write );
+               break;
+       case PXENV_UDP_READ:
+               pxenv_call.udp_read = pxenv_udp_read;
+               param_len = sizeof ( pxenv_any.udp_read );
+               break;
+       case PXENV_UNDI_STARTUP:
+               pxenv_call.undi_startup = pxenv_undi_startup;
+               param_len = sizeof ( pxenv_any.undi_startup );
+               break;
+       case PXENV_UNDI_CLEANUP:
+               pxenv_call.undi_cleanup = pxenv_undi_cleanup;
+               param_len = sizeof ( pxenv_any.undi_cleanup );
+               break;
+       case PXENV_UNDI_INITIALIZE:
+               pxenv_call.undi_initialize = pxenv_undi_initialize;
+               param_len = sizeof ( pxenv_any.undi_initialize );
+               break;
+       case PXENV_UNDI_RESET_ADAPTER:
+               pxenv_call.undi_reset_adapter = pxenv_undi_reset_adapter;
+               param_len = sizeof ( pxenv_any.undi_reset_adapter );
+               break;
+       case PXENV_UNDI_SHUTDOWN:
+               pxenv_call.undi_shutdown = pxenv_undi_shutdown;
+               param_len = sizeof ( pxenv_any.undi_shutdown );
+               break;
+       case PXENV_UNDI_OPEN:
+               pxenv_call.undi_open = pxenv_undi_open;
+               param_len = sizeof ( pxenv_any.undi_open );
+               break;
+       case PXENV_UNDI_CLOSE:
+               pxenv_call.undi_close = pxenv_undi_close;
+               param_len = sizeof ( pxenv_any.undi_close );
+               break;
+       case PXENV_UNDI_TRANSMIT:
+               pxenv_call.undi_transmit = pxenv_undi_transmit;
+               param_len = sizeof ( pxenv_any.undi_transmit );
+               break;
+       case PXENV_UNDI_SET_MCAST_ADDRESS:
+               pxenv_call.undi_set_mcast_address =
+                       pxenv_undi_set_mcast_address;
+               param_len = sizeof ( pxenv_any.undi_set_mcast_address );
+               break;
+       case PXENV_UNDI_SET_STATION_ADDRESS:
+               pxenv_call.undi_set_station_address =
+                       pxenv_undi_set_station_address;
+               param_len = sizeof ( pxenv_any.undi_set_station_address );
+               break;
+       case PXENV_UNDI_SET_PACKET_FILTER:
+               pxenv_call.undi_set_packet_filter =
+                       pxenv_undi_set_packet_filter;
+               param_len = sizeof ( pxenv_any.undi_set_packet_filter );
+               break;
+       case PXENV_UNDI_GET_INFORMATION:
+               pxenv_call.undi_get_information = pxenv_undi_get_information;
+               param_len = sizeof ( pxenv_any.undi_get_information );
+               break;
+       case PXENV_UNDI_GET_STATISTICS:
+               pxenv_call.undi_get_statistics = pxenv_undi_get_statistics;
+               param_len = sizeof ( pxenv_any.undi_get_statistics );
+               break;
+       case PXENV_UNDI_CLEAR_STATISTICS:
+               pxenv_call.undi_clear_statistics = pxenv_undi_clear_statistics;
+               param_len = sizeof ( pxenv_any.undi_clear_statistics );
+               break;
+       case PXENV_UNDI_INITIATE_DIAGS:
+               pxenv_call.undi_initiate_diags = pxenv_undi_initiate_diags;
+               param_len = sizeof ( pxenv_any.undi_initiate_diags );
+               break;
+       case PXENV_UNDI_FORCE_INTERRUPT:
+               pxenv_call.undi_force_interrupt = pxenv_undi_force_interrupt;
+               param_len = sizeof ( pxenv_any.undi_force_interrupt );
+               break;
+       case PXENV_UNDI_GET_MCAST_ADDRESS:
+               pxenv_call.undi_get_mcast_address =
+                       pxenv_undi_get_mcast_address;
+               param_len = sizeof ( pxenv_any.undi_get_mcast_address );
+               break;
+       case PXENV_UNDI_GET_NIC_TYPE:
+               pxenv_call.undi_get_nic_type = pxenv_undi_get_nic_type;
+               param_len = sizeof ( pxenv_any.undi_get_nic_type );
+               break;
+       case PXENV_UNDI_GET_IFACE_INFO:
+               pxenv_call.undi_get_iface_info = pxenv_undi_get_iface_info;
+               param_len = sizeof ( pxenv_any.undi_get_iface_info );
+               break;
+       case PXENV_UNDI_ISR:
+               pxenv_call.undi_isr = pxenv_undi_isr;
+               param_len = sizeof ( pxenv_any.undi_isr );
+               break;
+       default:
+               DBG ( "PXENV_UNKNOWN_%hx", opcode );
+               pxenv_call.unknown = pxenv_unknown;
+               param_len = sizeof ( pxenv_any.unknown );
+               break;
+       }
+
+       /* Copy parameter block from caller */
+       copy_from_user ( &pxenv_any, parameters, 0, param_len );
+
+       /* Set default status in case child routine fails to do so */
+       pxenv_any.Status = PXENV_STATUS_FAILURE;
+
+       /* Hand off to relevant API routine */
+       DBG ( "[" );
+       ret = pxenv_call.any ( &pxenv_any );
+       if ( pxenv_any.Status != PXENV_STATUS_SUCCESS ) {
+               DBG ( " %02x", pxenv_any.Status );
+       }
+       if ( ret != PXENV_EXIT_SUCCESS ) {
+               DBG ( ret == PXENV_EXIT_FAILURE ? " err" : " ??" );
+       }
+       DBG ( "]" );
+       
+       /* Copy modified parameter block back to caller and return */
+       copy_to_user ( parameters, 0, &pxenv_any, param_len );
+       ix86->regs.ax = ret;
+}
index a0e054d..0104cc0 100644 (file)
@@ -64,6 +64,9 @@ struct udp_operations {
         * @v conn      UDP connection
         * @v data      Data
         * @v len       Length of data
+        * @v st_src    Source address
+        * @v st_dest   Destination address
+        * @ret rc      Return status code
         */
        int ( * newdata ) ( struct udp_connection *conn, void *data,
                            size_t len, struct sockaddr_tcpip *st_src,
@@ -92,8 +95,10 @@ struct udp_connection {
  */
 
 extern int udp_bind ( struct udp_connection *conn, uint16_t local_port );
+extern void udp_bind_promisc ( struct udp_connection *conn );
 extern void udp_connect ( struct udp_connection *conn,
                          struct sockaddr_tcpip *peer );
+extern void udp_connect_promisc ( struct udp_connection *conn );
 extern int udp_open ( struct udp_connection *conn, uint16_t local_port );
 extern void udp_close ( struct udp_connection *conn );
 
index f8e2de7..7e61c6a 100644 (file)
@@ -3,8 +3,13 @@
 
 #include "pxe_types.h"
 #include "pxe_api.h"
-#include "etherboot.h"
-#include "tftp.h"
+
+/* 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
@@ -14,6 +19,7 @@
 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;
@@ -81,29 +87,11 @@ typedef enum {
 typedef struct pxe_stack {
        struct s_PXE            pxe     __attribute__ ((aligned(16)));
        struct s_PXENV          pxenv   __attribute__ ((aligned(16)));
-       pxe_stack_state_t state;
-       union {
-               BOOTPLAYER_t    cached_info;
-               char            packet[ETH_FRAME_LEN];
-               struct {
-                       uint32_t magic_cookie;
-                       unsigned int len;
-                       int eof;
-                       char data[TFTP_MAX_BLKSIZE];
-               } tftpdata;
-               struct {
-                       char *buffer;
-                       uint32_t offset;
-                       uint32_t bufferlen;
-               } readfile;
-       };
-       struct {}       arch_data __attribute__ ((aligned(16)));
+       pxe_stack_state_t       state;
 } pxe_stack_t;
 
 extern int ensure_pxe_state ( pxe_stack_state_t wanted );
 
 extern pxe_stack_t *pxe_stack;
 
-extern PXENV_EXIT_t pxe_api_call ( int opcode, union u_PXENV_ANY *any );
-
 #endif /* PXE_H */
index 4fcb6b3..6731a9f 100644 (file)
@@ -25,6 +25,8 @@
 #include "dev.h"
 #include "pxe.h"
 
+#if 0
+
 /* Global pointer to currently installed PXE stack */
 pxe_stack_t *pxe_stack = NULL;
 
@@ -162,151 +164,4 @@ int ensure_pxe_state ( pxe_stack_state_t wanted ) {
        return success;
 }
 
-/* API call dispatcher
- *
- * Status: complete
- */
-PXENV_EXIT_t pxe_api_call ( int opcode, union u_PXENV_ANY *any ) {
-       PXENV_EXIT_t ret = PXENV_EXIT_FAILURE;
-
-       /* Set default status in case child routine fails to do so */
-       any->Status = PXENV_STATUS_FAILURE;
-
-       DBG ( "[" );
-
-       /* Hand off to relevant API routine */
-       switch ( opcode ) {
-       case PXENV_START_UNDI:
-               ret = pxenv_start_undi ( &any->start_undi );
-               break;
-       case PXENV_UNDI_STARTUP:
-               ret = pxenv_undi_startup ( &any->undi_startup );
-               break;
-       case PXENV_UNDI_CLEANUP:
-               ret = pxenv_undi_cleanup ( &any->undi_cleanup );
-               break;
-       case PXENV_UNDI_INITIALIZE:
-               ret = pxenv_undi_initialize ( &any->undi_initialize );
-               break;
-       case PXENV_UNDI_RESET_ADAPTER:
-               ret = pxenv_undi_reset_adapter ( &any->undi_reset_adapter );
-               break;
-       case PXENV_UNDI_SHUTDOWN:
-               ret = pxenv_undi_shutdown ( &any->undi_shutdown );
-               break;
-       case PXENV_UNDI_OPEN:
-               ret = pxenv_undi_open ( &any->undi_open );
-               break;
-       case PXENV_UNDI_CLOSE:
-               ret = pxenv_undi_close ( &any->undi_close );
-               break;
-       case PXENV_UNDI_TRANSMIT:
-               ret = pxenv_undi_transmit ( &any->undi_transmit );
-               break;
-       case PXENV_UNDI_SET_MCAST_ADDRESS:
-               ret = pxenv_undi_set_mcast_address (
-                                               &any->undi_set_mcast_address );
-               break;
-       case PXENV_UNDI_SET_STATION_ADDRESS:
-               ret = pxenv_undi_set_station_address (
-                                             &any->undi_set_station_address );
-               break;
-       case PXENV_UNDI_SET_PACKET_FILTER:
-               ret = pxenv_undi_set_packet_filter (
-                                               &any->undi_set_packet_filter );
-               break;
-       case PXENV_UNDI_GET_INFORMATION:
-               ret = pxenv_undi_get_information (
-                                              &any->undi_get_information );
-               break;
-       case PXENV_UNDI_GET_STATISTICS:
-               ret = pxenv_undi_get_statistics ( &any->undi_get_statistics );
-               break;
-       case PXENV_UNDI_CLEAR_STATISTICS:
-               ret = pxenv_undi_clear_statistics (
-                                                &any->undi_clear_statistics );
-               break;
-       case PXENV_UNDI_INITIATE_DIAGS:
-               ret = pxenv_undi_initiate_diags ( &any->undi_initiate_diags );
-                                                
-               break;
-       case PXENV_UNDI_FORCE_INTERRUPT:
-               ret = pxenv_undi_force_interrupt (
-                                              &any->undi_force_interrupt );
-               break;
-       case PXENV_UNDI_GET_MCAST_ADDRESS:
-               ret = pxenv_undi_get_mcast_address (
-                                            &any->undi_get_mcast_address );
-               break;
-       case PXENV_UNDI_GET_NIC_TYPE:
-               ret = pxenv_undi_get_nic_type ( &any->undi_get_nic_type );
-               break;
-       case PXENV_UNDI_GET_IFACE_INFO:
-               ret = pxenv_undi_get_iface_info ( &any->undi_get_iface_info );
-               break;
-       case PXENV_UNDI_ISR:
-               ret = pxenv_undi_isr ( &any->undi_isr );
-               break;
-       case PXENV_STOP_UNDI:
-               ret = pxenv_stop_undi ( &any->stop_undi );
-               break;
-       case PXENV_TFTP_OPEN:
-               ret = pxenv_tftp_open ( &any->tftp_open );
-               break;
-       case PXENV_TFTP_CLOSE:
-               ret = pxenv_tftp_close ( &any->tftp_close );
-               break;
-       case PXENV_TFTP_READ:
-               ret = pxenv_tftp_read ( &any->tftp_read );
-               break;
-       case PXENV_TFTP_READ_FILE:
-               ret = pxenv_tftp_read_file ( &any->tftp_read_file );
-               break;
-       case PXENV_TFTP_GET_FSIZE:
-               ret = pxenv_tftp_get_fsize ( &any->tftp_get_fsize );
-               break;
-       case PXENV_UDP_OPEN:
-               ret = pxenv_udp_open ( &any->udp_open );
-               break;
-       case PXENV_UDP_CLOSE:
-               ret = pxenv_udp_close ( &any->udp_close );
-               break;
-       case PXENV_UDP_READ:
-               ret = pxenv_udp_read ( &any->udp_read );
-               break;
-       case PXENV_UDP_WRITE:
-               ret = pxenv_udp_write ( &any->udp_write );
-               break;
-       case PXENV_UNLOAD_STACK:
-               ret = pxenv_unload_stack ( &any->unload_stack );
-               break;
-       case PXENV_GET_CACHED_INFO:
-               ret = pxenv_get_cached_info ( &any->get_cached_info );
-               break;
-       case PXENV_RESTART_TFTP:
-               ret = pxenv_restart_tftp ( &any->restart_tftp );
-               break;
-       case PXENV_START_BASE:
-               ret = pxenv_start_base ( &any->start_base );
-               break;
-       case PXENV_STOP_BASE:
-               ret = pxenv_stop_base ( &any->stop_base );
-               break;
-               
-       default:
-               DBG ( "PXENV_UNKNOWN_%hx", opcode );
-               any->Status = PXENV_STATUS_UNSUPPORTED;
-               ret = PXENV_EXIT_FAILURE;
-               break;
-       }
-
-       if ( any->Status != PXENV_STATUS_SUCCESS ) {
-               DBG ( " %hx", any->Status );
-       }
-       if ( ret != PXENV_EXIT_SUCCESS ) {
-               DBG ( ret == PXENV_EXIT_FAILURE ? " err" : " ??" );
-       }
-       DBG ( "]" );
-
-       return ret;
-}
+#endif
index f0e12bb..fbe8929 100644 (file)
@@ -23,6 +23,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#if 0
+
 #include "pxe.h"
 #include "pxe_callbacks.h"
 
@@ -247,3 +249,5 @@ PXENV_EXIT_t pxenv_stop_base ( struct s_PXENV_STOP_BASE *stop_base ) {
        stop_base->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
 }
+
+#endif
index 2d824e1..fffebf2 100644 (file)
@@ -22,6 +22,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#if 0
+
 #include "pxe.h"
 
 static int pxe_tftp_read_block ( unsigned char *data, unsigned int block,
@@ -621,3 +623,5 @@ Note to future API designers at Intel: try to understand the
 underlying network protocol first!
 
 */
+
+#endif
index db5981b..34a2488 100644 (file)
@@ -4,9 +4,12 @@
  *
  */
 
-#include "pxe.h"
-#include "io.h"
-#include "string.h"
+#include <string.h>
+#include <byteswap.h>
+#include <gpxe/udp.h>
+#include <gpxe/uaccess.h>
+#include <gpxe/process.h>
+#include <pxe.h>
 
 /*
  * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+/** A PXE UDP connection */
+struct pxe_udp_connection {
+       /** Etherboot UDP connection */
+       struct udp_connection udp;
+       /** "Connection is open" flag */
+       int open;
+       /** Current pxenv_udp_read() operation, if any */
+       struct s_PXENV_UDP_READ *pxenv_udp_read;
+       /** Current pxenv_udp_write() operation, if any */
+       struct s_PXENV_UDP_WRITE *pxenv_udp_write;
+};
+
+static inline struct pxe_udp_connection *
+udp_to_pxe ( struct udp_connection *conn ) {
+       return container_of ( conn, struct pxe_udp_connection, udp );
+}
+
+/**
+ * Send PXE UDP data
+ *
+ * @v conn                     UDP connection
+ * @v data                     Temporary data buffer
+ * @v len                      Size of temporary data buffer
+ *
+ * Sends the packet belonging to the current pxenv_udp_write()
+ * operation.
+ */
+static void pxe_udp_senddata ( struct udp_connection *conn, void *data,
+                              size_t len ) {
+       struct pxe_udp_connection *pxe_udp = udp_to_pxe ( conn );
+       struct s_PXENV_UDP_WRITE *pxenv_udp_write = pxe_udp->pxenv_udp_write;
+       userptr_t buffer;
+
+       /* Transmit packet */
+       buffer = real_to_user ( pxenv_udp_write->buffer.segment,
+                               pxenv_udp_write->buffer.offset );
+       if ( len > pxenv_udp_write->buffer_size )
+               len = pxenv_udp_write->buffer_size;
+       copy_from_user ( data, buffer, 0, len );
+       udp_send ( conn, data, len );
+}
+
+/**
+ * Receive PXE UDP data
+ *
+ * @v conn                     UDP connection
+ * @v data                     Received data
+ * @v len                      Length of received data
+ * @v st_src                   Source address
+ * @v st_dest                  Destination address
+ *
+ * Receives a packet as part of the current pxenv_udp_read()
+ * operation.
+ */
+static int pxe_udp_newdata ( struct udp_connection *conn, void *data,
+                            size_t len, struct sockaddr_tcpip *st_src,
+                            struct sockaddr_tcpip *st_dest ) {
+       struct pxe_udp_connection *pxe_udp = udp_to_pxe ( conn );
+       struct s_PXENV_UDP_READ *pxenv_udp_read = pxe_udp->pxenv_udp_read;
+       struct sockaddr_in *sin_src = ( ( struct sockaddr_in * ) st_src );
+       struct sockaddr_in *sin_dest = ( ( struct sockaddr_in * ) st_dest );
+       userptr_t buffer;
+
+       if ( ! pxenv_udp_read ) {
+               DBG ( "PXE discarded UDP packet\n" );
+               return -ENOBUFS;
+       }
+
+       /* Copy packet to buffer and record length */
+       buffer = real_to_user ( pxenv_udp_read->buffer.segment,
+                               pxenv_udp_read->buffer.offset );
+       if ( len > pxenv_udp_read->buffer_size )
+               len = pxenv_udp_read->buffer_size;
+       copy_to_user ( buffer, 0, data, len );
+       pxenv_udp_read->buffer_size = len;
+
+       /* Fill in source/dest information */
+       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;
+       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;
+
+       return 0;
+}
+
+/** PXE UDP operations */
+static struct udp_operations pxe_udp_operations = {
+       .senddata = pxe_udp_senddata,
+       .newdata = pxe_udp_newdata,
+};
+
+/** The PXE UDP connection */
+static struct pxe_udp_connection pxe_udp = {
+       .udp.udp_op = &pxe_udp_operations,
+};
+
 /**
  * UDP OPEN
  *
- * @v udp_open                         Pointer to a struct s_PXENV_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_UNDI_INVALID_STATE NIC could not be initialised
+ * @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().
  * 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.  You cannot
- * have a UDP connection open at the same time as a TFTP connection.
- * (This is not strictly true for Etherboot; see the relevant @ref
- * pxe_note_udp "implementation note" for more details.)
+ * 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
  * 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 *udp_open ) {
+PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *pxenv_udp_open ) {
+       struct in_addr new_ip = { .s_addr = pxenv_udp_open->src_ip };
+
        DBG ( "PXENV_UDP_OPEN" );
-       ENSURE_READY ( udp_open );
 
-       if ( udp_open->src_ip &&
-            udp_open->src_ip != arptable[ARP_CLIENT].ipaddr.s_addr ) {
-               /* Overwrite our IP address */
-               DBG ( " with new IP %@", udp_open->src_ip );
-               arptable[ARP_CLIENT].ipaddr.s_addr = udp_open->src_ip;
+       /* Check connection is not already open */
+       if ( pxe_udp.open ) {
+               pxenv_udp_open->Status = PXENV_STATUS_UDP_OPEN;
+               return PXENV_EXIT_FAILURE;
+       }
+
+       /* Set IP address if specified */
+       if ( new_ip.s_addr ) {
+               /* FIXME: actually do something here */
+               DBG ( " with new IP address %s", inet_ntoa ( new_ip ) );
+       }
+
+       /* Open UDP connection */
+       if ( udp_open ( &pxe_udp.udp, 0 ) != 0 ) {
+               pxenv_udp_open->Status = PXENV_STATUS_OUT_OF_RESOURCES;
+               return PXENV_EXIT_FAILURE;
        }
+       pxe_udp.open = 1;
 
-       udp_open->Status = PXENV_STATUS_SUCCESS;
+       pxenv_udp_open->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
 }
 
 /**
  * UDP CLOSE
  *
- * @v udp_close                                Pointer to a struct s_PXENV_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().
+ * 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.  (This is not strictly true for
- * Etherboot; see the relevant @ref pxe_note_udp "implementation note"
- * for more details.)
+ * 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
@@ -99,16 +221,27 @@ PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *udp_open ) {
  * @ref pxe_x86_pmode16 "implementation note" for more details.)
  *
  */
-PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *udp_close __unused ) {
+PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *pxenv_udp_close ) {
        DBG ( "PXENV_UDP_CLOSE" );
-       udp_close->Status = PXENV_STATUS_SUCCESS;
+
+       /* Check connection is open */
+       if ( ! pxe_udp.open ) {
+               pxenv_udp_close->Status = PXENV_STATUS_UDP_CLOSED;
+               return PXENV_EXIT_SUCCESS; /* Well, it *is* closed */
+       }
+
+       /* Close UDP connection */
+       udp_close ( &pxe_udp.udp );
+       pxe_udp.open = 0;
+
+       pxenv_udp_close->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
 }
 
 /**
  * UDP WRITE
  *
- * @v udp_write                                Pointer to a struct s_PXENV_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
@@ -118,9 +251,8 @@ PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *udp_close __unused ) {
  * @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_UNDI_INVALID_STATE NIC could not be initialised
- * @err #PXENV_STATUS_OUT_OF_RESOURCES Packet was too large to transmit
- * @err other                          Any error from pxenv_undi_transmit()
+ * @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
@@ -136,116 +268,64 @@ PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *udp_close __unused ) {
  * 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().  (This is not strictly true for
- * Etherboot; see the relevant @ref pxe_note_udp "implementation note"
- * for more details.)
+ * 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 *udp_write ) {
-       uint16_t src_port;
-       uint16_t dst_port;
-       struct udppacket *packet = (struct udppacket *)nic.packet;
-       int packet_size;
+PXENV_EXIT_t pxenv_udp_write ( struct s_PXENV_UDP_WRITE *pxenv_udp_write ) {
+       union {
+               struct sockaddr_in sin;
+               struct sockaddr_tcpip st;
+       } dest;
 
        DBG ( "PXENV_UDP_WRITE" );
-       ENSURE_READY ( udp_write );
-
-       /* PXE spec says source port is 2069 if not specified */
-       src_port = ntohs(udp_write->src_port);
-       if ( src_port == 0 ) src_port = 2069;
-       dst_port = ntohs(udp_write->dst_port);
-       DBG ( " %d->%@:%d (%d)", src_port, udp_write->ip, dst_port,
-             udp_write->buffer_size );
-       
+
+       /* Check connection is open */
+       if ( ! pxe_udp.open ) {
+               pxenv_udp_write->Status = PXENV_STATUS_UDP_CLOSED;
+               return PXENV_EXIT_FAILURE;
+       }
+
+       /* Construct destination socket address */
+       memset ( &dest, 0, sizeof ( dest ) );
+       dest.sin.sin_family = AF_INET;
+       dest.sin.sin_addr.s_addr = pxenv_udp_write->ip;
+       dest.sin.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.
+        */
+       if ( ! pxenv_udp_write->src_port )
+               pxenv_udp_write->src_port = htons ( 2069 );
+       udp_bind ( &pxe_udp.udp, pxenv_udp_write->src_port );
+
        /* 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.
         */
        
-       /* Copy payload to packet buffer */
-       packet_size = ( (void*)&packet->payload - (void*)packet )
-               + udp_write->buffer_size;
-       if ( packet_size > ETH_FRAME_LEN ) {
-               udp_write->Status = PXENV_STATUS_OUT_OF_RESOURCES;
-               return PXENV_EXIT_FAILURE;
-       }
-       memcpy ( &packet->payload, SEGOFF16_TO_PTR(udp_write->buffer),
-                udp_write->buffer_size );
-
        /* Transmit packet */
-       if ( ! udp_transmit ( udp_write->ip, src_port, dst_port,
-                             packet_size, packet ) ) {
-               udp_write->Status = errno;
+       if ( udp_senddata ( &pxe_udp.udp ) != 0 ) {
+               pxenv_udp_write->Status = PXENV_STATUS_UNDI_TRANSMIT_ERROR;
                return PXENV_EXIT_FAILURE;
        }
 
-       udp_write->Status = PXENV_STATUS_SUCCESS;
+       pxenv_udp_write->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
 }
 
-/* Utility function for pxenv_udp_read() */
-static int await_pxe_udp ( int ival __unused, void *ptr,
-                          unsigned short ptype __unused,
-                          struct iphdr *ip, struct udphdr *udp,
-                          struct tcphdr *tcp __unused ) {
-       struct s_PXENV_UDP_READ *udp_read = (struct s_PXENV_UDP_READ*)ptr;
-       uint16_t d_port;
-       size_t size;
-
-       /* Ignore non-UDP packets */
-       if ( !udp ) {
-               DBG ( " non-UDP" );
-               return 0;
-       }
-       
-       /* Check dest_ip */
-       if ( udp_read->dest_ip && ( udp_read->dest_ip != ip->dest.s_addr ) ) {
-               DBG ( " wrong dest IP (got %@, wanted %@)",
-                     ip->dest.s_addr, udp_read->dest_ip );
-               return 0;
-       }
-
-       /* Check dest_port */
-       d_port = ntohs ( udp_read->d_port );
-       if ( d_port && ( d_port != ntohs(udp->dest) ) ) {
-               DBG ( " wrong dest port (got %d, wanted %d)",
-                     ntohs(udp->dest), d_port );
-               return 0;
-       }
-
-       /* Copy packet to buffer and fill in information */
-       udp_read->src_ip = ip->src.s_addr;
-       udp_read->s_port = udp->src; /* Both in network order */
-       size = ntohs(udp->len) - sizeof(*udp);
-       /* Workaround: NTLDR expects us to fill these in, even though
-        * PXESPEC clearly defines them as input parameters.
-        */
-       udp_read->dest_ip = ip->dest.s_addr;
-       udp_read->d_port = udp->dest;
-       DBG ( " %@:%d->%@:%d (%d)",
-             udp_read->src_ip, ntohs(udp_read->s_port),
-             udp_read->dest_ip, ntohs(udp_read->d_port), size );
-       if ( udp_read->buffer_size < size ) {
-               /* PXESPEC: what error code should we actually return? */
-               DBG ( " buffer too small (%d)", udp_read->buffer_size );
-               udp_read->Status = PXENV_STATUS_OUT_OF_RESOURCES;
-               return 0;
-       }
-       memcpy ( SEGOFF16_TO_PTR ( udp_read->buffer ), &udp->payload, size );
-       udp_read->buffer_size = size;
-
-       return 1;
-}
-
 /**
  * UDP READ
  *
- * @v udp_read                         Pointer to a struct s_PXENV_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
@@ -258,8 +338,7 @@ static int await_pxe_udp ( int ival __unused, void *ptr,
  * @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_UNDI_INVALID_STATE NIC could not be initialised
- * @err #PXENV_STATUS_OUT_OF_RESOURCES Buffer was too small for 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
@@ -273,9 +352,7 @@ static int await_pxe_udp ( int ival __unused, void *ptr,
  * 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().  (This is not strictly true for
- * Etherboot; see the relevant @ref pxe_note_udp "implementation note"
- * for more details.)
+ * 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
@@ -288,45 +365,40 @@ static int await_pxe_udp ( int ival __unused, void *ptr,
  * expects us to do so, and will fail if we don't.
  *
  */
-PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *udp_read ) {
+PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *pxenv_udp_read ) {
+       struct in_addr dest_ip = { .s_addr = pxenv_udp_read->dest_ip };
+       uint16_t d_port = pxenv_udp_read->d_port;
+
        DBG ( "PXENV_UDP_READ" );
-       ENSURE_READY ( udp_read );
 
-       /* Use await_reply with a timeout of zero */
-       /* Allow await_reply to change Status if necessary */
-       udp_read->Status = PXENV_STATUS_FAILURE;
-       if ( ! await_reply ( await_pxe_udp, 0, udp_read, 0 ) ) {
+       /* Check connection is open */
+       if ( ! pxe_udp.open ) {
+               pxenv_udp_read->Status = PXENV_STATUS_UDP_CLOSED;
                return PXENV_EXIT_FAILURE;
        }
 
-       udp_read->Status = PXENV_STATUS_SUCCESS;
+       /* Bind promiscuously; we will do our own filtering */
+       udp_bind_promisc ( &pxe_udp.udp );
+
+       /* 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;
+       }
+
+       /* Filter on destination address and/or port */
+       if ( dest_ip.s_addr && ( dest_ip.s_addr != pxenv_udp_read->dest_ip ) )
+               goto no_packet;
+       if ( d_port && ( d_port != pxenv_udp_read->d_port ) )
+               goto no_packet;
+
+       pxenv_udp_read->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
-}
 
-/** @page pxe_notes Etherboot PXE implementation notes
-
-@section pxe_note_udp The connectionless nature of UDP
-
-The PXE specification states that it is possible to have only one open
-UDP or TFTP connection at any one time.  Etherboot does not
-rigourously enforce this restriction, on the UNIX principle that the
-code should not prevent the user from doing stupid things, because
-that would also prevent the user from doing clever things.  Since UDP
-is a connectionless protocol, it is perfectly possible to have
-multiple concurrent UDP "connections" open, provided that you take the
-multiplicity of connections into account when calling
-pxenv_udp_read().  Similarly, there is no technical reason that
-prevents you from calling pxenv_udp_write() in the middle of a TFTP
-download.
-
-Etherboot will therefore never return error codes indicating "a
-connection is already open", such as #PXENV_STATUS_UDP_OPEN.  If you
-want to have multiple concurrent connections, go for it (but don't
-expect your perfectly sensible code to work with any other PXE stack).
-
-Since Etherboot treats UDP as the connectionless protocol that it
-really is, pxenv_udp_close() is actually a no-op, and there is no need
-to call pxenv_udp_open() before using pxenv_udp_write() or
-pxenv_udp_read().
-
-*/
+ no_packet:
+       pxenv_udp_read->Status = PXENV_STATUS_FAILURE;
+       return PXENV_EXIT_FAILURE;
+}
index b6e7463..fbc7867 100644 (file)
@@ -22,6 +22,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#if 0
+
 #include "pxe.h"
 
 typedef struct {
@@ -536,3 +538,5 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
        undi_isr->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
 }
+
+#endif
index eb640ad..9f55c94 100644 (file)
@@ -66,6 +66,18 @@ void udp_connect ( struct udp_connection *conn, struct sockaddr_tcpip *peer ) {
        memcpy ( &conn->peer, peer, sizeof ( conn->peer ) );
 }
 
+/**
+ * Connect UDP connection to all remote hosts and ports
+ *
+ * @v conn             UDP connection
+ *
+ * This undoes the effect of a call to udp_connect(), i.e. allows the
+ * connection to receive packets from all remote hosts and ports.
+ */
+void udp_connect_promisc ( struct udp_connection *conn ) {
+       memset ( &conn->peer, 0, sizeof ( conn->peer ) );
+}
+
 /**
  * Open a local port
  *