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 xfer_init ( &udp
->xfer
, &udp_xfer_operations
, &udp
->refcnt
);
115 memcpy ( &udp
->peer
, st_peer
, sizeof ( udp
->peer
) );
117 memcpy ( &udp
->local
, st_local
, sizeof ( udp
->local
) );
119 /* Bind to local port */
121 if ( ( rc
= udp_bind ( udp
) ) != 0 )
125 /* Attach parent interface, transfer reference to connection
128 xfer_plug_plug ( &udp
->xfer
, xfer
);
129 list_add ( &udp
->list
, &udp_conns
);
133 ref_put ( &udp
->refcnt
);
138 * Open a UDP connection
140 * @v xfer Data transfer interface
141 * @v peer Peer socket address
142 * @v local Local socket address, or NULL
143 * @ret rc Return status code
145 int udp_open ( struct xfer_interface
*xfer
, struct sockaddr
*peer
,
146 struct sockaddr
*local
) {
147 return udp_open_common ( xfer
, peer
, local
, 0 );
151 * Open a promiscuous UDP connection
153 * @v xfer Data transfer interface
154 * @ret rc Return status code
156 * Promiscuous UDP connections are required in order to support the
159 int udp_open_promisc ( struct xfer_interface
*xfer
) {
160 return udp_open_common ( xfer
, NULL
, NULL
, 1 );
164 * Close a UDP connection
166 * @v udp UDP connection
167 * @v rc Reason for close
169 static void udp_close ( struct udp_connection
*udp
, int rc
) {
171 /* Close data transfer interface */
172 xfer_nullify ( &udp
->xfer
);
173 xfer_close ( &udp
->xfer
, rc
);
175 /* Remove from list of connections and drop list's reference */
176 list_del ( &udp
->list
);
177 ref_put ( &udp
->refcnt
);
179 DBGC ( udp
, "UDP %p closed\n", udp
);
183 * Transmit data via a UDP connection to a specified address
185 * @v udp UDP connection
186 * @v iobuf I/O buffer
187 * @v src Source address, or NULL to use default
188 * @v dest Destination address, or NULL to use default
189 * @v netdev Network device, or NULL to use default
190 * @ret rc Return status code
192 static int udp_tx ( struct udp_connection
*udp
, struct io_buffer
*iobuf
,
193 struct sockaddr_tcpip
*src
, struct sockaddr_tcpip
*dest
,
194 struct net_device
*netdev
) {
195 struct udp_header
*udphdr
;
199 /* Check we can accommodate the header */
200 if ( ( rc
= iob_ensure_headroom ( iobuf
, UDP_MAX_HLEN
) ) != 0 ) {
205 /* Fill in default values if not explicitly provided */
211 /* Add the UDP header */
212 udphdr
= iob_push ( iobuf
, sizeof ( *udphdr
) );
213 len
= iob_len ( iobuf
);
214 udphdr
->dest
= dest
->st_port
;
215 udphdr
->src
= src
->st_port
;
216 udphdr
->len
= htons ( len
);
218 udphdr
->chksum
= tcpip_chksum ( udphdr
, len
);
220 /* Dump debugging information */
221 DBGC ( udp
, "UDP %p TX %d->%d len %d\n", udp
,
222 ntohs ( udphdr
->src
), ntohs ( udphdr
->dest
),
223 ntohs ( udphdr
->len
) );
225 /* Send it to the next layer for processing */
226 if ( ( rc
= tcpip_tx ( iobuf
, &udp_protocol
, src
, dest
, netdev
,
227 &udphdr
->chksum
) ) != 0 ) {
228 DBGC ( udp
, "UDP %p could not transmit packet: %s\n",
229 udp
, strerror ( rc
) );
237 * Identify UDP connection by local address
239 * @v local Local address
240 * @ret udp UDP connection, or NULL
242 static struct udp_connection
* udp_demux ( struct sockaddr_tcpip
*local
) {
243 static const struct sockaddr_tcpip empty_sockaddr
= { .pad
= { 0, } };
244 struct udp_connection
*udp
;
246 list_for_each_entry ( udp
, &udp_conns
, list
) {
247 if ( ( ( udp
->local
.st_family
== local
->st_family
) ||
248 ( udp
->local
.st_family
== 0 ) ) &&
249 ( ( udp
->local
.st_port
== local
->st_port
) ||
250 ( udp
->local
.st_port
== 0 ) ) &&
251 ( ( memcmp ( udp
->local
.pad
, local
->pad
,
252 sizeof ( udp
->local
.pad
) ) == 0 ) ||
253 ( memcmp ( udp
->local
.pad
, empty_sockaddr
.pad
,
254 sizeof ( udp
->local
.pad
) ) == 0 ) ) ) {
262 * Process a received packet
264 * @v iobuf I/O buffer
265 * @v st_src Partially-filled source address
266 * @v st_dest Partially-filled destination address
267 * @v pshdr_csum Pseudo-header checksum
268 * @ret rc Return status code
270 static int udp_rx ( struct io_buffer
*iobuf
, struct sockaddr_tcpip
*st_src
,
271 struct sockaddr_tcpip
*st_dest
, uint16_t pshdr_csum
) {
272 struct udp_header
*udphdr
= iobuf
->data
;
273 struct udp_connection
*udp
;
274 struct xfer_metadata meta
;
279 /* Sanity check packet */
280 if ( iob_len ( iobuf
) < sizeof ( *udphdr
) ) {
281 DBG ( "UDP packet too short at %zd bytes (min %zd bytes)\n",
282 iob_len ( iobuf
), sizeof ( *udphdr
) );
287 ulen
= ntohs ( udphdr
->len
);
288 if ( ulen
< sizeof ( *udphdr
) ) {
289 DBG ( "UDP length too short at %zd bytes "
290 "(header is %zd bytes)\n", ulen
, sizeof ( *udphdr
) );
294 if ( ulen
> iob_len ( iobuf
) ) {
295 DBG ( "UDP length too long at %zd bytes (packet is %zd "
296 "bytes)\n", ulen
, iob_len ( iobuf
) );
300 if ( udphdr
->chksum
) {
301 csum
= tcpip_continue_chksum ( pshdr_csum
, iobuf
->data
, ulen
);
303 DBG ( "UDP checksum incorrect (is %04x including "
304 "checksum field, should be 0000)\n", csum
);
310 /* Parse parameters from header and strip header */
311 st_src
->st_port
= udphdr
->src
;
312 st_dest
->st_port
= udphdr
->dest
;
313 udp
= udp_demux ( st_dest
);
314 iob_unput ( iobuf
, ( iob_len ( iobuf
) - ulen
) );
315 iob_pull ( iobuf
, sizeof ( *udphdr
) );
317 /* Dump debugging information */
318 DBGC ( udp
, "UDP %p RX %d<-%d len %zd\n", udp
,
319 ntohs ( udphdr
->dest
), ntohs ( udphdr
->src
), ulen
);
321 /* Ignore if no matching connection found */
323 DBG ( "No UDP connection listening on port %d\n",
324 ntohs ( udphdr
->dest
) );
329 /* Pass data to application */
330 memset ( &meta
, 0, sizeof ( meta
) );
331 meta
.src
= ( struct sockaddr
* ) st_src
;
332 meta
.dest
= ( struct sockaddr
* ) st_dest
;
333 rc
= xfer_deliver_iob_meta ( &udp
->xfer
, iob_disown ( iobuf
), &meta
);
340 struct tcpip_protocol udp_protocol __tcpip_protocol
= {
343 .tcpip_proto
= IP_UDP
,
346 /***************************************************************************
348 * Data transfer interface
350 ***************************************************************************
356 * @v xfer Data transfer interface
357 * @v rc Reason for close
359 static void udp_xfer_close ( struct xfer_interface
*xfer
, int rc
) {
360 struct udp_connection
*udp
=
361 container_of ( xfer
, struct udp_connection
, xfer
);
363 /* Close connection */
364 udp_close ( udp
, rc
);
368 * Allocate I/O buffer for UDP
370 * @v xfer Data transfer interface
371 * @v len Payload size
372 * @ret iobuf I/O buffer, or NULL
374 static struct io_buffer
* udp_alloc_iob ( struct xfer_interface
*xfer
,
376 struct udp_connection
*udp
=
377 container_of ( xfer
, struct udp_connection
, xfer
);
378 struct io_buffer
*iobuf
;
380 iobuf
= alloc_iob ( UDP_MAX_HLEN
+ len
);
382 DBGC ( udp
, "UDP %p cannot allocate buffer of length %zd\n",
386 iob_reserve ( iobuf
, UDP_MAX_HLEN
);
391 * Deliver datagram as I/O buffer
393 * @v xfer Data transfer interface
394 * @v iobuf Datagram I/O buffer
395 * @v meta Data transfer metadata
396 * @ret rc Return status code
398 static int udp_xfer_deliver_iob ( struct xfer_interface
*xfer
,
399 struct io_buffer
*iobuf
,
400 struct xfer_metadata
*meta
) {
401 struct udp_connection
*udp
=
402 container_of ( xfer
, struct udp_connection
, xfer
);
404 /* Transmit data, if possible */
405 udp_tx ( udp
, iobuf
, ( ( struct sockaddr_tcpip
* ) meta
->src
),
406 ( ( struct sockaddr_tcpip
* ) meta
->dest
), meta
->netdev
);
411 /** UDP data transfer interface operations */
412 static struct xfer_interface_operations udp_xfer_operations
= {
413 .close
= udp_xfer_close
,
414 .vredirect
= ignore_xfer_vredirect
,
415 .window
= unlimited_xfer_window
,
416 .alloc_iob
= udp_alloc_iob
,
417 .deliver_iob
= udp_xfer_deliver_iob
,
418 .deliver_raw
= xfer_deliver_as_iob
,
421 /***************************************************************************
425 ***************************************************************************
428 /** UDP socket opener */
429 struct socket_opener udp_socket_opener __socket_opener
= {
430 .semantics
= UDP_SOCK_DGRAM
,
436 int udp_sock_dgram
= UDP_SOCK_DGRAM
;
441 * @v xfer Data transfer interface
443 * @ret rc Return status code
445 static int udp_open_uri ( struct xfer_interface
*xfer
, struct uri
*uri
) {
446 struct sockaddr_tcpip peer
;
452 memset ( &peer
, 0, sizeof ( peer
) );
453 peer
.st_port
= htons ( uri_port ( uri
, 0 ) );
454 return xfer_open_named_socket ( xfer
, SOCK_DGRAM
,
455 ( struct sockaddr
* ) &peer
,
459 /** UDP URI opener */
460 struct uri_opener udp_uri_opener __uri_opener
= {
462 .open
= udp_open_uri
,