pxe_udp.c

Go to the documentation of this file.
00001 /** @file
00002  *
00003  * PXE UDP API
00004  *
00005  */
00006 
00007 #include <string.h>
00008 #include <byteswap.h>
00009 #include <gpxe/xfer.h>
00010 #include <gpxe/udp.h>
00011 #include <gpxe/uaccess.h>
00012 #include <gpxe/process.h>
00013 #include <pxe.h>
00014 
00015 /*
00016  * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
00017  *
00018  * This program is free software; you can redistribute it and/or
00019  * modify it under the terms of the GNU General Public License as
00020  * published by the Free Software Foundation; either version 2 of the
00021  * License, or any later version.
00022  *
00023  * This program is distributed in the hope that it will be useful, but
00024  * WITHOUT ANY WARRANTY; without even the implied warranty of
00025  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00026  * General Public License for more details.
00027  *
00028  * You should have received a copy of the GNU General Public License
00029  * along with this program; if not, write to the Free Software
00030  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00031  */
00032 
00033 FILE_LICENCE ( GPL2_OR_LATER );
00034 
00035 /** A PXE UDP connection */
00036 struct pxe_udp_connection {
00037         /** Data transfer interface to UDP stack */
00038         struct xfer_interface xfer;
00039         /** Local address */
00040         struct sockaddr_in local;
00041         /** Current PXENV_UDP_READ parameter block */
00042         struct s_PXENV_UDP_READ *pxenv_udp_read;
00043 };
00044 
00045 /**
00046  * Receive PXE UDP data
00047  *
00048  * @v xfer                      Data transfer interface
00049  * @v iobuf                     I/O buffer
00050  * @v meta                      Data transfer metadata
00051  * @ret rc                      Return status code
00052  *
00053  * Receives a packet as part of the current pxenv_udp_read()
00054  * operation.
00055  */
00056 static int pxe_udp_deliver_iob ( struct xfer_interface *xfer,
00057                                  struct io_buffer *iobuf,
00058                                  struct xfer_metadata *meta ) {
00059         struct pxe_udp_connection *pxe_udp = 
00060                 container_of ( xfer, struct pxe_udp_connection, xfer );
00061         struct s_PXENV_UDP_READ *pxenv_udp_read = pxe_udp->pxenv_udp_read;
00062         struct sockaddr_in *sin_src;
00063         struct sockaddr_in *sin_dest;
00064         userptr_t buffer;
00065         size_t len;
00066         int rc = 0;
00067 
00068         if ( ! pxenv_udp_read ) {
00069                 DBG ( "PXE discarded UDP packet\n" );
00070                 rc = -ENOBUFS;
00071                 goto done;
00072         }
00073 
00074         /* Copy packet to buffer and record length */
00075         buffer = real_to_user ( pxenv_udp_read->buffer.segment,
00076                                 pxenv_udp_read->buffer.offset );
00077         len = iob_len ( iobuf );
00078         if ( len > pxenv_udp_read->buffer_size )
00079                 len = pxenv_udp_read->buffer_size;
00080         copy_to_user ( buffer, 0, iobuf->data, len );
00081         pxenv_udp_read->buffer_size = len;
00082 
00083         /* Fill in source/dest information */
00084         assert ( meta );
00085         sin_src = ( struct sockaddr_in * ) meta->src;
00086         assert ( sin_src );
00087         assert ( sin_src->sin_family == AF_INET );
00088         pxenv_udp_read->src_ip = sin_src->sin_addr.s_addr;
00089         pxenv_udp_read->s_port = sin_src->sin_port;
00090         sin_dest = ( struct sockaddr_in * ) meta->dest;
00091         assert ( sin_dest );
00092         assert ( sin_dest->sin_family == AF_INET );
00093         pxenv_udp_read->dest_ip = sin_dest->sin_addr.s_addr;
00094         pxenv_udp_read->d_port = sin_dest->sin_port;
00095 
00096         /* Mark as received */
00097         pxe_udp->pxenv_udp_read = NULL;
00098 
00099  done:
00100         free_iob ( iobuf );
00101         return rc;
00102 }
00103 
00104 /** PXE UDP data transfer interface operations */
00105 static struct xfer_interface_operations pxe_udp_xfer_operations = {
00106         .close          = ignore_xfer_close,
00107         .vredirect      = ignore_xfer_vredirect,
00108         .window         = unlimited_xfer_window,
00109         .alloc_iob      = default_xfer_alloc_iob,
00110         .deliver_iob    = pxe_udp_deliver_iob,
00111         .deliver_raw    = xfer_deliver_as_iob,
00112 };
00113 
00114 /** The PXE UDP connection */
00115 static struct pxe_udp_connection pxe_udp = {
00116         .xfer = XFER_INIT ( &pxe_udp_xfer_operations ),
00117         .local = {
00118                 .sin_family = AF_INET,
00119         },
00120 };
00121 
00122 /**
00123  * UDP OPEN
00124  *
00125  * @v pxenv_udp_open                    Pointer to a struct s_PXENV_UDP_OPEN
00126  * @v s_PXENV_UDP_OPEN::src_ip          IP address of this station, or 0.0.0.0
00127  * @ret #PXENV_EXIT_SUCCESS             Always
00128  * @ret s_PXENV_UDP_OPEN::Status        PXE status code
00129  * @err #PXENV_STATUS_UDP_OPEN          UDP connection already open
00130  * @err #PXENV_STATUS_OUT_OF_RESOURCES  Could not open connection
00131  *
00132  * Prepares the PXE stack for communication using pxenv_udp_write()
00133  * and pxenv_udp_read().
00134  *
00135  * The IP address supplied in s_PXENV_UDP_OPEN::src_ip will be
00136  * recorded and used as the local station's IP address for all further
00137  * communication, including communication by means other than
00138  * pxenv_udp_write() and pxenv_udp_read().  (If
00139  * s_PXENV_UDP_OPEN::src_ip is 0.0.0.0, the local station's IP address
00140  * will remain unchanged.)
00141  *
00142  * You can only have one open UDP connection at a time.  This is not a
00143  * meaningful restriction, since pxenv_udp_write() and
00144  * pxenv_udp_read() allow you to specify arbitrary local and remote
00145  * ports and an arbitrary remote address for each packet.  According
00146  * to the PXE specifiation, you cannot have a UDP connection open at
00147  * the same time as a TFTP connection; this restriction does not apply
00148  * to Etherboot.
00149  *
00150  * On x86, you must set the s_PXE::StatusCallout field to a nonzero
00151  * value before calling this function in protected mode.  You cannot
00152  * call this function with a 32-bit stack segment.  (See the relevant
00153  * @ref pxe_x86_pmode16 "implementation note" for more details.)
00154  *
00155  * @note The PXE specification does not make it clear whether the IP
00156  * address supplied in s_PXENV_UDP_OPEN::src_ip should be used only
00157  * for this UDP connection, or retained for all future communication.
00158  * The latter seems more consistent with typical PXE stack behaviour.
00159  *
00160  * @note Etherboot currently ignores the s_PXENV_UDP_OPEN::src_ip
00161  * parameter.
00162  *
00163  */
00164 PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *pxenv_udp_open ) {
00165         int rc;
00166 
00167         DBG ( "PXENV_UDP_OPEN" );
00168 
00169         /* Record source IP address */
00170         pxe_udp.local.sin_addr.s_addr = pxenv_udp_open->src_ip;
00171         DBG ( " %s", inet_ntoa ( pxe_udp.local.sin_addr ) );
00172 
00173         /* Open promiscuous UDP connection */
00174         xfer_close ( &pxe_udp.xfer, 0 );
00175         if ( ( rc = udp_open_promisc ( &pxe_udp.xfer ) ) != 0 ) {
00176                 pxenv_udp_open->Status = PXENV_STATUS ( rc );
00177                 return PXENV_EXIT_FAILURE;
00178         }
00179 
00180         pxenv_udp_open->Status = PXENV_STATUS_SUCCESS;
00181         return PXENV_EXIT_SUCCESS;
00182 }
00183 
00184 /**
00185  * UDP CLOSE
00186  *
00187  * @v pxenv_udp_close                   Pointer to a struct s_PXENV_UDP_CLOSE
00188  * @ret #PXENV_EXIT_SUCCESS             Always
00189  * @ret s_PXENV_UDP_CLOSE::Status       PXE status code
00190  * @err None                            -
00191  *
00192  * Closes a UDP connection opened with pxenv_udp_open().
00193  *
00194  * You can only have one open UDP connection at a time.  You cannot
00195  * have a UDP connection open at the same time as a TFTP connection.
00196  * You cannot use pxenv_udp_close() to close a TFTP connection; use
00197  * pxenv_tftp_close() instead.
00198  *
00199  * On x86, you must set the s_PXE::StatusCallout field to a nonzero
00200  * value before calling this function in protected mode.  You cannot
00201  * call this function with a 32-bit stack segment.  (See the relevant
00202  * @ref pxe_x86_pmode16 "implementation note" for more details.)
00203  *
00204  */
00205 PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *pxenv_udp_close ) {
00206         DBG ( "PXENV_UDP_CLOSE" );
00207 
00208         /* Close UDP connection */
00209         xfer_close ( &pxe_udp.xfer, 0 );
00210 
00211         pxenv_udp_close->Status = PXENV_STATUS_SUCCESS;
00212         return PXENV_EXIT_SUCCESS;
00213 }
00214 
00215 /**
00216  * UDP WRITE
00217  *
00218  * @v pxenv_udp_write                   Pointer to a struct s_PXENV_UDP_WRITE
00219  * @v s_PXENV_UDP_WRITE::ip             Destination IP address
00220  * @v s_PXENV_UDP_WRITE::gw             Relay agent IP address, or 0.0.0.0
00221  * @v s_PXENV_UDP_WRITE::src_port       Source UDP port, or 0
00222  * @v s_PXENV_UDP_WRITE::dst_port       Destination UDP port
00223  * @v s_PXENV_UDP_WRITE::buffer_size    Length of the UDP payload
00224  * @v s_PXENV_UDP_WRITE::buffer         Address of the UDP payload
00225  * @ret #PXENV_EXIT_SUCCESS             Packet was transmitted successfully
00226  * @ret #PXENV_EXIT_FAILURE             Packet could not be transmitted
00227  * @ret s_PXENV_UDP_WRITE::Status       PXE status code
00228  * @err #PXENV_STATUS_UDP_CLOSED        UDP connection is not open
00229  * @err #PXENV_STATUS_UNDI_TRANSMIT_ERROR Could not transmit packet
00230  *
00231  * Transmits a single UDP packet.  A valid IP and UDP header will be
00232  * prepended to the payload in s_PXENV_UDP_WRITE::buffer; the buffer
00233  * should not contain precomputed IP and UDP headers, nor should it
00234  * contain space allocated for these headers.  The first byte of the
00235  * buffer will be transmitted as the first byte following the UDP
00236  * header.
00237  *
00238  * If s_PXENV_UDP_WRITE::gw is 0.0.0.0, normal IP routing will take
00239  * place.  See the relevant @ref pxe_routing "implementation note" for
00240  * more details.
00241  *
00242  * If s_PXENV_UDP_WRITE::src_port is 0, port 2069 will be used.
00243  *
00244  * You must have opened a UDP connection with pxenv_udp_open() before
00245  * calling pxenv_udp_write().
00246  *
00247  * On x86, you must set the s_PXE::StatusCallout field to a nonzero
00248  * value before calling this function in protected mode.  You cannot
00249  * call this function with a 32-bit stack segment.  (See the relevant
00250  * @ref pxe_x86_pmode16 "implementation note" for more details.)
00251  *
00252  * @note Etherboot currently ignores the s_PXENV_UDP_WRITE::gw
00253  * parameter.
00254  *
00255  */
00256 PXENV_EXIT_t pxenv_udp_write ( struct s_PXENV_UDP_WRITE *pxenv_udp_write ) {
00257         struct sockaddr_in dest;
00258         struct xfer_metadata meta = {
00259                 .src = ( struct sockaddr * ) &pxe_udp.local,
00260                 .dest = ( struct sockaddr * ) &dest,
00261                 .netdev = pxe_netdev,
00262         };
00263         size_t len;
00264         struct io_buffer *iobuf;
00265         userptr_t buffer;
00266         int rc;
00267 
00268         DBG ( "PXENV_UDP_WRITE" );
00269 
00270         /* Construct destination socket address */
00271         memset ( &dest, 0, sizeof ( dest ) );
00272         dest.sin_family = AF_INET;
00273         dest.sin_addr.s_addr = pxenv_udp_write->ip;
00274         dest.sin_port = pxenv_udp_write->dst_port;
00275 
00276         /* Set local (source) port.  PXE spec says source port is 2069
00277          * if not specified.  Really, this ought to be set at UDP open
00278          * time but hey, we didn't design this API.
00279          */
00280         pxe_udp.local.sin_port = pxenv_udp_write->src_port;
00281         if ( ! pxe_udp.local.sin_port )
00282                 pxe_udp.local.sin_port = htons ( 2069 );
00283 
00284         /* FIXME: we ignore the gateway specified, since we're
00285          * confident of being able to do our own routing.  We should
00286          * probably allow for multiple gateways.
00287          */
00288 
00289         /* Allocate and fill data buffer */
00290         len = pxenv_udp_write->buffer_size;
00291         iobuf = xfer_alloc_iob ( &pxe_udp.xfer, len );
00292         if ( ! iobuf ) {
00293                 pxenv_udp_write->Status = PXENV_STATUS_OUT_OF_RESOURCES;
00294                 return PXENV_EXIT_FAILURE;
00295         }
00296         buffer = real_to_user ( pxenv_udp_write->buffer.segment,
00297                                 pxenv_udp_write->buffer.offset );
00298         copy_from_user ( iob_put ( iobuf, len ), buffer, 0, len );
00299 
00300         DBG ( " %04x:%04x+%x %d->%s:%d", pxenv_udp_write->buffer.segment,
00301               pxenv_udp_write->buffer.offset, pxenv_udp_write->buffer_size,
00302               ntohs ( pxenv_udp_write->src_port ),
00303               inet_ntoa ( dest.sin_addr ),
00304               ntohs ( pxenv_udp_write->dst_port ) );
00305         
00306         /* Transmit packet */
00307         if ( ( rc = xfer_deliver_iob_meta ( &pxe_udp.xfer, iobuf,
00308                                             &meta ) ) != 0 ) {
00309                 pxenv_udp_write->Status = PXENV_STATUS ( rc );
00310                 return PXENV_EXIT_FAILURE;
00311         }
00312 
00313         pxenv_udp_write->Status = PXENV_STATUS_SUCCESS;
00314         return PXENV_EXIT_SUCCESS;
00315 }
00316 
00317 /**
00318  * UDP READ
00319  *
00320  * @v pxenv_udp_read                    Pointer to a struct s_PXENV_UDP_READ
00321  * @v s_PXENV_UDP_READ::dest_ip         Destination IP address, or 0.0.0.0
00322  * @v s_PXENV_UDP_READ::d_port          Destination UDP port, or 0
00323  * @v s_PXENV_UDP_READ::buffer_size     Size of the UDP payload buffer
00324  * @v s_PXENV_UDP_READ::buffer          Address of the UDP payload buffer
00325  * @ret #PXENV_EXIT_SUCCESS             A packet has been received
00326  * @ret #PXENV_EXIT_FAILURE             No packet has been received
00327  * @ret s_PXENV_UDP_READ::Status        PXE status code
00328  * @ret s_PXENV_UDP_READ::src_ip        Source IP address
00329  * @ret s_PXENV_UDP_READ::dest_ip       Destination IP address
00330  * @ret s_PXENV_UDP_READ::s_port        Source UDP port
00331  * @ret s_PXENV_UDP_READ::d_port        Destination UDP port
00332  * @ret s_PXENV_UDP_READ::buffer_size   Length of UDP payload
00333  * @err #PXENV_STATUS_UDP_CLOSED        UDP connection is not open
00334  * @err #PXENV_STATUS_FAILURE           No packet was ready to read
00335  *
00336  * Receive a single UDP packet.  This is a non-blocking call; if no
00337  * packet is ready to read, the call will return instantly with
00338  * s_PXENV_UDP_READ::Status==PXENV_STATUS_FAILURE.
00339  *
00340  * If s_PXENV_UDP_READ::dest_ip is 0.0.0.0, UDP packets addressed to
00341  * any IP address will be accepted and may be returned to the caller.
00342  *
00343  * If s_PXENV_UDP_READ::d_port is 0, UDP packets addressed to any UDP
00344  * port will be accepted and may be returned to the caller.
00345  *
00346  * You must have opened a UDP connection with pxenv_udp_open() before
00347  * calling pxenv_udp_read().
00348  *
00349  * On x86, you must set the s_PXE::StatusCallout field to a nonzero
00350  * value before calling this function in protected mode.  You cannot
00351  * call this function with a 32-bit stack segment.  (See the relevant
00352  * @ref pxe_x86_pmode16 "implementation note" for more details.)
00353  *
00354  * @note The PXE specification (version 2.1) does not state that we
00355  * should fill in s_PXENV_UDP_READ::dest_ip and
00356  * s_PXENV_UDP_READ::d_port, but Microsoft Windows' NTLDR program
00357  * expects us to do so, and will fail if we don't.
00358  *
00359  */
00360 PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *pxenv_udp_read ) {
00361         struct in_addr dest_ip_wanted = { .s_addr = pxenv_udp_read->dest_ip };
00362         struct in_addr dest_ip;
00363         uint16_t d_port_wanted = pxenv_udp_read->d_port;
00364         uint16_t d_port;
00365 
00366         DBG ( "PXENV_UDP_READ" );
00367 
00368         /* Try receiving a packet */
00369         pxe_udp.pxenv_udp_read = pxenv_udp_read;
00370         step();
00371         if ( pxe_udp.pxenv_udp_read ) {
00372                 /* No packet received */
00373                 pxe_udp.pxenv_udp_read = NULL;
00374                 goto no_packet;
00375         }
00376         dest_ip.s_addr = pxenv_udp_read->dest_ip;
00377         d_port = pxenv_udp_read->d_port;
00378 
00379         /* Filter on destination address and/or port */
00380         if ( dest_ip_wanted.s_addr &&
00381              ( dest_ip_wanted.s_addr != dest_ip.s_addr ) ) {
00382                 DBG ( " wrong IP %s", inet_ntoa ( dest_ip ) );
00383                 DBG ( " (wanted %s)", inet_ntoa ( dest_ip_wanted ) );
00384                 goto no_packet;
00385         }
00386         if ( d_port_wanted && ( d_port_wanted != d_port ) ) {
00387                 DBG ( " wrong port %d ", htons ( d_port ) );
00388                 DBG ( " (wanted %d)", htons ( d_port_wanted ) );
00389                 goto no_packet;
00390         }
00391 
00392         DBG ( " %04x:%04x+%x %s:", pxenv_udp_read->buffer.segment,
00393               pxenv_udp_read->buffer.offset, pxenv_udp_read->buffer_size,
00394               inet_ntoa ( *( ( struct in_addr * ) &pxenv_udp_read->src_ip ) ));
00395         DBG ( "%d<-%s:%d",  ntohs ( pxenv_udp_read->s_port ),
00396               inet_ntoa ( *( ( struct in_addr * ) &pxenv_udp_read->dest_ip ) ),
00397               ntohs ( pxenv_udp_read->d_port ) );
00398 
00399         pxenv_udp_read->Status = PXENV_STATUS_SUCCESS;
00400         return PXENV_EXIT_SUCCESS;
00401 
00402  no_packet:
00403         pxenv_udp_read->Status = PXENV_STATUS_FAILURE;
00404         return PXENV_EXIT_FAILURE;
00405 }

Generated on Tue Apr 6 20:00:51 2010 for gPXE by  doxygen 1.5.7.1