tests: net: socket: udp: Add IP_MULTICAST_IF set/get testing

Add tests that verify that IP_MULTICAST_IF socket option
set/get works as expected.

Signed-off-by: Jukka Rissanen <jukka.rissanen@nordicsemi.no>
This commit is contained in:
Jukka Rissanen 2024-11-15 17:05:07 +02:00 committed by Anas Nashif
commit 624f28cb65

View file

@ -949,6 +949,7 @@ static struct in6_addr my_addr3 = { { { 0x20, 0x01, 0x0d, 0xb8, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0x3 } } };
static struct in6_addr my_mcast_addr1 = { { { 0xff, 0x01, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0x1 } } };
static struct in_addr my_mcast_addr2 = { { { 224, 0, 0, 2 } } };
static uint8_t server_lladdr[] = { 0x01, 0x02, 0x03, 0xff, 0xfe,
0x04, 0x05, 0x06 };
static struct net_linkaddr server_link_addr = {
@ -2671,6 +2672,259 @@ ZTEST(net_socket_udp, test_38_ipv6_multicast_ifindex)
loopback_enable_address_swap(true);
}
ZTEST(net_socket_udp, test_39_ipv4_multicast_ifindex)
{
struct sockaddr_in saddr4 = {
.sin_family = AF_INET,
.sin_port = htons(SERVER_PORT),
.sin_addr = my_mcast_addr2,
};
struct sockaddr_in dst_addr = {
.sin_family = AF_INET,
.sin_port = htons(SERVER_PORT),
.sin_addr = my_mcast_addr2,
};
struct net_if_mcast_addr *ifmaddr;
struct net_if_addr *ifaddr;
struct in_addr addr = { 0 };
struct ip_mreqn mreqn;
struct ip_mreq mreq;
struct net_if *iface;
int server_sock;
size_t addrlen;
size_t optlen;
int ifindex;
int sock;
int ret;
int err;
net_if_foreach(iface_cb, &eth_iface);
zassert_not_null(eth_iface, "No ethernet interface found");
ifmaddr = net_if_ipv4_maddr_add(eth_iface, &my_mcast_addr2);
if (!ifmaddr) {
DBG("Cannot add IPv4 multicast address %s\n",
net_sprint_ipv4_addr(&my_mcast_addr2));
zassert_not_null(ifmaddr, "mcast_addr2");
}
ifaddr = net_if_ipv4_addr_add(eth_iface, &my_addr2,
NET_ADDR_MANUAL, 0);
if (!ifaddr) {
DBG("Cannot add IPv4 address %s\n",
net_sprint_ipv4_addr(&my_addr2));
zassert_not_null(ifaddr, "addr2");
}
net_if_up(eth_iface);
/* Check that we get the default interface */
sock = zsock_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
zassert_true(sock >= 0, "Cannot create socket (%d)", -errno);
optlen = sizeof(addr);
ret = zsock_getsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF,
&addr, &optlen);
zexpect_equal(ret, 0, "setsockopt failed (%d)", errno);
zexpect_equal(optlen, sizeof(addr), "invalid optlen %d vs %d",
optlen, sizeof(addr));
ifindex = net_if_get_by_iface(net_if_get_default());
ret = net_if_ipv4_addr_lookup_by_index(&addr);
zexpect_equal(ret, ifindex,
"getsockopt multicast ifindex (expected %d got %d)",
ifindex, ret);
ret = zsock_close(sock);
zassert_equal(sock, 0, "Cannot close socket (%d)", -errno);
/* Check failure for IPv6 socket */
sock = zsock_socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
zassert_true(sock >= 0, "Cannot create socket (%d)", -errno);
optlen = 0U;
ret = zsock_getsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF,
&addr, &optlen);
err = -errno;
zexpect_equal(ret, -1, "setsockopt failed (%d)", errno);
zexpect_equal(err, -EAFNOSUPPORT, "setsockopt failed (%d)", errno);
zexpect_equal(optlen, 0U, "setsockopt optlen (%d)", optlen);
ret = zsock_close(sock);
zassert_equal(sock, 0, "Cannot close socket (%d)", -errno);
/* Check that we can set the interface */
sock = zsock_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
zassert_true(sock >= 0, "Cannot create socket (%d)", -errno);
/* Clear any existing interface value by setting it to 0 */
optlen = sizeof(mreqn);
mreqn.imr_ifindex = 0;
mreqn.imr_address.s_addr = 0;
ret = zsock_setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF,
&mreqn, optlen);
err = -errno;
zexpect_equal(ret, 0, "setsockopt failed (%d)", err);
/* Verify that we get the empty value */
optlen = sizeof(addr);
ret = zsock_getsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF,
&addr, &optlen);
err = -errno;
zexpect_equal(ret, 0, "setsockopt failed (%d)", err);
zexpect_equal(optlen, sizeof(addr), "setsockopt optlen (%d)", optlen);
/* Set the output multicast packet interface to the default interface */
optlen = sizeof(mreqn);
mreqn.imr_ifindex = net_if_get_by_iface(net_if_get_default());
mreqn.imr_address.s_addr = 0;
ret = zsock_setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF,
&mreqn, optlen);
err = -errno;
zexpect_equal(ret, 0, "setsockopt failed (%d)", err);
/* Verify that we get the default interface */
optlen = sizeof(addr);
memset(&addr, 0, sizeof(addr));
ret = zsock_getsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF,
&addr, &optlen);
err = -errno;
zexpect_equal(ret, 0, "setsockopt failed (%d)", err);
zexpect_equal(optlen, sizeof(addr), "setsockopt optlen (%d)", optlen);
ifaddr = net_if_ipv4_addr_lookup(&addr, &iface);
zexpect_not_null(ifaddr, "Address %s not found",
net_sprint_ipv4_addr(&addr));
zexpect_equal(net_if_get_by_iface(iface),
net_if_get_by_iface(net_if_get_default()),
"Invalid interface %d vs %d",
net_if_get_by_iface(iface),
net_if_get_by_iface(net_if_get_default()));
/* Now send a packet and verify that it is sent via the default
* interface instead of the Ethernet interface.
*/
server_sock = prepare_listen_sock_udp_v4(&saddr4);
zassert_not_equal(server_sock, -1, "Cannot create server socket (%d)", -errno);
test_started = true;
loopback_enable_address_swap(false);
ret = zsock_sendto(sock, TEST_STR_SMALL, sizeof(TEST_STR_SMALL) - 1, 0,
(struct sockaddr *)&dst_addr, sizeof(dst_addr));
zexpect_equal(ret, STRLEN(TEST_STR_SMALL),
"invalid send len (was %d expected %d) (%d)",
ret, STRLEN(TEST_STR_SMALL), -errno);
/* Test that the sent data is received from Ethernet interface. */
addrlen = sizeof(saddr4);
ret = zsock_recvfrom(server_sock, rx_buf, sizeof(rx_buf),
0, (struct sockaddr *)&saddr4, &addrlen);
zexpect_true(ret >= 0, "recvfrom fail");
zexpect_equal(ret, strlen(TEST_STR_SMALL),
"unexpected received bytes");
zexpect_mem_equal(rx_buf, TEST_STR_SMALL, sizeof(TEST_STR_SMALL) - 1,
"wrong data");
/* Clear the old interface value by setting it to 0 */
optlen = sizeof(mreqn);
mreqn.imr_ifindex = 0;
mreqn.imr_address.s_addr = 0;
ret = zsock_setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF,
&mreqn, optlen);
err = -errno;
zexpect_equal(ret, 0, "setsockopt failed (%d)", err);
/* Then do it the other way around, set the address but leave the
* interface number unassigned.
*/
optlen = sizeof(mreqn);
mreqn.imr_ifindex = 0;
/* Get the address of default interface and set it as a target
* interface.
*/
ifaddr = net_if_ipv4_addr_get_first_by_index(net_if_get_by_iface(net_if_get_default()));
zexpect_not_null(ifaddr, "No address found for interface %d",
net_if_get_by_iface(net_if_get_default()));
mreqn.imr_address.s_addr = ifaddr->address.in_addr.s_addr;
ret = zsock_setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF,
&mreqn, optlen);
zexpect_equal(ret, 0, "setsockopt failed (%d)", errno);
/* Verify that we get the default interface address */
optlen = sizeof(struct in_addr);
ret = zsock_getsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF,
&addr, &optlen);
err = -errno;
zexpect_equal(ret, 0, "setsockopt failed (%d)", err);
zexpect_equal(optlen, sizeof(struct in_addr), "setsockopt optlen (%d)", optlen);
ret = net_if_ipv4_addr_lookup_by_index(&addr);
zexpect_equal(ret, net_if_get_by_iface(net_if_get_default()),
"getsockopt multicast ifindex (expected %d got %d)",
net_if_get_by_iface(net_if_get_default()), ret);
zexpect_equal(ifaddr->address.in_addr.s_addr,
addr.s_addr,
"getsockopt iface address mismatch (expected %s got %s)",
net_sprint_ipv4_addr(&ifaddr->address.in_addr),
net_sprint_ipv4_addr(&addr));
ret = zsock_sendto(sock, TEST_STR_SMALL, sizeof(TEST_STR_SMALL) - 1, 0,
(struct sockaddr *)&dst_addr, sizeof(dst_addr));
zexpect_equal(ret, STRLEN(TEST_STR_SMALL),
"invalid send len (was %d expected %d) (%d)",
ret, STRLEN(TEST_STR_SMALL), -errno);
/* Test that the sent data is received from default interface. */
addrlen = sizeof(saddr4);
ret = zsock_recvfrom(server_sock, rx_buf, sizeof(rx_buf),
0, (struct sockaddr *)&saddr4, &addrlen);
zexpect_true(ret >= 0, "recvfrom fail");
zexpect_equal(ret, strlen(TEST_STR_SMALL),
"unexpected received bytes");
zexpect_mem_equal(rx_buf, TEST_STR_SMALL, sizeof(TEST_STR_SMALL) - 1,
"wrong data");
/* Then use mreq structure to set the interface */
optlen = sizeof(mreq);
ifaddr = net_if_ipv4_addr_get_first_by_index(net_if_get_by_iface(net_if_get_default()));
zexpect_not_null(ifaddr, "No address found for interface %d",
net_if_get_by_iface(net_if_get_default()));
mreq.imr_interface.s_addr = ifaddr->address.in_addr.s_addr;
ret = zsock_setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF,
&mreq, optlen);
zexpect_equal(ret, 0, "setsockopt failed (%d)", errno);
ret = zsock_sendto(sock, TEST_STR_SMALL, sizeof(TEST_STR_SMALL) - 1, 0,
(struct sockaddr *)&dst_addr, sizeof(dst_addr));
zexpect_equal(ret, STRLEN(TEST_STR_SMALL),
"invalid send len (was %d expected %d) (%d)",
ret, STRLEN(TEST_STR_SMALL), -errno);
/* Test that the sent data is received from default interface. */
addrlen = sizeof(saddr4);
ret = zsock_recvfrom(server_sock, rx_buf, sizeof(rx_buf),
0, (struct sockaddr *)&saddr4, &addrlen);
zexpect_true(ret >= 0, "recvfrom fail");
zexpect_equal(ret, strlen(TEST_STR_SMALL),
"unexpected received bytes");
zexpect_mem_equal(rx_buf, TEST_STR_SMALL, sizeof(TEST_STR_SMALL) - 1,
"wrong data");
ret = zsock_close(sock);
zassert_equal(ret, 0, "Cannot close socket (%d)", -errno);
ret = zsock_close(server_sock);
zassert_equal(ret, 0, "Cannot close socket (%d)", -errno);
test_started = false;
loopback_enable_address_swap(true);
}
static void after(void *arg)
{
ARG_UNUSED(arg);