7 #include <gpxe/tcpip.h>
8 #include <gpxe/iobuf.h>
10 #include <gpxe/open.h>
23 struct udp_connection {
24 /** Reference counter */
26 /** List of UDP connections */
27 struct list_head list;
29 /** Data transfer interface */
30 struct xfer_interface xfer;
32 /** Local socket address */
33 struct sockaddr_tcpip local;
34 /** Remote socket address */
35 struct sockaddr_tcpip peer;
39 * List of registered UDP connections
41 static LIST_HEAD ( udp_conns );
43 /* Forward declatations */
44 static struct xfer_interface_operations udp_xfer_operations;
45 struct tcpip_protocol udp_protocol;
48 * Bind UDP connection to local port
50 * @v udp UDP connection
51 * @ret rc Return status code
53 * Opens the UDP connection and binds to the specified local port. If
54 * no local port is specified, the first available port will be used.
56 static int udp_bind ( struct udp_connection *udp ) {
57 struct udp_connection *existing;
58 static uint16_t try_port = 1023;
60 /* If no port specified, find the first available port */
61 if ( ! udp->local.st_port ) {
64 if ( try_port < 1024 )
66 udp->local.st_port = htons ( try_port );
67 if ( udp_bind ( udp ) == 0 )
73 /* Attempt bind to local port */
74 list_for_each_entry ( existing, &udp_conns, list ) {
75 if ( existing->local.st_port == udp->local.st_port ) {
76 DBGC ( udp, "UDP %p could not bind: port %d in use\n",
77 udp, ntohs ( udp->local.st_port ) );
82 /* Add to UDP connection list */
83 DBGC ( udp, "UDP %p bound to port %d\n",
84 udp, ntohs ( udp->local.st_port ) );
90 * Open a UDP connection
92 * @v xfer Data transfer interface
93 * @v peer Peer socket address, or NULL
94 * @v local Local socket address, or NULL
95 * @v promisc Socket is promiscuous
96 * @ret rc Return status code
98 static int udp_open_common ( struct xfer_interface *xfer,
99 struct sockaddr *peer, struct sockaddr *local,
101 struct sockaddr_tcpip *st_peer = ( struct sockaddr_tcpip * ) peer;
102 struct sockaddr_tcpip *st_local = ( struct sockaddr_tcpip * ) local;
103 struct udp_connection *udp;
106 /* Allocate and initialise structure */
107 udp = zalloc ( sizeof ( *udp ) );
110 DBGC ( udp, "UDP %p allocated\n", udp );
111 xfer_init ( &udp->xfer, &udp_xfer_operations, &udp->refcnt );
113 memcpy ( &udp->peer, st_peer, sizeof ( udp->peer ) );
115 memcpy ( &udp->local, st_local, sizeof ( udp->local ) );
117 /* Bind to local port */
119 if ( ( rc = udp_bind ( udp ) ) != 0 )
123 /* Attach parent interface, transfer reference to connection
126 xfer_plug_plug ( &udp->xfer, xfer );
127 list_add ( &udp->list, &udp_conns );
131 ref_put ( &udp->refcnt );
136 * Open a UDP connection
138 * @v xfer Data transfer interface
139 * @v peer Peer socket address
140 * @v local Local socket address, or NULL
141 * @ret rc Return status code
143 int udp_open ( struct xfer_interface *xfer, struct sockaddr *peer,
144 struct sockaddr *local ) {
145 return udp_open_common ( xfer, peer, local, 0 );
149 * Open a promiscuous UDP connection
151 * @v xfer Data transfer interface
152 * @ret rc Return status code
154 * Promiscuous UDP connections are required in order to support the
157 int udp_open_promisc ( struct xfer_interface *xfer ) {
158 return udp_open_common ( xfer, NULL, NULL, 1 );
162 * Close a UDP connection
164 * @v udp UDP connection
165 * @v rc Reason for close
167 static void udp_close ( struct udp_connection *udp, int rc ) {
169 /* Close data transfer interface */
170 xfer_nullify ( &udp->xfer );
171 xfer_close ( &udp->xfer, rc );
173 /* Remove from list of connections and drop list's reference */
174 list_del ( &udp->list );
175 ref_put ( &udp->refcnt );
177 DBGC ( udp, "UDP %p closed\n", udp );
181 * Transmit data via a UDP connection to a specified address
183 * @v udp UDP connection
184 * @v iobuf I/O buffer
185 * @v src Source address, or NULL to use default
186 * @v dest Destination address, or NULL to use default
187 * @v netdev Network device, or NULL to use default
188 * @ret rc Return status code
190 static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf,
191 struct sockaddr_tcpip *src, struct sockaddr_tcpip *dest,
192 struct net_device *netdev ) {
193 struct udp_header *udphdr;
197 /* Check we can accommodate the header */
198 if ( ( rc = iob_ensure_headroom ( iobuf, UDP_MAX_HLEN ) ) != 0 ) {
203 /* Fill in default values if not explicitly provided */
209 /* Add the UDP header */
210 udphdr = iob_push ( iobuf, sizeof ( *udphdr ) );
211 len = iob_len ( iobuf );
212 udphdr->dest = dest->st_port;
213 udphdr->src = src->st_port;
214 udphdr->len = htons ( len );
216 udphdr->chksum = tcpip_chksum ( udphdr, len );
218 /* Dump debugging information */
219 DBGC ( udp, "UDP %p TX %d->%d len %d\n", udp,
220 ntohs ( udphdr->src ), ntohs ( udphdr->dest ),
221 ntohs ( udphdr->len ) );
223 /* Send it to the next layer for processing */
224 if ( ( rc = tcpip_tx ( iobuf, &udp_protocol, src, dest, netdev,
225 &udphdr->chksum ) ) != 0 ) {
226 DBGC ( udp, "UDP %p could not transmit packet: %s\n",
227 udp, strerror ( rc ) );
235 * Identify UDP connection by local address
237 * @v local Local address
238 * @ret udp UDP connection, or NULL
240 static struct udp_connection * udp_demux ( struct sockaddr_tcpip *local ) {
241 static const struct sockaddr_tcpip empty_sockaddr;
242 struct udp_connection *udp;
244 list_for_each_entry ( udp, &udp_conns, list ) {
245 if ( ( ( udp->local.st_family == local->st_family ) ||
246 ( udp->local.st_family == 0 ) ) &&
247 ( ( udp->local.st_port == local->st_port ) ||
248 ( udp->local.st_port == 0 ) ) &&
249 ( ( memcmp ( udp->local.pad, local->pad,
250 sizeof ( udp->local.pad ) ) == 0 ) ||
251 ( memcmp ( udp->local.pad, empty_sockaddr.pad,
252 sizeof ( udp->local.pad ) ) == 0 ) ) ) {
260 * Process a received packet
262 * @v iobuf I/O buffer
263 * @v st_src Partially-filled source address
264 * @v st_dest Partially-filled destination address
265 * @v pshdr_csum Pseudo-header checksum
266 * @ret rc Return status code
268 static int udp_rx ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src,
269 struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum ) {
270 struct udp_header *udphdr = iobuf->data;
271 struct udp_connection *udp;
272 struct xfer_metadata meta;
277 /* Sanity check packet */
278 if ( iob_len ( iobuf ) < sizeof ( *udphdr ) ) {
279 DBG ( "UDP packet too short at %zd bytes (min %zd bytes)\n",
280 iob_len ( iobuf ), sizeof ( *udphdr ) );
285 ulen = ntohs ( udphdr->len );
286 if ( ulen < sizeof ( *udphdr ) ) {
287 DBG ( "UDP length too short at %zd bytes "
288 "(header is %zd bytes)\n", ulen, sizeof ( *udphdr ) );
292 if ( ulen > iob_len ( iobuf ) ) {
293 DBG ( "UDP length too long at %zd bytes (packet is %zd "
294 "bytes)\n", ulen, iob_len ( iobuf ) );
298 if ( udphdr->chksum ) {
299 csum = tcpip_continue_chksum ( pshdr_csum, iobuf->data, ulen );
301 DBG ( "UDP checksum incorrect (is %04x including "
302 "checksum field, should be 0000)\n", csum );
308 /* Parse parameters from header and strip header */
309 st_src->st_port = udphdr->src;
310 st_dest->st_port = udphdr->dest;
311 udp = udp_demux ( st_dest );
312 iob_unput ( iobuf, ( iob_len ( iobuf ) - ulen ) );
313 iob_pull ( iobuf, sizeof ( *udphdr ) );
315 /* Dump debugging information */
316 DBGC ( udp, "UDP %p RX %d<-%d len %zd\n", udp,
317 ntohs ( udphdr->dest ), ntohs ( udphdr->src ), ulen );
319 /* Ignore if no matching connection found */
321 DBG ( "No UDP connection listening on port %d\n",
322 ntohs ( udphdr->dest ) );
327 /* Pass data to application */
328 memset ( &meta, 0, sizeof ( meta ) );
329 meta.src = ( struct sockaddr * ) st_src;
330 meta.dest = ( struct sockaddr * ) st_dest;
331 rc = xfer_deliver_iob_meta ( &udp->xfer, iob_disown ( iobuf ), &meta );
338 struct tcpip_protocol udp_protocol __tcpip_protocol = {
341 .tcpip_proto = IP_UDP,
344 /***************************************************************************
346 * Data transfer interface
348 ***************************************************************************
354 * @v xfer Data transfer interface
355 * @v rc Reason for close
357 static void udp_xfer_close ( struct xfer_interface *xfer, int rc ) {
358 struct udp_connection *udp =
359 container_of ( xfer, struct udp_connection, xfer );
361 /* Close connection */
362 udp_close ( udp, rc );
366 * Allocate I/O buffer for UDP
368 * @v xfer Data transfer interface
369 * @v len Payload size
370 * @ret iobuf I/O buffer, or NULL
372 static struct io_buffer * udp_alloc_iob ( struct xfer_interface *xfer,
374 struct udp_connection *udp =
375 container_of ( xfer, struct udp_connection, xfer );
376 struct io_buffer *iobuf;
378 iobuf = alloc_iob ( UDP_MAX_HLEN + len );
380 DBGC ( udp, "UDP %p cannot allocate buffer of length %zd\n",
384 iob_reserve ( iobuf, UDP_MAX_HLEN );
389 * Deliver datagram as I/O buffer
391 * @v xfer Data transfer interface
392 * @v iobuf Datagram I/O buffer
393 * @v meta Data transfer metadata, or NULL
394 * @ret rc Return status code
396 static int udp_xfer_deliver_iob ( struct xfer_interface *xfer,
397 struct io_buffer *iobuf,
398 struct xfer_metadata *meta ) {
399 struct udp_connection *udp =
400 container_of ( xfer, struct udp_connection, xfer );
401 struct sockaddr_tcpip *src = NULL;
402 struct sockaddr_tcpip *dest = NULL;
403 struct net_device *netdev = NULL;
405 /* Apply xfer metadata */
407 src = ( struct sockaddr_tcpip * ) meta->src;
408 dest = ( struct sockaddr_tcpip * ) meta->dest;
409 netdev = meta->netdev;
412 /* Transmit data, if possible */
413 udp_tx ( udp, iobuf, src, dest, netdev );
418 /** UDP data transfer interface operations */
419 static struct xfer_interface_operations udp_xfer_operations = {
420 .close = udp_xfer_close,
421 .vredirect = ignore_xfer_vredirect,
422 .window = unlimited_xfer_window,
423 .alloc_iob = udp_alloc_iob,
424 .deliver_iob = udp_xfer_deliver_iob,
425 .deliver_raw = xfer_deliver_as_iob,
428 /***************************************************************************
432 ***************************************************************************
435 /** UDP socket opener */
436 struct socket_opener udp_socket_opener __socket_opener = {
437 .semantics = UDP_SOCK_DGRAM,
443 int udp_sock_dgram = UDP_SOCK_DGRAM;
448 * @v xfer Data transfer interface
450 * @ret rc Return status code
452 static int udp_open_uri ( struct xfer_interface *xfer, struct uri *uri ) {
453 struct sockaddr_tcpip peer;
459 memset ( &peer, 0, sizeof ( peer ) );
460 peer.st_port = htons ( uri_port ( uri, 0 ) );
461 return xfer_open_named_socket ( xfer, SOCK_DGRAM,
462 ( struct sockaddr * ) &peer,
466 /** UDP URI opener */
467 struct uri_opener udp_uri_opener __uri_opener = {
469 .open = udp_open_uri,