iPXE - Open Source Boot Firmware

[build] Handle R_X86_64_PLT32 from binutils 2.31
[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 };