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:
parent
d3bac7047d
commit
624f28cb65
1 changed files with 254 additions and 0 deletions
|
@ -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, ð_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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue