Skip to content
35 changes: 25 additions & 10 deletions drivers/net/loopback.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@

#include <zephyr/net/dummy.h>

/* Allow network tests to control the IP addresses swapping */
#if defined(CONFIG_NET_TEST)
static bool loopback_dont_swap_addresses;

void loopback_enable_address_swap(bool swap_addresses)
{
loopback_dont_swap_addresses = !swap_addresses;
}
#endif /* CONFIG_NET_TEST */

int loopback_dev_init(const struct device *dev)
{
ARG_UNUSED(dev);
Expand Down Expand Up @@ -123,17 +133,22 @@

/* We need to swap the IP addresses because otherwise
* the packet will be dropped.
*
* Some of the network tests require that addresses are not swapped so allow
* the test to control this remotely.
*/
if (net_pkt_family(pkt) == AF_INET6) {
net_ipv6_addr_copy_raw(NET_IPV6_HDR(cloned)->src,
NET_IPV6_HDR(pkt)->dst);
net_ipv6_addr_copy_raw(NET_IPV6_HDR(cloned)->dst,
NET_IPV6_HDR(pkt)->src);
} else {
net_ipv4_addr_copy_raw(NET_IPV4_HDR(cloned)->src,
NET_IPV4_HDR(pkt)->dst);
net_ipv4_addr_copy_raw(NET_IPV4_HDR(cloned)->dst,
NET_IPV4_HDR(pkt)->src);
if (!COND_CODE_1(CONFIG_NET_TEST, (loopback_dont_swap_addresses), (false))) {
if (net_pkt_family(pkt) == AF_INET6) {
net_ipv6_addr_copy_raw(NET_IPV6_HDR(cloned)->src,
NET_IPV6_HDR(pkt)->dst);
net_ipv6_addr_copy_raw(NET_IPV6_HDR(cloned)->dst,
NET_IPV6_HDR(pkt)->src);
} else {
net_ipv4_addr_copy_raw(NET_IPV4_HDR(cloned)->src,
NET_IPV4_HDR(pkt)->dst);
net_ipv4_addr_copy_raw(NET_IPV4_HDR(cloned)->dst,
NET_IPV4_HDR(pkt)->src);
}

Check notice on line 151 in drivers/net/loopback.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

drivers/net/loopback.c:151 - net_ipv6_addr_copy_raw(NET_IPV6_HDR(cloned)->src, - NET_IPV6_HDR(pkt)->dst); - net_ipv6_addr_copy_raw(NET_IPV6_HDR(cloned)->dst, - NET_IPV6_HDR(pkt)->src); + net_ipv6_addr_copy_raw(NET_IPV6_HDR(cloned)->src, NET_IPV6_HDR(pkt)->dst); + net_ipv6_addr_copy_raw(NET_IPV6_HDR(cloned)->dst, NET_IPV6_HDR(pkt)->src); } else { - net_ipv4_addr_copy_raw(NET_IPV4_HDR(cloned)->src, - NET_IPV4_HDR(pkt)->dst); - net_ipv4_addr_copy_raw(NET_IPV4_HDR(cloned)->dst, - NET_IPV4_HDR(pkt)->src); + net_ipv4_addr_copy_raw(NET_IPV4_HDR(cloned)->src, NET_IPV4_HDR(pkt)->dst); + net_ipv4_addr_copy_raw(NET_IPV4_HDR(cloned)->dst, NET_IPV4_HDR(pkt)->src);
}

res = net_recv_data(net_pkt_iface(cloned), cloned);
Expand Down
17 changes: 17 additions & 0 deletions include/zephyr/net/net_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,22 @@
*/
uint16_t addr_preferences;
#endif
#if defined(CONFIG_NET_IPV6) || defined(CONFIG_NET_IPV4)
union {
/**
* IPv6 multicast output network interface for this context/socket.
* Only allowed for SOCK_DGRAM or SOCK_RAW type sockets.
*/
uint8_t ipv6_mcast_ifindex;

/**
* IPv4 multicast output network interface for this context/socket.
* Only allowed for SOCK_DGRAM type sockets.
*/
uint8_t ipv4_mcast_ifindex;
};
#endif /* CONFIG_NET_IPV6 || CONFIG_NET_IPV4 */

#if defined(CONFIG_NET_CONTEXT_TIMESTAMPING)
/** Enable RX, TX or both timestamps of packets send through sockets. */
uint8_t timestamping;
Expand Down Expand Up @@ -1292,7 +1308,8 @@
NET_OPT_TTL = 16, /**< IPv4 unicast TTL */
NET_OPT_ADDR_PREFERENCES = 17, /**< IPv6 address preference */
NET_OPT_TIMESTAMPING = 18, /**< Packet timestamping */
NET_OPT_MCAST_IFINDEX = 19, /**< IPv6 multicast output network interface index */
NET_OPT_MTU = 20, /**< IPv4 socket path MTU */

Check notice on line 1312 in include/zephyr/net/net_context.h

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

include/zephyr/net/net_context.h:1312 - NET_OPT_MCAST_IFINDEX = 19, /**< IPv6 multicast output network interface index */ + NET_OPT_MCAST_IFINDEX = 19, /**< IPv6 multicast output network interface index */
};

/**
Expand Down
13 changes: 13 additions & 0 deletions include/zephyr/net/socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -1196,7 +1196,9 @@
*/
#define IP_MTU 14

/** Set IPv4 multicast datagram network interface. */
#define IP_MULTICAST_IF 32
/** Set IPv4 multicast TTL value. */

Check notice on line 1201 in include/zephyr/net/socket.h

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

include/zephyr/net/socket.h:1201 -#define IP_MULTICAST_IF 32 +#define IP_MULTICAST_IF 32
#define IP_MULTICAST_TTL 33
/** Join IPv4 multicast group. */
#define IP_ADD_MEMBERSHIP 35
Expand All @@ -1212,6 +1214,14 @@
int imr_ifindex; /**< Network interface index */
};

/**
* @brief Struct used when setting a IPv4 multicast network interface.
*/
struct ip_mreq {
struct in_addr imr_multiaddr; /**< IP multicast group address */
struct in_addr imr_interface; /**< IP address of local interface */
};

Check notice on line 1223 in include/zephyr/net/socket.h

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

include/zephyr/net/socket.h:1223 -struct ip_mreq { - struct in_addr imr_multiaddr; /**< IP multicast group address */ - struct in_addr imr_interface; /**< IP address of local interface */ +struct ip_mreq { + struct in_addr imr_multiaddr; /**< IP multicast group address */ + struct in_addr imr_interface; /**< IP address of local interface */

/** @} */

/**
Expand All @@ -1222,6 +1232,9 @@
/** Set the unicast hop limit for the socket. */
#define IPV6_UNICAST_HOPS 16

/** Set multicast output network interface index for the socket. */
#define IPV6_MULTICAST_IF 17

Check notice on line 1237 in include/zephyr/net/socket.h

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

include/zephyr/net/socket.h:1237 -#define IPV6_MULTICAST_IF 17 +#define IPV6_MULTICAST_IF 17
/** Set the multicast hop limit for the socket. */
#define IPV6_MULTICAST_HOPS 18

Expand Down
201 changes: 190 additions & 11 deletions subsys/net/ip/net_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,17 @@
if (net_ipv6_is_addr_mcast(&addr6->sin6_addr)) {
struct net_if_mcast_addr *maddr;

if (IS_ENABLED(CONFIG_NET_UDP) &&
net_context_get_type(context) == SOCK_DGRAM) {
if (COND_CODE_1(CONFIG_NET_IPV6,
(context->options.ipv6_mcast_ifindex > 0),
(false))) {
IF_ENABLED(CONFIG_NET_IPV6,
(iface = net_if_get_by_index(
context->options.ipv6_mcast_ifindex)));
}
}

maddr = net_if_ipv6_maddr_lookup(&addr6->sin6_addr,
&iface);
if (!maddr) {
Expand Down Expand Up @@ -869,6 +880,17 @@
if (net_ipv4_is_addr_mcast(&addr4->sin_addr)) {
struct net_if_mcast_addr *maddr;

if (IS_ENABLED(CONFIG_NET_UDP) &&
net_context_get_type(context) == SOCK_DGRAM) {
if (COND_CODE_1(CONFIG_NET_IPV4,
(context->options.ipv4_mcast_ifindex > 0),
(false))) {
IF_ENABLED(CONFIG_NET_IPV4,
(iface = net_if_get_by_index(
context->options.ipv4_mcast_ifindex)));
}
}

maddr = net_if_ipv4_maddr_lookup(&addr4->sin_addr,
&iface);
if (!maddr) {
Expand Down Expand Up @@ -1302,7 +1324,13 @@
goto unlock;
}

/* FIXME - Add multicast and broadcast address check */
if (net_context_get_proto(context) == IPPROTO_TCP &&
(net_ipv4_is_addr_mcast(&addr4->sin_addr) ||
net_ipv4_is_addr_bcast(net_context_get_iface(context),
&addr4->sin_addr))) {
ret = -EADDRNOTAVAIL;

Check notice on line 1331 in subsys/net/ip/net_context.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

subsys/net/ip/net_context.c:1331 - net_ipv4_is_addr_bcast(net_context_get_iface(context), - &addr4->sin_addr))) { + net_ipv4_is_addr_bcast(net_context_get_iface(context), &addr4->sin_addr))) {
goto unlock;
}

memcpy(&addr4->sin_addr, &net_sin(addr)->sin_addr,
sizeof(struct in_addr));
Expand Down Expand Up @@ -1830,6 +1858,64 @@
return 0;
}

static int get_context_mcast_ifindex(struct net_context *context,
void *value, size_t *len)
{

Check notice on line 1863 in subsys/net/ip/net_context.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

subsys/net/ip/net_context.c:1863 -static int get_context_mcast_ifindex(struct net_context *context, - void *value, size_t *len) +static int get_context_mcast_ifindex(struct net_context *context, void *value, size_t *len)
#if defined(CONFIG_NET_IPV6) || defined(CONFIG_NET_IPV4)
sa_family_t family = net_context_get_family(context);

if ((IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) ||
(IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET)) {
/* If user has not set the ifindex, then get the interface
* that this socket is bound to.
*/
if (context->options.ipv6_mcast_ifindex == 0) {
struct net_if *iface;
int ifindex;

if (net_context_is_bound_to_iface(context)) {
iface = net_context_get_iface(context);
} else {
iface = net_if_get_default();
}

if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) {
if (!net_if_flag_is_set(iface, NET_IF_IPV6)) {
return -EPROTOTYPE;
}
} else if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) {
if (!net_if_flag_is_set(iface, NET_IF_IPV4)) {
return -EPROTOTYPE;
}
}

ifindex = net_if_get_by_iface(iface);
if (ifindex < 1) {
return -ENOENT;
}

*((int *)value) = ifindex;
} else {
*((int *)value) = context->options.ipv6_mcast_ifindex;
}

if (len) {
*len = sizeof(int);
}

return 0;
}

return -EAFNOSUPPORT;
#else
ARG_UNUSED(context);
ARG_UNUSED(value);
ARG_UNUSED(len);

return -ENOTSUP;
#endif
}

/* If buf is not NULL, then use it. Otherwise read the data to be written
* to net_pkt from msghdr.
*/
Expand Down Expand Up @@ -2007,7 +2093,7 @@
bool sendto)
{
const struct msghdr *msghdr = NULL;
struct net_if *iface;
struct net_if *iface = NULL;
struct net_pkt *pkt = NULL;
sa_family_t family;
size_t tmp_len;
Expand Down Expand Up @@ -2067,18 +2153,31 @@
return -EDESTADDRREQ;
}

if (IS_ENABLED(CONFIG_NET_UDP) &&
net_context_get_type(context) == SOCK_DGRAM) {
if (net_ipv6_is_addr_mcast(&addr6->sin6_addr) &&

Check notice on line 2158 in subsys/net/ip/net_context.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

subsys/net/ip/net_context.c:2158 - if (IS_ENABLED(CONFIG_NET_UDP) && - net_context_get_type(context) == SOCK_DGRAM) { + if (IS_ENABLED(CONFIG_NET_UDP) && net_context_get_type(context) == SOCK_DGRAM) {
COND_CODE_1(CONFIG_NET_IPV6,
(context->options.ipv6_mcast_ifindex > 0), (false))) {
IF_ENABLED(CONFIG_NET_IPV6,
(iface = net_if_get_by_index(
context->options.ipv6_mcast_ifindex)));
}
}

/* If application has not yet set the destination address
* i.e., by not calling connect(), then set the interface
* here so that the packet gets sent to the correct network
* interface. This issue can be seen if there are multiple
* network interfaces and we are trying to send data to
* second or later network interface.
*/
if (net_ipv6_is_addr_unspecified(
&net_sin6(&context->remote)->sin6_addr) &&
!net_context_is_bound_to_iface(context)) {
iface = net_if_ipv6_select_src_iface(&addr6->sin6_addr);
net_context_set_iface(context, iface);
if (iface == NULL) {
if (net_ipv6_is_addr_unspecified(
&net_sin6(&context->remote)->sin6_addr) &&
!net_context_is_bound_to_iface(context)) {

Check notice on line 2177 in subsys/net/ip/net_context.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

subsys/net/ip/net_context.c:2177 - if (net_ipv6_is_addr_unspecified( - &net_sin6(&context->remote)->sin6_addr) && + if (net_ipv6_is_addr_unspecified(&net_sin6(&context->remote)->sin6_addr) &&
iface = net_if_ipv6_select_src_iface(&addr6->sin6_addr);
net_context_set_iface(context, iface);
}
}

} else if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) {
Expand Down Expand Up @@ -2120,17 +2219,30 @@
return -EDESTADDRREQ;
}

if (IS_ENABLED(CONFIG_NET_UDP) &&
net_context_get_type(context) == SOCK_DGRAM) {
if (net_ipv4_is_addr_mcast(&addr4->sin_addr) &&

Check notice on line 2224 in subsys/net/ip/net_context.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

subsys/net/ip/net_context.c:2224 - if (IS_ENABLED(CONFIG_NET_UDP) && - net_context_get_type(context) == SOCK_DGRAM) { + if (IS_ENABLED(CONFIG_NET_UDP) && net_context_get_type(context) == SOCK_DGRAM) {
COND_CODE_1(CONFIG_NET_IPV4,
(context->options.ipv4_mcast_ifindex > 0), (false))) {
IF_ENABLED(CONFIG_NET_IPV4,
(iface = net_if_get_by_index(
context->options.ipv4_mcast_ifindex)));
}
}

/* If application has not yet set the destination address
* i.e., by not calling connect(), then set the interface
* here so that the packet gets sent to the correct network
* interface. This issue can be seen if there are multiple
* network interfaces and we are trying to send data to
* second or later network interface.
*/
if (net_sin(&context->remote)->sin_addr.s_addr == 0U &&
!net_context_is_bound_to_iface(context)) {
iface = net_if_ipv4_select_src_iface(&addr4->sin_addr);
net_context_set_iface(context, iface);
if (iface == NULL) {
if (net_sin(&context->remote)->sin_addr.s_addr == 0U &&
!net_context_is_bound_to_iface(context)) {
iface = net_if_ipv4_select_src_iface(&addr4->sin_addr);
net_context_set_iface(context, iface);
}
}

} else if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) && family == AF_PACKET) {
Expand Down Expand Up @@ -3211,6 +3323,67 @@
#endif
}

static int set_context_mcast_ifindex(struct net_context *context,
const void *value, size_t len)
{
#if defined(CONFIG_NET_IPV6) || defined(CONFIG_NET_IPV4)
sa_family_t family = net_context_get_family(context);
int mcast_ifindex = *((int *)value);
enum net_sock_type type;
struct net_if *iface;

if ((IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) ||
(IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET)) {

if (len != sizeof(int)) {
return -EINVAL;
}

type = net_context_get_type(context);
if (type != SOCK_DGRAM) {
return -EINVAL;
}

/* optlen equal to 0 then remove the binding */
if (mcast_ifindex == 0) {
context->options.ipv6_mcast_ifindex = 0;
return 0;
}

if (mcast_ifindex < 1 || mcast_ifindex > 255) {
return -EINVAL;
}

iface = net_if_get_by_index(mcast_ifindex);
if (iface == NULL) {
return -ENOENT;
}

if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) {
if (!net_if_flag_is_set(iface, NET_IF_IPV6)) {
return -EPROTOTYPE;
}
} else if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) {
if (!net_if_flag_is_set(iface, NET_IF_IPV4)) {
return -EPROTOTYPE;
}
}

context->options.ipv6_mcast_ifindex = mcast_ifindex;

return 0;
}

return -EAFNOSUPPORT;
#else
ARG_UNUSED(context);
ARG_UNUSED(value);
ARG_UNUSED(len);

return -ENOTSUP;
#endif
}

int net_context_set_option(struct net_context *context,
enum net_context_option option,
const void *value, size_t len)
Expand Down Expand Up @@ -3290,6 +3463,9 @@
ret = set_context_ipv6_mtu(context, value, len);
}

break;
case NET_OPT_MCAST_IFINDEX:
ret = set_context_mcast_ifindex(context, value, len);
break;
}

Expand Down Expand Up @@ -3370,6 +3546,9 @@
case NET_OPT_MTU:
ret = get_context_mtu(context, value, len);
break;
case NET_OPT_MCAST_IFINDEX:
ret = get_context_mcast_ifindex(context, value, len);
break;
}

k_mutex_unlock(&context->lock);
Expand Down
Loading
Loading