|
|
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: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.