7 #include <ipxe/tcpip.h>
8 #include <ipxe/iobuf.h>
10 #include <ipxe/open.h>
12 #include <ipxe/netdevice.h>
20 FILE_LICENCE ( GPL2_OR_LATER );
26 struct udp_connection {
27 /** Reference counter */
29 /** List of UDP connections */
30 struct list_head list;
32 /** Data transfer interface */
33 struct interface xfer;
35 /** Local socket address */
36 struct sockaddr_tcpip local;
37 /** Remote socket address */
38 struct sockaddr_tcpip peer;
42 * List of registered UDP connections
44 static LIST_HEAD ( udp_conns );
46 /* Forward declatations */
47 static struct interface_descriptor udp_xfer_desc;
48 struct tcpip_protocol udp_protocol __tcpip_protocol;
51 * Check if local UDP port is available
53 * @v port Local port number
54 * @ret port Local port number, or negative error
56 static int udp_port_available ( int port ) {
57 struct udp_connection *udp;
59 list_for_each_entry ( udp, &udp_conns, list ) {
60 if ( udp->local.st_port == htons ( port ) )
67 * Open a UDP connection
69 * @v xfer Data transfer interface
70 * @v peer Peer socket address, or NULL
71 * @v local Local socket address, or NULL
72 * @v promisc Socket is promiscuous
73 * @ret rc Return status code
75 static int udp_open_common ( struct interface *xfer,
76 struct sockaddr *peer, struct sockaddr *local,
78 struct sockaddr_tcpip *st_peer = ( struct sockaddr_tcpip * ) peer;
79 struct sockaddr_tcpip *st_local = ( struct sockaddr_tcpip * ) local;
80 struct udp_connection *udp;
84 /* Allocate and initialise structure */
85 udp = zalloc ( sizeof ( *udp ) );
88 DBGC ( udp, "UDP %p allocated\n", udp );
89 ref_init ( &udp->refcnt, NULL );
90 intf_init ( &udp->xfer, &udp_xfer_desc, &udp->refcnt );
92 memcpy ( &udp->peer, st_peer, sizeof ( udp->peer ) );
94 memcpy ( &udp->local, st_local, sizeof ( udp->local ) );
96 /* Bind to local port */
98 port = tcpip_bind ( st_local, udp_port_available );
101 DBGC ( udp, "UDP %p could not bind: %s\n",
102 udp, strerror ( rc ) );
105 udp->local.st_port = htons ( port );
106 DBGC ( udp, "UDP %p bound to port %d\n",
107 udp, ntohs ( udp->local.st_port ) );
110 /* Attach parent interface, transfer reference to connection
113 intf_plug_plug ( &udp->xfer, xfer );
114 list_add ( &udp->list, &udp_conns );
118 ref_put ( &udp->refcnt );
123 * Open a UDP connection
125 * @v xfer Data transfer interface
126 * @v peer Peer socket address
127 * @v local Local socket address, or NULL
128 * @ret rc Return status code
130 int udp_open ( struct interface *xfer, struct sockaddr *peer,
131 struct sockaddr *local ) {
132 return udp_open_common ( xfer, peer, local, 0 );
136 * Open a promiscuous UDP connection
138 * @v xfer Data transfer interface
139 * @ret rc Return status code
141 * Promiscuous UDP connections are required in order to support the
144 int udp_open_promisc ( struct interface *xfer ) {
145 return udp_open_common ( xfer, NULL, NULL, 1 );
149 * Close a UDP connection
151 * @v udp UDP connection
152 * @v rc Reason for close
154 static void udp_close ( struct udp_connection *udp, int rc ) {
156 /* Close data transfer interface */
157 intf_shutdown ( &udp->xfer, rc );
159 /* Remove from list of connections and drop list's reference */
160 list_del ( &udp->list );
161 ref_put ( &udp->refcnt );
163 DBGC ( udp, "UDP %p closed\n", udp );
167 * Transmit data via a UDP connection to a specified address
169 * @v udp UDP connection
170 * @v iobuf I/O buffer
171 * @v src Source address, or NULL to use default
172 * @v dest Destination address, or NULL to use default
173 * @v netdev Network device, or NULL to use default
174 * @ret rc Return status code
176 static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf,
177 struct sockaddr_tcpip *src, struct sockaddr_tcpip *dest,
178 struct net_device *netdev ) {
179 struct udp_header *udphdr;
183 /* Check we can accommodate the header */
184 if ( ( rc = iob_ensure_headroom ( iobuf,
185 MAX_LL_NET_HEADER_LEN ) ) != 0 ) {
190 /* Fill in default values if not explicitly provided */
196 /* Add the UDP header */
197 udphdr = iob_push ( iobuf, sizeof ( *udphdr ) );
198 len = iob_len ( iobuf );
199 udphdr->dest = dest->st_port;
200 udphdr->src = src->st_port;
201 udphdr->len = htons ( len );
203 udphdr->chksum = tcpip_chksum ( udphdr, len );
205 /* Dump debugging information */
206 DBGC2 ( udp, "UDP %p TX %d->%d len %d\n", udp,
207 ntohs ( udphdr->src ), ntohs ( udphdr->dest ),
208 ntohs ( udphdr->len ) );
210 /* Send it to the next layer for processing */
211 if ( ( rc = tcpip_tx ( iobuf, &udp_protocol, src, dest, netdev,
212 &udphdr->chksum ) ) != 0 ) {
213 DBGC ( udp, "UDP %p could not transmit packet: %s\n",
214 udp, strerror ( rc ) );
222 * Identify UDP connection by local address
224 * @v local Local address
225 * @ret udp UDP connection, or NULL
227 static struct udp_connection * udp_demux ( struct sockaddr_tcpip *local ) {
228 static const struct sockaddr_tcpip empty_sockaddr = { .pad = { 0, } };
229 struct udp_connection *udp;
231 list_for_each_entry ( udp, &udp_conns, list ) {
232 if ( ( ( udp->local.st_family == local->st_family ) ||
233 ( udp->local.st_family == 0 ) ) &&
234 ( ( udp->local.st_port == local->st_port ) ||
235 ( udp->local.st_port == 0 ) ) &&
236 ( ( memcmp ( udp->local.pad, local->pad,
237 sizeof ( udp->local.pad ) ) == 0 ) ||
238 ( memcmp ( udp->local.pad, empty_sockaddr.pad,
239 sizeof ( udp->local.pad ) ) == 0 ) ) ) {
247 * Process a received packet
249 * @v iobuf I/O buffer
250 * @v netdev Network device
251 * @v st_src Partially-filled source address
252 * @v st_dest Partially-filled destination address
253 * @v pshdr_csum Pseudo-header checksum
254 * @ret rc Return status code
256 static int udp_rx ( struct io_buffer *iobuf,
257 struct net_device *netdev __unused,
258 struct sockaddr_tcpip *st_src,
259 struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum ) {
260 struct udp_header *udphdr = iobuf->data;
261 struct udp_connection *udp;
262 struct xfer_metadata meta;
267 /* Sanity check packet */
268 if ( iob_len ( iobuf ) < sizeof ( *udphdr ) ) {
269 DBG ( "UDP packet too short at %zd bytes (min %zd bytes)\n",
270 iob_len ( iobuf ), sizeof ( *udphdr ) );
275 ulen = ntohs ( udphdr->len );
276 if ( ulen < sizeof ( *udphdr ) ) {
277 DBG ( "UDP length too short at %zd bytes "
278 "(header is %zd bytes)\n", ulen, sizeof ( *udphdr ) );
282 if ( ulen > iob_len ( iobuf ) ) {
283 DBG ( "UDP length too long at %zd bytes (packet is %zd "
284 "bytes)\n", ulen, iob_len ( iobuf ) );
288 if ( udphdr->chksum ) {
289 csum = tcpip_continue_chksum ( pshdr_csum, iobuf->data, ulen );
291 DBG ( "UDP checksum incorrect (is %04x including "
292 "checksum field, should be 0000)\n", csum );
298 /* Parse parameters from header and strip header */
299 st_src->st_port = udphdr->src;
300 st_dest->st_port = udphdr->dest;
301 udp = udp_demux ( st_dest );
302 iob_unput ( iobuf, ( iob_len ( iobuf ) - ulen ) );
303 iob_pull ( iobuf, sizeof ( *udphdr ) );
305 /* Dump debugging information */
306 DBGC2 ( udp, "UDP %p RX %d<-%d len %zd\n", udp,
307 ntohs ( udphdr->dest ), ntohs ( udphdr->src ), ulen );
309 /* Ignore if no matching connection found */
311 DBG ( "No UDP connection listening on port %d\n",
312 ntohs ( udphdr->dest ) );
317 /* Pass data to application */
318 memset ( &meta, 0, sizeof ( meta ) );
319 meta.src = ( struct sockaddr * ) st_src;
320 meta.dest = ( struct sockaddr * ) st_dest;
321 rc = xfer_deliver ( &udp->xfer, iob_disown ( iobuf ), &meta );
328 struct tcpip_protocol udp_protocol __tcpip_protocol = {
331 .tcpip_proto = IP_UDP,
334 /***************************************************************************
336 * Data transfer interface
338 ***************************************************************************
342 * Allocate I/O buffer for UDP
344 * @v udp UDP connection
345 * @v len Payload size
346 * @ret iobuf I/O buffer, or NULL
348 static struct io_buffer * udp_xfer_alloc_iob ( struct udp_connection *udp,
350 struct io_buffer *iobuf;
352 iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN + len );
354 DBGC ( udp, "UDP %p cannot allocate buffer of length %zd\n",
358 iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN );
363 * Deliver datagram as I/O buffer
365 * @v udp UDP connection
366 * @v iobuf Datagram I/O buffer
367 * @v meta Data transfer metadata
368 * @ret rc Return status code
370 static int udp_xfer_deliver ( struct udp_connection *udp,
371 struct io_buffer *iobuf,
372 struct xfer_metadata *meta ) {
374 /* Transmit data, if possible */
375 return udp_tx ( udp, iobuf, ( ( struct sockaddr_tcpip * ) meta->src ),
376 ( ( struct sockaddr_tcpip * ) meta->dest ),
380 /** UDP data transfer interface operations */
381 static struct interface_operation udp_xfer_operations[] = {
382 INTF_OP ( xfer_deliver, struct udp_connection *, udp_xfer_deliver ),
383 INTF_OP ( xfer_alloc_iob, struct udp_connection *, udp_xfer_alloc_iob ),
384 INTF_OP ( intf_close, struct udp_connection *, udp_close ),
387 /** UDP data transfer interface descriptor */
388 static struct interface_descriptor udp_xfer_desc =
389 INTF_DESC ( struct udp_connection, xfer, udp_xfer_operations );
391 /***************************************************************************
395 ***************************************************************************
398 /** UDP IPv4 socket opener */
399 struct socket_opener udp_ipv4_socket_opener __socket_opener = {
400 .semantics = UDP_SOCK_DGRAM,
405 /** UDP IPv6 socket opener */
406 struct socket_opener udp_ipv6_socket_opener __socket_opener = {
407 .semantics = UDP_SOCK_DGRAM,
413 int udp_sock_dgram = UDP_SOCK_DGRAM;
418 * @v xfer Data transfer interface
420 * @ret rc Return status code
422 static int udp_open_uri ( struct interface *xfer, struct uri *uri ) {
423 struct sockaddr_tcpip peer;
429 memset ( &peer, 0, sizeof ( peer ) );
430 peer.st_port = htons ( uri_port ( uri, 0 ) );
431 return xfer_open_named_socket ( xfer, SOCK_DGRAM,
432 ( struct sockaddr * ) &peer,
436 /** UDP URI opener */
437 struct uri_opener udp_uri_opener __uri_opener = {
439 .open = udp_open_uri,