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