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 /** Remote socket address */
33 struct sockaddr_tcpip peer
;
34 /** Local port on which the connection receives packets */
35 unsigned int local_port
;
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 * @v port Local port, in network byte order, or zero
52 * @ret rc Return status code
54 * Opens the UDP connection and binds to a local port. If no local
55 * port is specified, the first available port will be used.
57 static int udp_bind ( struct udp_connection
*udp
, unsigned int port
) {
58 struct udp_connection
*existing
;
59 static uint16_t try_port
= 1024;
61 /* If no port specified, find the first available port */
63 for ( ; try_port
; try_port
++ ) {
64 if ( try_port
< 1024 )
66 if ( udp_bind ( udp
, htons ( try_port
) ) == 0 )
72 /* Attempt bind to local port */
73 list_for_each_entry ( existing
, &udp_conns
, list
) {
74 if ( existing
->local_port
== port
) {
75 DBGC ( udp
, "UDP %p could not bind: port %d in use\n",
76 udp
, ntohs ( port
) );
80 udp
->local_port
= port
;
82 /* Add to UDP connection list */
83 DBGC ( udp
, "UDP %p bound to port %d\n", udp
, ntohs ( port
) );
89 * Open a UDP connection
91 * @v xfer Data transfer interface
92 * @v peer Peer socket address, or NULL
93 * @v local Local socket address, or NULL
94 * @v promisc Socket is promiscuous
95 * @ret rc Return status code
97 static int udp_open_common ( struct xfer_interface
*xfer
,
98 struct sockaddr
*peer
, struct sockaddr
*local
,
100 struct sockaddr_tcpip
*st_peer
= ( struct sockaddr_tcpip
* ) peer
;
101 struct sockaddr_tcpip
*st_local
= ( struct sockaddr_tcpip
* ) local
;
102 struct udp_connection
*udp
;
103 unsigned int bind_port
;
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 /* Bind to local port */
117 bind_port
= ( st_local
? st_local
->st_port
: 0 );
118 if ( ( rc
= udp_bind ( udp
, bind_port
) ) != 0 )
122 /* Attach parent interface, transfer reference to connection
125 xfer_plug_plug ( &udp
->xfer
, xfer
);
126 list_add ( &udp
->list
, &udp_conns
);
130 ref_put ( &udp
->refcnt
);
135 * Open a UDP connection
137 * @v xfer Data transfer interface
138 * @v peer Peer socket address
139 * @v local Local socket address, or NULL
140 * @ret rc Return status code
142 int udp_open ( struct xfer_interface
*xfer
, struct sockaddr
*peer
,
143 struct sockaddr
*local
) {
144 return udp_open_common ( xfer
, peer
, local
, 0 );
148 * Open a promiscuous UDP connection
150 * @v xfer Data transfer interface
151 * @ret rc Return status code
153 * Promiscuous UDP connections are required in order to support the
156 int udp_open_promisc ( struct xfer_interface
*xfer
) {
157 return udp_open_common ( xfer
, NULL
, NULL
, 1 );
161 * Close a UDP connection
163 * @v udp UDP connection
164 * @v rc Reason for close
166 static void udp_close ( struct udp_connection
*udp
, int rc
) {
168 /* Close data transfer interface */
169 xfer_nullify ( &udp
->xfer
);
170 xfer_close ( &udp
->xfer
, rc
);
172 /* Remove from list of connections and drop list's reference */
173 list_del ( &udp
->list
);
174 ref_put ( &udp
->refcnt
);
176 DBGC ( udp
, "UDP %p closed\n", udp
);
180 * Transmit data via a UDP connection to a specified address
182 * @v udp UDP connection
183 * @v iobuf I/O buffer
184 * @v src_port Source port, or 0 to use default
185 * @v dest Destination address, or NULL to use default
186 * @v netdev Network device, or NULL to use default
187 * @ret rc Return status code
189 static int udp_tx ( struct udp_connection
*udp
, struct io_buffer
*iobuf
,
190 unsigned int src_port
, struct sockaddr_tcpip
*dest
,
191 struct net_device
*netdev
) {
192 struct udp_header
*udphdr
;
196 /* Check we can accommodate the header */
197 if ( ( rc
= iob_ensure_headroom ( iobuf
, UDP_MAX_HLEN
) ) != 0 ) {
202 /* Fill in default values if not explicitly provided */
204 src_port
= udp
->local_port
;
208 /* Add the UDP header */
209 udphdr
= iob_push ( iobuf
, sizeof ( *udphdr
) );
210 len
= iob_len ( iobuf
);
211 udphdr
->dest
= dest
->st_port
;
212 udphdr
->src
= src_port
;
213 udphdr
->len
= htons ( len
);
215 udphdr
->chksum
= tcpip_chksum ( udphdr
, len
);
217 /* Dump debugging information */
218 DBGC ( udp
, "UDP %p TX %d->%d len %d\n", udp
,
219 ntohs ( udphdr
->src
), ntohs ( udphdr
->dest
),
220 ntohs ( udphdr
->len
) );
222 /* Send it to the next layer for processing */
223 if ( ( rc
= tcpip_tx ( iobuf
, &udp_protocol
, dest
, netdev
,
224 &udphdr
->chksum
) ) != 0 ) {
225 DBGC ( udp
, "UDP %p could not transmit packet: %s\n",
226 udp
, strerror ( rc
) );
234 * Identify UDP connection by local port number
236 * @v local_port Local port (in network-endian order)
237 * @ret udp UDP connection, or NULL
239 static struct udp_connection
* udp_demux ( unsigned int local_port
) {
240 struct udp_connection
*udp
;
242 list_for_each_entry ( udp
, &udp_conns
, list
) {
243 if ( ( udp
->local_port
== local_port
) ||
244 ( udp
->local_port
== 0 ) ) {
252 * Process a received packet
254 * @v iobuf I/O buffer
255 * @v st_src Partially-filled source address
256 * @v st_dest Partially-filled destination address
257 * @v pshdr_csum Pseudo-header checksum
258 * @ret rc Return status code
260 static int udp_rx ( struct io_buffer
*iobuf
, struct sockaddr_tcpip
*st_src
,
261 struct sockaddr_tcpip
*st_dest
, uint16_t pshdr_csum
) {
262 struct udp_header
*udphdr
= iobuf
->data
;
263 struct udp_connection
*udp
;
264 struct xfer_metadata meta
;
269 /* Sanity check packet */
270 if ( iob_len ( iobuf
) < sizeof ( *udphdr
) ) {
271 DBG ( "UDP packet too short at %zd bytes (min %zd bytes)\n",
272 iob_len ( iobuf
), sizeof ( *udphdr
) );
277 ulen
= ntohs ( udphdr
->len
);
278 if ( ulen
< sizeof ( *udphdr
) ) {
279 DBG ( "UDP length too short at %zd bytes "
280 "(header is %zd bytes)\n", ulen
, sizeof ( *udphdr
) );
284 if ( ulen
> iob_len ( iobuf
) ) {
285 DBG ( "UDP length too long at %zd bytes (packet is %zd "
286 "bytes)\n", ulen
, iob_len ( iobuf
) );
290 if ( udphdr
->chksum
) {
291 csum
= tcpip_continue_chksum ( pshdr_csum
, iobuf
->data
, ulen
);
293 DBG ( "UDP checksum incorrect (is %04x including "
294 "checksum field, should be 0000)\n", csum
);
300 /* Parse parameters from header and strip header */
301 st_src
->st_port
= udphdr
->src
;
302 st_dest
->st_port
= udphdr
->dest
;
303 udp
= udp_demux ( udphdr
->dest
);
304 iob_unput ( iobuf
, ( iob_len ( iobuf
) - ulen
) );
305 iob_pull ( iobuf
, sizeof ( *udphdr
) );
307 /* Dump debugging information */
308 DBGC ( udp
, "UDP %p RX %d<-%d len %zd\n", udp
,
309 ntohs ( udphdr
->dest
), ntohs ( udphdr
->src
), ulen
);
311 /* Ignore if no matching connection found */
313 DBG ( "No UDP connection listening on port %d\n",
314 ntohs ( udphdr
->dest
) );
319 /* Pass data to application */
320 memset ( &meta
, 0, sizeof ( meta
) );
321 meta
.src
= ( struct sockaddr
* ) st_src
;
322 meta
.dest
= ( struct sockaddr
* ) st_dest
;
323 rc
= xfer_deliver_iob_meta ( &udp
->xfer
, iobuf
, &meta
);
331 struct tcpip_protocol udp_protocol __tcpip_protocol
= {
334 .tcpip_proto
= IP_UDP
,
337 /***************************************************************************
339 * Data transfer interface
341 ***************************************************************************
347 * @v xfer Data transfer interface
348 * @v rc Reason for close
350 static void udp_xfer_close ( struct xfer_interface
*xfer
, int rc
) {
351 struct udp_connection
*udp
=
352 container_of ( xfer
, struct udp_connection
, xfer
);
354 /* Close connection */
355 udp_close ( udp
, rc
);
359 * Allocate I/O buffer for UDP
361 * @v xfer Data transfer interface
362 * @v len Payload size
363 * @ret iobuf I/O buffer, or NULL
365 static struct io_buffer
* udp_alloc_iob ( struct xfer_interface
*xfer
,
367 struct udp_connection
*udp
=
368 container_of ( xfer
, struct udp_connection
, xfer
);
369 struct io_buffer
*iobuf
;
371 iobuf
= alloc_iob ( UDP_MAX_HLEN
+ len
);
373 DBGC ( udp
, "UDP %p cannot allocate buffer of length %zd\n",
377 iob_reserve ( iobuf
, UDP_MAX_HLEN
);
382 * Deliver datagram as I/O buffer
384 * @v xfer Data transfer interface
385 * @v iobuf Datagram I/O buffer
386 * @v meta Data transfer metadata, or NULL
387 * @ret rc Return status code
389 static int udp_xfer_deliver_iob ( struct xfer_interface
*xfer
,
390 struct io_buffer
*iobuf
,
391 struct xfer_metadata
*meta
) {
392 struct udp_connection
*udp
=
393 container_of ( xfer
, struct udp_connection
, xfer
);
394 struct sockaddr_tcpip
*src
;
395 struct sockaddr_tcpip
*dest
= NULL
;
396 struct net_device
*netdev
= NULL
;
397 unsigned int src_port
= 0;
399 /* Apply xfer metadata */
401 src
= ( struct sockaddr_tcpip
* ) meta
->src
;
403 src_port
= src
->st_port
;
404 dest
= ( struct sockaddr_tcpip
* ) meta
->dest
;
405 netdev
= meta
->netdev
;
408 /* Transmit data, if possible */
409 udp_tx ( udp
, iobuf
, src_port
, dest
, netdev
);
414 /** UDP data transfer interface operations */
415 static struct xfer_interface_operations udp_xfer_operations
= {
416 .close
= udp_xfer_close
,
417 .vredirect
= ignore_xfer_vredirect
,
418 .window
= unlimited_xfer_window
,
419 .alloc_iob
= udp_alloc_iob
,
420 .deliver_iob
= udp_xfer_deliver_iob
,
421 .deliver_raw
= xfer_deliver_as_iob
,
424 /***************************************************************************
428 ***************************************************************************
431 /** UDP socket opener */
432 struct socket_opener udp_socket_opener __socket_opener
= {
433 .semantics
= SOCK_DGRAM
,
438 char UDP_SOCK_DGRAM
[1];
443 * @v xfer Data transfer interface
445 * @ret rc Return status code
447 static int udp_open_uri ( struct xfer_interface
*xfer
, struct uri
*uri
) {
448 struct sockaddr_tcpip peer
;
454 memset ( &peer
, 0, sizeof ( peer
) );
455 peer
.st_port
= htons ( uri_port ( uri
, 0 ) );
456 return xfer_open_named_socket ( xfer
, SOCK_DGRAM
,
457 ( struct sockaddr
* ) &peer
,
461 /** UDP URI opener */
462 struct uri_opener udp_uri_opener __uri_opener
= {
464 .open
= udp_open_uri
,