iPXE
udp.c
Go to the documentation of this file.
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
20FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
21FILE_SECBOOT ( PERMITTED );
22
23/**
24 * A UDP connection
25 *
26 */
28 /** Reference counter */
29 struct refcnt refcnt;
30 /** List of UDP connections */
32
33 /** Data transfer interface */
35
36 /** Local socket address */
38 /** Remote socket address */
40};
41
42/**
43 * List of registered UDP connections
44 */
45static LIST_HEAD ( udp_conns );
46
47/* Forward declatations */
49struct tcpip_protocol udp_protocol __tcpip_protocol;
50
51/**
52 * Check if local UDP port is available
53 *
54 * @v port Local port number
55 * @ret port Local port number, or negative error
56 */
57static int udp_port_available ( int port ) {
58 struct udp_connection *udp;
59
60 list_for_each_entry ( udp, &udp_conns, list ) {
61 if ( udp->local.st_port == htons ( port ) )
62 return -EADDRINUSE;
63 }
64 return port;
65}
66
67/**
68 * Open a UDP connection
69 *
70 * @v xfer Data transfer interface
71 * @v peer Peer socket address, or NULL
72 * @v local Local socket address, or NULL
73 * @v promisc Socket is promiscuous
74 * @ret rc Return status code
75 */
76static int udp_open_common ( struct interface *xfer,
77 struct sockaddr *peer, struct sockaddr *local,
78 int promisc ) {
79 struct sockaddr_tcpip *st_peer = ( struct sockaddr_tcpip * ) peer;
80 struct sockaddr_tcpip *st_local = ( struct sockaddr_tcpip * ) local;
81 struct udp_connection *udp;
82 int port;
83 int rc;
84
85 /* Allocate and initialise structure */
86 udp = zalloc ( sizeof ( *udp ) );
87 if ( ! udp )
88 return -ENOMEM;
89 DBGC ( udp, "UDP %p allocated\n", udp );
90 ref_init ( &udp->refcnt, NULL );
91 intf_init ( &udp->xfer, &udp_xfer_desc, &udp->refcnt );
92 if ( st_peer )
93 memcpy ( &udp->peer, st_peer, sizeof ( udp->peer ) );
94 if ( st_local )
95 memcpy ( &udp->local, st_local, sizeof ( udp->local ) );
96
97 /* Bind to local port */
98 if ( ! promisc ) {
99 port = tcpip_bind ( st_local, udp_port_available );
100 if ( port < 0 ) {
101 rc = port;
102 DBGC ( udp, "UDP %p could not bind: %s\n",
103 udp, strerror ( rc ) );
104 goto err;
105 }
106 udp->local.st_port = htons ( port );
107 DBGC ( udp, "UDP %p bound to port %d\n",
108 udp, ntohs ( udp->local.st_port ) );
109 }
110
111 /* Attach parent interface, transfer reference to connection
112 * list and return
113 */
114 intf_plug_plug ( &udp->xfer, xfer );
115 list_add ( &udp->list, &udp_conns );
116 return 0;
117
118 err:
119 ref_put ( &udp->refcnt );
120 return rc;
121}
122
123/**
124 * Open a UDP connection
125 *
126 * @v xfer Data transfer interface
127 * @v peer Peer socket address
128 * @v local Local socket address, or NULL
129 * @ret rc Return status code
130 */
131int udp_open ( struct interface *xfer, struct sockaddr *peer,
132 struct sockaddr *local ) {
133 return udp_open_common ( xfer, peer, local, 0 );
134}
135
136/**
137 * Open a promiscuous UDP connection
138 *
139 * @v xfer Data transfer interface
140 * @ret rc Return status code
141 *
142 * Promiscuous UDP connections are required in order to support the
143 * PXE API.
144 */
146 return udp_open_common ( xfer, NULL, NULL, 1 );
147}
148
149/**
150 * Close a UDP connection
151 *
152 * @v udp UDP connection
153 * @v rc Reason for close
154 */
155static void udp_close ( struct udp_connection *udp, int rc ) {
156
157 /* Close data transfer interface */
158 intf_shutdown ( &udp->xfer, rc );
159
160 /* Remove from list of connections and drop list's reference */
161 list_del ( &udp->list );
162 ref_put ( &udp->refcnt );
163
164 DBGC ( udp, "UDP %p closed\n", udp );
165}
166
167/**
168 * Transmit data via a UDP connection to a specified address
169 *
170 * @v udp UDP connection
171 * @v iobuf I/O buffer
172 * @v src Source address, or NULL to use default
173 * @v dest Destination address, or NULL to use default
174 * @v netdev Network device, or NULL to use default
175 * @ret rc Return status code
176 */
177static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf,
178 struct sockaddr_tcpip *src, struct sockaddr_tcpip *dest,
179 struct net_device *netdev ) {
180 struct udp_header *udphdr;
181 size_t len;
182 int rc;
183
184 /* Check we can accommodate the header */
185 if ( ( rc = iob_ensure_headroom ( iobuf,
186 MAX_LL_NET_HEADER_LEN ) ) != 0 ) {
187 free_iob ( iobuf );
188 return rc;
189 }
190
191 /* Fill in default values if not explicitly provided */
192 if ( ! src )
193 src = &udp->local;
194 if ( ! dest )
195 dest = &udp->peer;
196
197 /* Add the UDP header */
198 udphdr = iob_push ( iobuf, sizeof ( *udphdr ) );
199 len = iob_len ( iobuf );
200 udphdr->dest = dest->st_port;
201 udphdr->src = src->st_port;
202 udphdr->len = htons ( len );
203 udphdr->chksum = 0;
204 udphdr->chksum = tcpip_chksum ( udphdr, len );
205
206 /* Dump debugging information */
207 DBGC2 ( udp, "UDP %p TX %d->%d len %d\n", udp,
208 ntohs ( udphdr->src ), ntohs ( udphdr->dest ),
209 ntohs ( udphdr->len ) );
210
211 /* Send it to the next layer for processing */
212 if ( ( rc = tcpip_tx ( iobuf, &udp_protocol, src, dest, netdev,
213 &udphdr->chksum ) ) != 0 ) {
214 DBGC ( udp, "UDP %p could not transmit packet: %s\n",
215 udp, strerror ( rc ) );
216 return rc;
217 }
218
219 return 0;
220}
221
222/**
223 * Identify UDP connection by local address
224 *
225 * @v local Local address
226 * @ret udp UDP connection, or NULL
227 */
228static struct udp_connection * udp_demux ( struct sockaddr_tcpip *local ) {
229 static const struct sockaddr_tcpip empty_sockaddr = { .pad = { 0, } };
230 struct udp_connection *udp;
231
232 list_for_each_entry ( udp, &udp_conns, list ) {
233 if ( ( ( udp->local.st_family == local->st_family ) ||
234 ( udp->local.st_family == 0 ) ) &&
235 ( ( udp->local.st_port == local->st_port ) ||
236 ( udp->local.st_port == 0 ) ) &&
237 ( ( memcmp ( udp->local.pad, local->pad,
238 sizeof ( udp->local.pad ) ) == 0 ) ||
239 ( memcmp ( udp->local.pad, empty_sockaddr.pad,
240 sizeof ( udp->local.pad ) ) == 0 ) ) ) {
241 return udp;
242 }
243 }
244 return NULL;
245}
246
247/**
248 * Process a received packet
249 *
250 * @v iobuf I/O buffer
251 * @v netdev Network device
252 * @v st_src Partially-filled source address
253 * @v st_dest Partially-filled destination address
254 * @v pshdr_csum Pseudo-header checksum
255 * @ret rc Return status code
256 */
257static int udp_rx ( struct io_buffer *iobuf,
258 struct net_device *netdev __unused,
259 struct sockaddr_tcpip *st_src,
260 struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum ) {
261 struct udp_header *udphdr = iobuf->data;
262 struct udp_connection *udp;
263 struct xfer_metadata meta;
264 size_t ulen;
265 unsigned int csum;
266 int rc = 0;
267
268 /* Sanity check packet */
269 if ( iob_len ( iobuf ) < sizeof ( *udphdr ) ) {
270 DBG ( "UDP packet too short at %zd bytes (min %zd bytes)\n",
271 iob_len ( iobuf ), sizeof ( *udphdr ) );
272
273 rc = -EINVAL;
274 goto done;
275 }
276 ulen = ntohs ( udphdr->len );
277 if ( ulen < sizeof ( *udphdr ) ) {
278 DBG ( "UDP length too short at %zd bytes "
279 "(header is %zd bytes)\n", ulen, sizeof ( *udphdr ) );
280 rc = -EINVAL;
281 goto done;
282 }
283 if ( ulen > iob_len ( iobuf ) ) {
284 DBG ( "UDP length too long at %zd bytes (packet is %zd "
285 "bytes)\n", ulen, iob_len ( iobuf ) );
286 rc = -EINVAL;
287 goto done;
288 }
289 if ( udphdr->chksum ) {
290 csum = tcpip_continue_chksum ( pshdr_csum, iobuf->data, ulen );
291 if ( csum != 0 ) {
292 DBG ( "UDP checksum incorrect (is %04x including "
293 "checksum field, should be 0000)\n", csum );
294 rc = -EINVAL;
295 goto done;
296 }
297 }
298
299 /* Parse parameters from header and strip header */
300 st_src->st_port = udphdr->src;
301 st_dest->st_port = udphdr->dest;
302 udp = udp_demux ( st_dest );
303 iob_unput ( iobuf, ( iob_len ( iobuf ) - ulen ) );
304 iob_pull ( iobuf, sizeof ( *udphdr ) );
305
306 /* Dump debugging information */
307 DBGC2 ( udp, "UDP %p RX %d<-%d len %zd\n", udp,
308 ntohs ( udphdr->dest ), ntohs ( udphdr->src ), ulen );
309
310 /* Ignore if no matching connection found */
311 if ( ! udp ) {
312 DBG ( "No UDP connection listening on port %d\n",
313 ntohs ( udphdr->dest ) );
314 rc = -ENOTCONN;
315 goto done;
316 }
317
318 /* Pass data to application */
319 memset ( &meta, 0, sizeof ( meta ) );
320 meta.src = ( struct sockaddr * ) st_src;
321 meta.dest = ( struct sockaddr * ) st_dest;
322 rc = xfer_deliver ( &udp->xfer, iob_disown ( iobuf ), &meta );
323
324 done:
325 free_iob ( iobuf );
326 return rc;
327}
328
329struct tcpip_protocol udp_protocol __tcpip_protocol = {
330 .name = "UDP",
331 .rx = udp_rx,
332 .zero_csum = TCPIP_NEGATIVE_ZERO_CSUM,
333 .tcpip_proto = IP_UDP,
334};
335
336/***************************************************************************
337 *
338 * Data transfer interface
339 *
340 ***************************************************************************
341 */
342
343/**
344 * Allocate I/O buffer for UDP
345 *
346 * @v udp UDP connection
347 * @v len Payload size
348 * @ret iobuf I/O buffer, or NULL
349 */
350static struct io_buffer * udp_xfer_alloc_iob ( struct udp_connection *udp,
351 size_t len ) {
352 struct io_buffer *iobuf;
353
354 iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN + len );
355 if ( ! iobuf ) {
356 DBGC ( udp, "UDP %p cannot allocate buffer of length %zd\n",
357 udp, len );
358 return NULL;
359 }
361 return iobuf;
362}
363
364/**
365 * Deliver datagram as I/O buffer
366 *
367 * @v udp UDP connection
368 * @v iobuf Datagram I/O buffer
369 * @v meta Data transfer metadata
370 * @ret rc Return status code
371 */
372static int udp_xfer_deliver ( struct udp_connection *udp,
373 struct io_buffer *iobuf,
374 struct xfer_metadata *meta ) {
375
376 /* Transmit data, if possible */
377 return udp_tx ( udp, iobuf, ( ( struct sockaddr_tcpip * ) meta->src ),
378 ( ( struct sockaddr_tcpip * ) meta->dest ),
379 meta->netdev );
380}
381
382/** UDP data transfer interface operations */
388
389/** UDP data transfer interface descriptor */
392
393/***************************************************************************
394 *
395 * Openers
396 *
397 ***************************************************************************
398 */
399
400/** UDP socket opener */
401struct socket_opener udp_socket_opener __socket_opener = {
402 .semantics = UDP_SOCK_DGRAM,
403 .open = udp_open,
404};
405
406/** Linkage hack */
408
409/**
410 * Open UDP URI
411 *
412 * @v xfer Data transfer interface
413 * @v uri URI
414 * @ret rc Return status code
415 */
416static int udp_open_uri ( struct interface *xfer, struct uri *uri ) {
417 struct sockaddr_tcpip peer;
418
419 /* Sanity check */
420 if ( ! uri->host )
421 return -EINVAL;
422
423 memset ( &peer, 0, sizeof ( peer ) );
424 peer.st_port = htons ( uri_port ( uri, 0 ) );
425 return xfer_open_named_socket ( xfer, SOCK_DGRAM,
426 ( struct sockaddr * ) &peer,
427 uri->host, NULL );
428}
429
430/** UDP URI opener */
431struct uri_opener udp_uri_opener __uri_opener = {
432 .scheme = "udp",
433 .open = udp_open_uri,
434};
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
u8 port
Port number.
Definition CIB_PRM.h:3
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
unsigned short uint16_t
Definition stdint.h:11
if(len >=6 *4) __asm__ __volatile__("movsl" if(len >=5 *4) __asm__ __volatile__("movsl" if(len >=4 *4) __asm__ __volatile__("movsl" if(len >=3 *4) __asm__ __volatile__("movsl" if(len >=2 *4) __asm__ __volatile__("movsl" if(len >=1 *4) __asm__ __volatile__("movsl" if((len % 4) >=2) __asm__ __volatile__("movsw" if((len % 2) >=1) __asm__ __volatile__("movsb" retur dest)
Definition string.h:151
static const void * src
Definition string.h:48
Assertions.
struct bofm_section_header done
Definition bofm_test.c:46
ring len
Length.
Definition dwmac.h:226
uint8_t meta
Metadata flags.
Definition ena.h:3
Error codes.
static struct net_device * netdev
Definition gdbudp.c:53
#define __unused
Declare a variable or data structure as unused.
Definition compiler.h:573
#define SOCK_DGRAM
Definition socket.h:30
int udp_sock_dgram
Linkage hack.
Definition udp.c:407
#define UDP_SOCK_DGRAM
Definition socket.h:29
#define DBGC2(...)
Definition compiler.h:522
#define DBGC(...)
Definition compiler.h:505
#define DBG(...)
Print a debugging message.
Definition compiler.h:498
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define EINVAL
Invalid argument.
Definition errno.h:429
#define EADDRINUSE
Address already in use.
Definition errno.h:304
#define ENOMEM
Not enough space.
Definition errno.h:535
#define ENOTCONN
The socket is not connected.
Definition errno.h:570
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
#define IP_UDP
Definition in.h:15
#define htons(value)
Definition byteswap.h:136
#define ntohs(value)
Definition byteswap.h:137
Transport-network layer interface.
#define __tcpip_protocol
Declare a TCP/IP transport-layer protocol.
Definition tcpip.h:182
#define TCPIP_NEGATIVE_ZERO_CSUM
Negative zero checksum value.
Definition tcpip.h:31
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void * memset(void *dest, int character, size_t len) __nonnull
void intf_close(struct interface *intf, int rc)
Close an object interface.
Definition interface.c:250
void intf_plug_plug(struct interface *a, struct interface *b)
Plug two object interfaces together.
Definition interface.c:108
void intf_shutdown(struct interface *intf, int rc)
Shut down an object interface.
Definition interface.c:279
#define INTF_DESC(object_type, intf, operations)
Define an object interface descriptor.
Definition interface.h:81
static void intf_init(struct interface *intf, struct interface_descriptor *desc, struct refcnt *refcnt)
Initialise an object interface.
Definition interface.h:204
#define INTF_OP(op_type, object_type, op_func)
Define an object interface operation.
Definition interface.h:33
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition iobuf.c:153
int iob_ensure_headroom(struct io_buffer *iobuf, size_t len)
Ensure I/O buffer has sufficient headroom.
Definition iobuf.c:235
struct io_buffer * alloc_iob(size_t len)
Allocate I/O buffer.
Definition iobuf.c:131
I/O buffers.
#define iob_push(iobuf, len)
Definition iobuf.h:89
#define iob_disown(iobuf)
Disown an I/O buffer.
Definition iobuf.h:217
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition iobuf.h:160
#define iob_reserve(iobuf, len)
Definition iobuf.h:72
#define iob_pull(iobuf, len)
Definition iobuf.h:107
#define iob_unput(iobuf, len)
Definition iobuf.h:140
#define list_for_each_entry(pos, head, member)
Iterate over entries in a list.
Definition list.h:432
#define list_del(list)
Delete an entry from a list.
Definition list.h:120
#define LIST_HEAD(list)
Declare a static list head.
Definition list.h:38
#define list_add(new, head)
Add a new entry to the head of a list.
Definition list.h:70
void * zalloc(size_t size)
Allocate cleared memory.
Definition malloc.c:662
struct mschapv2_challenge peer
Peer challenge.
Definition mschapv2.h:1
Network device management.
#define MAX_LL_NET_HEADER_LEN
Maximum combined length of a link-layer and network-layer header.
Definition netdevice.h:59
Data transfer interface opening.
#define __socket_opener
Register a socket opener.
Definition open.h:89
#define __uri_opener
Register a URI opener.
Definition open.h:68
#define ref_put(refcnt)
Drop reference to object.
Definition refcnt.h:107
#define ref_init(refcnt, free)
Initialise a reference counter.
Definition refcnt.h:65
int xfer_open_named_socket(struct interface *xfer, int semantics, struct sockaddr *peer, const char *name, struct sockaddr *local)
Open named socket.
Definition resolv.c:403
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition string.c:115
An object interface descriptor.
Definition interface.h:56
An object interface operation.
Definition interface.h:18
An object interface.
Definition interface.h:125
A persistent I/O buffer.
Definition iobuf.h:38
void * data
Start of data.
Definition iobuf.h:53
A doubly-linked list entry (or list head)
Definition list.h:19
A network device.
Definition netdevice.h:353
TCP/IP socket address.
Definition tcpip.h:76
sa_family_t st_family
Socket address family (part of struct sockaddr)
Definition tcpip.h:78
uint16_t st_port
TCP/IP port.
Definition tcpip.h:82
char pad[sizeof(struct sockaddr) -(sizeof(sa_family_t)+sizeof(uint16_t)+sizeof(uint16_t)+sizeof(uint16_t))]
Padding.
Definition tcpip.h:99
Generalized socket address structure.
Definition socket.h:97
A socket opener.
Definition open.h:71
A transport-layer protocol of the TCP/IP stack (eg.
Definition tcpip.h:105
A UDP connection.
Definition udp.c:27
struct refcnt refcnt
Reference counter.
Definition udp.c:29
struct list_head list
List of UDP connections.
Definition udp.c:31
struct interface xfer
Data transfer interface.
Definition udp.c:34
struct sockaddr_tcpip peer
Remote socket address.
Definition udp.c:39
struct sockaddr_tcpip local
Local socket address.
Definition udp.c:37
UDP constants.
Definition udp.h:30
uint16_t dest
Destination port.
Definition udp.h:34
uint16_t src
Source port.
Definition udp.h:32
uint16_t len
Length.
Definition udp.h:36
uint16_t chksum
Checksum.
Definition udp.h:38
A URI opener.
Definition open.h:48
A Uniform Resource Identifier.
Definition uri.h:65
const char * host
Host name.
Definition uri.h:77
Data transfer metadata.
Definition xfer.h:23
int tcpip_tx(struct io_buffer *iobuf, struct tcpip_protocol *tcpip_protocol, struct sockaddr_tcpip *st_src, struct sockaddr_tcpip *st_dest, struct net_device *netdev, uint16_t *trans_csum)
Transmit a TCP/IP packet.
Definition tcpip.c:92
uint16_t tcpip_chksum(const void *data, size_t len)
Calculate TCP/IP checkum.
Definition tcpip.c:204
int tcpip_bind(struct sockaddr_tcpip *st_local, int(*available)(int port))
Bind to local TCP/IP port.
Definition tcpip.c:215
static struct interface_operation udp_xfer_operations[]
UDP data transfer interface operations.
Definition udp.c:383
static struct io_buffer * udp_xfer_alloc_iob(struct udp_connection *udp, size_t len)
Allocate I/O buffer for UDP.
Definition udp.c:350
static struct udp_connection * udp_demux(struct sockaddr_tcpip *local)
Identify UDP connection by local address.
Definition udp.c:228
static struct interface_descriptor udp_xfer_desc
UDP data transfer interface descriptor.
Definition udp.c:48
static int udp_open_uri(struct interface *xfer, struct uri *uri)
Open UDP URI.
Definition udp.c:416
static int udp_tx(struct udp_connection *udp, struct io_buffer *iobuf, struct sockaddr_tcpip *src, struct sockaddr_tcpip *dest, struct net_device *netdev)
Transmit data via a UDP connection to a specified address.
Definition udp.c:177
static int udp_rx(struct io_buffer *iobuf, struct net_device *netdev __unused, struct sockaddr_tcpip *st_src, struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum)
Process a received packet.
Definition udp.c:257
static int udp_open_common(struct interface *xfer, struct sockaddr *peer, struct sockaddr *local, int promisc)
Open a UDP connection.
Definition udp.c:76
int udp_open_promisc(struct interface *xfer)
Open a promiscuous UDP connection.
Definition udp.c:145
static int udp_xfer_deliver(struct udp_connection *udp, struct io_buffer *iobuf, struct xfer_metadata *meta)
Deliver datagram as I/O buffer.
Definition udp.c:372
static void udp_close(struct udp_connection *udp, int rc)
Close a UDP connection.
Definition udp.c:155
static int udp_port_available(int port)
Check if local UDP port is available.
Definition udp.c:57
int udp_open(struct interface *xfer, struct sockaddr *peer, struct sockaddr *local)
Open a UDP connection.
Definition udp.c:131
UDP protocol.
unsigned int uri_port(const struct uri *uri, unsigned int default_port)
Get port from URI.
Definition uri.c:457
Uniform Resource Identifiers.
uint16_t tcpip_continue_chksum(uint16_t partial, const void *data, size_t len)
Calculate continued TCP/IP checkum.
Definition x86_tcpip.c:46
int xfer_deliver(struct interface *intf, struct io_buffer *iobuf, struct xfer_metadata *meta)
Deliver datagram.
Definition xfer.c:195
struct io_buffer * xfer_alloc_iob(struct interface *intf, size_t len)
Allocate I/O buffer.
Definition xfer.c:159
Data transfer interfaces.