diff options
author | Michael Brown | 2013-08-06 16:56:54 +0200 |
---|---|---|
committer | Michael Brown | 2013-08-06 16:56:54 +0200 |
commit | 252d28f098bfd12df59fe147d7e8354be61a6da8 (patch) | |
tree | 234bc573f3c7a27730d04016c809dc6ae5ba8c24 /src/net/tcpip.c | |
parent | [ipv6] Rename sin_{family,port} to sin6_{family,port} in struct sockaddr_in6 (diff) | |
download | ipxe-252d28f098bfd12df59fe147d7e8354be61a6da8.tar.gz ipxe-252d28f098bfd12df59fe147d7e8354be61a6da8.tar.xz ipxe-252d28f098bfd12df59fe147d7e8354be61a6da8.zip |
[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/tcpip.c')
-rw-r--r-- | src/net/tcpip.c | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/src/net/tcpip.c b/src/net/tcpip.c index 8e187f7e..721a4e48 100644 --- a/src/net/tcpip.c +++ b/src/net/tcpip.c @@ -1,4 +1,5 @@ #include <stdint.h> +#include <stdlib.h> #include <string.h> #include <errno.h> #include <byteswap.h> @@ -133,3 +134,46 @@ uint16_t generic_tcpip_continue_chksum ( uint16_t partial, uint16_t tcpip_chksum ( const void *data, size_t len ) { return tcpip_continue_chksum ( TCPIP_EMPTY_CSUM, data, len ); } + +/** + * Bind to local TCP/IP port + * + * @v st_local Local TCP/IP socket address, or NULL + * @v available Function to check port availability + * @ret port Local port number, or negative error + */ +int tcpip_bind ( struct sockaddr_tcpip *st_local, + int ( * available ) ( int port ) ) { + uint16_t flags = 0; + uint16_t try_port = 0; + uint16_t min_port; + uint16_t max_port; + unsigned int offset; + unsigned int i; + + /* Extract parameters from local socket address */ + if ( st_local ) { + flags = st_local->st_flags; + try_port = ntohs ( st_local->st_port ); + } + + /* If an explicit port is specified, check its availability */ + if ( try_port ) + return available ( try_port ); + + /* Otherwise, find an available port in the range [1,1023] or + * [1025,65535] as appropriate. + */ + min_port = ( ( ( ! flags ) & TCPIP_BIND_PRIVILEGED ) + 1 ); + max_port = ( ( flags & TCPIP_BIND_PRIVILEGED ) - 1 ); + offset = random(); + for ( i = 0 ; i <= max_port ; i++ ) { + try_port = ( ( i + offset ) & max_port ); + if ( try_port < min_port ) + continue; + if ( available ( try_port ) < 0 ) + continue; + return try_port; + } + return -EADDRINUSE; +} |