|
|
1.1 root 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: udp_tx ( udp, iobuf, ( ( struct sockaddr_tcpip * ) meta->src ),
390: ( ( struct sockaddr_tcpip * ) meta->dest ), meta->netdev );
391:
392: return 0;
393: }
394:
395: /** UDP data transfer interface operations */
396: static struct interface_operation udp_xfer_operations[] = {
397: INTF_OP ( xfer_deliver, struct udp_connection *, udp_xfer_deliver ),
398: INTF_OP ( xfer_alloc_iob, struct udp_connection *, udp_xfer_alloc_iob ),
399: INTF_OP ( intf_close, struct udp_connection *, udp_close ),
400: };
401:
402: /** UDP data transfer interface descriptor */
403: static struct interface_descriptor udp_xfer_desc =
404: INTF_DESC ( struct udp_connection, xfer, udp_xfer_operations );
405:
406: /***************************************************************************
407: *
408: * Openers
409: *
410: ***************************************************************************
411: */
412:
413: /** UDP socket opener */
414: struct socket_opener udp_socket_opener __socket_opener = {
415: .semantics = UDP_SOCK_DGRAM,
416: .family = AF_INET,
417: .open = udp_open,
418: };
419:
420: /** Linkage hack */
421: int udp_sock_dgram = UDP_SOCK_DGRAM;
422:
423: /**
424: * Open UDP URI
425: *
426: * @v xfer Data transfer interface
427: * @v uri URI
428: * @ret rc Return status code
429: */
430: static int udp_open_uri ( struct interface *xfer, struct uri *uri ) {
431: struct sockaddr_tcpip peer;
432:
433: /* Sanity check */
434: if ( ! uri->host )
435: return -EINVAL;
436:
437: memset ( &peer, 0, sizeof ( peer ) );
438: peer.st_port = htons ( uri_port ( uri, 0 ) );
439: return xfer_open_named_socket ( xfer, SOCK_DGRAM,
440: ( struct sockaddr * ) &peer,
441: uri->host, NULL );
442: }
443:
444: /** UDP URI opener */
445: struct uri_opener udp_uri_opener __uri_opener = {
446: .scheme = "udp",
447: .open = udp_open_uri,
448: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.