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);
+}

Reply via email to