From 9fb09da21a4080e921f9fc7bb2f77baf5085b2cb Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 13 Nov 2024 09:26:53 +0200 Subject: [PATCH] net: Add support for IPV6_MTU IPv6 socket option Add IPV6_MTU IPv6 socket option and implement getsockopt() and setsockopt() calls for the option. Signed-off-by: Jukka Rissanen --- include/zephyr/net/socket.h | 7 ++++ subsys/net/ip/net_context.c | 52 +++++++++++++++++++++++++++ subsys/net/lib/sockets/sockets_inet.c | 28 +++++++++++++++ 3 files changed, 87 insertions(+) diff --git a/include/zephyr/net/socket.h b/include/zephyr/net/socket.h index 94fc5efda92..06fd0be5ffa 100644 --- a/include/zephyr/net/socket.h +++ b/include/zephyr/net/socket.h @@ -1248,6 +1248,13 @@ struct ipv6_mreq { int ipv6mr_ifindex; }; +/** For getsockopt(), retrieve the current known IPv6 path MTU of the given socket. + * Valid only when the socket has been connected. + * For setsockopt(), set the MTU to be used for the socket. The MTU is limited by + * the device MTU or the path MTU when path MTU discovery is enabled. + */ +#define IPV6_MTU 24 + /** Don't support IPv4 access */ #define IPV6_V6ONLY 26 diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index 173000fad0d..0d304e624eb 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -3102,6 +3102,55 @@ static int set_context_reuseport(struct net_context *context, #endif } +static int set_context_ipv6_mtu(struct net_context *context, + const void *value, size_t len) +{ +#if defined(CONFIG_NET_IPV6) + struct net_if *iface; + uint16_t mtu; + + if (len != sizeof(int)) { + return -EINVAL; + } + + mtu = *((int *)value); + + if (IS_ENABLED(CONFIG_NET_IPV6_PMTU)) { + int ret; + + ret = net_pmtu_update_mtu(&context->remote, mtu); + if (ret < 0) { + return ret; + } + + return 0; + } + + if (net_context_is_bound_to_iface(context)) { + iface = net_context_get_iface(context); + } else { + sa_family_t family = net_context_get_family(context); + + if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) { + iface = net_if_ipv6_select_src_iface( + &net_sin6(&context->remote)->sin6_addr); + } else { + return -EAFNOSUPPORT; + } + } + + net_if_set_mtu(iface, (uint16_t)mtu); + + return 0; +#else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + + return -ENOTSUP; +#endif +} + static int set_context_ipv6_v6only(struct net_context *context, const void *value, size_t len) { @@ -3236,6 +3285,9 @@ int net_context_set_option(struct net_context *context, if (IS_ENABLED(CONFIG_NET_IPV4) && net_context_get_family(context) == AF_INET) { ret = -EOPNOTSUPP; + } else if (IS_ENABLED(CONFIG_NET_IPV6) && + net_context_get_family(context) == AF_INET6) { + ret = set_context_ipv6_mtu(context, value, len); } break; diff --git a/subsys/net/lib/sockets/sockets_inet.c b/subsys/net/lib/sockets/sockets_inet.c index af57c40e5bc..8e5673208aa 100644 --- a/subsys/net/lib/sockets/sockets_inet.c +++ b/subsys/net/lib/sockets/sockets_inet.c @@ -1858,6 +1858,20 @@ int zsock_getsockopt_ctx(struct net_context *ctx, int level, int optname, case IPPROTO_IPV6: switch (optname) { + case IPV6_MTU: + if (IS_ENABLED(CONFIG_NET_IPV6)) { + ret = net_context_get_option(ctx, NET_OPT_MTU, + optval, optlen); + if (ret < 0) { + errno = -ret; + return -1; + } + + return 0; + } + + break; + case IPV6_V6ONLY: if (IS_ENABLED(CONFIG_NET_IPV4_MAPPING_TO_IPV6)) { ret = net_context_get_option(ctx, @@ -2422,6 +2436,20 @@ int zsock_setsockopt_ctx(struct net_context *ctx, int level, int optname, case IPPROTO_IPV6: switch (optname) { + case IPV6_MTU: + if (IS_ENABLED(CONFIG_NET_IPV6)) { + ret = net_context_set_option(ctx, NET_OPT_MTU, + optval, optlen); + if (ret < 0) { + errno = -ret; + return -1; + } + + return 0; + } + + break; + case IPV6_V6ONLY: if (IS_ENABLED(CONFIG_NET_IPV4_MAPPING_TO_IPV6)) { ret = net_context_set_option(ctx,