net: add sndbuf socket option

Introduce set/get SO_SNDBUF option using the setsockopt
function. In addition, for TCP, check the sndbuf value
before queuing data.

Signed-off-by: Mohan Kumar Kumar <mohankm@fb.com>
This commit is contained in:
Mohan Kumar Kumar 2022-04-01 12:47:25 -07:00 committed by Carles Cufí
commit f105ea6ef5
5 changed files with 96 additions and 0 deletions

View file

@ -315,6 +315,9 @@ __net_socket struct net_context {
#endif #endif
#if defined(CONFIG_NET_CONTEXT_RCVBUF) #if defined(CONFIG_NET_CONTEXT_RCVBUF)
uint16_t rcvbuf; uint16_t rcvbuf;
#endif
#if defined(CONFIG_NET_CONTEXT_SNDBUF)
uint16_t sndbuf;
#endif #endif
} options; } options;
@ -1064,6 +1067,7 @@ enum net_context_option {
NET_OPT_RCVTIMEO = 4, NET_OPT_RCVTIMEO = 4,
NET_OPT_SNDTIMEO = 5, NET_OPT_SNDTIMEO = 5,
NET_OPT_RCVBUF = 6, NET_OPT_RCVBUF = 6,
NET_OPT_SNDBUF = 7,
}; };
/** /**

View file

@ -594,6 +594,13 @@ config NET_CONTEXT_RCVBUF
The default value is set by CONFIG_NET_TCP_MAX_RECV_WINDOW_SIZE. For The default value is set by CONFIG_NET_TCP_MAX_RECV_WINDOW_SIZE. For
TCP sockets, the rcvbuf will determine the receive window size. TCP sockets, the rcvbuf will determine the receive window size.
config NET_CONTEXT_SNDBUF
bool "Add SNDBUF support to net_context"
help
It is possible to define the maximum socket send buffer per socket.
For TCP sockets, the sndbuf will determine the total size of queued
data in the TCP layer.
config NET_TEST config NET_TEST
bool "Network Testing" bool "Network Testing"
help help

View file

@ -1260,6 +1260,21 @@ static int get_context_rcvbuf(struct net_context *context,
#endif #endif
} }
static int get_context_sndbuf(struct net_context *context,
void *value, size_t *len)
{
#if defined(CONFIG_NET_CONTEXT_SNDBUF)
*((int *)value) = context->options.sndbuf;
if (len) {
*len = sizeof(int);
}
return 0;
#else
return -ENOTSUP;
#endif
}
/* If buf is not NULL, then use it. Otherwise read the data to be written /* If buf is not NULL, then use it. Otherwise read the data to be written
* to net_pkt from msghdr. * to net_pkt from msghdr.
*/ */
@ -2251,6 +2266,27 @@ static int set_context_rcvbuf(struct net_context *context,
#endif #endif
} }
static int set_context_sndbuf(struct net_context *context,
const void *value, size_t len)
{
#if defined(CONFIG_NET_CONTEXT_SNDBUF)
int sndbuf_value = *((int *)value);
if (len != sizeof(int)) {
return -EINVAL;
}
if ((sndbuf_value < 0) || (sndbuf_value > UINT16_MAX)) {
return -EINVAL;
}
context->options.sndbuf = (uint16_t) sndbuf_value;
return 0;
#else
return -ENOTSUP;
#endif
}
int net_context_set_option(struct net_context *context, int net_context_set_option(struct net_context *context,
enum net_context_option option, enum net_context_option option,
const void *value, size_t len) const void *value, size_t len)
@ -2284,6 +2320,9 @@ int net_context_set_option(struct net_context *context,
case NET_OPT_RCVBUF: case NET_OPT_RCVBUF:
ret = set_context_rcvbuf(context, value, len); ret = set_context_rcvbuf(context, value, len);
break; break;
case NET_OPT_SNDBUF:
ret = set_context_sndbuf(context, value, len);
break;
} }
k_mutex_unlock(&context->lock); k_mutex_unlock(&context->lock);
@ -2324,6 +2363,9 @@ int net_context_get_option(struct net_context *context,
case NET_OPT_RCVBUF: case NET_OPT_RCVBUF:
ret = get_context_rcvbuf(context, value, len); ret = get_context_rcvbuf(context, value, len);
break; break;
case NET_OPT_SNDBUF:
ret = get_context_sndbuf(context, value, len);
break;
} }
k_mutex_unlock(&context->lock); k_mutex_unlock(&context->lock);

View file

@ -1782,6 +1782,9 @@ static void tcp_in(struct tcp *conn, struct net_pkt *pkt)
if (th) { if (th) {
size_t max_win; size_t max_win;
int sndbuf;
size_t sndbuf_len;
conn->send_win = ntohs(th_win(th)); conn->send_win = ntohs(th_win(th));
@ -1798,6 +1801,17 @@ static void tcp_in(struct tcp *conn, struct net_pkt *pkt)
CONFIG_NET_BUF_DATA_SIZE) / 3; CONFIG_NET_BUF_DATA_SIZE) / 3;
} }
if (IS_ENABLED(CONFIG_NET_CONTEXT_SNDBUF) &&
conn->state != TCP_SYN_SENT &&
net_context_get_option(conn->context,
NET_OPT_SNDBUF,
&sndbuf,
&sndbuf_len) == 0) {
if (sndbuf > 0) {
max_win = sndbuf;
}
}
max_win = MAX(max_win, NET_IPV6_MTU); max_win = MAX(max_win, NET_IPV6_MTU);
if ((size_t)conn->send_win > max_win) { if ((size_t)conn->send_win > max_win) {
NET_DBG("Lowering send window from %zd to %zd", NET_DBG("Lowering send window from %zd to %zd",

View file

@ -1763,6 +1763,20 @@ int zsock_getsockopt_ctx(struct net_context *ctx, int level, int optname,
return 0; return 0;
} }
break; break;
case SO_SNDBUF:
if (IS_ENABLED(CONFIG_NET_CONTEXT_SNDBUF)) {
ret = net_context_get_option(ctx,
NET_OPT_SNDBUF,
optval, optlen);
if (ret < 0) {
errno = -ret;
return -1;
}
return 0;
}
break;
} }
} }
@ -1830,6 +1844,21 @@ int zsock_setsockopt_ctx(struct net_context *ctx, int level, int optname,
break; break;
case SO_SNDBUF:
if (IS_ENABLED(CONFIG_NET_CONTEXT_SNDBUF)) {
ret = net_context_set_option(ctx,
NET_OPT_SNDBUF,
optval, optlen);
if (ret < 0) {
errno = -ret;
return -1;
}
return 0;
}
break;
case SO_REUSEADDR: case SO_REUSEADDR:
/* Ignore for now. Provided to let port /* Ignore for now. Provided to let port
* existing apps. * existing apps.