Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions include/zephyr/net/net_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,12 @@ __net_socket struct net_context {
#endif
#if defined(CONFIG_NET_CONTEXT_DSCP_ECN)
uint8_t dscp_ecn;
#endif
#if defined(CONFIG_NET_CONTEXT_REUSEADDR)
bool reuseaddr;
#endif
#if defined(CONFIG_NET_CONTEXT_REUSEPORT)
bool reuseport;
#endif
} options;

Expand Down Expand Up @@ -1073,6 +1079,8 @@ enum net_context_option {
NET_OPT_RCVBUF = 6,
NET_OPT_SNDBUF = 7,
NET_OPT_DSCP_ECN = 8,
NET_OPT_REUSEADDR = 9,
NET_OPT_REUSEPORT = 10,
};

/**
Expand Down
6 changes: 3 additions & 3 deletions include/zephyr/net/socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -1009,7 +1009,7 @@ struct ifreq {

/** sockopt: Recording debugging information (ignored, for compatibility) */
#define SO_DEBUG 1
/** sockopt: address reuse (ignored, for compatibility) */
/** sockopt: address reuse */
#define SO_REUSEADDR 2
/** sockopt: Type of the socket */
#define SO_TYPE 3
Expand All @@ -1020,7 +1020,7 @@ struct ifreq {
/** sockopt: Transmission of broadcast messages is supported (ignored, for compatibility) */
#define SO_BROADCAST 6

/** sockopt: Size of socket socket send buffer (ignored, for compatibility) */
/** sockopt: Size of socket send buffer */
#define SO_SNDBUF 7
/** sockopt: Size of socket recv buffer */
#define SO_RCVBUF 8
Expand All @@ -1031,7 +1031,7 @@ struct ifreq {
#define SO_OOBINLINE 10
/** sockopt: Socket lingers on close (ignored, for compatibility) */
#define SO_LINGER 13
/** sockopt: Allow multiple sockets to reuse a single port (ignored, for compatibility) */
/** sockopt: Allow multiple sockets to reuse a single port */
#define SO_REUSEPORT 15

/** sockopt: Receive low watermark (ignored, for compatibility) */
Expand Down
14 changes: 14 additions & 0 deletions subsys/net/ip/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,20 @@ config NET_CONTEXT_DSCP_ECN
Notification values on net_context. Those values are then used in
IPv4/IPv6 header when sending packets over net_context.

config NET_CONTEXT_REUSEADDR
bool "Add REUSEADDR support to net_context"
default y if NET_TCP || NET_UDP
help
Allow to set the SO_REUSEADDR flag on a socket. This enables multiple
sockets to bind to the same local IP address.

config NET_CONTEXT_REUSEPORT
bool "Add REUSEPORT support to net_context"
default y if NET_TCP || NET_UDP
help
Allow to set the SO_REUSEPORT flag on a socket. This enables multiple
sockets to bind to the same local IP address and port combination.

config NET_TEST
bool "Network Testing"
help
Expand Down
83 changes: 41 additions & 42 deletions subsys/net/ip/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,8 @@ static struct net_conn *conn_find_handler(uint16_t proto, uint8_t family,
const struct sockaddr *remote_addr,
const struct sockaddr *local_addr,
uint16_t remote_port,
uint16_t local_port)
uint16_t local_port,
bool reuseport_set)
{
struct net_conn *conn;
struct net_conn *tmp;
Expand All @@ -174,67 +175,75 @@ static struct net_conn *conn_find_handler(uint16_t proto, uint8_t family,
continue;
}

if (remote_addr) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes here were a bit difficult to read. Are we just swapping the remote/local address check branches here, if true, why do we need to do it.

if (!(conn->flags & NET_CONN_REMOTE_ADDR_SET)) {
if (local_addr) {
if (!(conn->flags & NET_CONN_LOCAL_ADDR_SET)) {
continue;
}

if (IS_ENABLED(CONFIG_NET_IPV6) &&
remote_addr->sa_family == AF_INET6 &&
remote_addr->sa_family ==
conn->remote_addr.sa_family) {
local_addr->sa_family == AF_INET6 &&
local_addr->sa_family ==
conn->local_addr.sa_family) {
if (!net_ipv6_addr_cmp(
&net_sin6(remote_addr)->sin6_addr,
&net_sin6(&conn->remote_addr)->
&net_sin6(local_addr)->sin6_addr,
&net_sin6(&conn->local_addr)->
sin6_addr)) {
continue;
}
} else if (IS_ENABLED(CONFIG_NET_IPV4) &&
remote_addr->sa_family == AF_INET &&
remote_addr->sa_family ==
conn->remote_addr.sa_family) {
local_addr->sa_family == AF_INET &&
local_addr->sa_family ==
conn->local_addr.sa_family) {
if (!net_ipv4_addr_cmp(
&net_sin(remote_addr)->sin_addr,
&net_sin(&conn->remote_addr)->
&net_sin(local_addr)->sin_addr,
&net_sin(&conn->local_addr)->
sin_addr)) {
continue;
}
} else {
continue;
}
} else if (conn->flags & NET_CONN_REMOTE_ADDR_SET) {
} else if (conn->flags & NET_CONN_LOCAL_ADDR_SET) {
continue;
}

if (local_addr) {
if (!(conn->flags & NET_CONN_LOCAL_ADDR_SET)) {
if (net_sin(&conn->local_addr)->sin_port !=
htons(local_port)) {
continue;
}

if (remote_addr) {
if (!(conn->flags & NET_CONN_REMOTE_ADDR_SET)) {
continue;
}

if (IS_ENABLED(CONFIG_NET_IPV6) &&
local_addr->sa_family == AF_INET6 &&
local_addr->sa_family ==
conn->local_addr.sa_family) {
remote_addr->sa_family == AF_INET6 &&
remote_addr->sa_family ==
conn->remote_addr.sa_family) {
if (!net_ipv6_addr_cmp(
&net_sin6(local_addr)->sin6_addr,
&net_sin6(&conn->local_addr)->
&net_sin6(remote_addr)->sin6_addr,
&net_sin6(&conn->remote_addr)->
sin6_addr)) {
continue;
}
} else if (IS_ENABLED(CONFIG_NET_IPV4) &&
local_addr->sa_family == AF_INET &&
local_addr->sa_family ==
conn->local_addr.sa_family) {
remote_addr->sa_family == AF_INET &&
remote_addr->sa_family ==
conn->remote_addr.sa_family) {
if (!net_ipv4_addr_cmp(
&net_sin(local_addr)->sin_addr,
&net_sin(&conn->local_addr)->
&net_sin(remote_addr)->sin_addr,
&net_sin(&conn->remote_addr)->
sin_addr)) {
continue;
}
} else {
continue;
}
} else if (conn->flags & NET_CONN_LOCAL_ADDR_SET) {
} else if (conn->flags & NET_CONN_REMOTE_ADDR_SET) {
continue;
} else if (reuseport_set && conn->context != NULL &&
net_context_is_reuseport_set(conn->context)) {
continue;
}

Expand All @@ -243,11 +252,6 @@ static struct net_conn *conn_find_handler(uint16_t proto, uint8_t family,
continue;
}

if (net_sin(&conn->local_addr)->sin_port !=
htons(local_port)) {
continue;
}

k_mutex_unlock(&conn_lock);
return conn;
}
Expand All @@ -270,10 +274,13 @@ int net_conn_register(uint16_t proto, uint8_t family,
uint8_t flags = 0U;

conn = conn_find_handler(proto, family, remote_addr, local_addr,
remote_port, local_port);
remote_port, local_port,
context != NULL ?
net_context_is_reuseport_set(context) :
false);
if (conn) {
NET_ERR("Identical connection handler %p already found.", conn);
return -EALREADY;
return -EADDRINUSE;
}

conn = conn_get_unused();
Expand Down Expand Up @@ -736,14 +743,6 @@ enum net_verdict net_conn_input(struct net_pkt *pkt,
continue; /* wrong local address */
}

/* If we have an existing best_match, and that one
* specifies a remote port, then we've matched to a
* LISTENING connection that we should not override.
*/
if (best_match != NULL && best_match->flags & NET_CONN_REMOTE_PORT_SPEC) {
continue; /* do not override listening connection */
}

if (best_rank < NET_CONN_RANK(conn->flags)) {
struct net_pkt *mcast_pkt;

Expand Down
Loading