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