iPXE
Data Structures | Functions | Variables
udp.c File Reference

UDP protocol. More...

#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <byteswap.h>
#include <errno.h>
#include <ipxe/tcpip.h>
#include <ipxe/iobuf.h>
#include <ipxe/xfer.h>
#include <ipxe/open.h>
#include <ipxe/uri.h>
#include <ipxe/netdevice.h>
#include <ipxe/udp.h>

Go to the source code of this file.

Data Structures

struct  udp_connection
 A UDP connection. More...

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static LIST_HEAD (udp_conns)
 List of registered UDP connections.
static int udp_port_available (int port)
 Check if local UDP port is available.
static int udp_open_common (struct interface *xfer, struct sockaddr *peer, struct sockaddr *local, int promisc)
 Open a UDP connection.
int udp_open (struct interface *xfer, struct sockaddr *peer, struct sockaddr *local)
 Open a UDP connection.
int udp_open_promisc (struct interface *xfer)
 Open a promiscuous UDP connection.
static void udp_close (struct udp_connection *udp, int rc)
 Close a UDP connection.
static int udp_tx (struct udp_connection *udp, struct io_buffer *iobuf, struct sockaddr_tcpip *src, struct sockaddr_tcpip *dest, struct net_device *netdev)
 Transmit data via a UDP connection to a specified address.
static struct udp_connectionudp_demux (struct sockaddr_tcpip *local)
 Identify UDP connection by local address.
static int udp_rx (struct io_buffer *iobuf, struct net_device *netdev __unused, struct sockaddr_tcpip *st_src, struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum)
 Process a received packet.
static struct io_bufferudp_xfer_alloc_iob (struct udp_connection *udp, size_t len)
 Allocate I/O buffer for UDP.
static int udp_xfer_deliver (struct udp_connection *udp, struct io_buffer *iobuf, struct xfer_metadata *meta)
 Deliver datagram as I/O buffer.
static int udp_open_uri (struct interface *xfer, struct uri *uri)
 Open UDP URI.

Variables

static struct interface_descriptor udp_xfer_desc
 UDP data transfer interface descriptor.
struct tcpip_protocol udp_protocol __tcpip_protocol
 ICMPv4 TCP/IP protocol.
static struct interface_operation udp_xfer_operations []
 UDP data transfer interface operations.
struct socket_opener
udp_ipv4_socket_opener 
__socket_opener
 UDP IPv4 socket opener.
int udp_sock_dgram = UDP_SOCK_DGRAM
 Linkage hack.
struct uri_opener udp_uri_opener __uri_opener
 UDP URI opener.

Detailed Description

UDP protocol.

Definition in file udp.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
static LIST_HEAD ( udp_conns  ) [static]

List of registered UDP connections.

static int udp_port_available ( int  port) [static]

Check if local UDP port is available.

Parameters:
portLocal port number
Return values:
portLocal port number, or negative error

Definition at line 56 of file udp.c.

References EADDRINUSE, htons, udp_connection::list, list_for_each_entry, udp_connection::local, port, and sockaddr_tcpip::st_port.

Referenced by udp_open_common().

                                           {
        struct udp_connection *udp;

        list_for_each_entry ( udp, &udp_conns, list ) {
                if ( udp->local.st_port == htons ( port ) )
                        return -EADDRINUSE;
        }
        return port;
}
static int udp_open_common ( struct interface xfer,
struct sockaddr peer,
struct sockaddr local,
int  promisc 
) [static]

Open a UDP connection.

Parameters:
xferData transfer interface
peerPeer socket address, or NULL
localLocal socket address, or NULL
promiscSocket is promiscuous
Return values:
rcReturn status code

Definition at line 75 of file udp.c.

References DBGC, ENOMEM, htons, intf_init(), intf_plug_plug(), udp_connection::list, list_add, udp_connection::local, memcpy(), ntohs, NULL, udp_connection::peer, port, rc, ref_init, ref_put, udp_connection::refcnt, sockaddr_tcpip::st_port, strerror(), tcpip_bind(), udp_port_available(), udp_xfer_desc, udp_connection::xfer, and zalloc().

Referenced by udp_open(), and udp_open_promisc().

                                           {
        struct sockaddr_tcpip *st_peer = ( struct sockaddr_tcpip * ) peer;
        struct sockaddr_tcpip *st_local = ( struct sockaddr_tcpip * ) local;
        struct udp_connection *udp;
        int port;
        int rc;

        /* Allocate and initialise structure */
        udp = zalloc ( sizeof ( *udp ) );
        if ( ! udp )
                return -ENOMEM;
        DBGC ( udp, "UDP %p allocated\n", udp );
        ref_init ( &udp->refcnt, NULL );
        intf_init ( &udp->xfer, &udp_xfer_desc, &udp->refcnt );
        if ( st_peer )
                memcpy ( &udp->peer, st_peer, sizeof ( udp->peer ) );
        if ( st_local )
                memcpy ( &udp->local, st_local, sizeof ( udp->local ) );

        /* Bind to local port */
        if ( ! promisc ) {
                port = tcpip_bind ( st_local, udp_port_available );
                if ( port < 0 ) {
                        rc = port;
                        DBGC ( udp, "UDP %p could not bind: %s\n",
                               udp, strerror ( rc ) );
                        goto err;
                }
                udp->local.st_port = htons ( port );
                DBGC ( udp, "UDP %p bound to port %d\n",
                       udp, ntohs ( udp->local.st_port ) );
        }

        /* Attach parent interface, transfer reference to connection
         * list and return
         */
        intf_plug_plug ( &udp->xfer, xfer );
        list_add ( &udp->list, &udp_conns );
        return 0;

 err:
        ref_put ( &udp->refcnt );
        return rc;
}
int udp_open ( struct interface xfer,
struct sockaddr peer,
struct sockaddr local 
)

Open a UDP connection.

Parameters:
xferData transfer interface
peerPeer socket address
localLocal socket address, or NULL
Return values:
rcReturn status code

Definition at line 130 of file udp.c.

References udp_open_common().

                                        {
        return udp_open_common ( xfer, peer, local, 0 );
}
int udp_open_promisc ( struct interface xfer)

Open a promiscuous UDP connection.

Parameters:
xferData transfer interface
Return values:
rcReturn status code

Promiscuous UDP connections are required in order to support the PXE API.

Definition at line 144 of file udp.c.

References NULL, and udp_open_common().

Referenced by efi_pxe_udp_open(), and pxenv_udp_open().

                                                {
        return udp_open_common ( xfer, NULL, NULL, 1 );
}
static void udp_close ( struct udp_connection udp,
int  rc 
) [static]

Close a UDP connection.

Parameters:
udpUDP connection
rcReason for close

Definition at line 154 of file udp.c.

References DBGC, intf_shutdown(), udp_connection::list, list_del, ref_put, udp_connection::refcnt, and udp_connection::xfer.

                                                             {

        /* Close data transfer interface */
        intf_shutdown ( &udp->xfer, rc );

        /* Remove from list of connections and drop list's reference */
        list_del ( &udp->list );
        ref_put ( &udp->refcnt );

        DBGC ( udp, "UDP %p closed\n", udp );
}
static int udp_tx ( struct udp_connection udp,
struct io_buffer iobuf,
struct sockaddr_tcpip src,
struct sockaddr_tcpip dest,
struct net_device netdev 
) [static]

Transmit data via a UDP connection to a specified address.

Parameters:
udpUDP connection
iobufI/O buffer
srcSource address, or NULL to use default
destDestination address, or NULL to use default
netdevNetwork device, or NULL to use default
Return values:
rcReturn status code

Definition at line 176 of file udp.c.

References udp_header::chksum, DBGC, DBGC2, udp_header::dest, free_iob(), htons, iob_ensure_headroom(), iob_len(), iob_push, udp_header::len, len, udp_connection::local, MAX_LL_NET_HEADER_LEN, ntohs, udp_connection::peer, rc, udp_header::src, sockaddr_tcpip::st_port, strerror(), tcpip_chksum(), and tcpip_tx().

Referenced by udp_xfer_deliver().

                                                {
        struct udp_header *udphdr;
        size_t len;
        int rc;

        /* Check we can accommodate the header */
        if ( ( rc = iob_ensure_headroom ( iobuf,
                                          MAX_LL_NET_HEADER_LEN ) ) != 0 ) {
                free_iob ( iobuf );
                return rc;
        }

        /* Fill in default values if not explicitly provided */
        if ( ! src )
                src = &udp->local;
        if ( ! dest )
                dest = &udp->peer;

        /* Add the UDP header */
        udphdr = iob_push ( iobuf, sizeof ( *udphdr ) );
        len = iob_len ( iobuf );
        udphdr->dest = dest->st_port;
        udphdr->src = src->st_port;
        udphdr->len = htons ( len );
        udphdr->chksum = 0;
        udphdr->chksum = tcpip_chksum ( udphdr, len );

        /* Dump debugging information */
        DBGC2 ( udp, "UDP %p TX %d->%d len %d\n", udp,
                ntohs ( udphdr->src ), ntohs ( udphdr->dest ),
                ntohs ( udphdr->len ) );

        /* Send it to the next layer for processing */
        if ( ( rc = tcpip_tx ( iobuf, &udp_protocol, src, dest, netdev,
                               &udphdr->chksum ) ) != 0 ) {
                DBGC ( udp, "UDP %p could not transmit packet: %s\n",
                       udp, strerror ( rc ) );
                return rc;
        }

        return 0;
}
static struct udp_connection* udp_demux ( struct sockaddr_tcpip local) [static, read]

Identify UDP connection by local address.

Parameters:
localLocal address
Return values:
udpUDP connection, or NULL

Definition at line 227 of file udp.c.

References udp_connection::list, list_for_each_entry, udp_connection::local, memcmp(), NULL, sockaddr_tcpip::pad, sockaddr_tcpip::st_family, and sockaddr_tcpip::st_port.

Referenced by udp_rx().

                                                                          {
        static const struct sockaddr_tcpip empty_sockaddr = { .pad = { 0, } };
        struct udp_connection *udp;

        list_for_each_entry ( udp, &udp_conns, list ) {
                if ( ( ( udp->local.st_family == local->st_family ) ||
                       ( udp->local.st_family == 0 ) ) &&
                     ( ( udp->local.st_port == local->st_port ) ||
                       ( udp->local.st_port == 0 ) ) &&
                     ( ( memcmp ( udp->local.pad, local->pad,
                                  sizeof ( udp->local.pad ) ) == 0 ) ||
                       ( memcmp ( udp->local.pad, empty_sockaddr.pad,
                                  sizeof ( udp->local.pad ) ) == 0 ) ) ) {
                        return udp;
                }
        }
        return NULL;
}
static int udp_rx ( struct io_buffer iobuf,
struct net_device *netdev  __unused,
struct sockaddr_tcpip st_src,
struct sockaddr_tcpip st_dest,
uint16_t  pshdr_csum 
) [static]

Process a received packet.

Parameters:
iobufI/O buffer
netdevNetwork device
st_srcPartially-filled source address
st_destPartially-filled destination address
pshdr_csumPseudo-header checksum
Return values:
rcReturn status code

Definition at line 256 of file udp.c.

References udp_header::chksum, io_buffer::data, DBG, DBGC2, udp_header::dest, xfer_metadata::dest, done, EINVAL, ENOTCONN, free_iob(), iob_disown, iob_len(), iob_pull, iob_unput, udp_header::len, memset(), ntohs, rc, udp_header::src, xfer_metadata::src, sockaddr_tcpip::st_port, tcpip_continue_chksum(), udp_demux(), udp_connection::xfer, and xfer_deliver().

                                                                          {
        struct udp_header *udphdr = iobuf->data;
        struct udp_connection *udp;
        struct xfer_metadata meta;
        size_t ulen;
        unsigned int csum;
        int rc = 0;

        /* Sanity check packet */
        if ( iob_len ( iobuf ) < sizeof ( *udphdr ) ) {
                DBG ( "UDP packet too short at %zd bytes (min %zd bytes)\n",
                      iob_len ( iobuf ), sizeof ( *udphdr ) );
                
                rc = -EINVAL;
                goto done;
        }
        ulen = ntohs ( udphdr->len );
        if ( ulen < sizeof ( *udphdr ) ) {
                DBG ( "UDP length too short at %zd bytes "
                      "(header is %zd bytes)\n", ulen, sizeof ( *udphdr ) );
                rc = -EINVAL;
                goto done;
        }
        if ( ulen > iob_len ( iobuf ) ) {
                DBG ( "UDP length too long at %zd bytes (packet is %zd "
                      "bytes)\n", ulen, iob_len ( iobuf ) );
                rc = -EINVAL;
                goto done;
        }
        if ( udphdr->chksum ) {
                csum = tcpip_continue_chksum ( pshdr_csum, iobuf->data, ulen );
                if ( csum != 0 ) {
                        DBG ( "UDP checksum incorrect (is %04x including "
                              "checksum field, should be 0000)\n", csum );
                        rc = -EINVAL;
                        goto done;
                }
        }

        /* Parse parameters from header and strip header */
        st_src->st_port = udphdr->src;
        st_dest->st_port = udphdr->dest;
        udp = udp_demux ( st_dest );
        iob_unput ( iobuf, ( iob_len ( iobuf ) - ulen ) );
        iob_pull ( iobuf, sizeof ( *udphdr ) );

        /* Dump debugging information */
        DBGC2 ( udp, "UDP %p RX %d<-%d len %zd\n", udp,
                ntohs ( udphdr->dest ), ntohs ( udphdr->src ), ulen );

        /* Ignore if no matching connection found */
        if ( ! udp ) {
                DBG ( "No UDP connection listening on port %d\n",
                      ntohs ( udphdr->dest ) );
                rc = -ENOTCONN;
                goto done;
        }

        /* Pass data to application */
        memset ( &meta, 0, sizeof ( meta ) );
        meta.src = ( struct sockaddr * ) st_src;
        meta.dest = ( struct sockaddr * ) st_dest;
        rc = xfer_deliver ( &udp->xfer, iob_disown ( iobuf ), &meta );

 done:
        free_iob ( iobuf );
        return rc;
}
static struct io_buffer* udp_xfer_alloc_iob ( struct udp_connection udp,
size_t  len 
) [static, read]

Allocate I/O buffer for UDP.

Parameters:
udpUDP connection
lenPayload size
Return values:
iobufI/O buffer, or NULL

Definition at line 349 of file udp.c.

References alloc_iob(), DBGC, iob_reserve, MAX_LL_NET_HEADER_LEN, and NULL.

                                                            {
        struct io_buffer *iobuf;

        iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN + len );
        if ( ! iobuf ) {
                DBGC ( udp, "UDP %p cannot allocate buffer of length %zd\n",
                       udp, len );
                return NULL;
        }
        iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN );
        return iobuf;
}
static int udp_xfer_deliver ( struct udp_connection udp,
struct io_buffer iobuf,
struct xfer_metadata meta 
) [static]

Deliver datagram as I/O buffer.

Parameters:
udpUDP connection
iobufDatagram I/O buffer
metaData transfer metadata
Return values:
rcReturn status code

Definition at line 371 of file udp.c.

References xfer_metadata::dest, xfer_metadata::netdev, xfer_metadata::src, and udp_tx().

                                                           {

        /* Transmit data, if possible */
        return udp_tx ( udp, iobuf, ( ( struct sockaddr_tcpip * ) meta->src ),
                        ( ( struct sockaddr_tcpip * ) meta->dest ),
                        meta->netdev );
}
static int udp_open_uri ( struct interface xfer,
struct uri uri 
) [static]

Open UDP URI.

Parameters:
xferData transfer interface
uriURI
Return values:
rcReturn status code

Definition at line 423 of file udp.c.

References EINVAL, uri::host, htons, memset(), NULL, SOCK_DGRAM, sockaddr_tcpip::st_port, uri_port(), and xfer_open_named_socket().

                                                                    {
        struct sockaddr_tcpip peer;

        /* Sanity check */
        if ( ! uri->host )
                return -EINVAL;

        memset ( &peer, 0, sizeof ( peer ) );
        peer.st_port = htons ( uri_port ( uri, 0 ) );
        return xfer_open_named_socket ( xfer, SOCK_DGRAM,
                                        ( struct sockaddr * ) &peer,
                                        uri->host, NULL );
}

Variable Documentation

static struct interface_descriptor udp_xfer_desc [static]
Initial value:

UDP data transfer interface descriptor.

Definition at line 47 of file udp.c.

Referenced by udp_open_common().

struct tcpip_protocol udp_protocol __tcpip_protocol
Initial value:
 {
        .name = "UDP",
        .rx = udp_rx,
        .zero_csum = TCPIP_NEGATIVE_ZERO_CSUM,
        .tcpip_proto = IP_UDP,
}

ICMPv4 TCP/IP protocol.

Definition at line 48 of file udp.c.

Initial value:

UDP data transfer interface operations.

Definition at line 382 of file udp.c.

struct socket_opener udp_ipv6_socket_opener __socket_opener
Initial value:
 {
        .semantics      = UDP_SOCK_DGRAM,
        .family         = AF_INET,
        .open           = udp_open,
}

UDP IPv4 socket opener.

UDP IPv6 socket opener.

Definition at line 400 of file udp.c.

struct uri_opener udp_uri_opener __uri_opener
Initial value:
 {
        .scheme         = "udp",
        .open           = udp_open_uri,
}

UDP URI opener.

Definition at line 438 of file udp.c.