7 #include <gpxe/tcpip.h>
8 #include <gpxe/iobuf.h>
10 #include <gpxe/open.h>
19 FILE_LICENCE ( GPL2_OR_LATER
);
25 struct udp_connection
{
26 /** Reference counter */
28 /** List of UDP connections */
29 struct list_head list
;
31 /** Data transfer interface */
32 struct xfer_interface xfer
;
34 /** Local socket address */
35 struct sockaddr_tcpip local
;
36 /** Remote socket address */
37 struct sockaddr_tcpip peer
;
41 * List of registered UDP connections
43 static LIST_HEAD ( udp_conns
);
45 /* Forward declatations */
46 static struct xfer_interface_operations udp_xfer_operations
;
47 struct tcpip_protocol udp_protocol
;
50 * Bind UDP connection to local port
52 * @v udp UDP connection
53 * @ret rc Return status code
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.
58 static int udp_bind ( struct udp_connection
*udp
) {
59 struct udp_connection
*existing
;
60 static uint16_t try_port
= 1023;
62 /* If no port specified, find the first available port */
63 if ( ! udp
->local
.st_port
) {
66 if ( try_port
< 1024 )
68 udp
->local
.st_port
= htons ( try_port
);
69 if ( udp_bind ( udp
) == 0 )
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
) );
84 /* Add to UDP connection list */
85 DBGC ( udp
, "UDP %p bound to port %d\n",
86 udp
, ntohs ( udp
->local
.st_port
) );
92 * Open a UDP connection
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
100 static int udp_open_common ( struct xfer_interface
*xfer
,
101 struct sockaddr
*peer
, struct sockaddr
*local
,
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
;
108 /* Allocate and initialise structure */
109 udp
= zalloc ( sizeof ( *udp
) );
112 DBGC ( udp
, "UDP %p allocated\n", udp
);
113 ref_init ( &udp
->refcnt
, NULL
);
114 xfer_init ( &udp
->xfer
, &udp_xfer_operations
, &udp
->refcnt
);
116 memcpy ( &udp
->peer
, st_peer
, sizeof ( udp
->peer
) );
118 memcpy ( &udp
->local
, st_local
, sizeof ( udp
->local
) );
120 /* Bind to local port */
122 if ( ( rc
= udp_bind ( udp
) ) != 0 )
126 /* Attach parent interface, transfer reference to connection
129 xfer_plug_plug ( &udp
->xfer
, xfer
);
130 list_add ( &udp
->list
, &udp_conns
);
134 ref_put ( &udp
->refcnt
);
139 * Open a UDP connection
141 * @v xfer Data transfer interface
142 * @v peer Peer socket address
143 * @v local Local socket address, or NULL
144 * @ret rc Return status code
146 int udp_open ( struct xfer_interface
*xfer
, struct sockaddr
*peer
,
147 struct sockaddr
*local
) {
148 return udp_open_common ( xfer
, peer
, local
, 0 );
152 * Open a promiscuous UDP connection
154 * @v xfer Data transfer interface
155 * @ret rc Return status code
157 * Promiscuous UDP connections are required in order to support the
160 int udp_open_promisc ( struct xfer_interface
*xfer
) {
161 return udp_open_common ( xfer
, NULL
, NULL
, 1 );
165 * Close a UDP connection
167 * @v udp UDP connection
168 * @v rc Reason for close
170 static void udp_close ( struct udp_connection
*udp
, int rc
) {
172 /* Close data transfer interface */
173 xfer_nullify ( &udp
->xfer
);
174 xfer_close ( &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
, UDP_MAX_HLEN
) ) != 0 ) {
206 /* Fill in default values if not explicitly provided */
212 /* Add the UDP header */
213 udphdr
= iob_push ( iobuf
, sizeof ( *udphdr
) );
214 len
= iob_len ( iobuf
);
215 udphdr
->dest
= dest
->st_port
;
216 udphdr
->src
= src
->st_port
;
217 udphdr
->len
= htons ( len
);
219 udphdr
->chksum
= tcpip_chksum ( udphdr
, len
);
221 /* Dump debugging information */
222 DBGC ( udp
, "UDP %p TX %d->%d len %d\n", udp
,
223 ntohs ( udphdr
->src
), ntohs ( udphdr
->dest
),
224 ntohs ( udphdr
->len
) );
226 /* Send it to the next layer for processing */
227 if ( ( rc
= tcpip_tx ( iobuf
, &udp_protocol
, src
, dest
, netdev
,
228 &udphdr
->chksum
) ) != 0 ) {
229 DBGC ( udp
, "UDP %p could not transmit packet: %s\n",
230 udp
, strerror ( rc
) );
238 * Identify UDP connection by local address
240 * @v local Local address
241 * @ret udp UDP connection, or NULL
243 static struct udp_connection
* udp_demux ( struct sockaddr_tcpip
*local
) {
244 static const struct sockaddr_tcpip empty_sockaddr
= { .pad
= { 0, } };
245 struct udp_connection
*udp
;
247 list_for_each_entry ( udp
, &udp_conns
, list
) {
248 if ( ( ( udp
->local
.st_family
== local
->st_family
) ||
249 ( udp
->local
.st_family
== 0 ) ) &&
250 ( ( udp
->local
.st_port
== local
->st_port
) ||
251 ( udp
->local
.st_port
== 0 ) ) &&
252 ( ( memcmp ( udp
->local
.pad
, local
->pad
,
253 sizeof ( udp
->local
.pad
) ) == 0 ) ||
254 ( memcmp ( udp
->local
.pad
, empty_sockaddr
.pad
,
255 sizeof ( udp
->local
.pad
) ) == 0 ) ) ) {
263 * Process a received packet
265 * @v iobuf I/O buffer
266 * @v st_src Partially-filled source address
267 * @v st_dest Partially-filled destination address
268 * @v pshdr_csum Pseudo-header checksum
269 * @ret rc Return status code
271 static int udp_rx ( struct io_buffer
*iobuf
, struct sockaddr_tcpip
*st_src
,
272 struct sockaddr_tcpip
*st_dest
, uint16_t pshdr_csum
) {
273 struct udp_header
*udphdr
= iobuf
->data
;
274 struct udp_connection
*udp
;
275 struct xfer_metadata meta
;
280 /* Sanity check packet */
281 if ( iob_len ( iobuf
) < sizeof ( *udphdr
) ) {
282 DBG ( "UDP packet too short at %zd bytes (min %zd bytes)\n",
283 iob_len ( iobuf
), sizeof ( *udphdr
) );
288 ulen
= ntohs ( udphdr
->len
);
289 if ( ulen
< sizeof ( *udphdr
) ) {
290 DBG ( "UDP length too short at %zd bytes "
291 "(header is %zd bytes)\n", ulen
, sizeof ( *udphdr
) );
295 if ( ulen
> iob_len ( iobuf
) ) {
296 DBG ( "UDP length too long at %zd bytes (packet is %zd "
297 "bytes)\n", ulen
, iob_len ( iobuf
) );
301 if ( udphdr
->chksum
) {
302 csum
= tcpip_continue_chksum ( pshdr_csum
, iobuf
->data
, ulen
);
304 DBG ( "UDP checksum incorrect (is %04x including "
305 "checksum field, should be 0000)\n", csum
);
311 /* Parse parameters from header and strip header */
312 st_src
->st_port
= udphdr
->src
;
313 st_dest
->st_port
= udphdr
->dest
;
314 udp
= udp_demux ( st_dest
);
315 iob_unput ( iobuf
, ( iob_len ( iobuf
) - ulen
) );
316 iob_pull ( iobuf
, sizeof ( *udphdr
) );
318 /* Dump debugging information */
319 DBGC ( udp
, "UDP %p RX %d<-%d len %zd\n", udp
,
320 ntohs ( udphdr
->dest
), ntohs ( udphdr
->src
), ulen
);
322 /* Ignore if no matching connection found */
324 DBG ( "No UDP connection listening on port %d\n",
325 ntohs ( udphdr
->dest
) );
330 /* Pass data to application */
331 memset ( &meta
, 0, sizeof ( meta
) );
332 meta
.src
= ( struct sockaddr
* ) st_src
;
333 meta
.dest
= ( struct sockaddr
* ) st_dest
;
334 rc
= xfer_deliver_iob_meta ( &udp
->xfer
, iob_disown ( iobuf
), &meta
);
341 struct tcpip_protocol udp_protocol __tcpip_protocol
= {
344 .tcpip_proto
= IP_UDP
,
347 /***************************************************************************
349 * Data transfer interface
351 ***************************************************************************
357 * @v xfer Data transfer interface
358 * @v rc Reason for close
360 static void udp_xfer_close ( struct xfer_interface
*xfer
, int rc
) {
361 struct udp_connection
*udp
=
362 container_of ( xfer
, struct udp_connection
, xfer
);
364 /* Close connection */
365 udp_close ( udp
, rc
);
369 * Allocate I/O buffer for UDP
371 * @v xfer Data transfer interface
372 * @v len Payload size
373 * @ret iobuf I/O buffer, or NULL
375 static struct io_buffer
* udp_alloc_iob ( struct xfer_interface
*xfer
,
377 struct udp_connection
*udp
=
378 container_of ( xfer
, struct udp_connection
, xfer
);
379 struct io_buffer
*iobuf
;
381 iobuf
= alloc_iob ( UDP_MAX_HLEN
+ len
);
383 DBGC ( udp
, "UDP %p cannot allocate buffer of length %zd\n",
387 iob_reserve ( iobuf
, UDP_MAX_HLEN
);
392 * Deliver datagram as I/O buffer
394 * @v xfer Data transfer interface
395 * @v iobuf Datagram I/O buffer
396 * @v meta Data transfer metadata
397 * @ret rc Return status code
399 static int udp_xfer_deliver_iob ( struct xfer_interface
*xfer
,
400 struct io_buffer
*iobuf
,
401 struct xfer_metadata
*meta
) {
402 struct udp_connection
*udp
=
403 container_of ( xfer
, struct udp_connection
, xfer
);
405 /* Transmit data, if possible */
406 udp_tx ( udp
, iobuf
, ( ( struct sockaddr_tcpip
* ) meta
->src
),
407 ( ( struct sockaddr_tcpip
* ) meta
->dest
), meta
->netdev
);
412 /** UDP data transfer interface operations */
413 static struct xfer_interface_operations udp_xfer_operations
= {
414 .close
= udp_xfer_close
,
415 .vredirect
= ignore_xfer_vredirect
,
416 .window
= unlimited_xfer_window
,
417 .alloc_iob
= udp_alloc_iob
,
418 .deliver_iob
= udp_xfer_deliver_iob
,
419 .deliver_raw
= xfer_deliver_as_iob
,
422 /***************************************************************************
426 ***************************************************************************
429 /** UDP socket opener */
430 struct socket_opener udp_socket_opener __socket_opener
= {
431 .semantics
= UDP_SOCK_DGRAM
,
436 /** UDP over IPv6 socket opener */
437 struct socket_opener udp_socket_opener_v6 __socket_opener
= {
438 .semantics
= UDP_SOCK_DGRAM
,
444 int udp_sock_dgram
= UDP_SOCK_DGRAM
;
449 * @v xfer Data transfer interface
451 * @ret rc Return status code
453 static int udp_open_uri ( struct xfer_interface
*xfer
, struct uri
*uri
) {
454 struct sockaddr_tcpip peer
;
460 memset ( &peer
, 0, sizeof ( peer
) );
461 peer
.st_port
= htons ( uri_port ( uri
, 0 ) );
462 return xfer_open_named_socket ( xfer
, SOCK_DGRAM
,
463 ( struct sockaddr
* ) &peer
,
467 /** UDP URI opener */
468 struct uri_opener udp_uri_opener __uri_opener
= {
470 .open
= udp_open_uri
,