diff options
author | Michael Brown <mcb30@ipxe.org> | 2013-08-06 15:56:54 +0100 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2013-08-06 15:56:54 +0100 |
commit | 252d28f098bfd12df59fe147d7e8354be61a6da8 (patch) | |
tree | 234bc573f3c7a27730d04016c809dc6ae5ba8c24 /src/net/tcp.c | |
parent | 03506828654a67c49471580a17fc91169b1ce96e (diff) | |
download | ipxe-252d28f098bfd12df59fe147d7e8354be61a6da8.tar.gz |
[tcpip] Allow binding to unspecified privileged ports (below 1024)
Originally-implemented-by: Marin Hannache <git@mareo.fr>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/net/tcp.c')
-rw-r--r-- | src/net/tcp.c | 53 |
1 files changed, 14 insertions, 39 deletions
diff --git a/src/net/tcp.c b/src/net/tcp.c index b97107fc..0e18c831 100644 --- a/src/net/tcp.c +++ b/src/net/tcp.c @@ -157,6 +157,7 @@ static LIST_HEAD ( tcp_conns ); static struct interface_descriptor tcp_xfer_desc; static void tcp_expired ( struct retry_timer *timer, int over ); static void tcp_wait_expired ( struct retry_timer *timer, int over ); +static struct tcp_connection * tcp_demux ( unsigned int local_port ); static int tcp_rx_ack ( struct tcp_connection *tcp, uint32_t ack, uint32_t win ); @@ -226,46 +227,14 @@ tcp_dump_flags ( struct tcp_connection *tcp, unsigned int flags ) { */ /** - * Bind TCP connection to local port + * Check if local TCP port is available * - * @v tcp TCP connection * @v port Local port number - * @ret rc Return status code - * - * If the port is 0, the connection is assigned an available port - * between 1024 and 65535. + * @ret port Local port number, or negative error */ -static int tcp_bind ( struct tcp_connection *tcp, unsigned int port ) { - struct tcp_connection *existing; - uint16_t try_port; - unsigned int i; - - /* If no port is specified, find an available port */ - if ( ! port ) { - try_port = random(); - for ( i = 0 ; i < 65536 ; i++ ) { - try_port++; - if ( try_port < 1024 ) - continue; - if ( tcp_bind ( tcp, try_port ) == 0 ) - return 0; - } - DBGC ( tcp, "TCP %p could not bind: no free ports\n", tcp ); - return -EADDRINUSE; - } - - /* Attempt bind to local port */ - list_for_each_entry ( existing, &tcp_conns, list ) { - if ( existing->local_port == port ) { - DBGC ( tcp, "TCP %p could not bind: port %d in use\n", - tcp, port ); - return -EADDRINUSE; - } - } - tcp->local_port = port; +static int tcp_port_available ( int port ) { - DBGC ( tcp, "TCP %p bound to port %d\n", tcp, port ); - return 0; + return ( tcp_demux ( port ) ? -EADDRINUSE : port ); } /** @@ -281,7 +250,7 @@ static int tcp_open ( struct interface *xfer, struct sockaddr *peer, struct sockaddr_tcpip *st_peer = ( struct sockaddr_tcpip * ) peer; struct sockaddr_tcpip *st_local = ( struct sockaddr_tcpip * ) local; struct tcp_connection *tcp; - unsigned int bind_port; + int port; int rc; /* Allocate and initialise structure */ @@ -303,9 +272,15 @@ static int tcp_open ( struct interface *xfer, struct sockaddr *peer, memcpy ( &tcp->peer, st_peer, sizeof ( tcp->peer ) ); /* Bind to local port */ - bind_port = ( st_local ? ntohs ( st_local->st_port ) : 0 ); - if ( ( rc = tcp_bind ( tcp, bind_port ) ) != 0 ) + port = tcpip_bind ( st_local, tcp_port_available ); + if ( port < 0 ) { + rc = port; + DBGC ( tcp, "TCP %p could not bind: %s\n", + tcp, strerror ( rc ) ); goto err; + } + tcp->local_port = port; + DBGC ( tcp, "TCP %p bound to port %d\n", tcp, tcp->local_port ); /* Start timer to initiate SYN */ start_timer_nodelay ( &tcp->timer ); |