Skip to content

Commit a54a83f

Browse files
Cristib05jhedberg
authored andcommitted
tests: net: socket: Add test for hop limit ancillary data using recvmsg()
Testing that recvmsg() returns IPv4 TTL and IPv6 hop limit ancillary data. Signed-off-by: Cristian Bulacu <[email protected]>
1 parent 3fcf06d commit a54a83f

File tree

2 files changed

+266
-0
lines changed

2 files changed

+266
-0
lines changed

tests/net/socket/udp/src/main.c

Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*
22
* Copyright (c) 2017 Linaro Limited
33
* Copyright (c) 2021 Nordic Semiconductor
4+
* Copyright 2025 NXP
45
*
56
* SPDX-License-Identifier: Apache-2.0
67
*/
@@ -3214,6 +3215,268 @@ ZTEST(net_socket_udp, test_42_v6_dgram_peer_addr_reset)
32143215
(struct sockaddr *)&server_addr_2, sizeof(server_addr_2));
32153216
}
32163217

3218+
static void comm_sendmsg_recvmsg_hop_limit(int client_sock,
3219+
struct sockaddr *client_addr,
3220+
socklen_t client_addrlen,
3221+
const struct msghdr *client_msg,
3222+
int server_sock,
3223+
struct sockaddr *server_addr,
3224+
socklen_t server_addrlen,
3225+
struct msghdr *msg,
3226+
void *cmsgbuf, int cmsgbuf_len,
3227+
bool expect_control_data)
3228+
{
3229+
#define MAX_BUF_LEN 64
3230+
char buf[MAX_BUF_LEN];
3231+
struct iovec io_vector[1];
3232+
ssize_t sent;
3233+
ssize_t recved;
3234+
struct sockaddr addr;
3235+
socklen_t addrlen = server_addrlen;
3236+
int len, i;
3237+
3238+
zassert_not_null(client_addr, "null client addr");
3239+
zassert_not_null(server_addr, "null server addr");
3240+
3241+
/*
3242+
* Test client -> server sending
3243+
*/
3244+
3245+
sent = zsock_sendmsg(client_sock, client_msg, 0);
3246+
zassert_true(sent > 0, "sendmsg failed, %s (%d)", strerror(errno), -errno);
3247+
3248+
/* One negative test with invalid msg_iov */
3249+
memset(msg, 0, sizeof(*msg));
3250+
recved = zsock_recvmsg(server_sock, msg, 0);
3251+
zassert_true(recved < 0 && errno == ENOMEM, "Wrong errno (%d)", errno);
3252+
3253+
for (i = 0, len = 0; i < client_msg->msg_iovlen; i++) {
3254+
len += client_msg->msg_iov[i].iov_len;
3255+
}
3256+
3257+
zassert_equal(sent, len, "iovec len (%d) vs sent (%d)", len, sent);
3258+
3259+
/* Test first with one iovec */
3260+
io_vector[0].iov_base = buf;
3261+
io_vector[0].iov_len = sizeof(buf);
3262+
3263+
memset(msg, 0, sizeof(*msg));
3264+
if (cmsgbuf != NULL) {
3265+
memset(cmsgbuf, 0, cmsgbuf_len);
3266+
}
3267+
msg->msg_control = cmsgbuf;
3268+
msg->msg_controllen = cmsgbuf_len;
3269+
msg->msg_iov = io_vector;
3270+
msg->msg_iovlen = 1;
3271+
msg->msg_name = &addr;
3272+
msg->msg_namelen = addrlen;
3273+
3274+
/* Test normal recvmsg() */
3275+
clear_buf(rx_buf);
3276+
recved = zsock_recvmsg(server_sock, msg, 0);
3277+
zassert_true(recved > 0, "recvfrom fail");
3278+
zassert_equal(recved, len, "unexpected received bytes");
3279+
zassert_equal(msg->msg_iovlen, 1, "recvmsg should not modify msg_iovlen");
3280+
zassert_equal(msg->msg_iov[0].iov_len, sizeof(buf),
3281+
"recvmsg should not modify buffer length");
3282+
zassert_mem_equal(buf, TEST_STR_SMALL, len,
3283+
"wrong data (%s)", rx_buf);
3284+
zassert_equal(addrlen, client_addrlen, "unexpected addrlen");
3285+
3286+
/* Control data should be empty */
3287+
if (!expect_control_data) {
3288+
zassert_equal(msg->msg_controllen, 0,
3289+
"We received control data (%u vs %zu)",
3290+
0U, msg->msg_controllen);
3291+
}
3292+
}
3293+
3294+
static void run_ancillary_recvmsg_hoplimit_test(int client_sock,
3295+
struct sockaddr *client_addr,
3296+
int client_addr_len,
3297+
int server_sock,
3298+
struct sockaddr *server_addr,
3299+
int server_addr_len)
3300+
{
3301+
int rv;
3302+
int opt;
3303+
socklen_t optlen;
3304+
struct msghdr msg;
3305+
struct msghdr server_msg;
3306+
struct iovec io_vector[1];
3307+
struct cmsghdr *cmsg, *prevcmsg;
3308+
int send_hop_limit = 90, recv_hop_limit = 0;
3309+
union {
3310+
struct cmsghdr hdr;
3311+
unsigned char buf[CMSG_SPACE(sizeof(int))];
3312+
} cmsgbuf;
3313+
3314+
Z_TEST_SKIP_IFNDEF(CONFIG_NET_CONTEXT_RECV_HOPLIMIT);
3315+
3316+
rv = zsock_bind(server_sock, server_addr, server_addr_len);
3317+
zassert_equal(rv, 0, "server bind failed");
3318+
3319+
rv = zsock_bind(client_sock, client_addr, client_addr_len);
3320+
zassert_equal(rv, 0, "client bind failed");
3321+
3322+
io_vector[0].iov_base = TEST_STR_SMALL;
3323+
io_vector[0].iov_len = strlen(TEST_STR_SMALL);
3324+
3325+
memset(&cmsgbuf, 0, sizeof(cmsgbuf));
3326+
3327+
memset(&msg, 0, sizeof(msg));
3328+
msg.msg_name = server_addr;
3329+
msg.msg_namelen = server_addr_len;
3330+
msg.msg_iov = io_vector;
3331+
msg.msg_iovlen = 1;
3332+
msg.msg_control = &cmsgbuf.buf;
3333+
msg.msg_controllen = sizeof(cmsgbuf.buf);
3334+
3335+
cmsg = CMSG_FIRSTHDR(&msg);
3336+
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
3337+
if (client_addr->sa_family == AF_INET) {
3338+
cmsg->cmsg_level = IPPROTO_IP;
3339+
cmsg->cmsg_type = IP_TTL;
3340+
} else {
3341+
cmsg->cmsg_level = IPPROTO_IPV6;
3342+
cmsg->cmsg_type = IPV6_HOPLIMIT;
3343+
}
3344+
3345+
*(int *)CMSG_DATA(cmsg) = send_hop_limit;
3346+
3347+
comm_sendmsg_recvmsg_hop_limit(client_sock,
3348+
client_addr,
3349+
client_addr_len,
3350+
&msg,
3351+
server_sock,
3352+
server_addr,
3353+
server_addr_len,
3354+
&server_msg,
3355+
&cmsgbuf.buf,
3356+
sizeof(cmsgbuf.buf),
3357+
true);
3358+
3359+
for (prevcmsg = NULL, cmsg = CMSG_FIRSTHDR(&server_msg);
3360+
cmsg != NULL && prevcmsg != cmsg;
3361+
prevcmsg = cmsg, cmsg = CMSG_NXTHDR(&server_msg, cmsg)) {
3362+
if (client_addr->sa_family == AF_INET) {
3363+
if (cmsg->cmsg_level == IPPROTO_IP &&
3364+
cmsg->cmsg_type == IP_TTL) {
3365+
recv_hop_limit = *(int *)CMSG_DATA(cmsg);
3366+
break;
3367+
}
3368+
} else {
3369+
if (cmsg->cmsg_level == IPPROTO_IPV6 &&
3370+
cmsg->cmsg_type == IPV6_HOPLIMIT) {
3371+
recv_hop_limit = *(int *)CMSG_DATA(cmsg);
3372+
break;
3373+
}
3374+
}
3375+
}
3376+
3377+
/* As we have not set the socket option, the hop_limit should not be set */
3378+
zassert_equal(recv_hop_limit, 0, "Hop limit set!");
3379+
3380+
opt = 1;
3381+
optlen = sizeof(opt);
3382+
if (server_addr->sa_family == AF_INET) {
3383+
rv = zsock_setsockopt(server_sock, IPPROTO_IP, IP_RECVTTL, &opt, optlen);
3384+
} else {
3385+
rv = zsock_setsockopt(server_sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &opt, optlen);
3386+
}
3387+
zassert_equal(rv, 0, "setsockopt failed (%d)", -errno);
3388+
3389+
memset(&cmsgbuf, 0, sizeof(cmsgbuf));
3390+
3391+
memset(&msg, 0, sizeof(msg));
3392+
msg.msg_name = server_addr;
3393+
msg.msg_namelen = server_addr_len;
3394+
msg.msg_iov = io_vector;
3395+
msg.msg_iovlen = 1;
3396+
msg.msg_control = &cmsgbuf.buf;
3397+
msg.msg_controllen = sizeof(cmsgbuf.buf);
3398+
3399+
cmsg = CMSG_FIRSTHDR(&msg);
3400+
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
3401+
if (client_addr->sa_family == AF_INET) {
3402+
cmsg->cmsg_level = IPPROTO_IP;
3403+
cmsg->cmsg_type = IP_TTL;
3404+
} else {
3405+
cmsg->cmsg_level = IPPROTO_IPV6;
3406+
cmsg->cmsg_type = IPV6_HOPLIMIT;
3407+
}
3408+
3409+
*(int *)CMSG_DATA(cmsg) = send_hop_limit;
3410+
3411+
comm_sendmsg_recvmsg_hop_limit(client_sock,
3412+
client_addr,
3413+
client_addr_len,
3414+
&msg,
3415+
server_sock,
3416+
server_addr,
3417+
server_addr_len,
3418+
&server_msg,
3419+
&cmsgbuf.buf,
3420+
sizeof(cmsgbuf.buf),
3421+
true);
3422+
3423+
for (prevcmsg = NULL, cmsg = CMSG_FIRSTHDR(&server_msg);
3424+
cmsg != NULL && prevcmsg != cmsg;
3425+
prevcmsg = cmsg, cmsg = CMSG_NXTHDR(&server_msg, cmsg)) {
3426+
if (client_addr->sa_family == AF_INET) {
3427+
if (cmsg->cmsg_level == IPPROTO_IP &&
3428+
cmsg->cmsg_type == IP_TTL) {
3429+
recv_hop_limit = *(int *)CMSG_DATA(cmsg);
3430+
break;
3431+
}
3432+
} else {
3433+
if (cmsg->cmsg_level == IPPROTO_IPV6 &&
3434+
cmsg->cmsg_type == IPV6_HOPLIMIT) {
3435+
recv_hop_limit = *(int *)CMSG_DATA(cmsg);
3436+
break;
3437+
}
3438+
}
3439+
}
3440+
3441+
zassert_equal(send_hop_limit, recv_hop_limit, "Hop limit not parsed correctly");
3442+
}
3443+
3444+
ZTEST_USER(net_socket_udp, test_43_recvmsg_ancillary_ipv4_hoplimit_data_user)
3445+
{
3446+
struct sockaddr_in client_addr;
3447+
struct sockaddr_in server_addr;
3448+
int client_sock;
3449+
int server_sock;
3450+
3451+
prepare_sock_udp_v4(MY_IPV4_ADDR, ANY_PORT, &client_sock, &client_addr);
3452+
prepare_sock_udp_v4(MY_IPV4_ADDR, SERVER_PORT, &server_sock, &server_addr);
3453+
3454+
run_ancillary_recvmsg_hoplimit_test(client_sock,
3455+
(struct sockaddr *)&client_addr,
3456+
sizeof(client_addr),
3457+
server_sock,
3458+
(struct sockaddr *)&server_addr,
3459+
sizeof(server_addr));
3460+
}
3461+
3462+
ZTEST_USER(net_socket_udp, test_44_recvmsg_ancillary_ipv6_hoplimit_data_user)
3463+
{
3464+
struct sockaddr_in6 client_addr;
3465+
struct sockaddr_in6 server_addr;
3466+
int client_sock;
3467+
int server_sock;
3468+
3469+
prepare_sock_udp_v6(MY_IPV6_ADDR, ANY_PORT, &client_sock, &client_addr);
3470+
prepare_sock_udp_v6(MY_IPV6_ADDR, SERVER_PORT, &server_sock, &server_addr);
3471+
3472+
run_ancillary_recvmsg_hoplimit_test(client_sock,
3473+
(struct sockaddr *)&client_addr,
3474+
sizeof(client_addr),
3475+
server_sock,
3476+
(struct sockaddr *)&server_addr,
3477+
sizeof(server_addr));
3478+
}
3479+
32173480
static void after(void *arg)
32183481
{
32193482
ARG_UNUSED(arg);

tests/net/socket/udp/testcase.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ tests:
2020
net.socket.udp.pktinfo:
2121
extra_configs:
2222
- CONFIG_NET_CONTEXT_RECV_PKTINFO=y
23+
net.socket.udp.hoplimit:
24+
extra_configs:
25+
- CONFIG_NET_CONTEXT_RECV_HOPLIMIT=y
2326
net.socket.udp.port_range:
2427
extra_configs:
2528
- CONFIG_NET_CONTEXT_CLAMP_PORT_RANGE=y

0 commit comments

Comments
 (0)