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 * Bind UDP connection to local port
53 * @v udp UDP connection
54 * @ret rc Return status code
56 * Opens the UDP connection and binds to the specified local port. If
57 * no local port is specified, the first available port will be used.
59 static int udp_bind ( struct udp_connection *udp ) {
60 struct udp_connection *existing;
61 static uint16_t try_port = 1023;
63 /* If no port specified, find the first available port */
64 if ( ! udp->local.st_port ) {
67 if ( try_port < 1024 )
69 udp->local.st_port = htons ( try_port );
70 if ( udp_bind ( udp ) == 0 )
76 /* Attempt bind to local port */
77 list_for_each_entry ( existing, &udp_conns, list ) {
78 if ( existing->local.st_port == udp->local.st_port ) {
79 DBGC ( udp, "UDP %p could not bind: port %d in use\n",
80 udp, ntohs ( udp->local.st_port ) );
85 /* Add to UDP connection list */
86 DBGC ( udp, "UDP %p bound to port %d\n",
87 udp, ntohs ( udp->local.st_port ) );
93 * Open a UDP connection
95 * @v xfer Data transfer interface
96 * @v peer Peer socket address, or NULL
97 * @v local Local socket address, or NULL
98 * @v promisc Socket is promiscuous
99 * @ret rc Return status code
101 static int udp_open_common ( struct interface *xfer,
102 struct sockaddr *peer, struct sockaddr *local,
104 struct sockaddr_tcpip *st_peer = ( struct sockaddr_tcpip * ) peer;
105 struct sockaddr_tcpip *st_local = ( struct sockaddr_tcpip * ) local;
106 struct udp_connection *udp;
109 /* Allocate and initialise structure */
110 udp = zalloc ( sizeof ( *udp ) );
113 DBGC ( udp, "UDP %p allocated\n", udp );
114 ref_init ( &udp->refcnt, NULL );
115 intf_init ( &udp->xfer, &udp_xfer_desc, &udp->refcnt );
117 memcpy ( &udp->peer, st_peer, sizeof ( udp->peer ) );
119 memcpy ( &udp->local, st_local, sizeof ( udp->local ) );
121 /* Bind to local port */
123 if ( ( rc = udp_bind ( udp ) ) != 0 )
127 /* Attach parent interface, transfer reference to connection
130 intf_plug_plug ( &udp->xfer, xfer );
131 list_add ( &udp->list, &udp_conns );
135 ref_put ( &udp->refcnt );
140 * Open a UDP connection
142 * @v xfer Data transfer interface
143 * @v peer Peer socket address
144 * @v local Local socket address, or NULL
145 * @ret rc Return status code
147 int udp_open ( struct interface *xfer, struct sockaddr *peer,
148 struct sockaddr *local ) {
149 return udp_open_common ( xfer, peer, local, 0 );
153 * Open a promiscuous UDP connection
155 * @v xfer Data transfer interface
156 * @ret rc Return status code
158 * Promiscuous UDP connections are required in order to support the
161 int udp_open_promisc ( struct interface *xfer ) {
162 return udp_open_common ( xfer, NULL, NULL, 1 );
166 * Close a UDP connection
168 * @v udp UDP connection
169 * @v rc Reason for close
171 static void udp_close ( struct udp_connection *udp, int rc ) {
173 /* Close data transfer interface */
174 intf_shutdown ( &udp->xfer, rc );
176 /* Remove from list of connections and drop list's reference */
177 list_del ( &udp->list );
178 ref_put ( &udp->refcnt );
180 DBGC ( udp, "UDP %p closed\n", udp );
184 * Transmit data via a UDP connection to a specified address
186 * @v udp UDP connection
187 * @v iobuf I/O buffer
188 * @v src Source address, or NULL to use default
189 * @v dest Destination address, or NULL to use default
190 * @v netdev Network device, or NULL to use default
191 * @ret rc Return status code
193 static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf,
194 struct sockaddr_tcpip *src, struct sockaddr_tcpip *dest,
195 struct net_device *netdev ) {
196 struct udp_header *udphdr;
200 /* Check we can accommodate the header */
201 if ( ( rc = iob_ensure_headroom ( iobuf,
202 MAX_LL_NET_HEADER_LEN ) ) != 0 ) {
207 /* Fill in default values if not explicitly provided */
213 /* Add the UDP header */
214 udphdr = iob_push ( iobuf, sizeof ( *udphdr ) );
215 len = iob_len ( iobuf );
216 udphdr->dest = dest->st_port;
217 udphdr->src = src->st_port;
218 udphdr->len = htons ( len );
220 udphdr->chksum = tcpip_chksum ( udphdr, len );
222 /* Dump debugging information */
223 DBGC ( udp, "UDP %p TX %d->%d len %d\n", udp,
224 ntohs ( udphdr->src ), ntohs ( udphdr->dest ),
225 ntohs ( udphdr->len ) );
227 /* Send it to the next layer for processing */
228 if ( ( rc = tcpip_tx ( iobuf, &udp_protocol, src, dest, netdev,
229 &udphdr->chksum ) ) != 0 ) {
230 DBGC ( udp, "UDP %p could not transmit packet: %s\n",
231 udp, strerror ( rc ) );
239 * Identify UDP connection by local address
241 * @v local Local address
242 * @ret udp UDP connection, or NULL
244 static struct udp_connection * udp_demux ( struct sockaddr_tcpip *local ) {
245 static const struct sockaddr_tcpip empty_sockaddr = { .pad = { 0, } };
246 struct udp_connection *udp;
248 list_for_each_entry ( udp, &udp_conns, list ) {
249 if ( ( ( udp->local.st_family == local->st_family ) ||
250 ( udp->local.st_family == 0 ) ) &&
251 ( ( udp->local.st_port == local->st_port ) ||
252 ( udp->local.st_port == 0 ) ) &&
253 ( ( memcmp ( udp->local.pad, local->pad,
254 sizeof ( udp->local.pad ) ) == 0 ) ||
255 ( memcmp ( udp->local.pad, empty_sockaddr.pad,
256 sizeof ( udp->local.pad ) ) == 0 ) ) ) {
264 * Process a received packet
266 * @v iobuf I/O buffer
267 * @v st_src Partially-filled source address
268 * @v st_dest Partially-filled destination address
269 * @v pshdr_csum Pseudo-header checksum
270 * @ret rc Return status code
272 static int udp_rx ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src,
273 struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum ) {
274 struct udp_header *udphdr = iobuf->data;
275 struct udp_connection *udp;
276 struct xfer_metadata meta;
281 /* Sanity check packet */
282 if ( iob_len ( iobuf ) < sizeof ( *udphdr ) ) {
283 DBG ( "UDP packet too short at %zd bytes (min %zd bytes)\n",
284 iob_len ( iobuf ), sizeof ( *udphdr ) );
289 ulen = ntohs ( udphdr->len );
290 if ( ulen < sizeof ( *udphdr ) ) {
291 DBG ( "UDP length too short at %zd bytes "
292 "(header is %zd bytes)\n", ulen, sizeof ( *udphdr ) );
296 if ( ulen > iob_len ( iobuf ) ) {
297 DBG ( "UDP length too long at %zd bytes (packet is %zd "
298 "bytes)\n", ulen, iob_len ( iobuf ) );
302 if ( udphdr->chksum ) {
303 csum = tcpip_continue_chksum ( pshdr_csum, iobuf->data, ulen );
305 DBG ( "UDP checksum incorrect (is %04x including "
306 "checksum field, should be 0000)\n", csum );
312 /* Parse parameters from header and strip header */
313 st_src->st_port = udphdr->src;
314 st_dest->st_port = udphdr->dest;
315 udp = udp_demux ( st_dest );
316 iob_unput ( iobuf, ( iob_len ( iobuf ) - ulen ) );
317 iob_pull ( iobuf, sizeof ( *udphdr ) );
319 /* Dump debugging information */
320 DBGC ( udp, "UDP %p RX %d<-%d len %zd\n", udp,
321 ntohs ( udphdr->dest ), ntohs ( udphdr->src ), ulen );
323 /* Ignore if no matching connection found */
325 DBG ( "No UDP connection listening on port %d\n",
326 ntohs ( udphdr->dest ) );
331 /* Pass data to application */
332 memset ( &meta, 0, sizeof ( meta ) );
333 meta.src = ( struct sockaddr * ) st_src;
334 meta.dest = ( struct sockaddr * ) st_dest;
335 rc = xfer_deliver ( &udp->xfer, iob_disown ( iobuf ), &meta );
342 struct tcpip_protocol udp_protocol __tcpip_protocol = {
345 .tcpip_proto = IP_UDP,
348 /***************************************************************************
350 * Data transfer interface
352 ***************************************************************************
356 * Allocate I/O buffer for UDP
358 * @v udp UDP connection
359 * @v len Payload size
360 * @ret iobuf I/O buffer, or NULL
362 static struct io_buffer * udp_xfer_alloc_iob ( struct udp_connection *udp,
364 struct io_buffer *iobuf;
366 iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN + len );
368 DBGC ( udp, "UDP %p cannot allocate buffer of length %zd\n",
372 iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN );
377 * Deliver datagram as I/O buffer
379 * @v udp UDP connection
380 * @v iobuf Datagram I/O buffer
381 * @v meta Data transfer metadata
382 * @ret rc Return status code
384 static int udp_xfer_deliver ( struct udp_connection *udp,
385 struct io_buffer *iobuf,
386 struct xfer_metadata *meta ) {
388 /* Transmit data, if possible */
389 return udp_tx ( udp, iobuf, ( ( struct sockaddr_tcpip * ) meta->src ),
390 ( ( struct sockaddr_tcpip * ) meta->dest ),
394 /** UDP data transfer interface operations */
395 static struct interface_operation udp_xfer_operations[] = {
396 INTF_OP ( xfer_deliver, struct udp_connection *, udp_xfer_deliver ),
397 INTF_OP ( xfer_alloc_iob, struct udp_connection *, udp_xfer_alloc_iob ),
398 INTF_OP ( intf_close, struct udp_connection *, udp_close ),
401 /** UDP data transfer interface descriptor */
402 static struct interface_descriptor udp_xfer_desc =
403 INTF_DESC ( struct udp_connection, xfer, udp_xfer_operations );
405 /***************************************************************************
409 ***************************************************************************
412 /** UDP socket opener */
413 struct socket_opener udp_socket_opener __socket_opener = {
414 .semantics = UDP_SOCK_DGRAM,
420 int udp_sock_dgram = UDP_SOCK_DGRAM;
425 * @v xfer Data transfer interface
427 * @ret rc Return status code
429 static int udp_open_uri ( struct interface *xfer, struct uri *uri ) {
430 struct sockaddr_tcpip peer;
436 memset ( &peer, 0, sizeof ( peer ) );
437 peer.st_port = htons ( uri_port ( uri, 0 ) );
438 return xfer_open_named_socket ( xfer, SOCK_DGRAM,
439 ( struct sockaddr * ) &peer,
443 /** UDP URI opener */
444 struct uri_opener udp_uri_opener __uri_opener = {
446 .open = udp_open_uri,