This is an automated email from the ASF dual-hosted git repository. acassis pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git
commit 6f3150f9bde2dd8fe1832717233a243194fdb089 Author: Marco Casaroli <[email protected]> AuthorDate: Sun Nov 8 19:17:47 2026 +0100 testing/nettest: Add a test of bind() of a CAN socket. A CAN_RAW socket must bind only to a CAN device. Add cmocka_net_can (testing/nettest/can, CONFIG_TESTING_NET_CAN, default y): bind() to an index with no device and to the loopback device fails with ENODEV, bind() to index 0 (all CAN devices) and to can0 (skipped without can0) succeeds, and an unbound socket cannot send with SO_BINDTODEVICE or with an address in sendto(). If bind() to lo succeeds, the test writes a frame, as a program would; so that case runs last. Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: Marco Casaroli <[email protected]> --- testing/nettest/CMakeLists.txt | 19 +++ testing/nettest/Kconfig | 9 ++ testing/nettest/Makefile | 6 + testing/nettest/can/test_can.c | 54 +++++++++ testing/nettest/can/test_can.h | 52 +++++++++ testing/nettest/can/test_can_bind.c | 222 ++++++++++++++++++++++++++++++++++++ 6 files changed, 362 insertions(+) diff --git a/testing/nettest/CMakeLists.txt b/testing/nettest/CMakeLists.txt index 760621931..296ae339d 100644 --- a/testing/nettest/CMakeLists.txt +++ b/testing/nettest/CMakeLists.txt @@ -217,4 +217,23 @@ if(CONFIG_TESTING_NET_TEST) ${SRCS}) endif() + if(CONFIG_TESTING_NET_CAN) + set(SRCS ${CMAKE_CURRENT_LIST_DIR}/can/test_can.c + ${CMAKE_CURRENT_LIST_DIR}/can/test_can_bind.c) + + nuttx_add_application( + NAME + cmocka_net_can + PRIORITY + ${CONFIG_TESTING_NET_TEST_PRIORITY} + STACKSIZE + ${CONFIG_TESTING_NET_TEST_STACKSIZE} + MODULE + ${CONFIG_TESTING_NET_TEST} + DEPENDS + cmocka + SRCS + ${SRCS}) + endif() + endif() diff --git a/testing/nettest/Kconfig b/testing/nettest/Kconfig index 4b9aeaf9f..e9fed0db8 100644 --- a/testing/nettest/Kconfig +++ b/testing/nettest/Kconfig @@ -89,4 +89,13 @@ config TESTING_NET_TIMESTAMP depends on NET_TIMESTAMP && NET_PKT default n +config TESTING_NET_CAN + bool "Enable cmocka net CAN socket test" + depends on NET_CAN && NET_LOOPBACK && NETDEV_IFINDEX + default y + ---help--- + Test that a CAN_RAW socket binds only to a CAN device or to + index 0 (all CAN devices), and that an unbound socket cannot send + (cmocka_net_can). + endif diff --git a/testing/nettest/Makefile b/testing/nettest/Makefile index 1fff32496..ff4c9aec2 100644 --- a/testing/nettest/Makefile +++ b/testing/nettest/Makefile @@ -109,5 +109,11 @@ PROGNAME += cmocka_net_timestamp CSRCS += timestamp/test_timestamp_common.c endif +ifeq ($(CONFIG_TESTING_NET_CAN),y) +MAINSRC += can/test_can.c +PROGNAME += cmocka_net_can +CSRCS += can/test_can_bind.c +endif + endif include $(APPDIR)/Application.mk diff --git a/testing/nettest/can/test_can.c b/testing/nettest/can/test_can.c new file mode 100644 index 000000000..ddb2bf4ca --- /dev/null +++ b/testing/nettest/can/test_can.c @@ -0,0 +1,54 @@ +/**************************************************************************** + * apps/testing/nettest/can/test_can.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <setjmp.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdint.h> +#include <cmocka.h> + +#include "test_can.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(int argc, FAR char *argv[]) +{ + /* test_can_bind_lo writes a frame if its bind() succeeds: it runs last */ + + const struct CMUnitTest can_tests[] = + { + cmocka_unit_test(test_can_bind_nodev), + cmocka_unit_test(test_can_bind_any), + cmocka_unit_test(test_can_bind_can0), + cmocka_unit_test(test_can_bind_todev), + cmocka_unit_test(test_can_bind_sendto), + cmocka_unit_test(test_can_bind_lo), + }; + + return cmocka_run_group_tests(can_tests, NULL, NULL); +} diff --git a/testing/nettest/can/test_can.h b/testing/nettest/can/test_can.h new file mode 100644 index 000000000..2c1cb9ad0 --- /dev/null +++ b/testing/nettest/can/test_can.h @@ -0,0 +1,52 @@ +/**************************************************************************** + * apps/testing/nettest/can/test_can.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __APPS_TESTING_NETTEST_CAN_TEST_CAN_H +#define __APPS_TESTING_NETTEST_CAN_TEST_CAN_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/compiler.h> + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: test_can_bind_* + * + * Description: + * bind() of a CAN_RAW socket: only a CAN device, or index 0 (all CAN + * devices), can be bound. An unbound socket cannot send. + * + ****************************************************************************/ + +void test_can_bind_nodev(FAR void **state); +void test_can_bind_any(FAR void **state); +void test_can_bind_can0(FAR void **state); +void test_can_bind_todev(FAR void **state); +void test_can_bind_sendto(FAR void **state); +void test_can_bind_lo(FAR void **state); + +#endif /* __APPS_TESTING_NETTEST_CAN_TEST_CAN_H */ diff --git a/testing/nettest/can/test_can_bind.c b/testing/nettest/can/test_can_bind.c new file mode 100644 index 000000000..267dc2a1f --- /dev/null +++ b/testing/nettest/can/test_can_bind.c @@ -0,0 +1,222 @@ +/**************************************************************************** + * apps/testing/nettest/can/test_can_bind.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <errno.h> +#include <setjmp.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <cmocka.h> +#include <net/if.h> +#include <sys/socket.h> + +#include <nuttx/can.h> + +#include "test_can.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define TEST_CAN_NODEV 99 /* An interface index with no device */ +#define TEST_CAN_WAIT_US (200 * 1000) /* Time for the poll after a write */ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int test_can_socket(void) +{ + int sd = socket(AF_CAN, SOCK_RAW | SOCK_CLOEXEC, CAN_RAW); + + assert_return_code(sd, errno); + return sd; +} + +/* bind() to 'ifindex'; the result, with errno saved in 'err' */ + +static int test_can_bindto(int sd, int ifindex, FAR int *err) +{ + struct sockaddr_can addr; + int ret; + + memset(&addr, 0, sizeof(addr)); + addr.can_family = AF_CAN; + addr.can_ifindex = ifindex; + ret = bind(sd, (FAR struct sockaddr *)&addr, sizeof(addr)); + *err = ret < 0 ? errno : 0; + return ret; +} + +static void test_can_frame(FAR struct can_frame *frame) +{ + memset(frame, 0, sizeof(*frame)); + frame->can_id = 0x123; + frame->can_dlc = 1; + frame->data[0] = 0x5a; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: test_can_bind_nodev + ****************************************************************************/ + +void test_can_bind_nodev(FAR void **state) +{ + int sd = test_can_socket(); + int err; + + assert_int_equal(test_can_bindto(sd, TEST_CAN_NODEV, &err), -1); + assert_int_equal(err, ENODEV); + close(sd); +} + +/**************************************************************************** + * Name: test_can_bind_any + ****************************************************************************/ + +void test_can_bind_any(FAR void **state) +{ + int sd = test_can_socket(); + int err; + + assert_int_equal(test_can_bindto(sd, 0, &err), 0); + close(sd); +} + +/**************************************************************************** + * Name: test_can_bind_can0 + ****************************************************************************/ + +void test_can_bind_can0(FAR void **state) +{ + int ifindex = if_nametoindex("can0"); + int sd; + int err; + + if (ifindex <= 0) + { + skip(); + } + + sd = test_can_socket(); + assert_int_equal(test_can_bindto(sd, ifindex, &err), 0); + close(sd); +} + +/**************************************************************************** + * Name: test_can_bind_todev + * + * Description: + * SO_BINDTODEVICE does not give a CAN socket a device: write() fails. + * + ****************************************************************************/ + +void test_can_bind_todev(FAR void **state) +{ +#ifdef CONFIG_NET_BINDTODEVICE + struct can_frame frame; + int sd = test_can_socket(); + int ret; + + assert_return_code(setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, "lo", 3), + errno); + test_can_frame(&frame); + ret = write(sd, &frame, sizeof(frame)); + usleep(TEST_CAN_WAIT_US); + assert_int_equal(ret, -1); + close(sd); +#else + skip(); +#endif +} + +/**************************************************************************** + * Name: test_can_bind_sendto + * + * Description: + * sendto() does not use its address: an unbound socket cannot send. + * + ****************************************************************************/ + +void test_can_bind_sendto(FAR void **state) +{ + struct sockaddr_can addr; + struct can_frame frame; + int sd = test_can_socket(); + int ret; + + memset(&addr, 0, sizeof(addr)); + addr.can_family = AF_CAN; + addr.can_ifindex = if_nametoindex("lo"); + test_can_frame(&frame); + ret = sendto(sd, &frame, sizeof(frame), 0, (FAR struct sockaddr *)&addr, + sizeof(addr)); + usleep(TEST_CAN_WAIT_US); + assert_int_equal(ret, -1); + close(sd); +} + +/**************************************************************************** + * Name: test_can_bind_lo + * + * Description: + * bind() to the loopback device fails with ENODEV. If it succeeds, a + * write follows, as a program would do. + * + ****************************************************************************/ + +void test_can_bind_lo(FAR void **state) +{ + struct can_frame frame; + int ifindex = if_nametoindex("lo"); + int sd; + int ret; + int err; + + assert_true(ifindex > 0); + sd = test_can_socket(); + ret = test_can_bindto(sd, ifindex, &err); + if (ret == 0) + { + /* The result does not matter: the kernel must not stop */ + + test_can_frame(&frame); + write(sd, &frame, sizeof(frame)); + usleep(TEST_CAN_WAIT_US); + } + + close(sd); + assert_int_equal(ret, -1); + assert_int_equal(err, ENODEV); +}
