|
1 | 1 | /*
|
2 | 2 | * Copyright (c) 2017 Linaro Limited
|
3 | 3 | * Copyright (c) 2021 Nordic Semiconductor
|
| 4 | + * Copyright 2025 NXP |
4 | 5 | *
|
5 | 6 | * SPDX-License-Identifier: Apache-2.0
|
6 | 7 | */
|
@@ -3214,6 +3215,268 @@ ZTEST(net_socket_udp, test_42_v6_dgram_peer_addr_reset)
|
3214 | 3215 | (struct sockaddr *)&server_addr_2, sizeof(server_addr_2));
|
3215 | 3216 | }
|
3216 | 3217 |
|
| 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 | + |
3217 | 3480 | static void after(void *arg)
|
3218 | 3481 | {
|
3219 | 3482 | ARG_UNUSED(arg);
|
|
0 commit comments