|
@@ -29,10 +29,10 @@ struct udp_connection {
|
29
|
29
|
/** Data transfer interface */
|
30
|
30
|
struct xfer_interface xfer;
|
31
|
31
|
|
|
32
|
+ /** Local socket address */
|
|
33
|
+ struct sockaddr_tcpip local;
|
32
|
34
|
/** Remote socket address */
|
33
|
35
|
struct sockaddr_tcpip peer;
|
34
|
|
- /** Local port on which the connection receives packets */
|
35
|
|
- unsigned int local_port;
|
36
|
36
|
};
|
37
|
37
|
|
38
|
38
|
/**
|
|
@@ -48,22 +48,22 @@ struct tcpip_protocol udp_protocol;
|
48
|
48
|
* Bind UDP connection to local port
|
49
|
49
|
*
|
50
|
50
|
* @v udp UDP connection
|
51
|
|
- * @v port Local port, in network byte order, or zero
|
52
|
51
|
* @ret rc Return status code
|
53
|
52
|
*
|
54
|
|
- * Opens the UDP connection and binds to a local port. If no local
|
55
|
|
- * port is specified, the first available port will be used.
|
|
53
|
+ * Opens the UDP connection and binds to the specified local port. If
|
|
54
|
+ * no local port is specified, the first available port will be used.
|
56
|
55
|
*/
|
57
|
|
-static int udp_bind ( struct udp_connection *udp, unsigned int port ) {
|
|
56
|
+static int udp_bind ( struct udp_connection *udp ) {
|
58
|
57
|
struct udp_connection *existing;
|
59
|
58
|
static uint16_t try_port = 1024;
|
60
|
59
|
|
61
|
60
|
/* If no port specified, find the first available port */
|
62
|
|
- if ( ! port ) {
|
|
61
|
+ if ( ! udp->local.st_port ) {
|
63
|
62
|
for ( ; try_port ; try_port++ ) {
|
64
|
63
|
if ( try_port < 1024 )
|
65
|
64
|
continue;
|
66
|
|
- if ( udp_bind ( udp, htons ( try_port ) ) == 0 )
|
|
65
|
+ udp->local.st_port = htons ( try_port );
|
|
66
|
+ if ( udp_bind ( udp ) == 0 )
|
67
|
67
|
return 0;
|
68
|
68
|
}
|
69
|
69
|
return -EADDRINUSE;
|
|
@@ -71,16 +71,16 @@ static int udp_bind ( struct udp_connection *udp, unsigned int port ) {
|
71
|
71
|
|
72
|
72
|
/* Attempt bind to local port */
|
73
|
73
|
list_for_each_entry ( existing, &udp_conns, list ) {
|
74
|
|
- if ( existing->local_port == port ) {
|
|
74
|
+ if ( existing->local.st_port == udp->local.st_port ) {
|
75
|
75
|
DBGC ( udp, "UDP %p could not bind: port %d in use\n",
|
76
|
|
- udp, ntohs ( port ) );
|
|
76
|
+ udp, ntohs ( udp->local.st_port ) );
|
77
|
77
|
return -EADDRINUSE;
|
78
|
78
|
}
|
79
|
79
|
}
|
80
|
|
- udp->local_port = port;
|
81
|
80
|
|
82
|
81
|
/* Add to UDP connection list */
|
83
|
|
- DBGC ( udp, "UDP %p bound to port %d\n", udp, ntohs ( port ) );
|
|
82
|
+ DBGC ( udp, "UDP %p bound to port %d\n",
|
|
83
|
+ udp, ntohs ( udp->local.st_port ) );
|
84
|
84
|
|
85
|
85
|
return 0;
|
86
|
86
|
}
|
|
@@ -100,7 +100,6 @@ static int udp_open_common ( struct xfer_interface *xfer,
|
100
|
100
|
struct sockaddr_tcpip *st_peer = ( struct sockaddr_tcpip * ) peer;
|
101
|
101
|
struct sockaddr_tcpip *st_local = ( struct sockaddr_tcpip * ) local;
|
102
|
102
|
struct udp_connection *udp;
|
103
|
|
- unsigned int bind_port;
|
104
|
103
|
int rc;
|
105
|
104
|
|
106
|
105
|
/* Allocate and initialise structure */
|
|
@@ -111,11 +110,12 @@ static int udp_open_common ( struct xfer_interface *xfer,
|
111
|
110
|
xfer_init ( &udp->xfer, &udp_xfer_operations, &udp->refcnt );
|
112
|
111
|
if ( st_peer )
|
113
|
112
|
memcpy ( &udp->peer, st_peer, sizeof ( udp->peer ) );
|
|
113
|
+ if ( st_local )
|
|
114
|
+ memcpy ( &udp->local, st_local, sizeof ( udp->local ) );
|
114
|
115
|
|
115
|
116
|
/* Bind to local port */
|
116
|
117
|
if ( ! promisc ) {
|
117
|
|
- bind_port = ( st_local ? st_local->st_port : 0 );
|
118
|
|
- if ( ( rc = udp_bind ( udp, bind_port ) ) != 0 )
|
|
118
|
+ if ( ( rc = udp_bind ( udp ) ) != 0 )
|
119
|
119
|
goto err;
|
120
|
120
|
}
|
121
|
121
|
|
|
@@ -201,7 +201,7 @@ static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf,
|
201
|
201
|
|
202
|
202
|
/* Fill in default values if not explicitly provided */
|
203
|
203
|
if ( ! src_port )
|
204
|
|
- src_port = udp->local_port;
|
|
204
|
+ src_port = udp->local.st_port;
|
205
|
205
|
if ( ! dest )
|
206
|
206
|
dest = &udp->peer;
|
207
|
207
|
|
|
@@ -231,17 +231,24 @@ static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf,
|
231
|
231
|
}
|
232
|
232
|
|
233
|
233
|
/**
|
234
|
|
- * Identify UDP connection by local port number
|
|
234
|
+ * Identify UDP connection by local address
|
235
|
235
|
*
|
236
|
|
- * @v local_port Local port (in network-endian order)
|
|
236
|
+ * @v local Local address
|
237
|
237
|
* @ret udp UDP connection, or NULL
|
238
|
238
|
*/
|
239
|
|
-static struct udp_connection * udp_demux ( unsigned int local_port ) {
|
|
239
|
+static struct udp_connection * udp_demux ( struct sockaddr_tcpip *local ) {
|
|
240
|
+ static const struct sockaddr_tcpip empty_sockaddr;
|
240
|
241
|
struct udp_connection *udp;
|
241
|
242
|
|
242
|
243
|
list_for_each_entry ( udp, &udp_conns, list ) {
|
243
|
|
- if ( ( udp->local_port == local_port ) ||
|
244
|
|
- ( udp->local_port == 0 ) ) {
|
|
244
|
+ if ( ( ( udp->local.st_family == local->st_family ) ||
|
|
245
|
+ ( udp->local.st_family == 0 ) ) &&
|
|
246
|
+ ( ( udp->local.st_port == local->st_port ) ||
|
|
247
|
+ ( udp->local.st_port == 0 ) ) &&
|
|
248
|
+ ( ( memcmp ( udp->local.pad, local->pad,
|
|
249
|
+ sizeof ( udp->local.pad ) ) == 0 ) ||
|
|
250
|
+ ( memcmp ( udp->local.pad, empty_sockaddr.pad,
|
|
251
|
+ sizeof ( udp->local.pad ) ) == 0 ) ) ) {
|
245
|
252
|
return udp;
|
246
|
253
|
}
|
247
|
254
|
}
|
|
@@ -300,7 +307,7 @@ static int udp_rx ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src,
|
300
|
307
|
/* Parse parameters from header and strip header */
|
301
|
308
|
st_src->st_port = udphdr->src;
|
302
|
309
|
st_dest->st_port = udphdr->dest;
|
303
|
|
- udp = udp_demux ( udphdr->dest );
|
|
310
|
+ udp = udp_demux ( st_dest );
|
304
|
311
|
iob_unput ( iobuf, ( iob_len ( iobuf ) - ulen ) );
|
305
|
312
|
iob_pull ( iobuf, sizeof ( *udphdr ) );
|
306
|
313
|
|