| /* |
| * Copyright (c) 2017 Linaro Limited |
| * Copyright (c) 2021 Nordic Semiconductor |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/logging/log.h> |
| LOG_MODULE_REGISTER(net_test, CONFIG_NET_SOCKETS_LOG_LEVEL); |
| |
| #include <stdio.h> |
| #include <zephyr/sys/mutex.h> |
| #include <zephyr/ztest_assert.h> |
| |
| #include <zephyr/net/socket.h> |
| #include <zephyr/net/ethernet.h> |
| #include <zephyr/net/net_mgmt.h> |
| #include <zephyr/net/net_event.h> |
| |
| #include "ipv6.h" |
| #include "net_private.h" |
| #include "../../socket_helpers.h" |
| |
| #if defined(CONFIG_NET_SOCKETS_LOG_LEVEL_DBG) |
| #define DBG(fmt, ...) printk(fmt, ##__VA_ARGS__) |
| #else |
| #define DBG(fmt, ...) |
| #endif |
| |
| #define BUF_AND_SIZE(buf) buf, sizeof(buf) - 1 |
| #define STRLEN(buf) (sizeof(buf) - 1) |
| |
| #define TEST_STR_SMALL "test" |
| /* More than 256 bytes, to use >1 net_buf. */ |
| #define TEST_STR2 \ |
| "The Zephyr Project, a Linux Foundation hosted Collaboration " \ |
| "Project, is an open source collaborative effort uniting leaders " \ |
| "from across the industry to build a best-in-breed small, scalable, " \ |
| "real-time operating system (RTOS) optimized for resource-" \ |
| "constrained devices, across multiple architectures." |
| /* More than available TX buffers */ |
| static const char test_str_all_tx_bufs[] = |
| #include <string_all_tx_bufs.inc> |
| "!" |
| ; |
| |
| #define MY_IPV4_ADDR "127.0.0.1" |
| #define MY_IPV6_ADDR "::1" |
| #define MY_MCAST_IPV4_ADDR "224.0.0.1" |
| #define MY_MCAST_IPV6_ADDR "ff00::1" |
| |
| #define ANY_PORT 0 |
| #define SERVER_PORT 4242 |
| #define CLIENT_PORT 9898 |
| |
| static ZTEST_BMEM char rx_buf[NET_ETH_MTU + 1]; |
| |
| /* Common routine to communicate packets over pair of sockets. */ |
| static void comm_sendto_recvfrom(int client_sock, |
| struct sockaddr *client_addr, |
| socklen_t client_addrlen, |
| int server_sock, |
| struct sockaddr *server_addr, |
| socklen_t server_addrlen) |
| { |
| int avail; |
| ssize_t sent = 0; |
| ssize_t recved = 0; |
| struct sockaddr addr; |
| socklen_t addrlen; |
| struct sockaddr addr2; |
| socklen_t addrlen2; |
| |
| zassert_not_null(client_addr, "null client addr"); |
| zassert_not_null(server_addr, "null server addr"); |
| |
| /* |
| * Test client -> server sending |
| */ |
| |
| sent = zsock_sendto(client_sock, TEST_STR_SMALL, strlen(TEST_STR_SMALL), |
| 0, server_addr, server_addrlen); |
| zassert_equal(sent, strlen(TEST_STR_SMALL), "sendto failed"); |
| |
| k_msleep(100); |
| |
| avail = 42; |
| zassert_ok(zsock_ioctl(server_sock, ZFD_IOCTL_FIONREAD, &avail)); |
| zassert_equal(avail, strlen(TEST_STR_SMALL)); |
| |
| /* Test recvfrom(MSG_PEEK) */ |
| addrlen = sizeof(addr); |
| clear_buf(rx_buf); |
| recved = zsock_recvfrom(server_sock, rx_buf, sizeof(rx_buf), |
| ZSOCK_MSG_PEEK, &addr, &addrlen); |
| zassert_true(recved >= 0, "recvfrom fail"); |
| zassert_equal(recved, strlen(TEST_STR_SMALL), |
| "unexpected received bytes"); |
| zassert_mem_equal(rx_buf, BUF_AND_SIZE(TEST_STR_SMALL), "wrong data"); |
| zassert_equal(addrlen, client_addrlen, "unexpected addrlen"); |
| |
| /* Test normal recvfrom() */ |
| addrlen = sizeof(addr); |
| clear_buf(rx_buf); |
| recved = zsock_recvfrom(server_sock, rx_buf, sizeof(rx_buf), |
| 0, &addr, &addrlen); |
| zassert_true(recved >= 0, "recvfrom fail"); |
| zassert_equal(recved, strlen(TEST_STR_SMALL), |
| "unexpected received bytes"); |
| zassert_mem_equal(rx_buf, BUF_AND_SIZE(TEST_STR_SMALL), "wrong data"); |
| zassert_equal(addrlen, client_addrlen, "unexpected addrlen"); |
| |
| /* Check the client port */ |
| if (net_sin(client_addr)->sin_port != ANY_PORT) { |
| zassert_equal(net_sin(client_addr)->sin_port, |
| net_sin(&addr)->sin_port, |
| "unexpected client port"); |
| } |
| |
| /* |
| * Test server -> client sending |
| */ |
| |
| sent = zsock_sendto(server_sock, BUF_AND_SIZE(TEST_STR2), |
| 0, &addr, addrlen); |
| zassert_equal(sent, STRLEN(TEST_STR2), "sendto failed"); |
| |
| /* Test normal recvfrom() */ |
| addrlen2 = sizeof(addr); |
| clear_buf(rx_buf); |
| recved = zsock_recvfrom(client_sock, rx_buf, sizeof(rx_buf), |
| 0, &addr2, &addrlen2); |
| zassert_true(recved >= 0, "recvfrom fail"); |
| zassert_equal(recved, STRLEN(TEST_STR2), |
| "unexpected received bytes"); |
| zassert_mem_equal(rx_buf, BUF_AND_SIZE(TEST_STR2), "wrong data"); |
| zassert_equal(addrlen2, server_addrlen, "unexpected addrlen"); |
| |
| /* Check the server port */ |
| zassert_equal(net_sin(server_addr)->sin_port, |
| net_sin(&addr2)->sin_port, |
| "unexpected server port"); |
| |
| /* Test that unleft leftover data from datagram is discarded. */ |
| |
| /* Send 2 datagrams */ |
| sent = zsock_sendto(server_sock, BUF_AND_SIZE(TEST_STR2), |
| 0, &addr, addrlen); |
| zassert_equal(sent, STRLEN(TEST_STR2), "sendto failed"); |
| sent = zsock_sendto(server_sock, BUF_AND_SIZE(TEST_STR_SMALL), |
| 0, &addr, addrlen); |
| zassert_equal(sent, STRLEN(TEST_STR_SMALL), "sendto failed"); |
| |
| /* Receive just beginning of 1st datagram */ |
| addrlen2 = sizeof(addr); |
| clear_buf(rx_buf); |
| recved = zsock_recvfrom(client_sock, rx_buf, 16, 0, &addr2, &addrlen2); |
| zassert_true(recved == 16, "recvfrom fail"); |
| zassert_mem_equal(rx_buf, TEST_STR2, 16, "wrong data"); |
| |
| /* Make sure that now we receive 2nd datagram */ |
| addrlen2 = sizeof(addr); |
| clear_buf(rx_buf); |
| recved = zsock_recvfrom(client_sock, rx_buf, 16, 0, &addr2, &addrlen2); |
| zassert_true(recved == STRLEN(TEST_STR_SMALL), "recvfrom fail"); |
| zassert_mem_equal(rx_buf, BUF_AND_SIZE(TEST_STR_SMALL), "wrong data"); |
| } |
| |
| ZTEST(net_socket_udp, test_02_v4_sendto_recvfrom) |
| { |
| int rv; |
| int client_sock; |
| int server_sock; |
| struct sockaddr_in client_addr; |
| struct sockaddr_in server_addr; |
| |
| prepare_sock_udp_v4(MY_IPV4_ADDR, ANY_PORT, &client_sock, &client_addr); |
| prepare_sock_udp_v4(MY_IPV4_ADDR, SERVER_PORT, &server_sock, &server_addr); |
| |
| rv = zsock_bind(server_sock, |
| (struct sockaddr *)&server_addr, |
| sizeof(server_addr)); |
| zassert_equal(rv, 0, "bind failed"); |
| |
| comm_sendto_recvfrom(client_sock, |
| (struct sockaddr *)&client_addr, |
| sizeof(client_addr), |
| server_sock, |
| (struct sockaddr *)&server_addr, |
| sizeof(server_addr)); |
| |
| rv = zsock_close(client_sock); |
| zassert_equal(rv, 0, "close failed"); |
| rv = zsock_close(server_sock); |
| zassert_equal(rv, 0, "close failed"); |
| } |
| |
| ZTEST(net_socket_udp, test_03_v6_sendto_recvfrom) |
| { |
| int rv; |
| int client_sock; |
| int server_sock; |
| struct sockaddr_in6 client_addr; |
| struct sockaddr_in6 server_addr; |
| |
| prepare_sock_udp_v6(MY_IPV6_ADDR, ANY_PORT, &client_sock, &client_addr); |
| prepare_sock_udp_v6(MY_IPV6_ADDR, SERVER_PORT, &server_sock, &server_addr); |
| |
| rv = zsock_bind(server_sock, |
| (struct sockaddr *)&server_addr, sizeof(server_addr)); |
| zassert_equal(rv, 0, "bind failed"); |
| |
| comm_sendto_recvfrom(client_sock, |
| (struct sockaddr *)&client_addr, |
| sizeof(client_addr), |
| server_sock, |
| (struct sockaddr *)&server_addr, |
| sizeof(server_addr)); |
| |
| rv = zsock_close(client_sock); |
| zassert_equal(rv, 0, "close failed"); |
| rv = zsock_close(server_sock); |
| zassert_equal(rv, 0, "close failed"); |
| } |
| |
| ZTEST(net_socket_udp, test_04_v4_bind_sendto) |
| { |
| int rv; |
| int client_sock; |
| int server_sock; |
| struct sockaddr_in client_addr; |
| struct sockaddr_in server_addr; |
| |
| prepare_sock_udp_v4(MY_IPV4_ADDR, CLIENT_PORT, &client_sock, &client_addr); |
| prepare_sock_udp_v4(MY_IPV4_ADDR, SERVER_PORT, &server_sock, &server_addr); |
| |
| rv = zsock_bind(client_sock, |
| (struct sockaddr *)&client_addr, sizeof(client_addr)); |
| zassert_equal(rv, 0, "bind failed"); |
| |
| rv = zsock_bind(server_sock, |
| (struct sockaddr *)&server_addr, sizeof(server_addr)); |
| zassert_equal(rv, 0, "bind failed"); |
| |
| comm_sendto_recvfrom(client_sock, |
| (struct sockaddr *)&client_addr, |
| sizeof(client_addr), |
| server_sock, |
| (struct sockaddr *)&server_addr, |
| sizeof(server_addr)); |
| |
| rv = zsock_close(client_sock); |
| zassert_equal(rv, 0, "close failed"); |
| rv = zsock_close(server_sock); |
| zassert_equal(rv, 0, "close failed"); |
| } |
| |
| ZTEST(net_socket_udp, test_05_v6_bind_sendto) |
| { |
| int rv; |
| int client_sock; |
| int server_sock; |
| struct sockaddr_in6 client_addr; |
| struct sockaddr_in6 server_addr; |
| |
| prepare_sock_udp_v6(MY_IPV6_ADDR, CLIENT_PORT, &client_sock, &client_addr); |
| prepare_sock_udp_v6(MY_IPV6_ADDR, SERVER_PORT, &server_sock, &server_addr); |
| |
| rv = zsock_bind(client_sock, |
| (struct sockaddr *)&client_addr, sizeof(client_addr)); |
| zassert_equal(rv, 0, "bind failed"); |
| |
| rv = zsock_bind(server_sock, |
| (struct sockaddr *)&server_addr, sizeof(server_addr)); |
| zassert_equal(rv, 0, "bind failed"); |
| |
| comm_sendto_recvfrom(client_sock, |
| (struct sockaddr *)&client_addr, |
| sizeof(client_addr), |
| server_sock, |
| (struct sockaddr *)&server_addr, |
| sizeof(server_addr)); |
| |
| rv = zsock_close(client_sock); |
| zassert_equal(rv, 0, "close failed"); |
| rv = zsock_close(server_sock); |
| zassert_equal(rv, 0, "close failed"); |
| } |
| |
| ZTEST(net_socket_udp, test_01_send_recv_2_sock) |
| { |
| int sock1, sock2; |
| struct sockaddr_in bind_addr, conn_addr; |
| char buf[10]; |
| int len, rv; |
| |
| prepare_sock_udp_v4(MY_IPV4_ADDR, 55555, &sock1, &bind_addr); |
| prepare_sock_udp_v4(MY_IPV4_ADDR, 55555, &sock2, &conn_addr); |
| |
| rv = zsock_bind(sock1, (struct sockaddr *)&bind_addr, sizeof(bind_addr)); |
| zassert_equal(rv, 0, "bind failed"); |
| |
| rv = zsock_connect(sock2, (struct sockaddr *)&conn_addr, sizeof(conn_addr)); |
| zassert_equal(rv, 0, "connect failed"); |
| |
| len = zsock_send(sock2, BUF_AND_SIZE(TEST_STR_SMALL), 0); |
| zassert_equal(len, STRLEN(TEST_STR_SMALL), "invalid send len"); |
| |
| clear_buf(buf); |
| len = zsock_recv(sock1, buf, sizeof(buf), ZSOCK_MSG_PEEK); |
| zassert_equal(len, STRLEN(TEST_STR_SMALL), "Invalid recv len"); |
| zassert_mem_equal(buf, BUF_AND_SIZE(TEST_STR_SMALL), "Wrong data"); |
| |
| clear_buf(buf); |
| len = zsock_recv(sock1, buf, sizeof(buf), 0); |
| zassert_equal(len, STRLEN(TEST_STR_SMALL), "Invalid recv len"); |
| zassert_mem_equal(buf, BUF_AND_SIZE(TEST_STR_SMALL), "Wrong data"); |
| |
| rv = zsock_close(sock1); |
| zassert_equal(rv, 0, "close failed"); |
| rv = zsock_close(sock2); |
| zassert_equal(rv, 0, "close failed"); |
| } |
| |
| ZTEST(net_socket_udp, test_07_so_priority) |
| { |
| struct sockaddr_in bind_addr4; |
| struct sockaddr_in6 bind_addr6; |
| int sock1, sock2, rv; |
| uint8_t optval; |
| |
| prepare_sock_udp_v4(MY_IPV4_ADDR, 55555, &sock1, &bind_addr4); |
| prepare_sock_udp_v6(MY_IPV6_ADDR, 55555, &sock2, &bind_addr6); |
| |
| rv = zsock_bind(sock1, (struct sockaddr *)&bind_addr4, sizeof(bind_addr4)); |
| zassert_equal(rv, 0, "bind failed"); |
| |
| rv = zsock_bind(sock2, (struct sockaddr *)&bind_addr6, sizeof(bind_addr6)); |
| zassert_equal(rv, 0, "bind failed"); |
| |
| optval = 2; |
| rv = zsock_setsockopt(sock1, SOL_SOCKET, SO_PRIORITY, &optval, |
| sizeof(optval)); |
| zassert_equal(rv, 0, "setsockopt failed (%d)", errno); |
| |
| optval = 8; |
| rv = zsock_setsockopt(sock2, SOL_SOCKET, SO_PRIORITY, &optval, |
| sizeof(optval)); |
| zassert_equal(rv, 0, "setsockopt failed"); |
| |
| rv = zsock_close(sock1); |
| zassert_equal(rv, 0, "close failed"); |
| rv = zsock_close(sock2); |
| zassert_equal(rv, 0, "close failed"); |
| } |
| |
| static void comm_sendmsg_recvfrom(int client_sock, |
| struct sockaddr *client_addr, |
| socklen_t client_addrlen, |
| const struct msghdr *client_msg, |
| int server_sock, |
| struct sockaddr *server_addr, |
| socklen_t server_addrlen) |
| { |
| ssize_t sent; |
| ssize_t recved; |
| struct sockaddr addr; |
| socklen_t addrlen; |
| int len, i; |
| |
| zassert_not_null(client_addr, "null client addr"); |
| zassert_not_null(server_addr, "null server addr"); |
| |
| /* |
| * Test client -> server sending |
| */ |
| |
| sent = zsock_sendmsg(client_sock, client_msg, 0); |
| zassert_true(sent > 0, "sendmsg failed (%d)", -errno); |
| |
| for (i = 0, len = 0; i < client_msg->msg_iovlen; i++) { |
| len += client_msg->msg_iov[i].iov_len; |
| } |
| |
| zassert_equal(sent, len, "iovec len (%d) vs sent (%d)", len, sent); |
| |
| /* Test recvfrom(MSG_PEEK) */ |
| addrlen = sizeof(addr); |
| clear_buf(rx_buf); |
| recved = zsock_recvfrom(server_sock, rx_buf, sizeof(rx_buf), |
| ZSOCK_MSG_PEEK, &addr, &addrlen); |
| zassert_true(recved >= 0, "recvfrom fail"); |
| zassert_equal(recved, strlen(TEST_STR_SMALL), |
| "unexpected received bytes"); |
| zassert_equal(sent, recved, "sent(%d)/received(%d) mismatch", |
| sent, recved); |
| |
| zassert_mem_equal(rx_buf, BUF_AND_SIZE(TEST_STR_SMALL), |
| "wrong data (%s)", rx_buf); |
| zassert_equal(addrlen, client_addrlen, "unexpected addrlen"); |
| |
| /* Test normal recvfrom() */ |
| addrlen = sizeof(addr); |
| clear_buf(rx_buf); |
| recved = zsock_recvfrom(server_sock, rx_buf, sizeof(rx_buf), |
| 0, &addr, &addrlen); |
| zassert_true(recved >= 0, "recvfrom fail"); |
| zassert_equal(recved, strlen(TEST_STR_SMALL), |
| "unexpected received bytes"); |
| zassert_mem_equal(rx_buf, BUF_AND_SIZE(TEST_STR_SMALL), "wrong data"); |
| zassert_equal(addrlen, client_addrlen, "unexpected addrlen"); |
| |
| /* Check the client port */ |
| if (net_sin(client_addr)->sin_port != ANY_PORT) { |
| zassert_equal(net_sin(client_addr)->sin_port, |
| net_sin(&addr)->sin_port, |
| "unexpected client port"); |
| } |
| } |
| |
| ZTEST_USER(net_socket_udp, test_12_v4_sendmsg_recvfrom) |
| { |
| int rv; |
| int client_sock; |
| int server_sock; |
| struct sockaddr_in client_addr; |
| struct sockaddr_in server_addr; |
| struct msghdr msg; |
| struct cmsghdr *cmsg; |
| struct iovec io_vector[1]; |
| union { |
| struct cmsghdr hdr; |
| unsigned char buf[CMSG_SPACE(sizeof(int))]; |
| } cmsgbuf; |
| |
| prepare_sock_udp_v4(MY_IPV4_ADDR, ANY_PORT, &client_sock, &client_addr); |
| prepare_sock_udp_v4(MY_IPV4_ADDR, SERVER_PORT, &server_sock, &server_addr); |
| |
| rv = zsock_bind(server_sock, |
| (struct sockaddr *)&server_addr, |
| sizeof(server_addr)); |
| zassert_equal(rv, 0, "server bind failed"); |
| |
| rv = zsock_bind(client_sock, |
| (struct sockaddr *)&client_addr, |
| sizeof(client_addr)); |
| zassert_equal(rv, 0, "client bind failed"); |
| |
| io_vector[0].iov_base = TEST_STR_SMALL; |
| io_vector[0].iov_len = strlen(TEST_STR_SMALL); |
| |
| memset(&msg, 0, sizeof(msg)); |
| msg.msg_control = &cmsgbuf.buf; |
| msg.msg_controllen = sizeof(cmsgbuf.buf); |
| msg.msg_iov = io_vector; |
| msg.msg_iovlen = 1; |
| msg.msg_name = &server_addr; |
| msg.msg_namelen = sizeof(server_addr); |
| |
| cmsg = CMSG_FIRSTHDR(&msg); |
| cmsg->cmsg_len = CMSG_LEN(sizeof(int)); |
| cmsg->cmsg_level = SOL_SOCKET; |
| cmsg->cmsg_type = 1122; |
| *(int *)CMSG_DATA(cmsg) = 42; |
| |
| comm_sendmsg_recvfrom(client_sock, |
| (struct sockaddr *)&client_addr, |
| sizeof(client_addr), |
| &msg, |
| server_sock, |
| (struct sockaddr *)&server_addr, |
| sizeof(server_addr)); |
| |
| rv = zsock_close(client_sock); |
| zassert_equal(rv, 0, "close failed"); |
| rv = zsock_close(server_sock); |
| zassert_equal(rv, 0, "close failed"); |
| } |
| |
| ZTEST_USER(net_socket_udp, test_13_v4_sendmsg_recvfrom_no_aux_data) |
| { |
| int rv; |
| int client_sock; |
| int server_sock; |
| struct sockaddr_in client_addr; |
| struct sockaddr_in server_addr; |
| struct msghdr msg; |
| struct iovec io_vector[1]; |
| |
| prepare_sock_udp_v4(MY_IPV4_ADDR, ANY_PORT, &client_sock, &client_addr); |
| prepare_sock_udp_v4(MY_IPV4_ADDR, SERVER_PORT, &server_sock, &server_addr); |
| |
| rv = zsock_bind(server_sock, |
| (struct sockaddr *)&server_addr, |
| sizeof(server_addr)); |
| zassert_equal(rv, 0, "server bind failed"); |
| |
| rv = zsock_bind(client_sock, |
| (struct sockaddr *)&client_addr, |
| sizeof(client_addr)); |
| zassert_equal(rv, 0, "client bind failed"); |
| |
| io_vector[0].iov_base = TEST_STR_SMALL; |
| io_vector[0].iov_len = strlen(TEST_STR_SMALL); |
| |
| memset(&msg, 0, sizeof(msg)); |
| msg.msg_iov = io_vector; |
| msg.msg_iovlen = 1; |
| msg.msg_name = &server_addr; |
| msg.msg_namelen = sizeof(server_addr); |
| |
| comm_sendmsg_recvfrom(client_sock, |
| (struct sockaddr *)&client_addr, |
| sizeof(client_addr), |
| &msg, |
| server_sock, |
| (struct sockaddr *)&server_addr, |
| sizeof(server_addr)); |
| |
| rv = zsock_close(client_sock); |
| zassert_equal(rv, 0, "close failed"); |
| rv = zsock_close(server_sock); |
| zassert_equal(rv, 0, "close failed"); |
| } |
| |
| ZTEST_USER(net_socket_udp, test_14_v6_sendmsg_recvfrom) |
| { |
| int rv; |
| int client_sock; |
| int server_sock; |
| struct sockaddr_in6 client_addr; |
| struct sockaddr_in6 server_addr; |
| struct msghdr msg; |
| struct cmsghdr *cmsg; |
| struct iovec io_vector[1]; |
| union { |
| struct cmsghdr hdr; |
| unsigned char buf[CMSG_SPACE(sizeof(int))]; |
| } cmsgbuf; |
| |
| prepare_sock_udp_v6(MY_IPV6_ADDR, ANY_PORT, &client_sock, &client_addr); |
| prepare_sock_udp_v6(MY_IPV6_ADDR, SERVER_PORT, &server_sock, &server_addr); |
| |
| rv = zsock_bind(server_sock, |
| (struct sockaddr *)&server_addr, sizeof(server_addr)); |
| zassert_equal(rv, 0, "server bind failed"); |
| |
| rv = zsock_bind(client_sock, |
| (struct sockaddr *)&client_addr, |
| sizeof(client_addr)); |
| zassert_equal(rv, 0, "client bind failed"); |
| |
| io_vector[0].iov_base = TEST_STR_SMALL; |
| io_vector[0].iov_len = strlen(TEST_STR_SMALL); |
| |
| memset(&msg, 0, sizeof(msg)); |
| msg.msg_control = &cmsgbuf.buf; |
| msg.msg_controllen = sizeof(cmsgbuf.buf); |
| msg.msg_iov = io_vector; |
| msg.msg_iovlen = 1; |
| msg.msg_name = &server_addr; |
| msg.msg_namelen = sizeof(server_addr); |
| |
| cmsg = CMSG_FIRSTHDR(&msg); |
| cmsg->cmsg_len = CMSG_LEN(sizeof(int)); |
| cmsg->cmsg_level = SOL_SOCKET; |
| cmsg->cmsg_type = 1122; |
| *(int *)CMSG_DATA(cmsg) = 42; |
| |
| comm_sendmsg_recvfrom(client_sock, |
| (struct sockaddr *)&client_addr, |
| sizeof(client_addr), |
| &msg, |
| server_sock, |
| (struct sockaddr *)&server_addr, |
| sizeof(server_addr)); |
| |
| rv = zsock_close(client_sock); |
| zassert_equal(rv, 0, "close failed"); |
| rv = zsock_close(server_sock); |
| zassert_equal(rv, 0, "close failed"); |
| } |
| |
| ZTEST_USER(net_socket_udp, test_15_v4_sendmsg_recvfrom_connected) |
| { |
| int rv; |
| int client_sock; |
| int server_sock; |
| struct sockaddr_in client_addr; |
| struct sockaddr_in server_addr; |
| struct msghdr msg; |
| struct cmsghdr *cmsg; |
| struct iovec io_vector[1]; |
| union { |
| struct cmsghdr hdr; |
| unsigned char buf[CMSG_SPACE(sizeof(int))]; |
| } cmsgbuf; |
| |
| prepare_sock_udp_v4(MY_IPV4_ADDR, ANY_PORT, &client_sock, &client_addr); |
| prepare_sock_udp_v4(MY_IPV4_ADDR, SERVER_PORT, &server_sock, &server_addr); |
| |
| rv = zsock_bind(server_sock, |
| (struct sockaddr *)&server_addr, |
| sizeof(server_addr)); |
| zassert_equal(rv, 0, "server bind failed"); |
| |
| rv = zsock_bind(client_sock, |
| (struct sockaddr *)&client_addr, |
| sizeof(client_addr)); |
| zassert_equal(rv, 0, "client bind failed"); |
| |
| rv = zsock_connect(client_sock, (struct sockaddr *)&server_addr, |
| sizeof(server_addr)); |
| zassert_equal(rv, 0, "connect failed"); |
| |
| io_vector[0].iov_base = TEST_STR_SMALL; |
| io_vector[0].iov_len = strlen(TEST_STR_SMALL); |
| |
| memset(&msg, 0, sizeof(msg)); |
| msg.msg_control = &cmsgbuf.buf; |
| msg.msg_controllen = sizeof(cmsgbuf.buf); |
| msg.msg_iov = io_vector; |
| msg.msg_iovlen = 1; |
| |
| cmsg = CMSG_FIRSTHDR(&msg); |
| cmsg->cmsg_len = CMSG_LEN(sizeof(int)); |
| cmsg->cmsg_level = SOL_SOCKET; |
| cmsg->cmsg_type = 1122; |
| *(int *)CMSG_DATA(cmsg) = 42; |
| |
| comm_sendmsg_recvfrom(client_sock, |
| (struct sockaddr *)&client_addr, |
| sizeof(client_addr), |
| &msg, |
| server_sock, |
| (struct sockaddr *)&server_addr, |
| sizeof(server_addr)); |
| |
| rv = zsock_close(client_sock); |
| zassert_equal(rv, 0, "close failed"); |
| rv = zsock_close(server_sock); |
| zassert_equal(rv, 0, "close failed"); |
| } |
| |
| ZTEST_USER(net_socket_udp, test_06_v6_sendmsg_recvfrom_connected) |
| { |
| int rv; |
| int client_sock; |
| int server_sock; |
| struct sockaddr_in6 client_addr; |
| struct sockaddr_in6 server_addr; |
| struct msghdr msg; |
| struct cmsghdr *cmsg; |
| struct iovec io_vector[1]; |
| union { |
| struct cmsghdr hdr; |
| unsigned char buf[CMSG_SPACE(sizeof(int))]; |
| } cmsgbuf; |
| |
| prepare_sock_udp_v6(MY_IPV6_ADDR, ANY_PORT, &client_sock, &client_addr); |
| prepare_sock_udp_v6(MY_IPV6_ADDR, SERVER_PORT, &server_sock, &server_addr); |
| |
| rv = zsock_bind(server_sock, |
| (struct sockaddr *)&server_addr, sizeof(server_addr)); |
| zassert_equal(rv, 0, "server bind failed"); |
| |
| rv = zsock_bind(client_sock, |
| (struct sockaddr *)&client_addr, |
| sizeof(client_addr)); |
| zassert_equal(rv, 0, "client bind failed"); |
| |
| rv = zsock_connect(client_sock, (struct sockaddr *)&server_addr, |
| sizeof(server_addr)); |
| zassert_equal(rv, 0, "connect failed"); |
| |
| io_vector[0].iov_base = TEST_STR_SMALL; |
| io_vector[0].iov_len = strlen(TEST_STR_SMALL); |
| |
| memset(&msg, 0, sizeof(msg)); |
| msg.msg_control = &cmsgbuf.buf; |
| msg.msg_controllen = sizeof(cmsgbuf.buf); |
| msg.msg_iov = io_vector; |
| msg.msg_iovlen = 1; |
| |
| cmsg = CMSG_FIRSTHDR(&msg); |
| cmsg->cmsg_len = CMSG_LEN(sizeof(int)); |
| cmsg->cmsg_level = SOL_SOCKET; |
| cmsg->cmsg_type = 1122; |
| *(int *)CMSG_DATA(cmsg) = 42; |
| |
| comm_sendmsg_recvfrom(client_sock, |
| (struct sockaddr *)&client_addr, |
| sizeof(client_addr), |
| &msg, |
| server_sock, |
| (struct sockaddr *)&server_addr, |
| sizeof(server_addr)); |
| |
| rv = zsock_close(client_sock); |
| zassert_equal(rv, 0, "close failed"); |
| rv = zsock_close(server_sock); |
| zassert_equal(rv, 0, "close failed"); |
| } |
| |
| ZTEST(net_socket_udp, test_06_so_type) |
| { |
| struct sockaddr_in bind_addr4; |
| struct sockaddr_in6 bind_addr6; |
| int sock1, sock2, rv; |
| int optval; |
| socklen_t optsize = sizeof(optval); |
| |
| prepare_sock_udp_v4(MY_IPV4_ADDR, 55555, &sock1, &bind_addr4); |
| prepare_sock_udp_v6(MY_IPV6_ADDR, 55555, &sock2, &bind_addr6); |
| |
| rv = zsock_getsockopt(sock1, SOL_SOCKET, SO_TYPE, &optval, &optsize); |
| zassert_equal(rv, 0, "getsockopt failed (%d)", errno); |
| zassert_equal(optval, SOCK_DGRAM, "getsockopt got invalid type"); |
| zassert_equal(optsize, sizeof(optval), "getsockopt got invalid size"); |
| |
| rv = zsock_getsockopt(sock2, SOL_SOCKET, SO_TYPE, &optval, &optsize); |
| zassert_equal(rv, 0, "getsockopt failed (%d)", errno); |
| zassert_equal(optval, SOCK_DGRAM, "getsockopt got invalid type"); |
| zassert_equal(optsize, sizeof(optval), "getsockopt got invalid size"); |
| |
| rv = zsock_close(sock1); |
| zassert_equal(rv, 0, "close failed"); |
| rv = zsock_close(sock2); |
| zassert_equal(rv, 0, "close failed"); |
| } |
| |
| ZTEST(net_socket_udp, test_08_so_txtime) |
| { |
| struct sockaddr_in bind_addr4; |
| struct sockaddr_in6 bind_addr6; |
| int sock1, sock2, rv; |
| socklen_t optlen; |
| int optval; |
| |
| prepare_sock_udp_v4(MY_IPV4_ADDR, 55555, &sock1, &bind_addr4); |
| prepare_sock_udp_v6(MY_IPV6_ADDR, 55555, &sock2, &bind_addr6); |
| |
| rv = zsock_bind(sock1, (struct sockaddr *)&bind_addr4, sizeof(bind_addr4)); |
| zassert_equal(rv, 0, "bind failed"); |
| |
| rv = zsock_bind(sock2, (struct sockaddr *)&bind_addr6, sizeof(bind_addr6)); |
| zassert_equal(rv, 0, "bind failed"); |
| |
| optval = true; |
| rv = zsock_setsockopt(sock1, SOL_SOCKET, SO_TXTIME, &optval, |
| sizeof(optval)); |
| zassert_equal(rv, 0, "setsockopt failed (%d)", errno); |
| |
| optval = false; |
| rv = zsock_setsockopt(sock2, SOL_SOCKET, SO_TXTIME, &optval, |
| sizeof(optval)); |
| zassert_equal(rv, 0, "setsockopt failed"); |
| |
| optlen = sizeof(optval); |
| rv = zsock_getsockopt(sock1, SOL_SOCKET, SO_TXTIME, &optval, &optlen); |
| zassert_equal(rv, 0, "getsockopt failed (%d)", errno); |
| zassert_equal(optlen, sizeof(optval), "invalid optlen %d vs %d", |
| optlen, sizeof(optval)); |
| zassert_equal(optval, true, "getsockopt txtime"); |
| |
| optlen = sizeof(optval); |
| rv = zsock_getsockopt(sock2, SOL_SOCKET, SO_TXTIME, &optval, &optlen); |
| zassert_equal(rv, 0, "getsockopt failed (%d)", errno); |
| zassert_equal(optlen, sizeof(optval), "invalid optlen %d vs %d", |
| optlen, sizeof(optval)); |
| zassert_equal(optval, false, "getsockopt txtime"); |
| |
| rv = zsock_close(sock1); |
| zassert_equal(rv, 0, "close failed"); |
| rv = zsock_close(sock2); |
| zassert_equal(rv, 0, "close failed"); |
| } |
| |
| ZTEST(net_socket_udp, test_09_so_rcvtimeo) |
| { |
| struct sockaddr_in bind_addr4; |
| struct sockaddr_in6 bind_addr6; |
| int sock1, sock2, rv; |
| ssize_t recved = 0; |
| struct sockaddr addr; |
| socklen_t addrlen; |
| uint32_t start_time, time_diff; |
| |
| struct timeval optval = { |
| .tv_sec = 0, |
| .tv_usec = 300000, |
| }; |
| |
| prepare_sock_udp_v4(MY_IPV4_ADDR, 55555, &sock1, &bind_addr4); |
| prepare_sock_udp_v6(MY_IPV6_ADDR, 55555, &sock2, &bind_addr6); |
| |
| rv = zsock_bind(sock1, (struct sockaddr *)&bind_addr4, sizeof(bind_addr4)); |
| zassert_equal(rv, 0, "bind failed"); |
| |
| rv = zsock_bind(sock2, (struct sockaddr *)&bind_addr6, sizeof(bind_addr6)); |
| zassert_equal(rv, 0, "bind failed"); |
| |
| rv = zsock_setsockopt(sock1, SOL_SOCKET, SO_RCVTIMEO, &optval, |
| sizeof(optval)); |
| zassert_equal(rv, 0, "setsockopt failed (%d)", errno); |
| |
| optval.tv_usec = 400000; |
| rv = zsock_setsockopt(sock2, SOL_SOCKET, SO_RCVTIMEO, &optval, |
| sizeof(optval)); |
| zassert_equal(rv, 0, "setsockopt failed (%d)", errno); |
| |
| addrlen = sizeof(addr); |
| clear_buf(rx_buf); |
| start_time = k_uptime_get_32(); |
| recved = zsock_recvfrom(sock1, rx_buf, sizeof(rx_buf), |
| 0, &addr, &addrlen); |
| time_diff = k_uptime_get_32() - start_time; |
| |
| zassert_equal(recved, -1, "Unexpected return code"); |
| zassert_equal(errno, EAGAIN, "Unexpected errno value: %d", errno); |
| zassert_true(time_diff >= 300, "Expected timeout after 300ms but " |
| "was %dms", time_diff); |
| |
| start_time = k_uptime_get_32(); |
| recved = zsock_recvfrom(sock2, rx_buf, sizeof(rx_buf), |
| 0, &addr, &addrlen); |
| time_diff = k_uptime_get_32() - start_time; |
| |
| zassert_equal(recved, -1, "Unexpected return code"); |
| zassert_equal(errno, EAGAIN, "Unexpected errno value: %d", errno); |
| zassert_true(time_diff >= 400, "Expected timeout after 400ms but " |
| "was %dms", time_diff); |
| |
| rv = zsock_close(sock1); |
| zassert_equal(rv, 0, "close failed"); |
| rv = zsock_close(sock2); |
| zassert_equal(rv, 0, "close failed"); |
| } |
| |
| ZTEST(net_socket_udp, test_10_so_sndtimeo) |
| { |
| struct sockaddr_in bind_addr4; |
| struct sockaddr_in6 bind_addr6; |
| int sock1, sock2, rv; |
| |
| struct timeval optval = { |
| .tv_sec = 2, |
| .tv_usec = 500000, |
| }; |
| |
| prepare_sock_udp_v4(MY_IPV4_ADDR, 55555, &sock1, &bind_addr4); |
| prepare_sock_udp_v6(MY_IPV6_ADDR, 55555, &sock2, &bind_addr6); |
| |
| rv = zsock_bind(sock1, (struct sockaddr *)&bind_addr4, sizeof(bind_addr4)); |
| zassert_equal(rv, 0, "bind failed"); |
| |
| rv = zsock_bind(sock2, (struct sockaddr *)&bind_addr6, sizeof(bind_addr6)); |
| zassert_equal(rv, 0, "bind failed"); |
| |
| rv = zsock_setsockopt(sock1, SOL_SOCKET, SO_SNDTIMEO, &optval, |
| sizeof(optval)); |
| zassert_equal(rv, 0, "setsockopt failed (%d)", errno); |
| |
| optval.tv_usec = 0; |
| rv = zsock_setsockopt(sock2, SOL_SOCKET, SO_SNDTIMEO, &optval, |
| sizeof(optval)); |
| zassert_equal(rv, 0, "setsockopt failed"); |
| |
| rv = zsock_close(sock1); |
| zassert_equal(rv, 0, "close failed"); |
| rv = zsock_close(sock2); |
| zassert_equal(rv, 0, "close failed"); |
| } |
| |
| ZTEST(net_socket_udp, test_11_so_protocol) |
| { |
| struct sockaddr_in bind_addr4; |
| struct sockaddr_in6 bind_addr6; |
| int sock1, sock2, rv; |
| int optval; |
| socklen_t optsize = sizeof(optval); |
| |
| prepare_sock_udp_v4(MY_IPV4_ADDR, 55555, &sock1, &bind_addr4); |
| prepare_sock_udp_v6(MY_IPV6_ADDR, 55555, &sock2, &bind_addr6); |
| |
| rv = zsock_getsockopt(sock1, SOL_SOCKET, SO_PROTOCOL, &optval, &optsize); |
| zassert_equal(rv, 0, "getsockopt failed (%d)", errno); |
| zassert_equal(optval, IPPROTO_UDP, "getsockopt got invalid protocol"); |
| zassert_equal(optsize, sizeof(optval), "getsockopt got invalid size"); |
| |
| rv = zsock_getsockopt(sock2, SOL_SOCKET, SO_PROTOCOL, &optval, &optsize); |
| zassert_equal(rv, 0, "getsockopt failed (%d)", errno); |
| zassert_equal(optval, IPPROTO_UDP, "getsockopt got invalid protocol"); |
| zassert_equal(optsize, sizeof(optval), "getsockopt got invalid size"); |
| |
| rv = zsock_close(sock1); |
| zassert_equal(rv, 0, "close failed"); |
| rv = zsock_close(sock2); |
| zassert_equal(rv, 0, "close failed"); |
| } |
| |
| static void comm_sendmsg_with_txtime(int client_sock, |
| struct sockaddr *client_addr, |
| socklen_t client_addrlen, |
| const struct msghdr *client_msg) |
| { |
| ssize_t sent; |
| int len, i; |
| |
| zassert_not_null(client_addr, "null client addr"); |
| |
| /* |
| * Test client -> server sending |
| */ |
| |
| sent = zsock_sendmsg(client_sock, client_msg, 0); |
| zassert_true(sent > 0, "sendmsg failed (%d)", -errno); |
| |
| for (i = 0, len = 0; i < client_msg->msg_iovlen; i++) { |
| len += client_msg->msg_iov[i].iov_len; |
| } |
| |
| zassert_equal(sent, len, "iovec len (%d) vs sent (%d)", len, sent); |
| } |
| |
| /* In order to verify that the network device driver is able to receive |
| * the TXTIME option, create a separate network device and catch the packets |
| * we are sending. |
| */ |
| struct eth_fake_context { |
| struct net_if *iface; |
| uint8_t mac_address[6]; |
| }; |
| |
| static struct eth_fake_context eth_fake_data; |
| static ZTEST_BMEM struct sockaddr_in6 udp_server_addr; |
| |
| /* The semaphore is there to wait the data to be received. */ |
| static ZTEST_BMEM SYS_MUTEX_DEFINE(wait_data); |
| |
| static struct net_if *eth_iface; |
| static struct net_if *lo0; |
| static ZTEST_BMEM bool test_started; |
| static ZTEST_BMEM bool test_failed; |
| static struct in6_addr my_addr1 = { { { 0x20, 0x01, 0x0d, 0xb8, 1, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; |
| static struct in_addr my_addr2 = { { { 192, 0, 2, 2 } } }; |
| static uint8_t server_lladdr[] = { 0x01, 0x02, 0x03, 0xff, 0xfe, |
| 0x04, 0x05, 0x06 }; |
| static struct net_linkaddr server_link_addr = { |
| .addr = server_lladdr, |
| .len = sizeof(server_lladdr), |
| }; |
| #define MY_IPV6_ADDR_ETH "2001:db8:100::1" |
| #define PEER_IPV6_ADDR_ETH "2001:db8:100::2" |
| #define TEST_TXTIME INT64_MAX |
| #define WAIT_TIME K_MSEC(250) |
| |
| static void eth_fake_iface_init(struct net_if *iface) |
| { |
| const struct device *dev = net_if_get_device(iface); |
| struct eth_fake_context *ctx = dev->data; |
| |
| ctx->iface = iface; |
| |
| net_if_set_link_addr(iface, ctx->mac_address, |
| sizeof(ctx->mac_address), |
| NET_LINK_ETHERNET); |
| |
| ethernet_init(iface); |
| } |
| |
| static int eth_fake_send(const struct device *dev, struct net_pkt *pkt) |
| { |
| net_time_t txtime; |
| |
| ARG_UNUSED(dev); |
| ARG_UNUSED(pkt); |
| |
| if (!test_started) { |
| return 0; |
| } |
| |
| txtime = net_pkt_timestamp_ns(pkt); |
| if (txtime != TEST_TXTIME) { |
| test_failed = true; |
| } else { |
| test_failed = false; |
| } |
| |
| sys_mutex_unlock(&wait_data); |
| |
| return 0; |
| } |
| |
| static struct ethernet_api eth_fake_api_funcs = { |
| .iface_api.init = eth_fake_iface_init, |
| .send = eth_fake_send, |
| }; |
| |
| ETH_NET_DEVICE_INIT(eth_fake, "eth_fake", NULL, NULL, ð_fake_data, NULL, |
| CONFIG_ETH_INIT_PRIORITY, ð_fake_api_funcs, NET_ETH_MTU); |
| |
| static void iface_cb(struct net_if *iface, void *user_data) |
| { |
| struct net_if **my_iface = user_data; |
| |
| if (net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET)) { |
| if (PART_OF_ARRAY(NET_IF_GET_NAME(eth_fake, 0), iface)) { |
| *my_iface = iface; |
| } |
| } |
| |
| if (net_if_l2(iface) == &NET_L2_GET_NAME(DUMMY)) { |
| lo0 = iface; |
| } |
| } |
| |
| ZTEST(net_socket_udp, test_17_setup_eth_for_ipv6) |
| { |
| struct net_if_addr *ifaddr; |
| int ret; |
| |
| net_if_foreach(iface_cb, ð_iface); |
| zassert_not_null(eth_iface, "No ethernet interface found"); |
| |
| ifaddr = net_if_ipv6_addr_add(eth_iface, &my_addr1, |
| NET_ADDR_MANUAL, 0); |
| if (!ifaddr) { |
| DBG("Cannot add IPv6 address %s\n", |
| net_sprint_ipv6_addr(&my_addr1)); |
| zassert_not_null(ifaddr, "addr1"); |
| } |
| |
| net_if_up(eth_iface); |
| |
| (void)memset(&udp_server_addr, 0, sizeof(udp_server_addr)); |
| udp_server_addr.sin6_family = AF_INET6; |
| udp_server_addr.sin6_port = htons(1234); |
| ret = zsock_inet_pton(AF_INET6, PEER_IPV6_ADDR_ETH, &udp_server_addr.sin6_addr); |
| zassert_equal(ret, 1, "inet_pton failed"); |
| |
| /* In order to avoid neighbor discovery, populate neighbor cache */ |
| net_ipv6_nbr_add(eth_iface, &udp_server_addr.sin6_addr, &server_link_addr, |
| true, NET_IPV6_NBR_STATE_REACHABLE); |
| } |
| |
| ZTEST_USER(net_socket_udp, test_18_v6_sendmsg_with_txtime) |
| { |
| int rv; |
| int client_sock; |
| int optval; |
| net_time_t txtime; |
| struct sockaddr_in6 client_addr; |
| struct msghdr msg; |
| struct cmsghdr *cmsg; |
| struct iovec io_vector[1]; |
| union { |
| struct cmsghdr hdr; |
| unsigned char buf[CMSG_SPACE(sizeof(uint64_t))]; |
| } cmsgbuf; |
| |
| prepare_sock_udp_v6(MY_IPV6_ADDR_ETH, ANY_PORT, &client_sock, &client_addr); |
| |
| rv = zsock_bind(client_sock, |
| (struct sockaddr *)&client_addr, |
| sizeof(client_addr)); |
| zassert_equal(rv, 0, "client bind failed"); |
| |
| io_vector[0].iov_base = TEST_STR_SMALL; |
| io_vector[0].iov_len = strlen(TEST_STR_SMALL); |
| |
| memset(&msg, 0, sizeof(msg)); |
| msg.msg_control = &cmsgbuf.buf; |
| msg.msg_controllen = sizeof(cmsgbuf.buf); |
| msg.msg_iov = io_vector; |
| msg.msg_iovlen = 1; |
| msg.msg_name = &udp_server_addr; |
| msg.msg_namelen = sizeof(udp_server_addr); |
| |
| txtime = TEST_TXTIME; |
| |
| cmsg = CMSG_FIRSTHDR(&msg); |
| cmsg->cmsg_len = CMSG_LEN(sizeof(txtime)); |
| cmsg->cmsg_level = SOL_SOCKET; |
| cmsg->cmsg_type = SCM_TXTIME; |
| *(net_time_t *)CMSG_DATA(cmsg) = txtime; |
| |
| optval = true; |
| rv = zsock_setsockopt(client_sock, SOL_SOCKET, SO_TXTIME, &optval, |
| sizeof(optval)); |
| |
| test_started = true; |
| |
| comm_sendmsg_with_txtime(client_sock, |
| (struct sockaddr *)&client_addr, |
| sizeof(client_addr), |
| &msg); |
| |
| rv = zsock_close(client_sock); |
| zassert_equal(rv, 0, "close failed"); |
| |
| if (sys_mutex_lock(&wait_data, WAIT_TIME)) { |
| zassert_true(false, "Timeout DNS query not received"); |
| } |
| |
| zassert_false(test_failed, "Invalid txtime received"); |
| |
| test_started = false; |
| } |
| |
| void test_msg_trunc(int sock_c, int sock_s, struct sockaddr *addr_c, |
| socklen_t addrlen_c, struct sockaddr *addr_s, |
| socklen_t addrlen_s) |
| { |
| int rv; |
| uint8_t str_buf[sizeof(TEST_STR_SMALL) - 1]; |
| |
| rv = zsock_bind(sock_s, addr_s, addrlen_s); |
| zassert_equal(rv, 0, "server bind failed"); |
| |
| rv = zsock_bind(sock_c, addr_c, addrlen_c); |
| zassert_equal(rv, 0, "client bind failed"); |
| |
| rv = zsock_connect(sock_c, addr_s, addrlen_s); |
| zassert_equal(rv, 0, "connect failed"); |
| |
| /* MSG_TRUNC */ |
| |
| rv = zsock_send(sock_c, BUF_AND_SIZE(TEST_STR_SMALL), 0); |
| zassert_equal(rv, sizeof(TEST_STR_SMALL) - 1, "send failed"); |
| |
| memset(str_buf, 0, sizeof(str_buf)); |
| rv = zsock_recv(sock_s, str_buf, 2, ZSOCK_MSG_TRUNC); |
| zassert_equal(rv, sizeof(TEST_STR_SMALL) - 1, "MSG_TRUNC flag failed"); |
| zassert_mem_equal(str_buf, TEST_STR_SMALL, 2, "invalid rx data"); |
| zassert_equal(str_buf[2], 0, "received more than requested"); |
| |
| /* The remaining data should've been discarded */ |
| rv = zsock_recv(sock_s, str_buf, sizeof(str_buf), ZSOCK_MSG_DONTWAIT); |
| zassert_equal(rv, -1, "consecutive recv should've failed"); |
| zassert_equal(errno, EAGAIN, "incorrect errno value"); |
| |
| /* MSG_TRUNC & MSG_PEEK combo */ |
| |
| rv = zsock_send(sock_c, BUF_AND_SIZE(TEST_STR_SMALL), 0); |
| zassert_equal(rv, sizeof(TEST_STR_SMALL) - 1, "send failed"); |
| |
| memset(str_buf, 0, sizeof(str_buf)); |
| rv = zsock_recv(sock_s, str_buf, 2, ZSOCK_MSG_TRUNC | ZSOCK_MSG_PEEK); |
| zassert_equal(rv, sizeof(TEST_STR_SMALL) - 1, "MSG_TRUNC flag failed"); |
| |
| /* The packet should still be available due to MSG_PEEK */ |
| rv = zsock_recv(sock_s, str_buf, sizeof(str_buf), ZSOCK_MSG_TRUNC); |
| zassert_equal(rv, sizeof(TEST_STR_SMALL) - 1, |
| "recv after MSG_PEEK failed"); |
| zassert_mem_equal(str_buf, BUF_AND_SIZE(TEST_STR_SMALL), |
| "invalid rx data"); |
| |
| rv = zsock_close(sock_c); |
| zassert_equal(rv, 0, "close failed"); |
| rv = zsock_close(sock_s); |
| zassert_equal(rv, 0, "close failed"); |
| } |
| |
| ZTEST(net_socket_udp, test_19_v4_msg_trunc) |
| { |
| int client_sock; |
| int server_sock; |
| struct sockaddr_in client_addr; |
| struct sockaddr_in server_addr; |
| |
| prepare_sock_udp_v4(MY_IPV4_ADDR, ANY_PORT, &client_sock, &client_addr); |
| prepare_sock_udp_v4(MY_IPV4_ADDR, SERVER_PORT, &server_sock, &server_addr); |
| |
| test_msg_trunc(client_sock, server_sock, |
| (struct sockaddr *)&client_addr, sizeof(client_addr), |
| (struct sockaddr *)&server_addr, sizeof(server_addr)); |
| } |
| |
| ZTEST(net_socket_udp, test_20_v6_msg_trunc) |
| { |
| int client_sock; |
| int server_sock; |
| struct sockaddr_in6 client_addr; |
| struct sockaddr_in6 server_addr; |
| |
| prepare_sock_udp_v6(MY_IPV6_ADDR, ANY_PORT, &client_sock, &client_addr); |
| prepare_sock_udp_v6(MY_IPV6_ADDR, SERVER_PORT, &server_sock, &server_addr); |
| |
| test_msg_trunc(client_sock, server_sock, |
| (struct sockaddr *)&client_addr, sizeof(client_addr), |
| (struct sockaddr *)&server_addr, sizeof(server_addr)); |
| } |
| |
| static void test_dgram_overflow(int sock_c, int sock_s, |
| struct sockaddr *addr_c, socklen_t addrlen_c, |
| struct sockaddr *addr_s, socklen_t addrlen_s, |
| const void *buf, size_t buf_size) |
| { |
| int rv; |
| |
| rv = zsock_bind(sock_s, addr_s, addrlen_s); |
| zassert_equal(rv, 0, "server bind failed"); |
| |
| rv = zsock_bind(sock_c, addr_c, addrlen_c); |
| zassert_equal(rv, 0, "client bind failed"); |
| |
| rv = zsock_connect(sock_c, addr_s, addrlen_s); |
| zassert_equal(rv, 0, "connect failed"); |
| |
| rv = zsock_send(sock_c, buf, buf_size, 0); |
| zassert_equal(rv, -1, "send succeeded"); |
| zassert_equal(errno, ENOMEM, "incorrect errno value"); |
| |
| rv = zsock_close(sock_c); |
| zassert_equal(rv, 0, "close failed"); |
| rv = zsock_close(sock_s); |
| zassert_equal(rv, 0, "close failed"); |
| } |
| |
| static void test_dgram_fragmented(int sock_c, int sock_s, |
| struct sockaddr *addr_c, socklen_t addrlen_c, |
| struct sockaddr *addr_s, socklen_t addrlen_s, |
| const void *buf, size_t buf_size) |
| { |
| int rv; |
| |
| rv = zsock_bind(sock_s, addr_s, addrlen_s); |
| zassert_equal(rv, 0, "server bind failed"); |
| |
| rv = zsock_bind(sock_c, addr_c, addrlen_c); |
| zassert_equal(rv, 0, "client bind failed"); |
| |
| rv = zsock_connect(sock_c, addr_s, addrlen_s); |
| zassert_equal(rv, 0, "connect failed"); |
| |
| rv = zsock_send(sock_c, buf, buf_size, 0); |
| zassert_equal(rv, buf_size, "send failed"); |
| |
| memset(rx_buf, 0, sizeof(rx_buf)); |
| rv = zsock_recv(sock_s, rx_buf, sizeof(rx_buf), 0); |
| zassert_equal(rv, buf_size, "recv failed"); |
| zassert_mem_equal(rx_buf, buf, buf_size, "wrong data"); |
| |
| rv = zsock_close(sock_c); |
| zassert_equal(rv, 0, "close failed"); |
| rv = zsock_close(sock_s); |
| zassert_equal(rv, 0, "close failed"); |
| } |
| |
| ZTEST(net_socket_udp, test_21_v4_dgram_overflow) |
| { |
| int client_sock; |
| int server_sock; |
| struct sockaddr_in client_addr; |
| struct sockaddr_in server_addr; |
| |
| prepare_sock_udp_v4(MY_IPV4_ADDR, ANY_PORT, &client_sock, &client_addr); |
| prepare_sock_udp_v4(MY_IPV4_ADDR, SERVER_PORT, &server_sock, &server_addr); |
| |
| test_dgram_overflow(client_sock, server_sock, |
| (struct sockaddr *)&client_addr, sizeof(client_addr), |
| (struct sockaddr *)&server_addr, sizeof(server_addr), |
| test_str_all_tx_bufs, NET_ETH_MTU + 1); |
| } |
| |
| ZTEST(net_socket_udp, test_22_v6_dgram_fragmented_or_overflow) |
| { |
| int client_sock; |
| int server_sock; |
| struct sockaddr_in6 client_addr; |
| struct sockaddr_in6 server_addr; |
| |
| prepare_sock_udp_v6(MY_IPV6_ADDR, ANY_PORT, &client_sock, &client_addr); |
| prepare_sock_udp_v6(MY_IPV6_ADDR, SERVER_PORT, &server_sock, &server_addr); |
| |
| if (IS_ENABLED(CONFIG_NET_IPV6_FRAGMENT)) { |
| test_dgram_fragmented(client_sock, server_sock, |
| (struct sockaddr *)&client_addr, sizeof(client_addr), |
| (struct sockaddr *)&server_addr, sizeof(server_addr), |
| test_str_all_tx_bufs, NET_ETH_MTU + 1); |
| } else { |
| test_dgram_overflow(client_sock, server_sock, |
| (struct sockaddr *)&client_addr, sizeof(client_addr), |
| (struct sockaddr *)&server_addr, sizeof(server_addr), |
| test_str_all_tx_bufs, NET_ETH_MTU + 1); |
| } |
| } |
| |
| ZTEST(net_socket_udp, test_23_v6_dgram_overflow) |
| { |
| int client_sock; |
| int server_sock; |
| struct sockaddr_in6 client_addr; |
| struct sockaddr_in6 server_addr; |
| |
| prepare_sock_udp_v6(MY_IPV6_ADDR, ANY_PORT, &client_sock, &client_addr); |
| prepare_sock_udp_v6(MY_IPV6_ADDR, SERVER_PORT, &server_sock, &server_addr); |
| |
| test_dgram_overflow(client_sock, server_sock, |
| (struct sockaddr *)&client_addr, sizeof(client_addr), |
| (struct sockaddr *)&server_addr, sizeof(server_addr), |
| BUF_AND_SIZE(test_str_all_tx_bufs)); |
| } |
| |
| static void test_dgram_connected(int sock_c, int sock_s1, int sock_s2, |
| struct sockaddr *addr_c, socklen_t addrlen_c, |
| struct sockaddr *addr_s1, socklen_t addrlen_s1, |
| struct sockaddr *addr_s2, socklen_t addrlen_s2) |
| { |
| uint8_t tx_buf = 0xab; |
| uint8_t rx_buf; |
| int rv; |
| |
| rv = zsock_bind(sock_c, addr_c, addrlen_c); |
| zassert_equal(rv, 0, "client bind failed"); |
| |
| rv = zsock_bind(sock_s1, addr_s1, addrlen_s1); |
| zassert_equal(rv, 0, "server bind failed"); |
| |
| rv = zsock_bind(sock_s2, addr_s2, addrlen_s2); |
| zassert_equal(rv, 0, "server bind failed"); |
| |
| rv = zsock_connect(sock_c, addr_s1, addrlen_s1); |
| zassert_equal(rv, 0, "connect failed"); |
| |
| /* Verify that a datagram can be received from the connected address */ |
| rv = zsock_sendto(sock_s1, &tx_buf, sizeof(tx_buf), 0, addr_c, addrlen_c); |
| zassert_equal(rv, sizeof(tx_buf), "send failed %d", errno); |
| |
| /* Give the packet a chance to go through the net stack */ |
| k_msleep(10); |
| |
| rx_buf = 0; |
| rv = zsock_recv(sock_c, &rx_buf, sizeof(rx_buf), ZSOCK_MSG_DONTWAIT); |
| zassert_equal(rv, sizeof(rx_buf), "recv failed"); |
| zassert_equal(rx_buf, tx_buf, "wrong data"); |
| |
| /* Verify that a datagram is not received from other address */ |
| rv = zsock_sendto(sock_s2, &tx_buf, sizeof(tx_buf), 0, addr_c, addrlen_c); |
| zassert_equal(rv, sizeof(tx_buf), "send failed"); |
| |
| /* Give the packet a chance to go through the net stack */ |
| k_msleep(10); |
| |
| rv = zsock_recv(sock_c, &rx_buf, sizeof(rx_buf), ZSOCK_MSG_DONTWAIT); |
| zassert_equal(rv, -1, "recv should've failed"); |
| zassert_equal(errno, EAGAIN, "incorrect errno"); |
| |
| rv = zsock_close(sock_c); |
| zassert_equal(rv, 0, "close failed"); |
| rv = zsock_close(sock_s1); |
| zassert_equal(rv, 0, "close failed"); |
| rv = zsock_close(sock_s2); |
| zassert_equal(rv, 0, "close failed"); |
| } |
| |
| ZTEST(net_socket_udp, test_24_v4_dgram_connected) |
| { |
| int client_sock; |
| int server_sock_1; |
| int server_sock_2; |
| struct sockaddr_in client_addr; |
| struct sockaddr_in server_addr_1; |
| struct sockaddr_in server_addr_2; |
| |
| prepare_sock_udp_v4(MY_IPV4_ADDR, CLIENT_PORT, &client_sock, &client_addr); |
| prepare_sock_udp_v4(MY_IPV4_ADDR, SERVER_PORT, &server_sock_1, &server_addr_1); |
| prepare_sock_udp_v4(MY_IPV4_ADDR, SERVER_PORT + 1, &server_sock_2, &server_addr_2); |
| |
| test_dgram_connected(client_sock, server_sock_1, server_sock_2, |
| (struct sockaddr *)&client_addr, sizeof(client_addr), |
| (struct sockaddr *)&server_addr_1, sizeof(server_addr_1), |
| (struct sockaddr *)&server_addr_2, sizeof(server_addr_2)); |
| } |
| |
| ZTEST(net_socket_udp, test_25_v6_dgram_connected) |
| { |
| int client_sock; |
| int server_sock_1; |
| int server_sock_2; |
| struct sockaddr_in6 client_addr; |
| struct sockaddr_in6 server_addr_1; |
| struct sockaddr_in6 server_addr_2; |
| |
| prepare_sock_udp_v6(MY_IPV6_ADDR, CLIENT_PORT, &client_sock, &client_addr); |
| prepare_sock_udp_v6(MY_IPV6_ADDR, SERVER_PORT, &server_sock_1, &server_addr_1); |
| prepare_sock_udp_v6(MY_IPV6_ADDR, SERVER_PORT + 1, &server_sock_2, &server_addr_2); |
| |
| test_dgram_connected(client_sock, server_sock_1, server_sock_2, |
| (struct sockaddr *)&client_addr, sizeof(client_addr), |
| (struct sockaddr *)&server_addr_1, sizeof(server_addr_1), |
| (struct sockaddr *)&server_addr_2, sizeof(server_addr_2)); |
| } |
| |
| ZTEST_USER(net_socket_udp, test_26_recvmsg_invalid) |
| { |
| struct msghdr msg; |
| struct sockaddr_in6 server_addr; |
| struct cmsghdr *cmsg; |
| struct iovec io_vector[1]; |
| union { |
| struct cmsghdr hdr; |
| unsigned char buf[CMSG_SPACE(sizeof(int))]; |
| } cmsgbuf; |
| int ret; |
| |
| /* Userspace is needed for this test */ |
| Z_TEST_SKIP_IFNDEF(CONFIG_USERSPACE); |
| |
| io_vector[0].iov_base = TEST_STR_SMALL; |
| io_vector[0].iov_len = strlen(TEST_STR_SMALL); |
| |
| ret = zsock_recvmsg(0, NULL, 0); |
| zassert_true(ret < 0 && errno == EINVAL, "Wrong errno (%d)", errno); |
| |
| /* Set various pointers to NULL or invalid value which should cause failure */ |
| memset(&msg, 0, sizeof(msg)); |
| msg.msg_controllen = sizeof(cmsgbuf.buf); |
| |
| ret = zsock_recvmsg(0, &msg, 0); |
| zassert_true(ret < 0, "recvmsg() succeed"); |
| |
| msg.msg_control = &cmsgbuf.buf; |
| |
| ret = zsock_recvmsg(0, &msg, 0); |
| zassert_true(ret < 0 && errno == ENOMEM, "Wrong errno (%d)", errno); |
| |
| msg.msg_iov = io_vector; |
| msg.msg_iovlen = 1; |
| msg.msg_name = (void *)1; |
| msg.msg_namelen = sizeof(server_addr); |
| |
| cmsg = CMSG_FIRSTHDR(&msg); |
| cmsg->cmsg_len = CMSG_LEN(sizeof(int)); |
| cmsg->cmsg_level = SOL_SOCKET; |
| cmsg->cmsg_type = 1122; |
| *(int *)CMSG_DATA(cmsg) = 42; |
| |
| ret = zsock_recvmsg(0, &msg, 0); |
| zassert_true(ret < 0, "recvmsg() succeed"); |
| } |
| |
| static void comm_sendmsg_recvmsg(int client_sock, |
| struct sockaddr *client_addr, |
| socklen_t client_addrlen, |
| const struct msghdr *client_msg, |
| int server_sock, |
| struct sockaddr *server_addr, |
| socklen_t server_addrlen, |
| struct msghdr *msg, |
| void *cmsgbuf, int cmsgbuf_len, |
| bool expect_control_data) |
| { |
| #define MAX_BUF_LEN 64 |
| #define SMALL_BUF_LEN (sizeof(TEST_STR_SMALL) - 1 - 2) |
| char buf[MAX_BUF_LEN]; |
| char buf2[SMALL_BUF_LEN]; |
| struct iovec io_vector[2]; |
| ssize_t sent; |
| ssize_t recved; |
| struct sockaddr addr; |
| socklen_t addrlen = server_addrlen; |
| int len, i; |
| |
| zassert_not_null(client_addr, "null client addr"); |
| zassert_not_null(server_addr, "null server addr"); |
| |
| /* |
| * Test client -> server sending |
| */ |
| |
| sent = zsock_sendmsg(client_sock, client_msg, 0); |
| zassert_true(sent > 0, "sendmsg failed, %s (%d)", strerror(errno), -errno); |
| |
| /* One negative test with invalid msg_iov */ |
| memset(msg, 0, sizeof(*msg)); |
| recved = zsock_recvmsg(server_sock, msg, 0); |
| zassert_true(recved < 0 && errno == ENOMEM, "Wrong errno (%d)", errno); |
| |
| for (i = 0, len = 0; i < client_msg->msg_iovlen; i++) { |
| len += client_msg->msg_iov[i].iov_len; |
| } |
| |
| zassert_equal(sent, len, "iovec len (%d) vs sent (%d)", len, sent); |
| |
| /* Test first with one iovec */ |
| io_vector[0].iov_base = buf; |
| io_vector[0].iov_len = sizeof(buf); |
| |
| memset(msg, 0, sizeof(*msg)); |
| msg->msg_control = cmsgbuf; |
| msg->msg_controllen = cmsgbuf_len; |
| msg->msg_iov = io_vector; |
| msg->msg_iovlen = 1; |
| msg->msg_name = &addr; |
| msg->msg_namelen = addrlen; |
| |
| /* Test recvmsg(MSG_PEEK) */ |
| recved = zsock_recvmsg(server_sock, msg, ZSOCK_MSG_PEEK); |
| zassert_true(recved > 0, "recvmsg fail, %s (%d)", strerror(errno), -errno); |
| zassert_equal(recved, strlen(TEST_STR_SMALL), |
| "unexpected received bytes (%d vs %d)", |
| recved, strlen(TEST_STR_SMALL)); |
| zassert_equal(sent, recved, "sent(%d)/received(%d) mismatch", |
| sent, recved); |
| |
| zassert_mem_equal(buf, TEST_STR_SMALL, strlen(TEST_STR_SMALL), |
| "wrong data (%s)", rx_buf); |
| zassert_equal(addrlen, client_addrlen, "unexpected addrlen"); |
| |
| /* Test normal recvmsg() */ |
| clear_buf(rx_buf); |
| recved = zsock_recvmsg(server_sock, msg, 0); |
| zassert_true(recved > 0, "recvfrom fail"); |
| zassert_equal(recved, strlen(TEST_STR_SMALL), |
| "unexpected received bytes"); |
| zassert_mem_equal(buf, TEST_STR_SMALL, strlen(TEST_STR_SMALL), |
| "wrong data (%s)", rx_buf); |
| zassert_equal(addrlen, client_addrlen, "unexpected addrlen"); |
| |
| /* Control data should be empty */ |
| if (!expect_control_data) { |
| zassert_equal(msg->msg_controllen, 0, |
| "We received control data (%u vs %zu)", |
| 0U, msg->msg_controllen); |
| } |
| |
| /* Check the client port */ |
| if (addr.sa_family == AF_INET) { |
| if (net_sin(client_addr)->sin_port != ANY_PORT) { |
| zassert_equal(net_sin(client_addr)->sin_port, |
| net_sin(&addr)->sin_port, |
| "unexpected client port"); |
| } |
| } |
| |
| if (addr.sa_family == AF_INET6) { |
| if (net_sin6(client_addr)->sin6_port != ANY_PORT) { |
| zassert_equal(net_sin6(client_addr)->sin6_port, |
| net_sin6(&addr)->sin6_port, |
| "unexpected client port"); |
| } |
| } |
| |
| /* Then send the message again and verify that we could receive |
| * the full message in smaller chunks too. |
| */ |
| sent = zsock_sendmsg(client_sock, client_msg, 0); |
| zassert_true(sent > 0, "sendmsg failed (%d)", -errno); |
| |
| for (i = 0, len = 0; i < client_msg->msg_iovlen; i++) { |
| len += client_msg->msg_iov[i].iov_len; |
| } |
| |
| zassert_equal(sent, len, "iovec len (%d) vs sent (%d)", len, sent); |
| |
| /* and then test with two iovec */ |
| io_vector[0].iov_base = buf2; |
| io_vector[0].iov_len = sizeof(buf2); |
| io_vector[1].iov_base = buf; |
| io_vector[1].iov_len = sizeof(buf); |
| |
| memset(msg, 0, sizeof(*msg)); |
| msg->msg_control = cmsgbuf; |
| msg->msg_controllen = cmsgbuf_len; |
| msg->msg_iov = io_vector; |
| msg->msg_iovlen = 2; |
| msg->msg_name = &addr; |
| msg->msg_namelen = addrlen; |
| |
| /* Test recvmsg(MSG_PEEK) */ |
| recved = zsock_recvmsg(server_sock, msg, ZSOCK_MSG_PEEK); |
| zassert_true(recved >= 0, "recvfrom fail (errno %d)", errno); |
| zassert_equal(recved, strlen(TEST_STR_SMALL), |
| "unexpected received bytes (%d vs %d)", recved, strlen(TEST_STR_SMALL)); |
| zassert_equal(sent, recved, "sent(%d)/received(%d) mismatch", |
| sent, recved); |
| |
| zassert_mem_equal(msg->msg_iov[0].iov_base, TEST_STR_SMALL, msg->msg_iov[0].iov_len, |
| "wrong data in %s", "iov[0]"); |
| zassert_mem_equal(msg->msg_iov[1].iov_base, &TEST_STR_SMALL[msg->msg_iov[0].iov_len], |
| msg->msg_iov[1].iov_len, |
| "wrong data in %s", "iov[1]"); |
| zassert_equal(addrlen, client_addrlen, "unexpected addrlen"); |
| |
| /* Test normal recvfrom() */ |
| recved = zsock_recvmsg(server_sock, msg, ZSOCK_MSG_PEEK); |
| zassert_true(recved >= 0, "recvfrom fail (errno %d)", errno); |
| zassert_equal(recved, strlen(TEST_STR_SMALL), |
| "unexpected received bytes (%d vs %d)", recved, strlen(TEST_STR_SMALL)); |
| zassert_equal(sent, recved, "sent(%d)/received(%d) mismatch", |
| sent, recved); |
| |
| zassert_mem_equal(msg->msg_iov[0].iov_base, TEST_STR_SMALL, msg->msg_iov[0].iov_len, |
| "wrong data in %s", "iov[0]"); |
| zassert_mem_equal(msg->msg_iov[1].iov_base, &TEST_STR_SMALL[msg->msg_iov[0].iov_len], |
| msg->msg_iov[1].iov_len, |
| "wrong data in %s", "iov[1]"); |
| zassert_equal(addrlen, client_addrlen, "unexpected addrlen"); |
| |
| /* Control data should be empty */ |
| if (!expect_control_data) { |
| zassert_equal(msg->msg_controllen, 0, |
| "We received control data (%u vs %zu)", |
| 0U, msg->msg_controllen); |
| } |
| |
| /* Then check that the trucation flag is set correctly */ |
| sent = zsock_sendmsg(client_sock, client_msg, 0); |
| zassert_true(sent > 0, "sendmsg failed (%d)", -errno); |
| |
| for (i = 0, len = 0; i < client_msg->msg_iovlen; i++) { |
| len += client_msg->msg_iov[i].iov_len; |
| } |
| |
| zassert_equal(sent, len, "iovec len (%d) vs sent (%d)", len, sent); |
| |
| /* Test first with one iovec */ |
| io_vector[0].iov_base = buf2; |
| io_vector[0].iov_len = sizeof(buf2); |
| |
| memset(msg, 0, sizeof(*msg)); |
| msg->msg_control = cmsgbuf; |
| msg->msg_controllen = cmsgbuf_len; |
| msg->msg_iov = io_vector; |
| msg->msg_iovlen = 1; |
| msg->msg_name = &addr; |
| msg->msg_namelen = addrlen; |
| |
| /* Test recvmsg */ |
| recved = zsock_recvmsg(server_sock, msg, 0); |
| zassert_true(recved > 0, "recvmsg fail, %s (%d)", strerror(errno), errno); |
| zassert_equal(recved, sizeof(buf2), |
| "unexpected received bytes (%d vs %d)", |
| recved, sizeof(buf2)); |
| zassert_true(msg->msg_flags & ZSOCK_MSG_TRUNC, "Message not truncated"); |
| |
| zassert_mem_equal(buf2, TEST_STR_SMALL, sizeof(buf2), |
| "wrong data (%s)", buf2); |
| zassert_equal(addrlen, client_addrlen, "unexpected addrlen"); |
| |
| /* Control data should be empty */ |
| if (!expect_control_data) { |
| zassert_equal(msg->msg_controllen, 0, |
| "We received control data (%u vs %zu)", |
| 0U, msg->msg_controllen); |
| } |
| } |
| |
| ZTEST_USER(net_socket_udp, test_27_recvmsg_user) |
| { |
| int rv; |
| int client_sock; |
| int server_sock; |
| struct sockaddr_in client_addr; |
| struct sockaddr_in server_addr; |
| struct msghdr msg, server_msg; |
| struct iovec io_vector[1]; |
| |
| prepare_sock_udp_v4(MY_IPV4_ADDR, ANY_PORT, &client_sock, &client_addr); |
| prepare_sock_udp_v4(MY_IPV4_ADDR, SERVER_PORT, &server_sock, &server_addr); |
| |
| rv = zsock_bind(server_sock, |
| (struct sockaddr *)&server_addr, |
| sizeof(server_addr)); |
| zassert_equal(rv, 0, "server bind failed"); |
| |
| rv = zsock_bind(client_sock, |
| (struct sockaddr *)&client_addr, |
| sizeof(client_addr)); |
| zassert_equal(rv, 0, "client bind failed"); |
| |
| io_vector[0].iov_base = TEST_STR_SMALL; |
| io_vector[0].iov_len = strlen(TEST_STR_SMALL); |
| |
| memset(&msg, 0, sizeof(msg)); |
| msg.msg_iov = io_vector; |
| msg.msg_iovlen = 1; |
| msg.msg_name = &server_addr; |
| msg.msg_namelen = sizeof(server_addr); |
| |
| comm_sendmsg_recvmsg(client_sock, |
| (struct sockaddr *)&client_addr, |
| sizeof(client_addr), |
| &msg, |
| server_sock, |
| (struct sockaddr *)&server_addr, |
| sizeof(server_addr), |
| &server_msg, NULL, 0, false); |
| |
| rv = zsock_close(client_sock); |
| zassert_equal(rv, 0, "close failed"); |
| rv = zsock_close(server_sock); |
| zassert_equal(rv, 0, "close failed"); |
| } |
| |
| static void run_ancillary_recvmsg_test(int client_sock, |
| struct sockaddr *client_addr, |
| int client_addr_len, |
| int server_sock, |
| struct sockaddr *server_addr, |
| int server_addr_len) |
| { |
| int rv; |
| int opt; |
| int ifindex = 0; |
| socklen_t optlen; |
| struct sockaddr addr = { 0 }; |
| struct net_if *iface; |
| struct msghdr msg; |
| struct msghdr server_msg; |
| struct iovec io_vector[1]; |
| struct cmsghdr *cmsg, *prevcmsg; |
| union { |
| struct cmsghdr hdr; |
| unsigned char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; |
| } cmsgbuf; |
| #define SMALL_BUF_LEN (sizeof(TEST_STR_SMALL) - 1 - 2) |
| char buf[MAX_BUF_LEN]; |
| |
| Z_TEST_SKIP_IFNDEF(CONFIG_NET_CONTEXT_RECV_PKTINFO); |
| |
| rv = zsock_bind(server_sock, server_addr, server_addr_len); |
| zassert_equal(rv, 0, "server bind failed"); |
| |
| rv = zsock_bind(client_sock, client_addr, client_addr_len); |
| zassert_equal(rv, 0, "client bind failed"); |
| |
| io_vector[0].iov_base = TEST_STR_SMALL; |
| io_vector[0].iov_len = strlen(TEST_STR_SMALL); |
| |
| memset(&cmsgbuf, 0, sizeof(cmsgbuf)); |
| |
| memset(&msg, 0, sizeof(msg)); |
| msg.msg_iov = io_vector; |
| msg.msg_iovlen = 1; |
| msg.msg_name = server_addr; |
| msg.msg_namelen = server_addr_len; |
| |
| comm_sendmsg_recvmsg(client_sock, |
| client_addr, |
| client_addr_len, |
| &msg, |
| server_sock, |
| server_addr, |
| server_addr_len, |
| &server_msg, |
| &cmsgbuf.buf, |
| sizeof(cmsgbuf.buf), |
| true); |
| |
| for (prevcmsg = NULL, cmsg = CMSG_FIRSTHDR(&server_msg); |
| cmsg != NULL && prevcmsg != cmsg; |
| prevcmsg = cmsg, cmsg = CMSG_NXTHDR(&server_msg, cmsg)) { |
| if (cmsg->cmsg_level == IPPROTO_IP && |
| cmsg->cmsg_type == IP_PKTINFO) { |
| net_sin(&addr)->sin_addr = ((struct in_pktinfo *)CMSG_DATA(cmsg))->ipi_addr; |
| break; |
| } |
| } |
| |
| /* As we have not set the socket option, the address should not be set */ |
| if (server_addr->sa_family == AF_INET) { |
| zassert_equal(net_sin(&addr)->sin_addr.s_addr, INADDR_ANY, "Source address set!"); |
| } |
| |
| if (server_addr->sa_family == AF_INET6) { |
| zassert_true(net_sin6(&addr)->sin6_addr.s6_addr32[0] == 0 && |
| net_sin6(&addr)->sin6_addr.s6_addr32[1] == 0 && |
| net_sin6(&addr)->sin6_addr.s6_addr32[2] == 0 && |
| net_sin6(&addr)->sin6_addr.s6_addr32[3] == 0, |
| "Source address set!"); |
| } |
| |
| opt = 1; |
| optlen = sizeof(opt); |
| rv = zsock_setsockopt(server_sock, IPPROTO_IP, IP_PKTINFO, &opt, optlen); |
| zassert_equal(rv, 0, "setsockopt failed (%d)", -errno); |
| |
| memset(&cmsgbuf, 0, sizeof(cmsgbuf)); |
| |
| memset(&msg, 0, sizeof(msg)); |
| msg.msg_iov = io_vector; |
| msg.msg_iovlen = 1; |
| msg.msg_name = server_addr; |
| msg.msg_namelen = server_addr_len; |
| |
| comm_sendmsg_recvmsg(client_sock, |
| client_addr, |
| client_addr_len, |
| &msg, |
| server_sock, |
| server_addr, |
| server_addr_len, |
| &server_msg, |
| &cmsgbuf.buf, |
| sizeof(cmsgbuf.buf), |
| true); |
| |
| for (cmsg = CMSG_FIRSTHDR(&server_msg); cmsg != NULL; |
| cmsg = CMSG_NXTHDR(&server_msg, cmsg)) { |
| if (cmsg->cmsg_level == IPPROTO_IP && |
| cmsg->cmsg_type == IP_PKTINFO) { |
| net_sin(&addr)->sin_addr = |
| ((struct in_pktinfo *)CMSG_DATA(cmsg))->ipi_addr; |
| ifindex = ((struct in_pktinfo *)CMSG_DATA(cmsg))->ipi_ifindex; |
| break; |
| } |
| |
| if (cmsg->cmsg_level == IPPROTO_IPV6 && |
| cmsg->cmsg_type == IPV6_RECVPKTINFO) { |
| net_ipaddr_copy(&net_sin6(&addr)->sin6_addr, |
| &((struct in6_pktinfo *)CMSG_DATA(cmsg))->ipi6_addr); |
| ifindex = ((struct in6_pktinfo *)CMSG_DATA(cmsg))->ipi6_ifindex; |
| break; |
| } |
| } |
| |
| if (server_addr->sa_family == AF_INET) { |
| zassert_equal(net_sin(&addr)->sin_addr.s_addr, |
| net_sin(server_addr)->sin_addr.s_addr, |
| "Source address not set properly!"); |
| } |
| |
| if (server_addr->sa_family == AF_INET6) { |
| zassert_mem_equal(&net_sin6(&addr)->sin6_addr, |
| &net_sin6(server_addr)->sin6_addr, |
| sizeof(struct in6_addr), |
| "Source address not set properly!"); |
| } |
| |
| if (!k_is_user_context()) { |
| iface = net_if_get_default(); |
| zassert_equal(ifindex, net_if_get_by_iface(iface)); |
| } |
| |
| /* Make sure that the recvmsg() fails if control area is too small */ |
| rv = zsock_sendto(client_sock, BUF_AND_SIZE(TEST_STR_SMALL), 0, |
| server_addr, server_addr_len); |
| zassert_equal(rv, STRLEN(TEST_STR_SMALL), "sendto failed (%d)", -errno); |
| |
| io_vector[0].iov_base = buf; |
| io_vector[0].iov_len = sizeof(buf); |
| |
| memset(&msg, 0, sizeof(msg)); |
| msg.msg_control = &cmsgbuf.buf; |
| msg.msg_controllen = 1; /* making sure the control buf is always too small */ |
| msg.msg_iov = io_vector; |
| msg.msg_iovlen = 1; |
| |
| rv = zsock_recvmsg(server_sock, &msg, 0); |
| zassert_true(rv, "recvmsg succeed (%d)", rv); |
| |
| zassert_true(msg.msg_flags & ZSOCK_MSG_CTRUNC, "Control message not truncated"); |
| |
| rv = zsock_close(client_sock); |
| zassert_equal(rv, 0, "close failed"); |
| rv = zsock_close(server_sock); |
| zassert_equal(rv, 0, "close failed"); |
| } |
| |
| ZTEST_USER(net_socket_udp, test_28_recvmsg_ancillary_ipv4_pktinfo_data_user) |
| { |
| struct sockaddr_in client_addr; |
| struct sockaddr_in server_addr; |
| int client_sock; |
| int server_sock; |
| |
| prepare_sock_udp_v4(MY_IPV4_ADDR, ANY_PORT, &client_sock, &client_addr); |
| prepare_sock_udp_v4(MY_IPV4_ADDR, SERVER_PORT, &server_sock, &server_addr); |
| |
| run_ancillary_recvmsg_test(client_sock, |
| (struct sockaddr *)&client_addr, |
| sizeof(client_addr), |
| server_sock, |
| (struct sockaddr *)&server_addr, |
| sizeof(server_addr)); |
| } |
| |
| ZTEST_USER(net_socket_udp, test_29_recvmsg_ancillary_ipv6_pktinfo_data_user) |
| { |
| struct sockaddr_in6 client_addr; |
| struct sockaddr_in6 server_addr; |
| int client_sock; |
| int server_sock; |
| |
| prepare_sock_udp_v6(MY_IPV6_ADDR, ANY_PORT, &client_sock, &client_addr); |
| prepare_sock_udp_v6(MY_IPV6_ADDR, SERVER_PORT, &server_sock, &server_addr); |
| |
| run_ancillary_recvmsg_test(client_sock, |
| (struct sockaddr *)&client_addr, |
| sizeof(client_addr), |
| server_sock, |
| (struct sockaddr *)&server_addr, |
| sizeof(server_addr)); |
| } |
| |
| ZTEST(net_socket_udp, test_30_setup_eth_for_ipv4) |
| { |
| struct net_if_addr *ifaddr; |
| |
| net_if_foreach(iface_cb, ð_iface); |
| zassert_not_null(eth_iface, "No ethernet interface found"); |
| |
| net_if_down(eth_iface); |
| |
| 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); |
| } |
| |
| static int bind_socket(int sock, struct net_if *iface) |
| { |
| struct sockaddr_ll addr; |
| |
| memset(&addr, 0, sizeof(addr)); |
| |
| addr.sll_ifindex = net_if_get_by_iface(iface); |
| addr.sll_family = AF_PACKET; |
| |
| return zsock_bind(sock, (struct sockaddr *)&addr, sizeof(addr)); |
| } |
| |
| static void test_check_ttl(int sock_c, int sock_s, int sock_p, |
| struct sockaddr *addr_c, socklen_t addrlen_c, |
| struct sockaddr *addr_s, socklen_t addrlen_s, |
| struct sockaddr *addr_sendto, socklen_t addrlen_sendto, |
| sa_family_t family, uint8_t expected_ttl, |
| uint8_t expected_mcast_ttl) |
| { |
| uint8_t tx_buf = 0xab; |
| uint8_t rx_buf; |
| int ret, count = 10, opt; |
| #define IPV4_HDR_SIZE sizeof(struct net_ipv4_hdr) |
| #define IPV6_HDR_SIZE sizeof(struct net_ipv6_hdr) |
| #define UDP_HDR_SIZE sizeof(struct net_udp_hdr) |
| #define V4_HDR_SIZE (IPV4_HDR_SIZE + UDP_HDR_SIZE) |
| #define V6_HDR_SIZE (IPV6_HDR_SIZE + UDP_HDR_SIZE) |
| #define MAX_HDR_SIZE (IPV6_HDR_SIZE + UDP_HDR_SIZE) |
| uint8_t data_to_receive[sizeof(tx_buf) + MAX_HDR_SIZE]; |
| struct sockaddr_ll src; |
| socklen_t addrlen; |
| char ifname[CONFIG_NET_INTERFACE_NAME_LEN]; |
| struct ifreq ifreq = { 0 }; |
| struct timeval timeo_optval = { |
| .tv_sec = 0, |
| .tv_usec = 100000, |
| }; |
| #if defined(CONFIG_NET_STATISTICS) |
| struct net_stats_ip ipv4_stats_before, ipv4_stats_after; |
| struct net_stats_ip ipv6_stats_before, ipv6_stats_after; |
| #endif |
| |
| Z_TEST_SKIP_IFNDEF(CONFIG_NET_INTERFACE_NAME); |
| |
| ret = zsock_bind(sock_c, addr_c, addrlen_c); |
| zassert_equal(ret, 0, "client bind failed"); |
| |
| ret = net_if_get_name(lo0, ifname, sizeof(ifname)); |
| zassert_true(ret > 0, "cannot get interface name (%d)", ret); |
| |
| strncpy(ifreq.ifr_name, ifname, sizeof(ifreq.ifr_name)); |
| ret = zsock_setsockopt(sock_c, SOL_SOCKET, SO_BINDTODEVICE, &ifreq, |
| sizeof(ifreq)); |
| zassert_equal(ret, 0, "SO_BINDTODEVICE failed, %d", -errno); |
| |
| ret = zsock_connect(sock_c, addr_s, addrlen_s); |
| zassert_equal(ret, 0, "connect failed"); |
| |
| ret = zsock_setsockopt(sock_s, SOL_SOCKET, SO_RCVTIMEO, |
| &timeo_optval, sizeof(timeo_optval)); |
| zassert_equal(ret, 0, "Cannot set receive timeout (%d)", -errno); |
| |
| while (count > 0) { |
| ret = zsock_sendto(sock_c, &tx_buf, sizeof(tx_buf), 0, |
| addr_sendto, addrlen_sendto); |
| zassert_equal(ret, sizeof(tx_buf), "send failed (%d)", -errno); |
| |
| ret = zsock_recv(sock_s, &rx_buf, sizeof(rx_buf), ZSOCK_MSG_DONTWAIT); |
| if (ret > 0) { |
| zassert_equal(ret, sizeof(rx_buf), "recv failed (%d)", ret); |
| zassert_equal(rx_buf, tx_buf, "wrong data"); |
| } |
| |
| ret = zsock_recvfrom(sock_p, data_to_receive, sizeof(data_to_receive), 0, |
| (struct sockaddr *)&src, &addrlen); |
| if (ret > 0) { |
| int hdr_size = family == AF_INET ? |
| V4_HDR_SIZE : V6_HDR_SIZE; |
| zassert_equal(ret, sizeof(tx_buf) + hdr_size, |
| "Cannot receive all data (%d vs %zd) (%d)", |
| ret, sizeof(tx_buf), -errno); |
| zassert_mem_equal(&data_to_receive[hdr_size], &tx_buf, |
| sizeof(tx_buf), |
| "Sent and received buffers do not match"); |
| |
| if (family == AF_INET) { |
| struct net_ipv4_hdr *ipv4 = |
| (struct net_ipv4_hdr *)&data_to_receive[0]; |
| |
| if (expected_ttl > 0) { |
| zassert_equal(ipv4->ttl, expected_ttl, |
| "Invalid ttl (%d vs %d)", |
| ipv4->ttl, expected_ttl); |
| } else if (expected_mcast_ttl > 0) { |
| zassert_equal(ipv4->ttl, expected_mcast_ttl, |
| "Invalid mcast ttl (%d vs %d)", |
| ipv4->ttl, expected_mcast_ttl); |
| } |
| } else if (family == AF_INET6) { |
| struct net_ipv6_hdr *ipv6 = |
| (struct net_ipv6_hdr *)&data_to_receive[0]; |
| |
| if (expected_ttl > 0) { |
| zassert_equal(ipv6->hop_limit, expected_ttl, |
| "Invalid hop limit (%d vs %d)", |
| ipv6->hop_limit, expected_ttl); |
| } else if (expected_mcast_ttl > 0) { |
| zassert_equal(ipv6->hop_limit, expected_mcast_ttl, |
| "Invalid mcast hop limit (%d vs %d)", |
| ipv6->hop_limit, expected_mcast_ttl); |
| } |
| } else { |
| zassert_true(false, "Invalid address family (%d)", |
| family); |
| } |
| |
| break; |
| } |
| |
| count--; |
| } |
| |
| zassert_true(count > 0, "timeout while waiting data"); |
| |
| if (family == AF_INET) { |
| /* Set TTL to 0 and make sure the packet is dropped and not |
| * received |
| */ |
| int option; |
| |
| if (expected_ttl > 0) { |
| option = IP_TTL; |
| } else { |
| option = IP_MULTICAST_TTL; |
| } |
| |
| opt = 0; |
| ret = zsock_setsockopt(sock_c, IPPROTO_IP, option, &opt, sizeof(opt)); |
| zassert_equal(ret, 0, "Cannot set %s TTL (%d)", |
| option == IP_TTL ? "unicast" : "multicast", |
| -errno); |
| |
| #if defined(CONFIG_NET_STATISTICS) |
| /* Get IPv4 stats and verify they are updated for dropped |
| * packets. |
| */ |
| net_mgmt(NET_REQUEST_STATS_GET_IPV4, lo0, |
| &ipv4_stats_before, sizeof(ipv4_stats_before)); |
| #endif |
| ret = zsock_sendto(sock_c, &tx_buf, sizeof(tx_buf), 0, |
| addr_sendto, addrlen_sendto); |
| zassert_equal(ret, sizeof(tx_buf), "send failed (%d)", -errno); |
| |
| #if defined(CONFIG_NET_STATISTICS) |
| net_mgmt(NET_REQUEST_STATS_GET_IPV4, lo0, |
| &ipv4_stats_after, sizeof(ipv4_stats_after)); |
| |
| zassert_equal(ipv4_stats_before.drop + 1, |
| ipv4_stats_after.drop, |
| "Dropped statistics not updated (%d vs %d)", |
| ipv4_stats_before.drop + 1, |
| ipv4_stats_after.drop); |
| #endif |
| ret = zsock_recv(sock_s, &rx_buf, sizeof(rx_buf), 0); |
| zassert_true(ret < 0 && errno == EAGAIN, "recv succeed (%d)", -errno); |
| } |
| |
| if (family == AF_INET6) { |
| /* Set hoplimit to 0 and make sure the packet is dropped and not |
| * received. |
| */ |
| int option; |
| |
| if (expected_ttl > 0) { |
| option = IPV6_UNICAST_HOPS; |
| } else { |
| option = IPV6_MULTICAST_HOPS; |
| } |
| |
| opt = 0; |
| ret = zsock_setsockopt(sock_c, IPPROTO_IPV6, option, |
| &opt, sizeof(opt)); |
| zassert_equal(ret, 0, "Cannot set %s hops (%d)", |
| option == IPV6_UNICAST_HOPS ? "unicast" : "multicast", |
| -errno); |
| |
| #if defined(CONFIG_NET_STATISTICS) |
| /* Get IPv6 stats and verify they are updated for dropped |
| * packets. |
| */ |
| net_mgmt(NET_REQUEST_STATS_GET_IPV6, lo0, |
| &ipv6_stats_before, sizeof(ipv6_stats_before)); |
| #endif |
| ret = zsock_sendto(sock_c, &tx_buf, sizeof(tx_buf), 0, |
| addr_sendto, addrlen_sendto); |
| zassert_equal(ret, sizeof(tx_buf), "send failed (%d)", -errno); |
| |
| #if defined(CONFIG_NET_STATISTICS) |
| net_mgmt(NET_REQUEST_STATS_GET_IPV6, lo0, |
| &ipv6_stats_after, sizeof(ipv6_stats_after)); |
| |
| zassert_equal(ipv6_stats_before.drop + 1, |
| ipv6_stats_after.drop, |
| "Dropped statistics not updated (%d vs %d)", |
| ipv6_stats_before.drop + 1, |
| ipv6_stats_after.drop); |
| #endif |
| ret = zsock_recv(sock_s, &rx_buf, sizeof(rx_buf), 0); |
| zassert_true(ret < 0 && errno == EAGAIN, "recv succeed (%d)", -errno); |
| |
| } |
| |
| ret = zsock_close(sock_c); |
| zassert_equal(ret, 0, "close failed"); |
| ret = zsock_close(sock_s); |
| zassert_equal(ret, 0, "close failed"); |
| ret = zsock_close(sock_p); |
| zassert_equal(ret, 0, "close failed"); |
| } |
| |
| ZTEST(net_socket_udp, test_31_v4_ttl) |
| { |
| int ret; |
| int client_sock; |
| int server_sock; |
| int packet_sock; |
| int ttl, verify; |
| socklen_t optlen; |
| struct sockaddr_in client_addr; |
| struct sockaddr_in server_addr; |
| |
| Z_TEST_SKIP_IFNDEF(CONFIG_NET_SOCKETS_PACKET); |
| |
| prepare_sock_udp_v4(MY_IPV4_ADDR, CLIENT_PORT, &client_sock, &client_addr); |
| prepare_sock_udp_v4(MY_IPV4_ADDR, SERVER_PORT, &server_sock, &server_addr); |
| |
| packet_sock = zsock_socket(AF_PACKET, SOCK_RAW, ETH_P_ALL); |
| zassert_true(packet_sock >= 0, "Cannot create packet socket (%d)", -errno); |
| |
| ret = bind_socket(packet_sock, lo0); |
| zassert_equal(ret, 0, "packet socket bind failed"); |
| |
| zassert_not_null(lo0->config.ip.ipv4, |
| "Interface %d (%p) no IPv4 configured", |
| net_if_get_by_iface(lo0), lo0); |
| |
| ttl = 16; |
| net_if_ipv4_set_ttl(lo0, ttl); |
| verify = net_if_ipv4_get_ttl(lo0); |
| zassert_equal(verify, ttl, "Different TTLs (%d vs %d)", ttl, verify); |
| |
| ttl = 128; |
| ret = zsock_setsockopt(client_sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); |
| zassert_equal(ret, 0, "Cannot set unicast TTL (%d)", -errno); |
| |
| optlen = sizeof(verify); |
| ret = zsock_getsockopt(client_sock, IPPROTO_IP, IP_TTL, &verify, &optlen); |
| zassert_equal(ret, 0, "Cannot get unicast TTL (%d)", -errno); |
| zassert_equal(verify, ttl, "Different unicast TTL (%d vs %d)", |
| ttl, verify); |
| |
| test_check_ttl(client_sock, server_sock, packet_sock, |
| (struct sockaddr *)&client_addr, sizeof(client_addr), |
| (struct sockaddr *)&server_addr, sizeof(server_addr), |
| (struct sockaddr *)&server_addr, sizeof(server_addr), |
| AF_INET, ttl, 0); |
| } |
| |
| ZTEST(net_socket_udp, test_32_v4_mcast_ttl) |
| { |
| int ret; |
| int client_sock; |
| int server_sock; |
| int packet_sock; |
| int mcast_ttl, verify; |
| socklen_t optlen; |
| struct sockaddr_in client_addr; |
| struct sockaddr_in server_addr; |
| struct sockaddr_in sendto_addr; |
| |
| Z_TEST_SKIP_IFNDEF(CONFIG_NET_SOCKETS_PACKET); |
| |
| prepare_sock_udp_v4(MY_IPV4_ADDR, CLIENT_PORT, &client_sock, &client_addr); |
| prepare_sock_udp_v4(MY_IPV4_ADDR, SERVER_PORT, &server_sock, &server_addr); |
| |
| packet_sock = zsock_socket(AF_PACKET, SOCK_RAW, ETH_P_ALL); |
| zassert_true(packet_sock >= 0, "Cannot create packet socket (%d)", -errno); |
| |
| ret = bind_socket(packet_sock, lo0); |
| zassert_equal(ret, 0, "packet socket bind failed"); |
| |
| zassert_not_null(lo0->config.ip.ipv4, |
| "Interface %d (%p) no IPv4 configured", |
| net_if_get_by_iface(lo0), lo0); |
| |
| mcast_ttl = 8; |
| ret = zsock_setsockopt(client_sock, IPPROTO_IP, IP_MULTICAST_TTL, &mcast_ttl, |
| sizeof(mcast_ttl)); |
| zassert_equal(ret, 0, "Cannot set multicast ttl (%d)", -errno); |
| |
| optlen = sizeof(verify); |
| ret = zsock_getsockopt(client_sock, IPPROTO_IP, IP_MULTICAST_TTL, &verify, |
| &optlen); |
| zassert_equal(ret, 0, "Cannot get multicast ttl (%d)", -errno); |
| zassert_equal(verify, mcast_ttl, "Different multicast TTLs (%d vs %d)", |
| mcast_ttl, verify); |
| |
| ret = net_addr_pton(AF_INET, MY_MCAST_IPV4_ADDR, &sendto_addr.sin_addr); |
| zassert_equal(ret, 0, "Cannot get IPv4 address (%d)", ret); |
| |
| test_check_ttl(client_sock, server_sock, packet_sock, |
| (struct sockaddr *)&client_addr, sizeof(client_addr), |
| (struct sockaddr *)&server_addr, sizeof(server_addr), |
| (struct sockaddr *)&sendto_addr, sizeof(sendto_addr), |
| AF_INET, 0, mcast_ttl); |
| } |
| |
| ZTEST(net_socket_udp, test_33_v6_mcast_hops) |
| { |
| int ret; |
| int client_sock; |
| int server_sock; |
| int packet_sock; |
| int mcast_hops, if_mcast_hops; |
| int verify, opt; |
| socklen_t optlen; |
| struct sockaddr_in6 client_addr; |
| struct sockaddr_in6 server_addr; |
| struct sockaddr_in6 sendto_addr; |
| |
| Z_TEST_SKIP_IFNDEF(CONFIG_NET_SOCKETS_PACKET); |
| |
| prepare_sock_udp_v6(MY_IPV6_ADDR, CLIENT_PORT, &client_sock, &client_addr); |
| prepare_sock_udp_v6(MY_IPV6_ADDR, SERVER_PORT, &server_sock, &server_addr); |
| |
| packet_sock = zsock_socket(AF_PACKET, SOCK_RAW, ETH_P_ALL); |
| zassert_true(packet_sock >= 0, "Cannot create packet socket (%d)", -errno); |
| |
| ret = bind_socket(packet_sock, lo0); |
| zassert_equal(ret, 0, "packet socket bind failed"); |
| |
| zassert_not_null(lo0->config.ip.ipv6, |
| "Interface %d (%p) no IPv6 configured", |
| net_if_get_by_iface(lo0), lo0); |
| |
| /* First make sure setting hop limit to -1 works as expected (route default |
| * value should be used). |
| */ |
| if_mcast_hops = net_if_ipv6_get_mcast_hop_limit(lo0); |
| |
| opt = -1; |
| ret = zsock_setsockopt(client_sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &opt, |
| sizeof(opt)); |
| zassert_equal(ret, 0, "Cannot set multicast hop limit (%d)", -errno); |
| |
| optlen = sizeof(verify); |
| ret = zsock_getsockopt(client_sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &verify, |
| &optlen); |
| zassert_equal(ret, 0, "Cannot get multicast hop limit (%d)", -errno); |
| zassert_equal(verify, if_mcast_hops, "Different multicast hop limit (%d vs %d)", |
| if_mcast_hops, verify); |
| |
| /* Then test the normal case where we set the value */ |
| mcast_hops = 8; |
| ret = zsock_setsockopt(client_sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &mcast_hops, |
| sizeof(mcast_hops)); |
| zassert_equal(ret, 0, "Cannot set multicast hop limit (%d)", -errno); |
| |
| optlen = sizeof(verify); |
| ret = zsock_getsockopt(client_sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &verify, |
| &optlen); |
| zassert_equal(ret, 0, "Cannot get multicast hop limit (%d)", -errno); |
| zassert_equal(verify, mcast_hops, "Different multicast hop limit (%d vs %d)", |
| mcast_hops, verify); |
| |
| ret = net_addr_pton(AF_INET6, MY_MCAST_IPV6_ADDR, &sendto_addr.sin6_addr); |
| zassert_equal(ret, 0, "Cannot get IPv6 address (%d)", ret); |
| |
| test_check_ttl(client_sock, server_sock, packet_sock, |
| (struct sockaddr *)&client_addr, sizeof(client_addr), |
| (struct sockaddr *)&server_addr, sizeof(server_addr), |
| (struct sockaddr *)&sendto_addr, sizeof(sendto_addr), |
| AF_INET6, 0, mcast_hops); |
| } |
| |
| ZTEST(net_socket_udp, test_34_v6_hops) |
| { |
| int ret; |
| int client_sock; |
| int server_sock; |
| int packet_sock; |
| int hops, verify; |
| socklen_t optlen; |
| struct sockaddr_in6 client_addr; |
| struct sockaddr_in6 server_addr; |
| |
| Z_TEST_SKIP_IFNDEF(CONFIG_NET_SOCKETS_PACKET); |
| |
| prepare_sock_udp_v6(MY_IPV6_ADDR, CLIENT_PORT, &client_sock, &client_addr); |
| prepare_sock_udp_v6(MY_IPV6_ADDR, SERVER_PORT, &server_sock, &server_addr); |
| |
| packet_sock = zsock_socket(AF_PACKET, SOCK_RAW, ETH_P_ALL); |
| zassert_true(packet_sock >= 0, "Cannot create packet socket (%d)", -errno); |
| |
| ret = bind_socket(packet_sock, lo0); |
| zassert_equal(ret, 0, "packet socket bind failed"); |
| |
| zassert_not_null(lo0->config.ip.ipv6, |
| "Interface %d (%p) no IPv6 configured", |
| net_if_get_by_iface(lo0), lo0); |
| |
| hops = 16; |
| net_if_ipv6_set_hop_limit(lo0, hops); |
| verify = net_if_ipv6_get_hop_limit(lo0); |
| zassert_equal(verify, hops, "Different hop limit (%d vs %d)", hops, verify); |
| |
| hops = 8; |
| ret = zsock_setsockopt(client_sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hops, |
| sizeof(hops)); |
| zassert_equal(ret, 0, "Cannot set unicast hops (%d)", -errno); |
| |
| optlen = sizeof(verify); |
| ret = zsock_getsockopt(client_sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &verify, |
| &optlen); |
| zassert_equal(ret, 0, "Cannot get unicast hops (%d)", -errno); |
| zassert_equal(verify, hops, "Different unicast hops (%d vs %d)", |
| hops, verify); |
| |
| test_check_ttl(client_sock, server_sock, packet_sock, |
| (struct sockaddr *)&client_addr, sizeof(client_addr), |
| (struct sockaddr *)&server_addr, sizeof(server_addr), |
| (struct sockaddr *)&server_addr, sizeof(server_addr), |
| AF_INET6, hops, 0); |
| } |
| |
| ZTEST_USER(net_socket_udp, test_35_recvmsg_msg_controllen_update) |
| { |
| int rv; |
| int client_sock; |
| int server_sock; |
| struct sockaddr_in client_addr; |
| struct sockaddr_in server_addr; |
| struct msghdr msg, server_msg; |
| struct iovec io_vector[1]; |
| union { |
| struct cmsghdr hdr; |
| unsigned char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; |
| } cmsgbuf; |
| |
| prepare_sock_udp_v4(MY_IPV4_ADDR, ANY_PORT, &client_sock, &client_addr); |
| prepare_sock_udp_v4(MY_IPV4_ADDR, SERVER_PORT, &server_sock, &server_addr); |
| |
| rv = zsock_bind(server_sock, |
| (struct sockaddr *)&server_addr, |
| sizeof(server_addr)); |
| zassert_equal(rv, 0, "server bind failed"); |
| |
| rv = zsock_bind(client_sock, |
| (struct sockaddr *)&client_addr, |
| sizeof(client_addr)); |
| zassert_equal(rv, 0, "client bind failed"); |
| |
| memset(&cmsgbuf, 0, sizeof(cmsgbuf)); |
| |
| io_vector[0].iov_base = TEST_STR_SMALL; |
| io_vector[0].iov_len = strlen(TEST_STR_SMALL); |
| |
| memset(&msg, 0, sizeof(msg)); |
| msg.msg_iov = io_vector; |
| msg.msg_iovlen = 1; |
| msg.msg_name = &server_addr; |
| msg.msg_namelen = sizeof(server_addr); |
| |
| comm_sendmsg_recvmsg(client_sock, |
| (struct sockaddr *)&client_addr, |
| sizeof(client_addr), |
| &msg, |
| server_sock, |
| (struct sockaddr *)&server_addr, |
| sizeof(server_addr), |
| &server_msg, |
| &cmsgbuf.buf, |
| sizeof(cmsgbuf.buf), |
| false); |
| |
| rv = zsock_close(client_sock); |
| zassert_equal(rv, 0, "close failed"); |
| rv = zsock_close(server_sock); |
| zassert_equal(rv, 0, "close failed"); |
| } |
| |
| static void after(void *arg) |
| { |
| ARG_UNUSED(arg); |
| |
| for (int i = 0; i < CONFIG_POSIX_MAX_FDS; ++i) { |
| (void)zsock_close(i); |
| } |
| } |
| |
| ZTEST_SUITE(net_socket_udp, NULL, NULL, NULL, after, NULL); |