[infiniband] Use "%#lx" as format specifier for queue pair numbers
[ipxe.git] / src / net / udp.c
1 #include <stdint.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <assert.h>
5 #include <byteswap.h>
6 #include <errno.h>
7 #include <ipxe/tcpip.h>
8 #include <ipxe/iobuf.h>
9 #include <ipxe/xfer.h>
10 #include <ipxe/open.h>
11 #include <ipxe/uri.h>
12 #include <ipxe/netdevice.h>
13 #include <ipxe/udp.h>
14
15 /** @file
16 *
17 * UDP protocol
18 */
19
20 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
21
22 /**
23 * A UDP connection
24 *
25 */
26 struct udp_connection {
27 /** Reference counter */
28 struct refcnt refcnt;
29 /** List of UDP connections */
30 struct list_head list;
31
32 /** Data transfer interface */
33 struct interface xfer;
34
35 /** Local socket address */
36 struct sockaddr_tcpip local;
37 /** Remote socket address */
38 struct sockaddr_tcpip peer;
39 };
40
41 /**
42 * List of registered UDP connections
43 */
44 static LIST_HEAD ( udp_conns );
45
46 /* Forward declatations */
47 static struct interface_descriptor udp_xfer_desc;
48 struct tcpip_protocol udp_protocol __tcpip_protocol;
49
50 /**
51 * Check if local UDP port is available
52 *
53 * @v port Local port number
54 * @ret port Local port number, or negative error
55 */
56 static int udp_port_available ( int port ) {
57 struct udp_connection *udp;
58
59 list_for_each_entry ( udp, &udp_conns, list ) {
60 if ( udp->local.st_port == htons ( port ) )
61 return -EADDRINUSE;
62 }
63 return port;
64 }
65
66 /**
67 * Open a UDP connection
68 *
69 * @v xfer Data transfer interface
70 * @v peer Peer socket address, or NULL
71 * @v local Local socket address, or NULL
72 * @v promisc Socket is promiscuous
73 * @ret rc Return status code
74 */
75 static int udp_open_common ( struct interface *xfer,
76 struct sockaddr *peer, struct sockaddr *local,
77 int promisc ) {
78 struct sockaddr_tcpip *st_peer = ( struct sockaddr_tcpip * ) peer;
79 struct sockaddr_tcpip *st_local = ( struct sockaddr_tcpip * ) local;
80 struct udp_connection *udp;
81 int port;
82 int rc;
83
84 /* Allocate and initialise structure */
85 udp = zalloc ( sizeof ( *udp ) );
86 if ( ! udp )
87 return -ENOMEM;
88 DBGC ( udp, "UDP %p allocated\n", udp );
89 ref_init ( &udp->refcnt, NULL );
90 intf_init ( &udp->xfer, &udp_xfer_desc, &udp->refcnt );
91 if ( st_peer )
92 memcpy ( &udp->peer, st_peer, sizeof ( udp->peer ) );
93 if ( st_local )
94 memcpy ( &udp->local, st_local, sizeof ( udp->local ) );
95
96 /* Bind to local port */
97 if ( ! promisc ) {
98 port = tcpip_bind ( st_local, udp_port_available );
99 if ( port < 0 ) {
100 rc = port;
101 DBGC ( udp, "UDP %p could not bind: %s\n",
102 udp, strerror ( rc ) );
103 goto err;
104 }
105 udp->local.st_port = htons ( port );
106 DBGC ( udp, "UDP %p bound to port %d\n",
107 udp, ntohs ( udp->local.st_port ) );
108 }
109
110 /* Attach parent interface, transfer reference to connection
111 * list and return
112 */
113 intf_plug_plug ( &udp->xfer, xfer );
114 list_add ( &udp->list, &udp_conns );
115 return 0;
116
117 err:
118 ref_put ( &udp->refcnt );
119 return rc;
120 }
121
122 /**
123 * Open a UDP connection
124 *
125 * @v xfer Data transfer interface
126 * @v peer Peer socket address
127 * @v local Local socket address, or NULL
128 * @ret rc Return status code
129 */
130 int udp_open ( struct interface *xfer, struct sockaddr *peer,
131 struct sockaddr *local ) {
132 return udp_open_common ( xfer, peer, local, 0 );
133 }
134
135 /**
136 * Open a promiscuous UDP connection
137 *
138 * @v xfer Data transfer interface
139 * @ret rc Return status code
140 *
141 * Promiscuous UDP connections are required in order to support the
142 * PXE API.
143 */
144 int udp_open_promisc ( struct interface *xfer ) {
145 return udp_open_common ( xfer, NULL, NULL, 1 );
146 }
147
148 /**
149 * Close a UDP connection
150 *
151 * @v udp UDP connection
152 * @v rc Reason for close
153 */
154 static void udp_close ( struct udp_connection *udp, int rc ) {
155
156 /* Close data transfer interface */
157 intf_shutdown ( &udp->xfer, rc );
158
159 /* Remove from list of connections and drop list's reference */
160 list_del ( &udp->list );
161 ref_put ( &udp->refcnt );
162
163 DBGC ( udp, "UDP %p closed\n", udp );
164 }
165
166 /**
167 * Transmit data via a UDP connection to a specified address
168 *
169 * @v udp UDP connection
170 * @v iobuf I/O buffer
171 * @v src Source address, or NULL to use default
172 * @v dest Destination address, or NULL to use default
173 * @v netdev Network device, or NULL to use default
174 * @ret rc Return status code
175 */
176 static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf,
177 struct sockaddr_tcpip *src, struct sockaddr_tcpip *dest,
178 struct net_device *netdev ) {
179 struct udp_header *udphdr;
180 size_t len;
181 int rc;
182
183 /* Check we can accommodate the header */
184 if ( ( rc = iob_ensure_headroom ( iobuf,
185 MAX_LL_NET_HEADER_LEN ) ) != 0 ) {
186 free_iob ( iobuf );
187 return rc;
188 }
189
190 /* Fill in default values if not explicitly provided */
191 if ( ! src )
192 src = &udp->local;
193 if ( ! dest )
194 dest = &udp->peer;
195
196 /* Add the UDP header */
197 udphdr = iob_push ( iobuf, sizeof ( *udphdr ) );
198 len = iob_len ( iobuf );
199 udphdr->dest = dest->st_port;
200 udphdr->src = src->st_port;
201 udphdr->len = htons ( len );
202 udphdr->chksum = 0;
203 udphdr->chksum = tcpip_chksum ( udphdr, len );
204
205 /* Dump debugging information */
206 DBGC2 ( udp, "UDP %p TX %d->%d len %d\n", udp,
207 ntohs ( udphdr->src ), ntohs ( udphdr->dest ),
208 ntohs ( udphdr->len ) );
209
210 /* Send it to the next layer for processing */
211 if ( ( rc = tcpip_tx ( iobuf, &udp_protocol, src, dest, netdev,
212 &udphdr->chksum ) ) != 0 ) {
213 DBGC ( udp, "UDP %p could not transmit packet: %s\n",
214 udp, strerror ( rc ) );
215 return rc;
216 }
217
218 return 0;
219 }
220
221 /**
222 * Identify UDP connection by local address
223 *
224 * @v local Local address
225 * @ret udp UDP connection, or NULL
226 */
227 static struct udp_connection * udp_demux ( struct sockaddr_tcpip *local ) {
228 static const struct sockaddr_tcpip empty_sockaddr = { .pad = { 0, } };
229 struct udp_connection *udp;
230
231 list_for_each_entry ( udp, &udp_conns, list ) {
232 if ( ( ( udp->local.st_family == local->st_family ) ||
233 ( udp->local.st_family == 0 ) ) &&
234 ( ( udp->local.st_port == local->st_port ) ||
235 ( udp->local.st_port == 0 ) ) &&
236 ( ( memcmp ( udp->local.pad, local->pad,
237 sizeof ( udp->local.pad ) ) == 0 ) ||
238 ( memcmp ( udp->local.pad, empty_sockaddr.pad,
239 sizeof ( udp->local.pad ) ) == 0 ) ) ) {
240 return udp;
241 }
242 }
243 return NULL;
244 }
245
246 /**
247 * Process a received packet
248 *
249 * @v iobuf I/O buffer
250 * @v netdev Network device
251 * @v st_src Partially-filled source address
252 * @v st_dest Partially-filled destination address
253 * @v pshdr_csum Pseudo-header checksum
254 * @ret rc Return status code
255 */
256 static int udp_rx ( struct io_buffer *iobuf,
257 struct net_device *netdev __unused,
258 struct sockaddr_tcpip *st_src,
259 struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum ) {
260 struct udp_header *udphdr = iobuf->data;
261 struct udp_connection *udp;
262 struct xfer_metadata meta;
263 size_t ulen;
264 unsigned int csum;
265 int rc = 0;
266
267 /* Sanity check packet */
268 if ( iob_len ( iobuf ) < sizeof ( *udphdr ) ) {
269 DBG ( "UDP packet too short at %zd bytes (min %zd bytes)\n",
270 iob_len ( iobuf ), sizeof ( *udphdr ) );
271
272 rc = -EINVAL;
273 goto done;
274 }
275 ulen = ntohs ( udphdr->len );
276 if ( ulen < sizeof ( *udphdr ) ) {
277 DBG ( "UDP length too short at %zd bytes "
278 "(header is %zd bytes)\n", ulen, sizeof ( *udphdr ) );
279 rc = -EINVAL;
280 goto done;
281 }
282 if ( ulen > iob_len ( iobuf ) ) {
283 DBG ( "UDP length too long at %zd bytes (packet is %zd "
284 "bytes)\n", ulen, iob_len ( iobuf ) );
285 rc = -EINVAL;
286 goto done;
287 }
288 if ( udphdr->chksum ) {
289 csum = tcpip_continue_chksum ( pshdr_csum, iobuf->data, ulen );
290 if ( csum != 0 ) {
291 DBG ( "UDP checksum incorrect (is %04x including "
292 "checksum field, should be 0000)\n", csum );
293 rc = -EINVAL;
294 goto done;
295 }
296 }
297
298 /* Parse parameters from header and strip header */
299 st_src->st_port = udphdr->src;
300 st_dest->st_port = udphdr->dest;
301 udp = udp_demux ( st_dest );
302 iob_unput ( iobuf, ( iob_len ( iobuf ) - ulen ) );
303 iob_pull ( iobuf, sizeof ( *udphdr ) );
304
305 /* Dump debugging information */
306 DBGC2 ( udp, "UDP %p RX %d<-%d len %zd\n", udp,
307 ntohs ( udphdr->dest ), ntohs ( udphdr->src ), ulen );
308
309 /* Ignore if no matching connection found */
310 if ( ! udp ) {
311 DBG ( "No UDP connection listening on port %d\n",
312 ntohs ( udphdr->dest ) );
313 rc = -ENOTCONN;
314 goto done;
315 }
316
317 /* Pass data to application */
318 memset ( &meta, 0, sizeof ( meta ) );
319 meta.src = ( struct sockaddr * ) st_src;
320 meta.dest = ( struct sockaddr * ) st_dest;
321 rc = xfer_deliver ( &udp->xfer, iob_disown ( iobuf ), &meta );
322
323 done:
324 free_iob ( iobuf );
325 return rc;
326 }
327
328 struct tcpip_protocol udp_protocol __tcpip_protocol = {
329 .name = "UDP",
330 .rx = udp_rx,
331 .zero_csum = TCPIP_NEGATIVE_ZERO_CSUM,
332 .tcpip_proto = IP_UDP,
333 };
334
335 /***************************************************************************
336 *
337 * Data transfer interface
338 *
339 ***************************************************************************
340 */
341
342 /**
343 * Allocate I/O buffer for UDP
344 *
345 * @v udp UDP connection
346 * @v len Payload size
347 * @ret iobuf I/O buffer, or NULL
348 */
349 static struct io_buffer * udp_xfer_alloc_iob ( struct udp_connection *udp,
350 size_t len ) {
351 struct io_buffer *iobuf;
352
353 iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN + len );
354 if ( ! iobuf ) {
355 DBGC ( udp, "UDP %p cannot allocate buffer of length %zd\n",
356 udp, len );
357 return NULL;
358 }
359 iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN );
360 return iobuf;
361 }
362
363 /**
364 * Deliver datagram as I/O buffer
365 *
366 * @v udp UDP connection
367 * @v iobuf Datagram I/O buffer
368 * @v meta Data transfer metadata
369 * @ret rc Return status code
370 */
371 static int udp_xfer_deliver ( struct udp_connection *udp,
372 struct io_buffer *iobuf,
373 struct xfer_metadata *meta ) {
374
375 /* Transmit data, if possible */
376 return udp_tx ( udp, iobuf, ( ( struct sockaddr_tcpip * ) meta->src ),
377 ( ( struct sockaddr_tcpip * ) meta->dest ),
378 meta->netdev );
379 }
380
381 /** UDP data transfer interface operations */
382 static struct interface_operation udp_xfer_operations[] = {
383 INTF_OP ( xfer_deliver, struct udp_connection *, udp_xfer_deliver ),
384 INTF_OP ( xfer_alloc_iob, struct udp_connection *, udp_xfer_alloc_iob ),
385 INTF_OP ( intf_close, struct udp_connection *, udp_close ),
386 };
387
388 /** UDP data transfer interface descriptor */
389 static struct interface_descriptor udp_xfer_desc =
390 INTF_DESC ( struct udp_connection, xfer, udp_xfer_operations );
391
392 /***************************************************************************
393 *
394 * Openers
395 *
396 ***************************************************************************
397 */
398
399 /** UDP IPv4 socket opener */
400 struct socket_opener udp_ipv4_socket_opener __socket_opener = {
401 .semantics = UDP_SOCK_DGRAM,
402 .family = AF_INET,
403 .open = udp_open,
404 };
405
406 /** UDP IPv6 socket opener */
407 struct socket_opener udp_ipv6_socket_opener __socket_opener = {
408 .semantics = UDP_SOCK_DGRAM,
409 .family = AF_INET6,
410 .open = udp_open,
411 };
412
413 /** Linkage hack */
414 int udp_sock_dgram = UDP_SOCK_DGRAM;
415
416 /**
417 * Open UDP URI
418 *
419 * @v xfer Data transfer interface
420 * @v uri URI
421 * @ret rc Return status code
422 */
423 static int udp_open_uri ( struct interface *xfer, struct uri *uri ) {
424 struct sockaddr_tcpip peer;
425
426 /* Sanity check */
427 if ( ! uri->host )
428 return -EINVAL;
429
430 memset ( &peer, 0, sizeof ( peer ) );
431 peer.st_port = htons ( uri_port ( uri, 0 ) );
432 return xfer_open_named_socket ( xfer, SOCK_DGRAM,
433 ( struct sockaddr * ) &peer,
434 uri->host, NULL );
435 }
436
437 /** UDP URI opener */
438 struct uri_opener udp_uri_opener __uri_opener = {
439 .scheme = "udp",
440 .open = udp_open_uri,
441 };