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