#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <byteswap.h>
#include <errno.h>
#include <gpxe/tcpip.h>
#include <gpxe/iobuf.h>
#include <gpxe/xfer.h>
#include <gpxe/open.h>
#include <gpxe/uri.h>
#include <gpxe/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) | |
| static | LIST_HEAD (udp_conns) |
| List of registered UDP connections. | |
| static int | udp_bind (struct udp_connection *udp) |
| Bind UDP connection to local port. | |
| static int | udp_open_common (struct xfer_interface *xfer, struct sockaddr *peer, struct sockaddr *local, int promisc) |
| Open a UDP connection. | |
| int | udp_open (struct xfer_interface *xfer, struct sockaddr *peer, struct sockaddr *local) |
| Open a UDP connection. | |
| int | udp_open_promisc (struct xfer_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_connection * | udp_demux (struct sockaddr_tcpip *local) |
| Identify UDP connection by local address. | |
| static int | udp_rx (struct io_buffer *iobuf, struct sockaddr_tcpip *st_src, struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum) |
| Process a received packet. | |
| static void | udp_xfer_close (struct xfer_interface *xfer, int rc) |
| Close interface. | |
| static struct io_buffer * | udp_alloc_iob (struct xfer_interface *xfer, size_t len) |
| Allocate I/O buffer for UDP. | |
| static int | udp_xfer_deliver_iob (struct xfer_interface *xfer, struct io_buffer *iobuf, struct xfer_metadata *meta) |
| Deliver datagram as I/O buffer. | |
| static int | udp_open_uri (struct xfer_interface *xfer, struct uri *uri) |
| Open UDP URI. | |
Variables | |
| static struct xfer_interface_operations | udp_xfer_operations |
| UDP data transfer interface operations. | |
| struct tcpip_protocol | udp_protocol |
| struct tcpip_protocol udp_protocol | __tcpip_protocol |
| struct socket_opener udp_socket_opener | __socket_opener |
| UDP socket opener. | |
| int | udp_sock_dgram = UDP_SOCK_DGRAM |
| Linkage hack. | |
| struct uri_opener udp_uri_opener | __uri_opener |
| UDP URI opener. | |
Definition in file udp.c.
| FILE_LICENCE | ( | GPL2_OR_LATER | ) |
| static LIST_HEAD | ( | udp_conns | ) | [static] |
List of registered UDP connections.
| static int udp_bind | ( | struct udp_connection * | udp | ) | [static] |
Bind UDP connection to local port.
| udp | UDP connection |
| rc | Return status code |
Definition at line 58 of file udp.c.
References DBGC, EADDRINUSE, htons, udp_connection::list, list_for_each_entry, udp_connection::local, ntohs, and sockaddr_tcpip::st_port.
Referenced by udp_open_common().
00058 { 00059 struct udp_connection *existing; 00060 static uint16_t try_port = 1023; 00061 00062 /* If no port specified, find the first available port */ 00063 if ( ! udp->local.st_port ) { 00064 while ( try_port ) { 00065 try_port++; 00066 if ( try_port < 1024 ) 00067 continue; 00068 udp->local.st_port = htons ( try_port ); 00069 if ( udp_bind ( udp ) == 0 ) 00070 return 0; 00071 } 00072 return -EADDRINUSE; 00073 } 00074 00075 /* Attempt bind to local port */ 00076 list_for_each_entry ( existing, &udp_conns, list ) { 00077 if ( existing->local.st_port == udp->local.st_port ) { 00078 DBGC ( udp, "UDP %p could not bind: port %d in use\n", 00079 udp, ntohs ( udp->local.st_port ) ); 00080 return -EADDRINUSE; 00081 } 00082 } 00083 00084 /* Add to UDP connection list */ 00085 DBGC ( udp, "UDP %p bound to port %d\n", 00086 udp, ntohs ( udp->local.st_port ) ); 00087 00088 return 0; 00089 }
| static int udp_open_common | ( | struct xfer_interface * | xfer, | |
| struct sockaddr * | peer, | |||
| struct sockaddr * | local, | |||
| int | promisc | |||
| ) | [static] |
Open a UDP connection.
| xfer | Data transfer interface | |
| peer | Peer socket address, or NULL | |
| local | Local socket address, or NULL | |
| promisc | Socket is promiscuous |
| rc | Return status code |
Definition at line 100 of file udp.c.
References DBGC, ENOMEM, udp_connection::list, list_add, udp_connection::local, memcpy, udp_connection::peer, ref_put(), udp_connection::refcnt, udp_bind(), udp_xfer_operations, udp_connection::xfer, xfer_init(), and zalloc().
Referenced by udp_open(), and udp_open_promisc().
00102 { 00103 struct sockaddr_tcpip *st_peer = ( struct sockaddr_tcpip * ) peer; 00104 struct sockaddr_tcpip *st_local = ( struct sockaddr_tcpip * ) local; 00105 struct udp_connection *udp; 00106 int rc; 00107 00108 /* Allocate and initialise structure */ 00109 udp = zalloc ( sizeof ( *udp ) ); 00110 if ( ! udp ) 00111 return -ENOMEM; 00112 DBGC ( udp, "UDP %p allocated\n", udp ); 00113 xfer_init ( &udp->xfer, &udp_xfer_operations, &udp->refcnt ); 00114 if ( st_peer ) 00115 memcpy ( &udp->peer, st_peer, sizeof ( udp->peer ) ); 00116 if ( st_local ) 00117 memcpy ( &udp->local, st_local, sizeof ( udp->local ) ); 00118 00119 /* Bind to local port */ 00120 if ( ! promisc ) { 00121 if ( ( rc = udp_bind ( udp ) ) != 0 ) 00122 goto err; 00123 } 00124 00125 /* Attach parent interface, transfer reference to connection 00126 * list and return 00127 */ 00128 xfer_plug_plug ( &udp->xfer, xfer ); 00129 list_add ( &udp->list, &udp_conns ); 00130 return 0; 00131 00132 err: 00133 ref_put ( &udp->refcnt ); 00134 return rc; 00135 }
| int udp_open | ( | struct xfer_interface * | xfer, | |
| struct sockaddr * | peer, | |||
| struct sockaddr * | local | |||
| ) |
Open a UDP connection.
| xfer | Data transfer interface | |
| peer | Peer socket address | |
| local | Local socket address, or NULL |
| rc | Return status code |
Definition at line 145 of file udp.c.
References udp_open_common().
00146 { 00147 return udp_open_common ( xfer, peer, local, 0 ); 00148 }
| int udp_open_promisc | ( | struct xfer_interface * | xfer | ) |
Open a promiscuous UDP connection.
| xfer | Data transfer interface |
| rc | Return status code |
Definition at line 159 of file udp.c.
References NULL, and udp_open_common().
Referenced by pxenv_udp_open().
00159 { 00160 return udp_open_common ( xfer, NULL, NULL, 1 ); 00161 }
| static void udp_close | ( | struct udp_connection * | udp, | |
| int | rc | |||
| ) | [static] |
Close a UDP connection.
| udp | UDP connection | |
| rc | Reason for close |
Definition at line 169 of file udp.c.
References DBGC, udp_connection::list, list_del, ref_put(), udp_connection::refcnt, udp_connection::xfer, and xfer_close().
Referenced by udp_xfer_close().
00169 { 00170 00171 /* Close data transfer interface */ 00172 xfer_nullify ( &udp->xfer ); 00173 xfer_close ( &udp->xfer, rc ); 00174 00175 /* Remove from list of connections and drop list's reference */ 00176 list_del ( &udp->list ); 00177 ref_put ( &udp->refcnt ); 00178 00179 DBGC ( udp, "UDP %p closed\n", udp ); 00180 }
| 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.
| udp | UDP connection | |
| iobuf | I/O buffer | |
| src | Source address, or NULL to use default | |
| dest | Destination address, or NULL to use default | |
| netdev | Network device, or NULL to use default |
| rc | Return status code |
Definition at line 192 of file udp.c.
References udp_header::chksum, DBGC, udp_header::dest, free_iob(), htons, iob_ensure_headroom(), iob_len(), iob_push, udp_header::len, udp_connection::local, ntohs, udp_connection::peer, udp_header::src, sockaddr_tcpip::st_port, strerror(), tcpip_chksum(), tcpip_tx(), UDP_MAX_HLEN, and udp_protocol.
Referenced by udp_xfer_deliver_iob().
00194 { 00195 struct udp_header *udphdr; 00196 size_t len; 00197 int rc; 00198 00199 /* Check we can accommodate the header */ 00200 if ( ( rc = iob_ensure_headroom ( iobuf, UDP_MAX_HLEN ) ) != 0 ) { 00201 free_iob ( iobuf ); 00202 return rc; 00203 } 00204 00205 /* Fill in default values if not explicitly provided */ 00206 if ( ! src ) 00207 src = &udp->local; 00208 if ( ! dest ) 00209 dest = &udp->peer; 00210 00211 /* Add the UDP header */ 00212 udphdr = iob_push ( iobuf, sizeof ( *udphdr ) ); 00213 len = iob_len ( iobuf ); 00214 udphdr->dest = dest->st_port; 00215 udphdr->src = src->st_port; 00216 udphdr->len = htons ( len ); 00217 udphdr->chksum = 0; 00218 udphdr->chksum = tcpip_chksum ( udphdr, len ); 00219 00220 /* Dump debugging information */ 00221 DBGC ( udp, "UDP %p TX %d->%d len %d\n", udp, 00222 ntohs ( udphdr->src ), ntohs ( udphdr->dest ), 00223 ntohs ( udphdr->len ) ); 00224 00225 /* Send it to the next layer for processing */ 00226 if ( ( rc = tcpip_tx ( iobuf, &udp_protocol, src, dest, netdev, 00227 &udphdr->chksum ) ) != 0 ) { 00228 DBGC ( udp, "UDP %p could not transmit packet: %s\n", 00229 udp, strerror ( rc ) ); 00230 return rc; 00231 } 00232 00233 return 0; 00234 }
| static struct udp_connection* udp_demux | ( | struct sockaddr_tcpip * | local | ) | [static, read] |
Identify UDP connection by local address.
| local | Local address |
| udp | UDP connection, or NULL |
Definition at line 242 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().
00242 { 00243 static const struct sockaddr_tcpip empty_sockaddr = { .pad = { 0, } }; 00244 struct udp_connection *udp; 00245 00246 list_for_each_entry ( udp, &udp_conns, list ) { 00247 if ( ( ( udp->local.st_family == local->st_family ) || 00248 ( udp->local.st_family == 0 ) ) && 00249 ( ( udp->local.st_port == local->st_port ) || 00250 ( udp->local.st_port == 0 ) ) && 00251 ( ( memcmp ( udp->local.pad, local->pad, 00252 sizeof ( udp->local.pad ) ) == 0 ) || 00253 ( memcmp ( udp->local.pad, empty_sockaddr.pad, 00254 sizeof ( udp->local.pad ) ) == 0 ) ) ) { 00255 return udp; 00256 } 00257 } 00258 return NULL; 00259 }
| static int udp_rx | ( | struct io_buffer * | iobuf, | |
| struct sockaddr_tcpip * | st_src, | |||
| struct sockaddr_tcpip * | st_dest, | |||
| uint16_t | pshdr_csum | |||
| ) | [static] |
Process a received packet.
| iobuf | I/O buffer | |
| st_src | Partially-filled source address | |
| st_dest | Partially-filled destination address | |
| pshdr_csum | Pseudo-header checksum |
| rc | Return status code |
Definition at line 270 of file udp.c.
References udp_header::chksum, io_buffer::data, DBG, DBGC, xfer_metadata::dest, udp_header::dest, EINVAL, ENOTCONN, free_iob(), iob_disown, iob_len(), iob_pull, iob_unput, udp_header::len, memset(), ntohs, xfer_metadata::src, udp_header::src, sockaddr_tcpip::st_port, tcpip_continue_chksum(), udp_demux(), udp_connection::xfer, and xfer_deliver_iob_meta().
00271 { 00272 struct udp_header *udphdr = iobuf->data; 00273 struct udp_connection *udp; 00274 struct xfer_metadata meta; 00275 size_t ulen; 00276 unsigned int csum; 00277 int rc = 0; 00278 00279 /* Sanity check packet */ 00280 if ( iob_len ( iobuf ) < sizeof ( *udphdr ) ) { 00281 DBG ( "UDP packet too short at %zd bytes (min %zd bytes)\n", 00282 iob_len ( iobuf ), sizeof ( *udphdr ) ); 00283 00284 rc = -EINVAL; 00285 goto done; 00286 } 00287 ulen = ntohs ( udphdr->len ); 00288 if ( ulen < sizeof ( *udphdr ) ) { 00289 DBG ( "UDP length too short at %zd bytes " 00290 "(header is %zd bytes)\n", ulen, sizeof ( *udphdr ) ); 00291 rc = -EINVAL; 00292 goto done; 00293 } 00294 if ( ulen > iob_len ( iobuf ) ) { 00295 DBG ( "UDP length too long at %zd bytes (packet is %zd " 00296 "bytes)\n", ulen, iob_len ( iobuf ) ); 00297 rc = -EINVAL; 00298 goto done; 00299 } 00300 if ( udphdr->chksum ) { 00301 csum = tcpip_continue_chksum ( pshdr_csum, iobuf->data, ulen ); 00302 if ( csum != 0 ) { 00303 DBG ( "UDP checksum incorrect (is %04x including " 00304 "checksum field, should be 0000)\n", csum ); 00305 rc = -EINVAL; 00306 goto done; 00307 } 00308 } 00309 00310 /* Parse parameters from header and strip header */ 00311 st_src->st_port = udphdr->src; 00312 st_dest->st_port = udphdr->dest; 00313 udp = udp_demux ( st_dest ); 00314 iob_unput ( iobuf, ( iob_len ( iobuf ) - ulen ) ); 00315 iob_pull ( iobuf, sizeof ( *udphdr ) ); 00316 00317 /* Dump debugging information */ 00318 DBGC ( udp, "UDP %p RX %d<-%d len %zd\n", udp, 00319 ntohs ( udphdr->dest ), ntohs ( udphdr->src ), ulen ); 00320 00321 /* Ignore if no matching connection found */ 00322 if ( ! udp ) { 00323 DBG ( "No UDP connection listening on port %d\n", 00324 ntohs ( udphdr->dest ) ); 00325 rc = -ENOTCONN; 00326 goto done; 00327 } 00328 00329 /* Pass data to application */ 00330 memset ( &meta, 0, sizeof ( meta ) ); 00331 meta.src = ( struct sockaddr * ) st_src; 00332 meta.dest = ( struct sockaddr * ) st_dest; 00333 rc = xfer_deliver_iob_meta ( &udp->xfer, iob_disown ( iobuf ), &meta ); 00334 00335 done: 00336 free_iob ( iobuf ); 00337 return rc; 00338 }
| static void udp_xfer_close | ( | struct xfer_interface * | xfer, | |
| int | rc | |||
| ) | [static] |
Close interface.
| xfer | Data transfer interface | |
| rc | Reason for close |
Definition at line 359 of file udp.c.
References container_of, and udp_close().
00359 { 00360 struct udp_connection *udp = 00361 container_of ( xfer, struct udp_connection, xfer ); 00362 00363 /* Close connection */ 00364 udp_close ( udp, rc ); 00365 }
| static struct io_buffer* udp_alloc_iob | ( | struct xfer_interface * | xfer, | |
| size_t | len | |||
| ) | [static, read] |
Allocate I/O buffer for UDP.
| xfer | Data transfer interface | |
| len | Payload size |
| iobuf | I/O buffer, or NULL |
Definition at line 374 of file udp.c.
References alloc_iob(), container_of, DBGC, iob_reserve, NULL, and UDP_MAX_HLEN.
00375 { 00376 struct udp_connection *udp = 00377 container_of ( xfer, struct udp_connection, xfer ); 00378 struct io_buffer *iobuf; 00379 00380 iobuf = alloc_iob ( UDP_MAX_HLEN + len ); 00381 if ( ! iobuf ) { 00382 DBGC ( udp, "UDP %p cannot allocate buffer of length %zd\n", 00383 udp, len ); 00384 return NULL; 00385 } 00386 iob_reserve ( iobuf, UDP_MAX_HLEN ); 00387 return iobuf; 00388 }
| static int udp_xfer_deliver_iob | ( | struct xfer_interface * | xfer, | |
| struct io_buffer * | iobuf, | |||
| struct xfer_metadata * | meta | |||
| ) | [static] |
Deliver datagram as I/O buffer.
| xfer | Data transfer interface | |
| iobuf | Datagram I/O buffer | |
| meta | Data transfer metadata |
| rc | Return status code |
Definition at line 398 of file udp.c.
References container_of, xfer_metadata::dest, xfer_metadata::netdev, xfer_metadata::src, and udp_tx().
00400 { 00401 struct udp_connection *udp = 00402 container_of ( xfer, struct udp_connection, xfer ); 00403 00404 /* Transmit data, if possible */ 00405 udp_tx ( udp, iobuf, ( ( struct sockaddr_tcpip * ) meta->src ), 00406 ( ( struct sockaddr_tcpip * ) meta->dest ), meta->netdev ); 00407 00408 return 0; 00409 }
| static int udp_open_uri | ( | struct xfer_interface * | xfer, | |
| struct uri * | uri | |||
| ) | [static] |
Open UDP URI.
| rc | Return status code |
Definition at line 445 of file udp.c.
References EINVAL, uri::host, htons, memset(), NULL, SOCK_DGRAM, sockaddr_tcpip::st_port, uri_port(), and xfer_open_named_socket().
00445 { 00446 struct sockaddr_tcpip peer; 00447 00448 /* Sanity check */ 00449 if ( ! uri->host ) 00450 return -EINVAL; 00451 00452 memset ( &peer, 0, sizeof ( peer ) ); 00453 peer.st_port = htons ( uri_port ( uri, 0 ) ); 00454 return xfer_open_named_socket ( xfer, SOCK_DGRAM, 00455 ( struct sockaddr * ) &peer, 00456 uri->host, NULL ); 00457 }
static struct xfer_interface_operations udp_xfer_operations [static, read] |
Initial value:
{
.close = udp_xfer_close,
.vredirect = ignore_xfer_vredirect,
.window = unlimited_xfer_window,
.alloc_iob = udp_alloc_iob,
.deliver_iob = udp_xfer_deliver_iob,
.deliver_raw = xfer_deliver_as_iob,
}
Definition at line 46 of file udp.c.
Referenced by udp_open_common().
| struct tcpip_protocol udp_protocol |
| struct socket_opener udp_socket_opener __socket_opener |
Initial value:
{
.semantics = UDP_SOCK_DGRAM,
.family = AF_INET,
.open = udp_open,
}
| struct uri_opener udp_uri_opener __uri_opener |
1.5.7.1