iPXE - Open Source Boot Firmware

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