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
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
);
112 memcpy ( &udp
->peer
, st_peer
, sizeof ( udp
->peer
) );
114 /* Bind to local port */
116 bind_port
= ( st_local
? st_local
->st_port
: 0 );
117 if ( ( rc
= udp_bind ( udp
, bind_port
) ) != 0 )
121 /* Attach parent interface, transfer reference to connection
124 xfer_plug_plug ( &udp
->xfer
, xfer
);
125 list_add ( &udp
->list
, &udp_conns
);
129 ref_put ( &udp
->refcnt
);
134 * Open a UDP connection
136 * @v xfer Data transfer interface
137 * @v peer Peer socket address
138 * @v local Local socket address, or NULL
139 * @ret rc Return status code
141 int udp_open ( struct xfer_interface
*xfer
, struct sockaddr
*peer
,
142 struct sockaddr
*local
) {
143 return udp_open_common ( xfer
, peer
, local
, 0 );
147 * Open a promiscuous UDP connection
149 * @v xfer Data transfer interface
150 * @ret rc Return status code
152 * Promiscuous UDP connections are required in order to support the
155 int udp_open_promisc ( struct xfer_interface
*xfer
) {
156 return udp_open_common ( xfer
, NULL
, NULL
, 1 );
160 * Close a UDP connection
162 * @v udp UDP connection
163 * @v rc Reason for close
165 static void udp_close ( struct udp_connection
*udp
, int rc
) {
167 /* Close data transfer interface */
168 xfer_nullify ( &udp
->xfer
);
169 xfer_close ( &udp
->xfer
, rc
);
171 /* Remove from list of connections and drop list's reference */
172 list_del ( &udp
->list
);
173 ref_put ( &udp
->refcnt
);
175 DBGC ( udp
, "UDP %p closed\n", udp
);
179 * Transmit data via a UDP connection to a specified address
181 * @v udp UDP connection
182 * @v iobuf I/O buffer
183 * @v src_port Source port, or 0 to use default
184 * @v dest Destination address, or NULL to use default
185 * @v netdev Network device, or NULL to use default
186 * @ret rc Return status code
188 static int udp_tx ( struct udp_connection
*udp
, struct io_buffer
*iobuf
,
189 unsigned int src_port
, struct sockaddr_tcpip
*dest
,
190 struct net_device
*netdev
) {
191 struct udp_header
*udphdr
;
195 /* Check we can accommodate the header */
196 if ( ( rc
= iob_ensure_headroom ( iobuf
, UDP_MAX_HLEN
) ) != 0 ) {
201 /* Fill in default values if not explicitly provided */
203 src_port
= udp
->local_port
;
207 /* Add the UDP header */
208 udphdr
= iob_push ( iobuf
, sizeof ( *udphdr
) );
209 len
= iob_len ( iobuf
);
210 udphdr
->dest
= dest
->st_port
;
211 udphdr
->src
= src_port
;
212 udphdr
->len
= htons ( len
);
214 udphdr
->chksum
= tcpip_chksum ( udphdr
, len
);
216 /* Dump debugging information */
217 DBGC ( udp
, "UDP %p TX %d->%d len %zd\n", udp
,
218 ntohs ( udphdr
->src
), ntohs ( udphdr
->dest
),
219 ntohs ( udphdr
->len
) );
221 /* Send it to the next layer for processing */
222 if ( ( rc
= tcpip_tx ( iobuf
, &udp_protocol
, dest
, netdev
,
223 &udphdr
->chksum
) ) != 0 ) {
224 DBGC ( udp
, "UDP %p could not transmit packet: %s\n",
225 udp
, strerror ( rc
) );
233 * Identify UDP connection by local port number
235 * @v local_port Local port (in network-endian order)
236 * @ret udp UDP connection, or NULL
238 static struct udp_connection
* udp_demux ( unsigned int local_port
) {
239 struct udp_connection
*udp
;
241 list_for_each_entry ( udp
, &udp_conns
, list
) {
242 if ( ( udp
->local_port
== local_port
) ||
243 ( udp
->local_port
== 0 ) ) {
251 * Process a received packet
253 * @v iobuf I/O buffer
254 * @v st_src Partially-filled source address
255 * @v st_dest Partially-filled destination address
256 * @v pshdr_csum Pseudo-header checksum
257 * @ret rc Return status code
259 static int udp_rx ( struct io_buffer
*iobuf
, struct sockaddr_tcpip
*st_src
,
260 struct sockaddr_tcpip
*st_dest
, uint16_t pshdr_csum
) {
261 struct udp_header
*udphdr
= iobuf
->data
;
262 struct udp_connection
*udp
;
263 struct xfer_metadata meta
;
268 /* Sanity check packet */
269 if ( iob_len ( iobuf
) < sizeof ( *udphdr
) ) {
270 DBG ( "UDP packet too short at %d bytes (min %d bytes)\n",
271 iob_len ( iobuf
), sizeof ( *udphdr
) );
276 ulen
= ntohs ( udphdr
->len
);
277 if ( ulen
< sizeof ( *udphdr
) ) {
278 DBG ( "UDP length too short at %d bytes "
279 "(header is %d bytes)\n", ulen
, sizeof ( *udphdr
) );
283 if ( ulen
> iob_len ( iobuf
) ) {
284 DBG ( "UDP length too long at %d bytes (packet is %d bytes)\n",
285 ulen
, iob_len ( iobuf
) );
289 if ( udphdr
->chksum
) {
290 csum
= tcpip_continue_chksum ( pshdr_csum
, iobuf
->data
, ulen
);
292 DBG ( "UDP checksum incorrect (is %04x including "
293 "checksum field, should be 0000)\n", csum
);
299 /* Parse parameters from header and strip header */
300 st_src
->st_port
= udphdr
->src
;
301 st_dest
->st_port
= udphdr
->dest
;
302 udp
= udp_demux ( udphdr
->dest
);
303 iob_unput ( iobuf
, ( iob_len ( iobuf
) - ulen
) );
304 iob_pull ( iobuf
, sizeof ( *udphdr
) );
306 /* Dump debugging information */
307 DBGC ( udp
, "UDP %p RX %d<-%d len %zd\n", udp
,
308 ntohs ( udphdr
->dest
), ntohs ( udphdr
->src
), ulen
);
310 /* Ignore if no matching connection found */
312 DBG ( "No UDP connection listening on port %d\n",
313 ntohs ( udphdr
->dest
) );
318 /* Pass data to application */
319 memset ( &meta
, 0, sizeof ( meta
) );
320 meta
.src
= ( struct sockaddr
* ) st_src
;
321 meta
.dest
= ( struct sockaddr
* ) st_dest
;
322 rc
= xfer_deliver_iob_meta ( &udp
->xfer
, iobuf
, &meta
);
330 struct tcpip_protocol udp_protocol __tcpip_protocol
= {
333 .tcpip_proto
= IP_UDP
,
336 /***************************************************************************
338 * Data transfer interface
340 ***************************************************************************
346 * @v xfer Data transfer interface
347 * @v rc Reason for close
349 static void udp_xfer_close ( struct xfer_interface
*xfer
, int rc
) {
350 struct udp_connection
*udp
=
351 container_of ( xfer
, struct udp_connection
, xfer
);
353 /* Close connection */
354 udp_close ( udp
, rc
);
358 * Allocate I/O buffer for UDP
360 * @v xfer Data transfer interface
361 * @v len Payload size
362 * @ret iobuf I/O buffer, or NULL
364 static struct io_buffer
* udp_alloc_iob ( struct xfer_interface
*xfer
,
366 struct udp_connection
*udp
=
367 container_of ( xfer
, struct udp_connection
, xfer
);
368 struct io_buffer
*iobuf
;
370 iobuf
= alloc_iob ( UDP_MAX_HLEN
+ len
);
372 DBGC ( udp
, "UDP %p cannot allocate buffer of length %d\n",
376 iob_reserve ( iobuf
, UDP_MAX_HLEN
);
381 * Deliver datagram as I/O buffer
383 * @v xfer Data transfer interface
384 * @v iobuf Datagram I/O buffer
385 * @v meta Data transfer metadata, or NULL
386 * @ret rc Return status code
388 static int udp_xfer_deliver_iob ( struct xfer_interface
*xfer
,
389 struct io_buffer
*iobuf
,
390 struct xfer_metadata
*meta
) {
391 struct udp_connection
*udp
=
392 container_of ( xfer
, struct udp_connection
, xfer
);
393 struct sockaddr_tcpip
*src
;
394 struct sockaddr_tcpip
*dest
= NULL
;
395 struct net_device
*netdev
= NULL
;
396 unsigned int src_port
= 0;
398 /* Apply xfer metadata */
400 src
= ( struct sockaddr_tcpip
* ) meta
->src
;
402 src_port
= src
->st_port
;
403 dest
= ( struct sockaddr_tcpip
* ) meta
->dest
;
404 netdev
= meta
->netdev
;
407 /* Transmit data, if possible */
408 udp_tx ( udp
, iobuf
, src_port
, dest
, netdev
);
413 /** UDP data transfer interface operations */
414 static struct xfer_interface_operations udp_xfer_operations
= {
415 .close
= udp_xfer_close
,
416 .vredirect
= ignore_xfer_vredirect
,
417 .seek
= ignore_xfer_seek
,
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
,