Annotation of qemu/roms/ipxe/src/net/udp.c, revision 1.1.1.1

1.1       root        1: #include <stdint.h>
                      2: #include <stdlib.h>
                      3: #include <string.h>
                      4: #include <assert.h>
                      5: #include <byteswap.h>
                      6: #include <errno.h>
                      7: #include <ipxe/tcpip.h>
                      8: #include <ipxe/iobuf.h>
                      9: #include <ipxe/xfer.h>
                     10: #include <ipxe/open.h>
                     11: #include <ipxe/uri.h>
                     12: #include <ipxe/netdevice.h>
                     13: #include <ipxe/udp.h>
                     14: 
                     15: /** @file
                     16:  *
                     17:  * UDP protocol
                     18:  */
                     19: 
                     20: FILE_LICENCE ( GPL2_OR_LATER );
                     21: 
                     22: /**
                     23:  * A UDP connection
                     24:  *
                     25:  */
                     26: struct udp_connection {
                     27:        /** Reference counter */
                     28:        struct refcnt refcnt;
                     29:        /** List of UDP connections */
                     30:        struct list_head list;
                     31: 
                     32:        /** Data transfer interface */
                     33:        struct interface xfer;
                     34: 
                     35:        /** Local socket address */
                     36:        struct sockaddr_tcpip local;
                     37:        /** Remote socket address */
                     38:        struct sockaddr_tcpip peer;
                     39: };
                     40: 
                     41: /**
                     42:  * List of registered UDP connections
                     43:  */
                     44: static LIST_HEAD ( udp_conns );
                     45: 
                     46: /* Forward declatations */
                     47: static struct interface_descriptor udp_xfer_desc;
                     48: struct tcpip_protocol udp_protocol __tcpip_protocol;
                     49: 
                     50: /**
                     51:  * Bind UDP connection to local port
                     52:  *
                     53:  * @v udp              UDP connection
                     54:  * @ret rc             Return status code
                     55:  *
                     56:  * Opens the UDP connection and binds to the specified local port.  If
                     57:  * no local port is specified, the first available port will be used.
                     58:  */
                     59: static int udp_bind ( struct udp_connection *udp ) {
                     60:        struct udp_connection *existing;
                     61:        static uint16_t try_port = 1023;
                     62: 
                     63:        /* If no port specified, find the first available port */
                     64:        if ( ! udp->local.st_port ) {
                     65:                while ( try_port ) {
                     66:                        try_port++;
                     67:                        if ( try_port < 1024 )
                     68:                                continue;
                     69:                        udp->local.st_port = htons ( try_port );
                     70:                        if ( udp_bind ( udp ) == 0 )
                     71:                                return 0;
                     72:                }
                     73:                return -EADDRINUSE;
                     74:        }
                     75: 
                     76:        /* Attempt bind to local port */
                     77:        list_for_each_entry ( existing, &udp_conns, list ) {
                     78:                if ( existing->local.st_port == udp->local.st_port ) {
                     79:                        DBGC ( udp, "UDP %p could not bind: port %d in use\n",
                     80:                               udp, ntohs ( udp->local.st_port ) );
                     81:                        return -EADDRINUSE;
                     82:                }
                     83:        }
                     84: 
                     85:        /* Add to UDP connection list */
                     86:        DBGC ( udp, "UDP %p bound to port %d\n",
                     87:               udp, ntohs ( udp->local.st_port ) );
                     88: 
                     89:        return 0;
                     90: }
                     91: 
                     92: /**
                     93:  * Open a UDP connection
                     94:  *
                     95:  * @v xfer             Data transfer interface
                     96:  * @v peer             Peer socket address, or NULL
                     97:  * @v local            Local socket address, or NULL
                     98:  * @v promisc          Socket is promiscuous
                     99:  * @ret rc             Return status code
                    100:  */
                    101: static int udp_open_common ( struct interface *xfer,
                    102:                             struct sockaddr *peer, struct sockaddr *local,
                    103:                             int promisc ) {
                    104:        struct sockaddr_tcpip *st_peer = ( struct sockaddr_tcpip * ) peer;
                    105:        struct sockaddr_tcpip *st_local = ( struct sockaddr_tcpip * ) local;
                    106:        struct udp_connection *udp;
                    107:        int rc;
                    108: 
                    109:        /* Allocate and initialise structure */
                    110:        udp = zalloc ( sizeof ( *udp ) );
                    111:        if ( ! udp )
                    112:                return -ENOMEM;
                    113:        DBGC ( udp, "UDP %p allocated\n", udp );
                    114:        ref_init ( &udp->refcnt, NULL );
                    115:        intf_init ( &udp->xfer, &udp_xfer_desc, &udp->refcnt );
                    116:        if ( st_peer )
                    117:                memcpy ( &udp->peer, st_peer, sizeof ( udp->peer ) );
                    118:        if ( st_local )
                    119:                memcpy ( &udp->local, st_local, sizeof ( udp->local ) );
                    120: 
                    121:        /* Bind to local port */
                    122:        if ( ! promisc ) {
                    123:                if ( ( rc = udp_bind ( udp ) ) != 0 )
                    124:                        goto err;
                    125:        }
                    126: 
                    127:        /* Attach parent interface, transfer reference to connection
                    128:         * list and return
                    129:         */
                    130:        intf_plug_plug ( &udp->xfer, xfer );
                    131:        list_add ( &udp->list, &udp_conns );
                    132:        return 0;
                    133: 
                    134:  err:
                    135:        ref_put ( &udp->refcnt );
                    136:        return rc;
                    137: }
                    138: 
                    139: /**
                    140:  * Open a UDP connection
                    141:  *
                    142:  * @v xfer             Data transfer interface
                    143:  * @v peer             Peer socket address
                    144:  * @v local            Local socket address, or NULL
                    145:  * @ret rc             Return status code
                    146:  */
                    147: int udp_open ( struct interface *xfer, struct sockaddr *peer,
                    148:               struct sockaddr *local ) {
                    149:        return udp_open_common ( xfer, peer, local, 0 );
                    150: }
                    151: 
                    152: /**
                    153:  * Open a promiscuous UDP connection
                    154:  *
                    155:  * @v xfer             Data transfer interface
                    156:  * @ret rc             Return status code
                    157:  *
                    158:  * Promiscuous UDP connections are required in order to support the
                    159:  * PXE API.
                    160:  */
                    161: int udp_open_promisc ( struct interface *xfer ) {
                    162:        return udp_open_common ( xfer, NULL, NULL, 1 );
                    163: }
                    164: 
                    165: /**
                    166:  * Close a UDP connection
                    167:  *
                    168:  * @v udp              UDP connection
                    169:  * @v rc               Reason for close
                    170:  */
                    171: static void udp_close ( struct udp_connection *udp, int rc ) {
                    172: 
                    173:        /* Close data transfer interface */
                    174:        intf_shutdown ( &udp->xfer, rc );
                    175: 
                    176:        /* Remove from list of connections and drop list's reference */
                    177:        list_del ( &udp->list );
                    178:        ref_put ( &udp->refcnt );
                    179: 
                    180:        DBGC ( udp, "UDP %p closed\n", udp );
                    181: }
                    182: 
                    183: /**
                    184:  * Transmit data via a UDP connection to a specified address
                    185:  *
                    186:  * @v udp              UDP connection
                    187:  * @v iobuf            I/O buffer
                    188:  * @v src              Source address, or NULL to use default
                    189:  * @v dest             Destination address, or NULL to use default
                    190:  * @v netdev           Network device, or NULL to use default
                    191:  * @ret rc             Return status code
                    192:  */
                    193: static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf,
                    194:                    struct sockaddr_tcpip *src, struct sockaddr_tcpip *dest,
                    195:                    struct net_device *netdev ) {
                    196:                struct udp_header *udphdr;
                    197:        size_t len;
                    198:        int rc;
                    199: 
                    200:        /* Check we can accommodate the header */
                    201:        if ( ( rc = iob_ensure_headroom ( iobuf,
                    202:                                          MAX_LL_NET_HEADER_LEN ) ) != 0 ) {
                    203:                free_iob ( iobuf );
                    204:                return rc;
                    205:        }
                    206: 
                    207:        /* Fill in default values if not explicitly provided */
                    208:        if ( ! src )
                    209:                src = &udp->local;
                    210:        if ( ! dest )
                    211:                dest = &udp->peer;
                    212: 
                    213:        /* Add the UDP header */
                    214:        udphdr = iob_push ( iobuf, sizeof ( *udphdr ) );
                    215:        len = iob_len ( iobuf );
                    216:        udphdr->dest = dest->st_port;
                    217:        udphdr->src = src->st_port;
                    218:        udphdr->len = htons ( len );
                    219:        udphdr->chksum = 0;
                    220:        udphdr->chksum = tcpip_chksum ( udphdr, len );
                    221: 
                    222:        /* Dump debugging information */
                    223:        DBGC ( udp, "UDP %p TX %d->%d len %d\n", udp,
                    224:               ntohs ( udphdr->src ), ntohs ( udphdr->dest ),
                    225:               ntohs ( udphdr->len ) );
                    226: 
                    227:        /* Send it to the next layer for processing */
                    228:        if ( ( rc = tcpip_tx ( iobuf, &udp_protocol, src, dest, netdev,
                    229:                               &udphdr->chksum ) ) != 0 ) {
                    230:                DBGC ( udp, "UDP %p could not transmit packet: %s\n",
                    231:                       udp, strerror ( rc ) );
                    232:                return rc;
                    233:        }
                    234: 
                    235:        return 0;
                    236: }
                    237: 
                    238: /**
                    239:  * Identify UDP connection by local address
                    240:  *
                    241:  * @v local            Local address
                    242:  * @ret udp            UDP connection, or NULL
                    243:  */
                    244: static struct udp_connection * udp_demux ( struct sockaddr_tcpip *local ) {
                    245:        static const struct sockaddr_tcpip empty_sockaddr = { .pad = { 0, } };
                    246:        struct udp_connection *udp;
                    247: 
                    248:        list_for_each_entry ( udp, &udp_conns, list ) {
                    249:                if ( ( ( udp->local.st_family == local->st_family ) ||
                    250:                       ( udp->local.st_family == 0 ) ) &&
                    251:                     ( ( udp->local.st_port == local->st_port ) ||
                    252:                       ( udp->local.st_port == 0 ) ) &&
                    253:                     ( ( memcmp ( udp->local.pad, local->pad,
                    254:                                  sizeof ( udp->local.pad ) ) == 0 ) ||
                    255:                       ( memcmp ( udp->local.pad, empty_sockaddr.pad,
                    256:                                  sizeof ( udp->local.pad ) ) == 0 ) ) ) {
                    257:                        return udp;
                    258:                }
                    259:        }
                    260:        return NULL;
                    261: }
                    262: 
                    263: /**
                    264:  * Process a received packet
                    265:  *
                    266:  * @v iobuf            I/O buffer
                    267:  * @v st_src           Partially-filled source address
                    268:  * @v st_dest          Partially-filled destination address
                    269:  * @v pshdr_csum       Pseudo-header checksum
                    270:  * @ret rc             Return status code
                    271:  */
                    272: static int udp_rx ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src,
                    273:                    struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum ) {
                    274:        struct udp_header *udphdr = iobuf->data;
                    275:        struct udp_connection *udp;
                    276:        struct xfer_metadata meta;
                    277:        size_t ulen;
                    278:        unsigned int csum;
                    279:        int rc = 0;
                    280: 
                    281:        /* Sanity check packet */
                    282:        if ( iob_len ( iobuf ) < sizeof ( *udphdr ) ) {
                    283:                DBG ( "UDP packet too short at %zd bytes (min %zd bytes)\n",
                    284:                      iob_len ( iobuf ), sizeof ( *udphdr ) );
                    285:                
                    286:                rc = -EINVAL;
                    287:                goto done;
                    288:        }
                    289:        ulen = ntohs ( udphdr->len );
                    290:        if ( ulen < sizeof ( *udphdr ) ) {
                    291:                DBG ( "UDP length too short at %zd bytes "
                    292:                      "(header is %zd bytes)\n", ulen, sizeof ( *udphdr ) );
                    293:                rc = -EINVAL;
                    294:                goto done;
                    295:        }
                    296:        if ( ulen > iob_len ( iobuf ) ) {
                    297:                DBG ( "UDP length too long at %zd bytes (packet is %zd "
                    298:                      "bytes)\n", ulen, iob_len ( iobuf ) );
                    299:                rc = -EINVAL;
                    300:                goto done;
                    301:        }
                    302:        if ( udphdr->chksum ) {
                    303:                csum = tcpip_continue_chksum ( pshdr_csum, iobuf->data, ulen );
                    304:                if ( csum != 0 ) {
                    305:                        DBG ( "UDP checksum incorrect (is %04x including "
                    306:                              "checksum field, should be 0000)\n", csum );
                    307:                        rc = -EINVAL;
                    308:                        goto done;
                    309:                }
                    310:        }
                    311: 
                    312:        /* Parse parameters from header and strip header */
                    313:        st_src->st_port = udphdr->src;
                    314:        st_dest->st_port = udphdr->dest;
                    315:        udp = udp_demux ( st_dest );
                    316:        iob_unput ( iobuf, ( iob_len ( iobuf ) - ulen ) );
                    317:        iob_pull ( iobuf, sizeof ( *udphdr ) );
                    318: 
                    319:        /* Dump debugging information */
                    320:        DBGC ( udp, "UDP %p RX %d<-%d len %zd\n", udp,
                    321:               ntohs ( udphdr->dest ), ntohs ( udphdr->src ), ulen );
                    322: 
                    323:        /* Ignore if no matching connection found */
                    324:        if ( ! udp ) {
                    325:                DBG ( "No UDP connection listening on port %d\n",
                    326:                      ntohs ( udphdr->dest ) );
                    327:                rc = -ENOTCONN;
                    328:                goto done;
                    329:        }
                    330: 
                    331:        /* Pass data to application */
                    332:        memset ( &meta, 0, sizeof ( meta ) );
                    333:        meta.src = ( struct sockaddr * ) st_src;
                    334:        meta.dest = ( struct sockaddr * ) st_dest;
                    335:        rc = xfer_deliver ( &udp->xfer, iob_disown ( iobuf ), &meta );
                    336: 
                    337:  done:
                    338:        free_iob ( iobuf );
                    339:        return rc;
                    340: }
                    341: 
                    342: struct tcpip_protocol udp_protocol __tcpip_protocol = {
                    343:        .name = "UDP",
                    344:        .rx = udp_rx,
                    345:        .tcpip_proto = IP_UDP,
                    346: };
                    347: 
                    348: /***************************************************************************
                    349:  *
                    350:  * Data transfer interface
                    351:  *
                    352:  ***************************************************************************
                    353:  */
                    354: 
                    355: /**
                    356:  * Allocate I/O buffer for UDP
                    357:  *
                    358:  * @v udp              UDP connection
                    359:  * @v len              Payload size
                    360:  * @ret iobuf          I/O buffer, or NULL
                    361:  */
                    362: static struct io_buffer * udp_xfer_alloc_iob ( struct udp_connection *udp,
                    363:                                               size_t len ) {
                    364:        struct io_buffer *iobuf;
                    365: 
                    366:        iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN + len );
                    367:        if ( ! iobuf ) {
                    368:                DBGC ( udp, "UDP %p cannot allocate buffer of length %zd\n",
                    369:                       udp, len );
                    370:                return NULL;
                    371:        }
                    372:        iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN );
                    373:        return iobuf;
                    374: }
                    375: 
                    376: /**
                    377:  * Deliver datagram as I/O buffer
                    378:  *
                    379:  * @v udp              UDP connection
                    380:  * @v iobuf            Datagram I/O buffer
                    381:  * @v meta             Data transfer metadata
                    382:  * @ret rc             Return status code
                    383:  */
                    384: static int udp_xfer_deliver ( struct udp_connection *udp,
                    385:                              struct io_buffer *iobuf,
                    386:                              struct xfer_metadata *meta ) {
                    387: 
                    388:        /* Transmit data, if possible */
                    389:        udp_tx ( udp, iobuf, ( ( struct sockaddr_tcpip * ) meta->src ),
                    390:                 ( ( struct sockaddr_tcpip * ) meta->dest ), meta->netdev );
                    391: 
                    392:        return 0;
                    393: }
                    394: 
                    395: /** UDP data transfer interface operations */
                    396: static struct interface_operation udp_xfer_operations[] = {
                    397:        INTF_OP ( xfer_deliver, struct udp_connection *, udp_xfer_deliver ),
                    398:        INTF_OP ( xfer_alloc_iob, struct udp_connection *, udp_xfer_alloc_iob ),
                    399:        INTF_OP ( intf_close, struct udp_connection *, udp_close ),
                    400: };
                    401: 
                    402: /** UDP data transfer interface descriptor */
                    403: static struct interface_descriptor udp_xfer_desc =
                    404:        INTF_DESC ( struct udp_connection, xfer, udp_xfer_operations );
                    405: 
                    406: /***************************************************************************
                    407:  *
                    408:  * Openers
                    409:  *
                    410:  ***************************************************************************
                    411:  */
                    412: 
                    413: /** UDP socket opener */
                    414: struct socket_opener udp_socket_opener __socket_opener = {
                    415:        .semantics      = UDP_SOCK_DGRAM,
                    416:        .family         = AF_INET,
                    417:        .open           = udp_open,
                    418: };
                    419: 
                    420: /** Linkage hack */
                    421: int udp_sock_dgram = UDP_SOCK_DGRAM;
                    422: 
                    423: /**
                    424:  * Open UDP URI
                    425:  *
                    426:  * @v xfer             Data transfer interface
                    427:  * @v uri              URI
                    428:  * @ret rc             Return status code
                    429:  */
                    430: static int udp_open_uri ( struct interface *xfer, struct uri *uri ) {
                    431:        struct sockaddr_tcpip peer;
                    432: 
                    433:        /* Sanity check */
                    434:        if ( ! uri->host )
                    435:                return -EINVAL;
                    436: 
                    437:        memset ( &peer, 0, sizeof ( peer ) );
                    438:        peer.st_port = htons ( uri_port ( uri, 0 ) );
                    439:        return xfer_open_named_socket ( xfer, SOCK_DGRAM,
                    440:                                        ( struct sockaddr * ) &peer,
                    441:                                        uri->host, NULL );
                    442: }
                    443: 
                    444: /** UDP URI opener */
                    445: struct uri_opener udp_uri_opener __uri_opener = {
                    446:        .scheme         = "udp",
                    447:        .open           = udp_open_uri,
                    448: };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.