net: context: Add support for adjusting IPv4 multicast ttl
Add option support for adjusting the IPv4 multicast time-to-live value. Fixes #60299 Signed-off-by: Jukka Rissanen <jukka.rissanen@nordicsemi.no>
This commit is contained in:
parent
a65ebbd6bc
commit
de0268def0
|
@ -349,7 +349,10 @@ __net_socket struct net_context {
|
|||
/** IPv6 hop limit or IPv4 ttl for packets sent via this context. */
|
||||
union {
|
||||
uint8_t ipv6_hop_limit;
|
||||
uint8_t ipv4_ttl;
|
||||
struct {
|
||||
uint8_t ipv4_ttl;
|
||||
uint8_t ipv4_mcast_ttl;
|
||||
};
|
||||
};
|
||||
|
||||
#if defined(CONFIG_SOCKS)
|
||||
|
@ -703,6 +706,17 @@ static inline void net_context_set_ipv4_ttl(struct net_context *context,
|
|||
context->ipv4_ttl = ttl;
|
||||
}
|
||||
|
||||
static inline uint8_t net_context_get_ipv4_mcast_ttl(struct net_context *context)
|
||||
{
|
||||
return context->ipv4_mcast_ttl;
|
||||
}
|
||||
|
||||
static inline void net_context_set_ipv4_mcast_ttl(struct net_context *context,
|
||||
uint8_t ttl)
|
||||
{
|
||||
context->ipv4_mcast_ttl = ttl;
|
||||
}
|
||||
|
||||
static inline uint8_t net_context_get_ipv6_hop_limit(struct net_context *context)
|
||||
{
|
||||
return context->ipv6_hop_limit;
|
||||
|
@ -1106,6 +1120,7 @@ enum net_context_option {
|
|||
NET_OPT_REUSEPORT = 10,
|
||||
NET_OPT_IPV6_V6ONLY = 11,
|
||||
NET_OPT_RECV_PKTINFO = 12,
|
||||
NET_OPT_MCAST_TTL = 13,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -380,6 +380,9 @@ struct net_if_ipv4 {
|
|||
|
||||
/** IPv4 time-to-live */
|
||||
uint8_t ttl;
|
||||
|
||||
/** IPv4 time-to-live for multicast packets */
|
||||
uint8_t mcast_ttl;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_NET_DHCPV4) && defined(CONFIG_NET_NATIVE_IPV4)
|
||||
|
@ -1916,6 +1919,23 @@ uint8_t net_if_ipv4_get_ttl(struct net_if *iface);
|
|||
*/
|
||||
void net_if_ipv4_set_ttl(struct net_if *iface, uint8_t ttl);
|
||||
|
||||
/**
|
||||
* @brief Get IPv4 multicast time-to-live value specified for a given interface
|
||||
*
|
||||
* @param iface Network interface
|
||||
*
|
||||
* @return Time-to-live
|
||||
*/
|
||||
uint8_t net_if_ipv4_get_mcast_ttl(struct net_if *iface);
|
||||
|
||||
/**
|
||||
* @brief Set IPv4 multicast time-to-live value specified to a given interface
|
||||
*
|
||||
* @param iface Network interface
|
||||
* @param ttl Time-to-live value
|
||||
*/
|
||||
void net_if_ipv4_set_mcast_ttl(struct net_if *iface, uint8_t ttl);
|
||||
|
||||
/**
|
||||
* @brief Check if this IPv4 address belongs to one of the interfaces.
|
||||
*
|
||||
|
|
|
@ -1112,6 +1112,9 @@ struct in_pktinfo {
|
|||
struct in_addr ipi_addr; /* Header Destination address */
|
||||
};
|
||||
|
||||
/** sockopt: Set IPv4 multicast TTL value. */
|
||||
#define IP_MULTICAST_TTL 33
|
||||
|
||||
/* Socket options for IPPROTO_IPV6 level */
|
||||
/** sockopt: Don't support IPv4 access */
|
||||
#define IPV6_V6ONLY 26
|
||||
|
|
|
@ -12,10 +12,27 @@ menuconfig NET_IPV4
|
|||
if NET_IPV4
|
||||
|
||||
config NET_INITIAL_TTL
|
||||
int "Initial time to live for a connection"
|
||||
int "Initial IPv4 time to live value for unicast packets"
|
||||
default 64
|
||||
range 0 255
|
||||
help
|
||||
The value should be > 0
|
||||
The value should normally be > 0. The device receiving the IPv4
|
||||
packet will decrement the value and will drop the packet if the TTL
|
||||
value is 0. When sending, the packet is dropped before transmitting
|
||||
to network if TTL is 0.
|
||||
|
||||
config NET_INITIAL_MCAST_TTL
|
||||
int "Initial IPv4 time to live value for multicast packets"
|
||||
default 1
|
||||
range 0 255
|
||||
help
|
||||
The value should normally be > 0. The device receiving the IPv4
|
||||
packet will decrement the value and will drop the packet if the TTL
|
||||
value is 0. When sending, the packet is dropped before transmitting
|
||||
to network if TTL is 0.
|
||||
The default is 1 (same as in Linux) which means that multicast packets
|
||||
don't leave the local network unless the application explicitly
|
||||
requests it.
|
||||
|
||||
config NET_IF_MAX_IPV4_COUNT
|
||||
int "Max number of IPv4 network interfaces in the system"
|
||||
|
|
|
@ -191,6 +191,9 @@ static int igmp_v2_create_packet(struct net_pkt *pkt, const struct in_addr *dst,
|
|||
const uint32_t router_alert = 0x94040000; /* RFC 2213 ch 2.1 */
|
||||
int ret;
|
||||
|
||||
/* TTL set to 1, RFC 3376 ch 2 */
|
||||
net_pkt_set_ipv4_ttl(pkt, 1U);
|
||||
|
||||
ret = net_ipv4_create_full(pkt,
|
||||
net_if_ipv4_select_src_addr(
|
||||
net_pkt_iface(pkt),
|
||||
|
@ -199,8 +202,7 @@ static int igmp_v2_create_packet(struct net_pkt *pkt, const struct in_addr *dst,
|
|||
0U,
|
||||
0U,
|
||||
0U,
|
||||
0U,
|
||||
1U); /* TTL set to 1, RFC 3376 ch 2 */
|
||||
0U);
|
||||
if (ret) {
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
@ -222,8 +224,11 @@ static int igmp_v3_create_packet(struct net_pkt *pkt, const struct in_addr *dst,
|
|||
const uint32_t router_alert = 0x94040000; /* RFC 2213 ch 2.1 */
|
||||
int ret;
|
||||
|
||||
/* TTL set to 1, RFC 3376 ch 2 */
|
||||
net_pkt_set_ipv4_ttl(pkt, 1U);
|
||||
|
||||
ret = net_ipv4_create_full(pkt, net_if_ipv4_select_src_addr(net_pkt_iface(pkt), dst), dst,
|
||||
0U, 0U, 0U, 0U, 1U); /* TTL set to 1, RFC 3376 ch 2 */
|
||||
0U, 0U, 0U, 0U);
|
||||
if (ret) {
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
|
|
@ -37,8 +37,7 @@ int net_ipv4_create_full(struct net_pkt *pkt,
|
|||
uint8_t tos,
|
||||
uint16_t id,
|
||||
uint8_t flags,
|
||||
uint16_t offset,
|
||||
uint8_t ttl)
|
||||
uint16_t offset)
|
||||
{
|
||||
NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv4_access, struct net_ipv4_hdr);
|
||||
struct net_ipv4_hdr *ipv4_hdr;
|
||||
|
@ -55,10 +54,24 @@ int net_ipv4_create_full(struct net_pkt *pkt,
|
|||
ipv4_hdr->id[1] = id;
|
||||
ipv4_hdr->offset[0] = (offset >> 8) | (flags << 5);
|
||||
ipv4_hdr->offset[1] = offset;
|
||||
ipv4_hdr->ttl = ttl;
|
||||
|
||||
if (ttl == 0U) {
|
||||
ipv4_hdr->ttl = net_if_ipv4_get_ttl(net_pkt_iface(pkt));
|
||||
ipv4_hdr->ttl = net_pkt_ipv4_ttl(pkt);
|
||||
if (ipv4_hdr->ttl == 0U) {
|
||||
if (net_ipv4_is_addr_mcast(dst)) {
|
||||
if (net_pkt_context(pkt) != NULL) {
|
||||
ipv4_hdr->ttl =
|
||||
net_context_get_ipv4_mcast_ttl(net_pkt_context(pkt));
|
||||
} else {
|
||||
ipv4_hdr->ttl = net_if_ipv4_get_mcast_ttl(net_pkt_iface(pkt));
|
||||
}
|
||||
} else {
|
||||
if (net_pkt_context(pkt) != NULL) {
|
||||
ipv4_hdr->ttl =
|
||||
net_context_get_ipv4_ttl(net_pkt_context(pkt));
|
||||
} else {
|
||||
ipv4_hdr->ttl = net_if_ipv4_get_ttl(net_pkt_iface(pkt));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ipv4_hdr->proto = 0U;
|
||||
|
@ -83,8 +96,7 @@ int net_ipv4_create(struct net_pkt *pkt,
|
|||
net_ipv4_set_ecn(&tos, net_pkt_ip_ecn(pkt));
|
||||
}
|
||||
|
||||
return net_ipv4_create_full(pkt, src, dst, tos, 0U, 0U, 0U,
|
||||
net_pkt_ipv4_ttl(pkt));
|
||||
return net_ipv4_create_full(pkt, src, dst, tos, 0U, 0U, 0U);
|
||||
}
|
||||
|
||||
int net_ipv4_finalize(struct net_pkt *pkt, uint8_t next_header_proto)
|
||||
|
|
|
@ -127,7 +127,6 @@ struct net_ipv4_igmp_v3_report {
|
|||
* @param id Fragment id
|
||||
* @param flags Fragmentation flags
|
||||
* @param offset Fragment offset
|
||||
* @param ttl Time-to-live value
|
||||
*
|
||||
* @return 0 on success, negative errno otherwise.
|
||||
*/
|
||||
|
@ -138,8 +137,7 @@ int net_ipv4_create_full(struct net_pkt *pkt,
|
|||
uint8_t tos,
|
||||
uint16_t id,
|
||||
uint8_t flags,
|
||||
uint16_t offset,
|
||||
uint8_t ttl);
|
||||
uint16_t offset);
|
||||
#else
|
||||
static inline int net_ipv4_create_full(struct net_pkt *pkt,
|
||||
const struct in_addr *src,
|
||||
|
@ -147,8 +145,7 @@ static inline int net_ipv4_create_full(struct net_pkt *pkt,
|
|||
uint8_t tos,
|
||||
uint16_t id,
|
||||
uint8_t flags,
|
||||
uint16_t offset,
|
||||
uint8_t ttl)
|
||||
uint16_t offset)
|
||||
{
|
||||
ARG_UNUSED(pkt);
|
||||
ARG_UNUSED(src);
|
||||
|
@ -157,7 +154,6 @@ static inline int net_ipv4_create_full(struct net_pkt *pkt,
|
|||
ARG_UNUSED(id);
|
||||
ARG_UNUSED(flags);
|
||||
ARG_UNUSED(offset);
|
||||
ARG_UNUSED(ttl);
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,12 @@ LOG_MODULE_REGISTER(net_ctx, CONFIG_NET_CONTEXT_LOG_LEVEL);
|
|||
#include "tcp.h"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_INITIAL_MCAST_TTL
|
||||
#define INITIAL_MCAST_TTL CONFIG_NET_INITIAL_MCAST_TTL
|
||||
#else
|
||||
#define INITIAL_MCAST_TTL 1
|
||||
#endif
|
||||
|
||||
#ifndef EPFNOSUPPORT
|
||||
/* Some old versions of newlib haven't got this defined in errno.h,
|
||||
* Just use EPROTONOSUPPORT in this case
|
||||
|
@ -479,6 +485,8 @@ int net_context_get(sa_family_t family, enum net_sock_type type, uint16_t proto,
|
|||
ret = -EADDRINUSE;
|
||||
break;
|
||||
}
|
||||
|
||||
contexts[i].ipv4_mcast_ttl = INITIAL_MCAST_TTL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1544,6 +1552,26 @@ static int get_context_dscp_ecn(struct net_context *context,
|
|||
#endif
|
||||
}
|
||||
|
||||
static int get_context_mcast_ttl(struct net_context *context,
|
||||
void *value, size_t *len)
|
||||
{
|
||||
#if defined(CONFIG_NET_IPV4)
|
||||
*((int *)value) = context->ipv4_mcast_ttl;
|
||||
|
||||
if (len) {
|
||||
*len = sizeof(int);
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
ARG_UNUSED(context);
|
||||
ARG_UNUSED(value);
|
||||
ARG_UNUSED(len);
|
||||
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int get_context_reuseaddr(struct net_context *context,
|
||||
void *value, size_t *len)
|
||||
{
|
||||
|
@ -2712,6 +2740,24 @@ static int set_context_dscp_ecn(struct net_context *context,
|
|||
#endif
|
||||
}
|
||||
|
||||
static int set_context_mcast_ttl(struct net_context *context,
|
||||
const void *value, size_t len)
|
||||
{
|
||||
#if defined(CONFIG_NET_IPV4)
|
||||
uint8_t mcast_ttl = *((int *)value);
|
||||
|
||||
len = sizeof(context->ipv4_mcast_ttl);
|
||||
|
||||
return set_uint8_option(&context->ipv4_mcast_ttl, &mcast_ttl, len);
|
||||
#else
|
||||
ARG_UNUSED(context);
|
||||
ARG_UNUSED(value);
|
||||
ARG_UNUSED(len);
|
||||
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int set_context_reuseaddr(struct net_context *context,
|
||||
const void *value, size_t len)
|
||||
{
|
||||
|
@ -2807,6 +2853,9 @@ int net_context_set_option(struct net_context *context,
|
|||
case NET_OPT_DSCP_ECN:
|
||||
ret = set_context_dscp_ecn(context, value, len);
|
||||
break;
|
||||
case NET_OPT_MCAST_TTL:
|
||||
ret = set_context_mcast_ttl(context, value, len);
|
||||
break;
|
||||
case NET_OPT_REUSEADDR:
|
||||
ret = set_context_reuseaddr(context, value, len);
|
||||
break;
|
||||
|
@ -2865,6 +2914,9 @@ int net_context_get_option(struct net_context *context,
|
|||
case NET_OPT_DSCP_ECN:
|
||||
ret = get_context_dscp_ecn(context, value, len);
|
||||
break;
|
||||
case NET_OPT_MCAST_TTL:
|
||||
ret = get_context_mcast_ttl(context, value, len);
|
||||
break;
|
||||
case NET_OPT_REUSEADDR:
|
||||
ret = get_context_reuseaddr(context, value, len);
|
||||
break;
|
||||
|
|
|
@ -3151,6 +3151,47 @@ out:
|
|||
#endif
|
||||
}
|
||||
|
||||
uint8_t net_if_ipv4_get_mcast_ttl(struct net_if *iface)
|
||||
{
|
||||
#if defined(CONFIG_NET_NATIVE_IPV4)
|
||||
int ret = 0;
|
||||
|
||||
net_if_lock(iface);
|
||||
|
||||
if (!iface->config.ip.ipv4) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = iface->config.ip.ipv4->mcast_ttl;
|
||||
out:
|
||||
net_if_unlock(iface);
|
||||
|
||||
return ret;
|
||||
#else
|
||||
ARG_UNUSED(iface);
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void net_if_ipv4_set_mcast_ttl(struct net_if *iface, uint8_t ttl)
|
||||
{
|
||||
#if defined(CONFIG_NET_NATIVE_IPV4)
|
||||
net_if_lock(iface);
|
||||
|
||||
if (!iface->config.ip.ipv4) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
iface->config.ip.ipv4->mcast_ttl = ttl;
|
||||
out:
|
||||
net_if_unlock(iface);
|
||||
#else
|
||||
ARG_UNUSED(iface);
|
||||
ARG_UNUSED(ttl);
|
||||
#endif
|
||||
}
|
||||
|
||||
struct net_if_router *net_if_ipv4_router_lookup(struct net_if *iface,
|
||||
struct in_addr *addr)
|
||||
{
|
||||
|
@ -4035,6 +4076,7 @@ static void iface_ipv4_init(int if_count)
|
|||
|
||||
for (i = 0; i < ARRAY_SIZE(ipv4_addresses); i++) {
|
||||
ipv4_addresses[i].ipv4.ttl = CONFIG_NET_INITIAL_TTL;
|
||||
ipv4_addresses[i].ipv4.mcast_ttl = CONFIG_NET_INITIAL_MCAST_TTL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -207,7 +207,7 @@ static int interface_send(struct net_if *iface, struct net_pkt *pkt)
|
|||
ret = net_ipv4_create_full(tmp, ctx->my4addr,
|
||||
&ctx->peer.in_addr,
|
||||
tos, 0U, NET_IPV4_DF,
|
||||
0U, net_pkt_ipv4_ttl(tmp));
|
||||
0U);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -2517,6 +2517,16 @@ int zsock_getsockopt_ctx(struct net_context *ctx, int level, int optname,
|
|||
}
|
||||
|
||||
break;
|
||||
|
||||
case IP_MULTICAST_TTL:
|
||||
ret = net_context_get_option(ctx, NET_OPT_MCAST_TTL,
|
||||
optval, optlen);
|
||||
if (ret < 0) {
|
||||
errno = -ret;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -2885,6 +2895,16 @@ int zsock_setsockopt_ctx(struct net_context *ctx, int level, int optname,
|
|||
}
|
||||
|
||||
break;
|
||||
|
||||
case IP_MULTICAST_TTL:
|
||||
ret = net_context_set_option(ctx, NET_OPT_MCAST_TTL,
|
||||
optval, optlen);
|
||||
if (ret < 0) {
|
||||
errno = -ret;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
|
@ -207,8 +207,10 @@ static int get_ipv4_reply(struct net_if *iface,
|
|||
ipv4_hdr = net_pkt_cursor_get_pos(reply);
|
||||
*hdr_ipv4 = ipv4_hdr;
|
||||
|
||||
net_pkt_set_ipv4_ttl(reply, 1U);
|
||||
|
||||
ret = net_ipv4_create_full(reply, src4, dest4, params->tc_tos,
|
||||
params->identifier, 0, 0, 1);
|
||||
params->identifier, 0, 0);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Cannot create IPv4 pkt (%d)", ret);
|
||||
return ret;
|
||||
|
|
Loading…
Reference in a new issue