iPXE
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 <ipxe/iobuf.h>
00010 #include <ipxe/xfer.h>
00011 #include <ipxe/udp.h>
00012 #include <ipxe/uaccess.h>
00013 #include <ipxe/process.h>
00014 #include <ipxe/netdevice.h>
00015 #include <realmode.h>
00016 #include <pxe.h>
00017 
00018 /*
00019  * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
00020  *
00021  * This program is free software; you can redistribute it and/or
00022  * modify it under the terms of the GNU General Public License as
00023  * published by the Free Software Foundation; either version 2 of the
00024  * License, or any later version.
00025  *
00026  * This program is distributed in the hope that it will be useful, but
00027  * WITHOUT ANY WARRANTY; without even the implied warranty of
00028  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00029  * General Public License for more details.
00030  *
00031  * You should have received a copy of the GNU General Public License
00032  * along with this program; if not, write to the Free Software
00033  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00034  * 02110-1301, USA.
00035  *
00036  * You can also choose to distribute this program under the terms of
00037  * the Unmodified Binary Distribution Licence (as given in the file
00038  * COPYING.UBDL), provided that you have satisfied its requirements.
00039  */
00040 
00041 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00042 
00043 /** A PXE UDP pseudo-header */
00044 struct pxe_udp_pseudo_header {
00045         /** Source IP address */
00046         IP4_t src_ip;
00047         /** Source port */
00048         UDP_PORT_t s_port;
00049         /** Destination IP address */
00050         IP4_t dest_ip;
00051         /** Destination port */
00052         UDP_PORT_t d_port;
00053 } __attribute__ (( packed ));
00054 
00055 /** A PXE UDP connection */
00056 struct pxe_udp_connection {
00057         /** Data transfer interface to UDP stack */
00058         struct interface xfer;
00059         /** Local address */
00060         struct sockaddr_in local;
00061         /** List of received packets */
00062         struct list_head list;
00063 };
00064 
00065 /**
00066  * Receive PXE UDP data
00067  *
00068  * @v pxe_udp                   PXE UDP connection
00069  * @v iobuf                     I/O buffer
00070  * @v meta                      Data transfer metadata
00071  * @ret rc                      Return status code
00072  *
00073  * Receives a packet as part of the current pxenv_udp_read()
00074  * operation.
00075  */
00076 static int pxe_udp_deliver ( struct pxe_udp_connection *pxe_udp,
00077                              struct io_buffer *iobuf,
00078                              struct xfer_metadata *meta ) {
00079         struct pxe_udp_pseudo_header *pshdr;
00080         struct sockaddr_in *sin_src;
00081         struct sockaddr_in *sin_dest;
00082         int rc;
00083 
00084         /* Extract metadata */
00085         assert ( meta );
00086         sin_src = ( struct sockaddr_in * ) meta->src;
00087         assert ( sin_src );
00088         assert ( sin_src->sin_family == AF_INET );
00089         sin_dest = ( struct sockaddr_in * ) meta->dest;
00090         assert ( sin_dest );
00091         assert ( sin_dest->sin_family == AF_INET );
00092 
00093         /* Construct pseudo-header */
00094         if ( ( rc = iob_ensure_headroom ( iobuf, sizeof ( *pshdr ) ) ) != 0 ) {
00095                 DBG ( "PXE could not prepend pseudo-header\n" );
00096                 rc = -ENOMEM;
00097                 goto drop;
00098         }
00099         pshdr = iob_push ( iobuf, sizeof ( *pshdr ) );
00100         pshdr->src_ip = sin_src->sin_addr.s_addr;
00101         pshdr->s_port = sin_src->sin_port;
00102         pshdr->dest_ip = sin_dest->sin_addr.s_addr;
00103         pshdr->d_port = sin_dest->sin_port;
00104 
00105         /* Add to queue */
00106         list_add_tail ( &iobuf->list, &pxe_udp->list );
00107 
00108         return 0;
00109 
00110  drop:
00111         free_iob ( iobuf );
00112         return rc;
00113 }
00114 
00115 /** PXE UDP data transfer interface operations */
00116 static struct interface_operation pxe_udp_xfer_operations[] = {
00117         INTF_OP ( xfer_deliver, struct pxe_udp_connection *, pxe_udp_deliver ),
00118 };
00119 
00120 /** PXE UDP data transfer interface descriptor */
00121 static struct interface_descriptor pxe_udp_xfer_desc =
00122         INTF_DESC ( struct pxe_udp_connection, xfer, pxe_udp_xfer_operations );
00123 
00124 /** The PXE UDP connection */
00125 static struct pxe_udp_connection pxe_udp = {
00126         .xfer = INTF_INIT ( pxe_udp_xfer_desc ),
00127         .local = {
00128                 .sin_family = AF_INET,
00129         },
00130         .list = LIST_HEAD_INIT ( pxe_udp.list ),
00131 };
00132 
00133 /**
00134  * UDP OPEN
00135  *
00136  * @v pxenv_udp_open                    Pointer to a struct s_PXENV_UDP_OPEN
00137  * @v s_PXENV_UDP_OPEN::src_ip          IP address of this station, or 0.0.0.0
00138  * @ret #PXENV_EXIT_SUCCESS             Always
00139  * @ret s_PXENV_UDP_OPEN::Status        PXE status code
00140  * @err #PXENV_STATUS_UDP_OPEN          UDP connection already open
00141  * @err #PXENV_STATUS_OUT_OF_RESOURCES  Could not open connection
00142  *
00143  * Prepares the PXE stack for communication using pxenv_udp_write()
00144  * and pxenv_udp_read().
00145  *
00146  * The IP address supplied in s_PXENV_UDP_OPEN::src_ip will be
00147  * recorded and used as the local station's IP address for all further
00148  * communication, including communication by means other than
00149  * pxenv_udp_write() and pxenv_udp_read().  (If
00150  * s_PXENV_UDP_OPEN::src_ip is 0.0.0.0, the local station's IP address
00151  * will remain unchanged.)
00152  *
00153  * You can only have one open UDP connection at a time.  This is not a
00154  * meaningful restriction, since pxenv_udp_write() and
00155  * pxenv_udp_read() allow you to specify arbitrary local and remote
00156  * ports and an arbitrary remote address for each packet.  According
00157  * to the PXE specifiation, you cannot have a UDP connection open at
00158  * the same time as a TFTP connection; this restriction does not apply
00159  * to Etherboot.
00160  *
00161  * On x86, you must set the s_PXE::StatusCallout field to a nonzero
00162  * value before calling this function in protected mode.  You cannot
00163  * call this function with a 32-bit stack segment.  (See the relevant
00164  * @ref pxe_x86_pmode16 "implementation note" for more details.)
00165  *
00166  * @note The PXE specification does not make it clear whether the IP
00167  * address supplied in s_PXENV_UDP_OPEN::src_ip should be used only
00168  * for this UDP connection, or retained for all future communication.
00169  * The latter seems more consistent with typical PXE stack behaviour.
00170  *
00171  * @note Etherboot currently ignores the s_PXENV_UDP_OPEN::src_ip
00172  * parameter.
00173  *
00174  */
00175 static PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *pxenv_udp_open ) {
00176         int rc;
00177 
00178         DBG ( "PXENV_UDP_OPEN" );
00179 
00180         /* Record source IP address */
00181         pxe_udp.local.sin_addr.s_addr = pxenv_udp_open->src_ip;
00182         DBG ( " %s\n", inet_ntoa ( pxe_udp.local.sin_addr ) );
00183 
00184         /* Open network device, if necessary */
00185         if ( pxe_netdev && ( ! netdev_is_open ( pxe_netdev ) ) &&
00186              ( ( rc = netdev_open ( pxe_netdev ) ) != 0 ) ) {
00187                 DBG ( "PXENV_UDP_OPEN could not (implicitly) open %s: %s\n",
00188                       pxe_netdev->name, strerror ( rc ) );
00189                 pxenv_udp_open->Status = PXENV_STATUS ( rc );
00190                 return PXENV_EXIT_FAILURE;
00191         }
00192 
00193         /* Open promiscuous UDP connection */
00194         intf_restart ( &pxe_udp.xfer, 0 );
00195         if ( ( rc = udp_open_promisc ( &pxe_udp.xfer ) ) != 0 ) {
00196                 DBG ( "PXENV_UDP_OPEN could not open promiscuous socket: %s\n",
00197                       strerror ( rc ) );
00198                 pxenv_udp_open->Status = PXENV_STATUS ( rc );
00199                 return PXENV_EXIT_FAILURE;
00200         }
00201 
00202         pxenv_udp_open->Status = PXENV_STATUS_SUCCESS;
00203         return PXENV_EXIT_SUCCESS;
00204 }
00205 
00206 /**
00207  * UDP CLOSE
00208  *
00209  * @v pxenv_udp_close                   Pointer to a struct s_PXENV_UDP_CLOSE
00210  * @ret #PXENV_EXIT_SUCCESS             Always
00211  * @ret s_PXENV_UDP_CLOSE::Status       PXE status code
00212  * @err None                            -
00213  *
00214  * Closes a UDP connection opened with pxenv_udp_open().
00215  *
00216  * You can only have one open UDP connection at a time.  You cannot
00217  * have a UDP connection open at the same time as a TFTP connection.
00218  * You cannot use pxenv_udp_close() to close a TFTP connection; use
00219  * pxenv_tftp_close() instead.
00220  *
00221  * On x86, you must set the s_PXE::StatusCallout field to a nonzero
00222  * value before calling this function in protected mode.  You cannot
00223  * call this function with a 32-bit stack segment.  (See the relevant
00224  * @ref pxe_x86_pmode16 "implementation note" for more details.)
00225  *
00226  */
00227 static PXENV_EXIT_t
00228 pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *pxenv_udp_close ) {
00229         struct io_buffer *iobuf;
00230         struct io_buffer *tmp;
00231 
00232         DBG ( "PXENV_UDP_CLOSE\n" );
00233 
00234         /* Close UDP connection */
00235         intf_restart ( &pxe_udp.xfer, 0 );
00236 
00237         /* Discard any received packets */
00238         list_for_each_entry_safe ( iobuf, tmp, &pxe_udp.list, list ) {
00239                 list_del ( &iobuf->list );
00240                 free_iob ( iobuf );
00241         }
00242 
00243         pxenv_udp_close->Status = PXENV_STATUS_SUCCESS;
00244         return PXENV_EXIT_SUCCESS;
00245 }
00246 
00247 /**
00248  * UDP WRITE
00249  *
00250  * @v pxenv_udp_write                   Pointer to a struct s_PXENV_UDP_WRITE
00251  * @v s_PXENV_UDP_WRITE::ip             Destination IP address
00252  * @v s_PXENV_UDP_WRITE::gw             Relay agent IP address, or 0.0.0.0
00253  * @v s_PXENV_UDP_WRITE::src_port       Source UDP port, or 0
00254  * @v s_PXENV_UDP_WRITE::dst_port       Destination UDP port
00255  * @v s_PXENV_UDP_WRITE::buffer_size    Length of the UDP payload
00256  * @v s_PXENV_UDP_WRITE::buffer         Address of the UDP payload
00257  * @ret #PXENV_EXIT_SUCCESS             Packet was transmitted successfully
00258  * @ret #PXENV_EXIT_FAILURE             Packet could not be transmitted
00259  * @ret s_PXENV_UDP_WRITE::Status       PXE status code
00260  * @err #PXENV_STATUS_UDP_CLOSED        UDP connection is not open
00261  * @err #PXENV_STATUS_UNDI_TRANSMIT_ERROR Could not transmit packet
00262  *
00263  * Transmits a single UDP packet.  A valid IP and UDP header will be
00264  * prepended to the payload in s_PXENV_UDP_WRITE::buffer; the buffer
00265  * should not contain precomputed IP and UDP headers, nor should it
00266  * contain space allocated for these headers.  The first byte of the
00267  * buffer will be transmitted as the first byte following the UDP
00268  * header.
00269  *
00270  * If s_PXENV_UDP_WRITE::gw is 0.0.0.0, normal IP routing will take
00271  * place.  See the relevant @ref pxe_routing "implementation note" for
00272  * more details.
00273  *
00274  * If s_PXENV_UDP_WRITE::src_port is 0, port 2069 will be used.
00275  *
00276  * You must have opened a UDP connection with pxenv_udp_open() before
00277  * calling pxenv_udp_write().
00278  *
00279  * On x86, you must set the s_PXE::StatusCallout field to a nonzero
00280  * value before calling this function in protected mode.  You cannot
00281  * call this function with a 32-bit stack segment.  (See the relevant
00282  * @ref pxe_x86_pmode16 "implementation note" for more details.)
00283  *
00284  * @note Etherboot currently ignores the s_PXENV_UDP_WRITE::gw
00285  * parameter.
00286  *
00287  */
00288 static PXENV_EXIT_t
00289 pxenv_udp_write ( struct s_PXENV_UDP_WRITE *pxenv_udp_write ) {
00290         struct sockaddr_in dest;
00291         struct xfer_metadata meta = {
00292                 .src = ( struct sockaddr * ) &pxe_udp.local,
00293                 .dest = ( struct sockaddr * ) &dest,
00294                 .netdev = pxe_netdev,
00295         };
00296         size_t len;
00297         struct io_buffer *iobuf;
00298         userptr_t buffer;
00299         int rc;
00300 
00301         DBG ( "PXENV_UDP_WRITE" );
00302 
00303         /* Construct destination socket address */
00304         memset ( &dest, 0, sizeof ( dest ) );
00305         dest.sin_family = AF_INET;
00306         dest.sin_addr.s_addr = pxenv_udp_write->ip;
00307         dest.sin_port = pxenv_udp_write->dst_port;
00308 
00309         /* Set local (source) port.  PXE spec says source port is 2069
00310          * if not specified.  Really, this ought to be set at UDP open
00311          * time but hey, we didn't design this API.
00312          */
00313         pxe_udp.local.sin_port = pxenv_udp_write->src_port;
00314         if ( ! pxe_udp.local.sin_port )
00315                 pxe_udp.local.sin_port = htons ( 2069 );
00316 
00317         /* FIXME: we ignore the gateway specified, since we're
00318          * confident of being able to do our own routing.  We should
00319          * probably allow for multiple gateways.
00320          */
00321 
00322         /* Allocate and fill data buffer */
00323         len = pxenv_udp_write->buffer_size;
00324         iobuf = xfer_alloc_iob ( &pxe_udp.xfer, len );
00325         if ( ! iobuf ) {
00326                 DBG ( " out of memory\n" );
00327                 pxenv_udp_write->Status = PXENV_STATUS_OUT_OF_RESOURCES;
00328                 return PXENV_EXIT_FAILURE;
00329         }
00330         buffer = real_to_user ( pxenv_udp_write->buffer.segment,
00331                                 pxenv_udp_write->buffer.offset );
00332         copy_from_user ( iob_put ( iobuf, len ), buffer, 0, len );
00333 
00334         DBG ( " %04x:%04x+%x %d->%s:%d\n", pxenv_udp_write->buffer.segment,
00335               pxenv_udp_write->buffer.offset, pxenv_udp_write->buffer_size,
00336               ntohs ( pxenv_udp_write->src_port ),
00337               inet_ntoa ( dest.sin_addr ),
00338               ntohs ( pxenv_udp_write->dst_port ) );
00339         
00340         /* Transmit packet */
00341         if ( ( rc = xfer_deliver ( &pxe_udp.xfer, iobuf, &meta ) ) != 0 ) {
00342                 DBG ( "PXENV_UDP_WRITE could not transmit: %s\n",
00343                       strerror ( rc ) );
00344                 pxenv_udp_write->Status = PXENV_STATUS ( rc );
00345                 return PXENV_EXIT_FAILURE;
00346         }
00347 
00348         pxenv_udp_write->Status = PXENV_STATUS_SUCCESS;
00349         return PXENV_EXIT_SUCCESS;
00350 }
00351 
00352 /**
00353  * UDP READ
00354  *
00355  * @v pxenv_udp_read                    Pointer to a struct s_PXENV_UDP_READ
00356  * @v s_PXENV_UDP_READ::dest_ip         Destination IP address, or 0.0.0.0
00357  * @v s_PXENV_UDP_READ::d_port          Destination UDP port, or 0
00358  * @v s_PXENV_UDP_READ::buffer_size     Size of the UDP payload buffer
00359  * @v s_PXENV_UDP_READ::buffer          Address of the UDP payload buffer
00360  * @ret #PXENV_EXIT_SUCCESS             A packet has been received
00361  * @ret #PXENV_EXIT_FAILURE             No packet has been received
00362  * @ret s_PXENV_UDP_READ::Status        PXE status code
00363  * @ret s_PXENV_UDP_READ::src_ip        Source IP address
00364  * @ret s_PXENV_UDP_READ::dest_ip       Destination IP address
00365  * @ret s_PXENV_UDP_READ::s_port        Source UDP port
00366  * @ret s_PXENV_UDP_READ::d_port        Destination UDP port
00367  * @ret s_PXENV_UDP_READ::buffer_size   Length of UDP payload
00368  * @err #PXENV_STATUS_UDP_CLOSED        UDP connection is not open
00369  * @err #PXENV_STATUS_FAILURE           No packet was ready to read
00370  *
00371  * Receive a single UDP packet.  This is a non-blocking call; if no
00372  * packet is ready to read, the call will return instantly with
00373  * s_PXENV_UDP_READ::Status==PXENV_STATUS_FAILURE.
00374  *
00375  * If s_PXENV_UDP_READ::dest_ip is 0.0.0.0, UDP packets addressed to
00376  * any IP address will be accepted and may be returned to the caller.
00377  *
00378  * If s_PXENV_UDP_READ::d_port is 0, UDP packets addressed to any UDP
00379  * port will be accepted and may be returned to the caller.
00380  *
00381  * You must have opened a UDP connection with pxenv_udp_open() before
00382  * calling pxenv_udp_read().
00383  *
00384  * On x86, you must set the s_PXE::StatusCallout field to a nonzero
00385  * value before calling this function in protected mode.  You cannot
00386  * call this function with a 32-bit stack segment.  (See the relevant
00387  * @ref pxe_x86_pmode16 "implementation note" for more details.)
00388  *
00389  * @note The PXE specification (version 2.1) does not state that we
00390  * should fill in s_PXENV_UDP_READ::dest_ip and
00391  * s_PXENV_UDP_READ::d_port, but Microsoft Windows' NTLDR program
00392  * expects us to do so, and will fail if we don't.
00393  *
00394  */
00395 static PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *pxenv_udp_read ) {
00396         struct in_addr dest_ip_wanted = { .s_addr = pxenv_udp_read->dest_ip };
00397         struct in_addr dest_ip;
00398         struct io_buffer *iobuf;
00399         struct pxe_udp_pseudo_header *pshdr;
00400         uint16_t d_port_wanted = pxenv_udp_read->d_port;
00401         uint16_t d_port;
00402         userptr_t buffer;
00403         size_t len;
00404 
00405         /* Try receiving a packet, if the queue is empty */
00406         if ( list_empty ( &pxe_udp.list ) )
00407                 step();
00408 
00409         /* Remove first packet from the queue */
00410         iobuf = list_first_entry ( &pxe_udp.list, struct io_buffer, list );
00411         if ( ! iobuf ) {
00412                 /* No packet received */
00413                 DBG2 ( "PXENV_UDP_READ\n" );
00414                 goto no_packet;
00415         }
00416         list_del ( &iobuf->list );
00417 
00418         /* Strip pseudo-header */
00419         assert ( iob_len ( iobuf ) >= sizeof ( *pshdr ) );
00420         pshdr = iobuf->data;
00421         iob_pull ( iobuf, sizeof ( *pshdr ) );
00422         dest_ip.s_addr = pshdr->dest_ip;
00423         d_port = pshdr->d_port;
00424         DBG ( "PXENV_UDP_READ" );
00425 
00426         /* Filter on destination address and/or port */
00427         if ( dest_ip_wanted.s_addr &&
00428              ( dest_ip_wanted.s_addr != dest_ip.s_addr ) ) {
00429                 DBG ( " wrong IP %s", inet_ntoa ( dest_ip ) );
00430                 DBG ( " (wanted %s)\n", inet_ntoa ( dest_ip_wanted ) );
00431                 goto drop;
00432         }
00433         if ( d_port_wanted && ( d_port_wanted != d_port ) ) {
00434                 DBG ( " wrong port %d", htons ( d_port ) );
00435                 DBG ( " (wanted %d)\n", htons ( d_port_wanted ) );
00436                 goto drop;
00437         }
00438 
00439         /* Copy packet to buffer and record length */
00440         buffer = real_to_user ( pxenv_udp_read->buffer.segment,
00441                                 pxenv_udp_read->buffer.offset );
00442         len = iob_len ( iobuf );
00443         if ( len > pxenv_udp_read->buffer_size )
00444                 len = pxenv_udp_read->buffer_size;
00445         copy_to_user ( buffer, 0, iobuf->data, len );
00446         pxenv_udp_read->buffer_size = len;
00447 
00448         /* Fill in source/dest information */
00449         pxenv_udp_read->src_ip = pshdr->src_ip;
00450         pxenv_udp_read->s_port = pshdr->s_port;
00451         pxenv_udp_read->dest_ip = pshdr->dest_ip;
00452         pxenv_udp_read->d_port = pshdr->d_port;
00453 
00454         DBG ( " %04x:%04x+%x %s:", pxenv_udp_read->buffer.segment,
00455               pxenv_udp_read->buffer.offset, pxenv_udp_read->buffer_size,
00456               inet_ntoa ( *( ( struct in_addr * ) &pxenv_udp_read->src_ip ) ));
00457         DBG ( "%d<-%s:%d\n",  ntohs ( pxenv_udp_read->s_port ),
00458               inet_ntoa ( *( ( struct in_addr * ) &pxenv_udp_read->dest_ip ) ),
00459               ntohs ( pxenv_udp_read->d_port ) );
00460 
00461         /* Free I/O buffer */
00462         free_iob ( iobuf );
00463 
00464         pxenv_udp_read->Status = PXENV_STATUS_SUCCESS;
00465         return PXENV_EXIT_SUCCESS;
00466 
00467  drop:
00468         free_iob ( iobuf );
00469  no_packet:
00470         pxenv_udp_read->Status = PXENV_STATUS_FAILURE;
00471         return PXENV_EXIT_FAILURE;
00472 }
00473 
00474 /** PXE UDP API */
00475 struct pxe_api_call pxe_udp_api[] __pxe_api_call = {
00476         PXE_API_CALL ( PXENV_UDP_OPEN, pxenv_udp_open,
00477                        struct s_PXENV_UDP_OPEN ),
00478         PXE_API_CALL ( PXENV_UDP_CLOSE, pxenv_udp_close,
00479                        struct s_PXENV_UDP_CLOSE ),
00480         PXE_API_CALL ( PXENV_UDP_WRITE, pxenv_udp_write,
00481                        struct s_PXENV_UDP_WRITE ),
00482         PXE_API_CALL ( PXENV_UDP_READ, pxenv_udp_read,
00483                        struct s_PXENV_UDP_READ ),
00484 };