Skip to content

Commit 273d601

Browse files
sayoojkkarunkartben
authored andcommitted
net: sockets: IPv6_MULTICAST_LOOP Support
Add support for the IPV6_MULTICAST_LOOP socket option. This option allows enabling or disabling the consumption of multicast packets by the sender. By default, the socket option will be enabled. Co-authored-by: Pieter De Gendt <pieter.degendt@gmail.com> Signed-off-by: Sayooj K Karun <sayooj@aerlync.com>
1 parent a61287e commit 273d601

File tree

6 files changed

+140
-0
lines changed

6 files changed

+140
-0
lines changed

include/zephyr/net/net_context.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
/*
88
* Copyright (c) 2016 Intel Corporation
99
* Copyright (c) 2021 Nordic Semiconductor
10+
* Copyright (c) 2025 Aerlync Labs Inc.
1011
*
1112
* SPDX-License-Identifier: Apache-2.0
1213
*/
@@ -390,6 +391,10 @@ __net_socket struct net_context {
390391
*/
391392
uint8_t ipv4_mcast_ifindex;
392393
};
394+
/** Flag to enable/disable multicast loop */
395+
union {
396+
bool ipv6_mcast_loop; /**< IPv6 multicast loop */
397+
};
393398
#endif /* CONFIG_NET_IPV6 || CONFIG_NET_IPV4 */
394399

395400
#if defined(CONFIG_NET_CONTEXT_TIMESTAMPING)
@@ -897,6 +902,40 @@ static inline void net_context_set_ipv6_mcast_hop_limit(struct net_context *cont
897902
context->ipv6_mcast_hop_limit = hop_limit;
898903
}
899904

905+
#if defined(CONFIG_NET_IPV6)
906+
907+
/**
908+
* @brief Get IPv6 multicast loop value for this context.
909+
*
910+
* @details This function returns the IPv6 multicast loop value
911+
* that is set to this context.
912+
*
913+
* @param context Network context.
914+
*
915+
* @return IPv6 multicast loop value
916+
*/
917+
static inline bool net_context_get_ipv6_mcast_loop(struct net_context *context)
918+
{
919+
return context->options.ipv6_mcast_loop;
920+
}
921+
922+
/**
923+
* @brief Set IPv6 multicast loop value for this context.
924+
*
925+
* @details This function sets the IPv6 multicast loop value for
926+
* this context.
927+
*
928+
* @param context Network context.
929+
* @param ipv6_mcast_loop IPv6 multicast loop value.
930+
*/
931+
static inline void net_context_set_ipv6_mcast_loop(struct net_context *context,
932+
bool ipv6_mcast_loop)
933+
{
934+
context->options.ipv6_mcast_loop = ipv6_mcast_loop;
935+
}
936+
937+
#endif
938+
900939
/**
901940
* @brief Enable or disable socks proxy support for this context.
902941
*
@@ -1325,6 +1364,7 @@ enum net_context_option {
13251364
NET_OPT_MCAST_IFINDEX = 19, /**< IPv6 multicast output network interface index */
13261365
NET_OPT_MTU = 20, /**< IPv4 socket path MTU */
13271366
NET_OPT_LOCAL_PORT_RANGE = 21, /**< Clamp local port range */
1367+
NET_OPT_IPV6_MCAST_LOOP = 22, /**< IPV6 multicast loop */
13281368
};
13291369

13301370
/**

include/zephyr/net/socket.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
/*
99
* Copyright (c) 2017-2018 Linaro Limited
1010
* Copyright (c) 2021 Nordic Semiconductor
11+
* Copyright (c) 2025 Aerlync Labs Inc.
1112
*
1213
* SPDX-License-Identifier: Apache-2.0
1314
*/
@@ -1005,6 +1006,9 @@ struct ip_mreq {
10051006
/** Set the multicast hop limit for the socket. */
10061007
#define IPV6_MULTICAST_HOPS 18
10071008

1009+
/** Set the multicast loop bit for the socket. */
1010+
#define IPV6_MULTICAST_LOOP 19
1011+
10081012
/** Join IPv6 multicast group. */
10091013
#define IPV6_ADD_MEMBERSHIP 20
10101014

subsys/net/ip/Kconfig.ipv6

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# IPv6 Options
22

33
# Copyright (c) 2016 Intel Corporation.
4+
# Copyright (c) 2025 Aerlync Labs Inc.
45
# SPDX-License-Identifier: Apache-2.0
56

67
menuconfig NET_IPV6
@@ -81,6 +82,13 @@ config NET_INITIAL_MCAST_HOP_LIMIT
8182
don't leave the local network unless the application explicitly
8283
requests it.
8384

85+
config NET_INITIAL_IPV6_MCAST_LOOP
86+
bool "Control whether the socket sees multicast packets sent by itself"
87+
default y
88+
help
89+
Assign initial value to IPV6_MULTICAST_LOOP in socket options,
90+
if not set by the user using setsockopt().
91+
8492
config NET_IPV6_MAX_NEIGHBORS
8593
int "How many IPv6 neighbors are supported"
8694
default 8

subsys/net/ip/net_context.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
/*
88
* Copyright (c) 2016 Intel Corporation
99
* Copyright (c) 2021 Nordic Semiconductor
10+
* Copyright (c) 2025 Aerlync Labs Inc.
1011
*
1112
* SPDX-License-Identifier: Apache-2.0
1213
*/
@@ -583,6 +584,10 @@ int net_context_get(sa_family_t family, enum net_sock_type type, uint16_t proto,
583584

584585
contexts[i].ipv6_hop_limit = INITIAL_HOP_LIMIT;
585586
contexts[i].ipv6_mcast_hop_limit = INITIAL_MCAST_HOP_LIMIT;
587+
#if defined(CONFIG_NET_IPV6)
588+
contexts[i].options.ipv6_mcast_loop =
589+
IS_ENABLED(CONFIG_NET_INITIAL_IPV6_MCAST_LOOP);
590+
#endif
586591
}
587592
if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) {
588593
struct sockaddr_in *addr = (struct sockaddr_in *)&contexts[i].local;
@@ -2033,6 +2038,20 @@ static int get_context_local_port_range(struct net_context *context,
20332038
#endif
20342039
}
20352040

2041+
static int get_context_ipv6_mcast_loop(struct net_context *context,
2042+
void *value, size_t *len)
2043+
{
2044+
#if defined(CONFIG_NET_IPV6)
2045+
return get_bool_option(context->options.ipv6_mcast_loop, value, len);
2046+
#else
2047+
ARG_UNUSED(context);
2048+
ARG_UNUSED(value);
2049+
ARG_UNUSED(len);
2050+
2051+
return -ENOTSUP;
2052+
#endif
2053+
}
2054+
20362055
/* If buf is not NULL, then use it. Otherwise read the data to be written
20372056
* to net_pkt from msghdr.
20382057
*/
@@ -3329,6 +3348,20 @@ static int set_context_unicast_hop_limit(struct net_context *context,
33293348
#endif
33303349
}
33313350

3351+
static int set_context_ipv6_mcast_loop(struct net_context *context,
3352+
const void *value, size_t len)
3353+
{
3354+
#if defined(CONFIG_NET_IPV6)
3355+
return set_bool_option(&context->options.ipv6_mcast_loop, value, len);
3356+
#else
3357+
ARG_UNUSED(context);
3358+
ARG_UNUSED(value);
3359+
ARG_UNUSED(len);
3360+
3361+
return -ENOTSUP;
3362+
#endif
3363+
}
3364+
33323365
static int set_context_reuseaddr(struct net_context *context,
33333366
const void *value, size_t len)
33343367
{
@@ -3652,6 +3685,9 @@ int net_context_set_option(struct net_context *context,
36523685
case NET_OPT_LOCAL_PORT_RANGE:
36533686
ret = set_context_local_port_range(context, value, len);
36543687
break;
3688+
case NET_OPT_IPV6_MCAST_LOOP:
3689+
ret = set_context_ipv6_mcast_loop(context, value, len);
3690+
break;
36553691
}
36563692

36573693
k_mutex_unlock(&context->lock);
@@ -3737,6 +3773,9 @@ int net_context_get_option(struct net_context *context,
37373773
case NET_OPT_LOCAL_PORT_RANGE:
37383774
ret = get_context_local_port_range(context, value, len);
37393775
break;
3776+
case NET_OPT_IPV6_MCAST_LOOP:
3777+
ret = get_context_ipv6_mcast_loop(context, value, len);
3778+
break;
37403779
}
37413780

37423781
k_mutex_unlock(&context->lock);

subsys/net/ip/net_core.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
/*
99
* Copyright (c) 2016 Intel Corporation
10+
* Copyright (c) 2025 Aerlync Labs Inc.
1011
*
1112
* SPDX-License-Identifier: Apache-2.0
1213
*/
@@ -409,6 +410,30 @@ int net_try_send_data(struct net_pkt *pkt, k_timeout_t timeout)
409410
goto err;
410411
}
411412

413+
#if defined(CONFIG_NET_IPV6)
414+
if (net_pkt_family(pkt) == AF_INET6) {
415+
const struct in6_addr *dest = (const struct in6_addr *)&NET_IPV6_HDR(pkt)->dst;
416+
struct net_context *ctx = net_pkt_context(pkt);
417+
418+
if (net_ipv6_is_addr_mcast(dest) && ctx != NULL &&
419+
net_context_get_ipv6_mcast_loop(ctx)) {
420+
struct net_pkt *clone = net_pkt_clone(pkt, K_NO_WAIT);
421+
422+
if (clone != NULL) {
423+
net_pkt_set_iface(clone, net_pkt_iface(pkt));
424+
if (net_recv_data(net_pkt_iface(clone), clone) < 0) {
425+
if (IS_ENABLED(CONFIG_NET_STATISTICS)) {
426+
net_stats_update_ipv6_drop(net_pkt_iface(pkt));
427+
}
428+
net_pkt_unref(clone);
429+
}
430+
} else {
431+
NET_DBG("Failed to clone multicast packet");
432+
}
433+
}
434+
}
435+
#endif
436+
412437
if (net_if_try_send_data(net_pkt_iface(pkt), pkt, timeout) == NET_DROP) {
413438
ret = -EIO;
414439
goto err;

subsys/net/lib/sockets/sockets_inet.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* Copyright (c) 2017 Linaro Limited
33
* Copyright (c) 2021 Nordic Semiconductor
44
* Copyright (c) 2023 Arm Limited (or its affiliates). All rights reserved.
5+
* Copyright (c) 2025 Aerlync Labs Inc.
56
*
67
* SPDX-License-Identifier: Apache-2.0
78
*/
@@ -2080,6 +2081,18 @@ int zsock_getsockopt_ctx(struct net_context *ctx, int level, int optname,
20802081
}
20812082

20822083
return 0;
2084+
2085+
case IPV6_MULTICAST_LOOP:
2086+
ret = net_context_get_option(ctx,
2087+
NET_OPT_IPV6_MCAST_LOOP,
2088+
optval, optlen);
2089+
if (ret < 0) {
2090+
errno = -ret;
2091+
return -1;
2092+
}
2093+
2094+
return 0;
2095+
20832096
}
20842097

20852098
break;
@@ -2722,6 +2735,17 @@ int zsock_setsockopt_ctx(struct net_context *ctx, int level, int optname,
27222735
}
27232736

27242737
break;
2738+
2739+
case IPV6_MULTICAST_LOOP:
2740+
ret = net_context_set_option(ctx,
2741+
NET_OPT_IPV6_MCAST_LOOP,
2742+
optval, optlen);
2743+
if (ret < 0) {
2744+
errno = -ret;
2745+
return -1;
2746+
}
2747+
2748+
return 0;
27252749
}
27262750

27272751
break;

0 commit comments

Comments
 (0)