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


The following commit(s) were added to refs/heads/master by this push:
     new 964099ffc testing/nettest: Add a test of dual-stack UDP sockets.
964099ffc is described below

commit 964099ffc3250bf6c079115bb85180229e2365fe
Author: Marco Casaroli <[email protected]>
AuthorDate: Mon Nov 9 17:27:41 2026 +0100

    testing/nettest: Add a test of dual-stack UDP sockets.
    
    Add cmocka_net_udp (testing/nettest/udp, CONFIG_TESTING_NET_UDP, default
    y like the other nettest programs).  It runs over the loopback device
    and checks UDP sockets of AF_INET and AF_INET6 on one port:
    
    - IPV6_V6ONLY: 0 by default; without it an IPv6 socket on [::] gets an
      IPv4 datagram from an IPv4-mapped address, with it the socket gets
      none and sendto() and connect() to an IPv4-mapped address fail with
      ENETUNREACH; it can change only before bind() (EINVAL after).  A TCP
      socket of AF_INET6 is always IPv6-only: 1 is accepted, 0 fails with
      ENOPROTOOPT, an IPv6 listener gets no IPv4 connection.
    - Delivery: an IPv4 socket gets no IPv6 datagram, alone on its port and
      next to an IPv6 socket; an IPv6 socket on ::1 gets no IPv4 datagram;
      after connect() to [::], and with sendto() to [::] or 0.0.0.0, a
      datagram goes to the loopback address.
    - bind(): a dual-stack IPv6 socket and an IPv4 socket cannot use the
      same port (EADDRINUSE in both orders); with IPV6_V6ONLY, with
      SO_REUSEADDR on both, or with the IPv6 socket on ::1 they can.
    
    Each test keeps its sockets in the test state, and the teardown closes
    them, also when an assertion ends the test.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 testing/nettest/CMakeLists.txt        |  23 +++
 testing/nettest/Kconfig               |  11 ++
 testing/nettest/Makefile              |   7 +
 testing/nettest/udp/test_udp.c        |  79 +++++++++
 testing/nettest/udp/test_udp.h        | 165 ++++++++++++++++++
 testing/nettest/udp/test_udp_bind.c   | 212 +++++++++++++++++++++++
 testing/nettest/udp/test_udp_common.c | 226 ++++++++++++++++++++++++
 testing/nettest/udp/test_udp_family.c | 237 +++++++++++++++++++++++++
 testing/nettest/udp/test_udp_v6only.c | 317 ++++++++++++++++++++++++++++++++++
 9 files changed, 1277 insertions(+)

diff --git a/testing/nettest/CMakeLists.txt b/testing/nettest/CMakeLists.txt
index 2b506689a..760621931 100644
--- a/testing/nettest/CMakeLists.txt
+++ b/testing/nettest/CMakeLists.txt
@@ -50,6 +50,29 @@ if(CONFIG_TESTING_NET_TEST)
       ${SRCS})
   endif()
 
+  if(CONFIG_TESTING_NET_UDP)
+    set(SRCS
+        ${CMAKE_CURRENT_LIST_DIR}/udp/test_udp.c
+        ${CMAKE_CURRENT_LIST_DIR}/udp/test_udp_common.c
+        ${CMAKE_CURRENT_LIST_DIR}/udp/test_udp_v6only.c
+        ${CMAKE_CURRENT_LIST_DIR}/udp/test_udp_family.c
+        ${CMAKE_CURRENT_LIST_DIR}/udp/test_udp_bind.c)
+
+    nuttx_add_application(
+      NAME
+      cmocka_net_udp
+      PRIORITY
+      ${CONFIG_TESTING_NET_TEST_PRIORITY}
+      STACKSIZE
+      ${CONFIG_TESTING_NET_TEST_STACKSIZE}
+      MODULE
+      ${CONFIG_TESTING_NET_TEST}
+      DEPENDS
+      cmocka
+      SRCS
+      ${SRCS})
+  endif()
+
   if(CONFIG_TESTING_NET_LOCAL)
     set(SRCS
         ${CMAKE_CURRENT_LIST_DIR}/local/test_local.c
diff --git a/testing/nettest/Kconfig b/testing/nettest/Kconfig
index c4a089639..4b9aeaf9f 100644
--- a/testing/nettest/Kconfig
+++ b/testing/nettest/Kconfig
@@ -35,6 +35,17 @@ config TESTING_NET_TCP_PORT
 
 endif
 
+config TESTING_NET_UDP
+       bool "Enable cmocka net udp test"
+       depends on NET_UDP && !NET_UDP_NO_STACK
+       depends on NET_IPv4 && NET_IPv6 && NET_LOOPBACK && NET_SOCKOPTS
+       default y
+       ---help---
+               Test UDP sockets of AF_INET and AF_INET6 on one port over the
+               loopback device: IPV6_V6ONLY (also on TCP sockets), the delivery
+               of IPv4 and IPv6 datagrams, and EADDRINUSE from bind()
+               (cmocka_net_udp).
+
 config TESTING_NET_LOCAL
        bool "Enable cmocka net local test"
        depends on NET_LOCAL && NET_LOCAL_SCM
diff --git a/testing/nettest/Makefile b/testing/nettest/Makefile
index 6e1ab5784..1fff32496 100644
--- a/testing/nettest/Makefile
+++ b/testing/nettest/Makefile
@@ -45,6 +45,13 @@ endif
 
 endif
 
+ifeq ($(CONFIG_TESTING_NET_UDP),y)
+MAINSRC  += udp/test_udp.c
+PROGNAME += cmocka_net_udp
+CSRCS    += udp/test_udp_common.c udp/test_udp_v6only.c
+CSRCS    += udp/test_udp_family.c udp/test_udp_bind.c
+endif
+
 ifeq ($(CONFIG_TESTING_NET_LOCAL),y)
 MAINSRC  += local/test_local.c
 PROGNAME += cmocka_net_local
diff --git a/testing/nettest/udp/test_udp.c b/testing/nettest/udp/test_udp.c
new file mode 100644
index 000000000..584af4f4b
--- /dev/null
+++ b/testing/nettest/udp/test_udp.c
@@ -0,0 +1,79 @@
+/****************************************************************************
+ * apps/testing/nettest/udp/test_udp.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 <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <cmocka.h>
+
+#include "test_udp.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define TEST_UDP(f) \
+  cmocka_unit_test_setup_teardown(f, test_udp_setup, test_udp_teardown)
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int main(int argc, FAR char *argv[])
+{
+  const struct CMUnitTest udp_tests[] =
+    {
+      TEST_UDP(test_udp_v6only_default),
+      TEST_UDP(test_udp_v6only_mapped),
+      TEST_UDP(test_udp_v6only_set0),
+      TEST_UDP(test_udp_v6only_set1),
+      TEST_UDP(test_udp_v6only_both),
+      TEST_UDP(test_udp_v6only_send),
+      TEST_UDP(test_udp_v6only_bound),
+#if defined(CONFIG_NET_TCP) && defined(CONFIG_NET_TCPBACKLOG)
+      TEST_UDP(test_udp_v6only_tcp_set1),
+      TEST_UDP(test_udp_v6only_tcp_set0),
+      TEST_UDP(test_udp_v6only_tcp_ipv4),
+      TEST_UDP(test_udp_v6only_tcp_bound),
+#endif
+      TEST_UDP(test_udp_family_alone),
+      TEST_UDP(test_udp_family_both),
+      TEST_UDP(test_udp_family_v6addr),
+      TEST_UDP(test_udp_family_connect),
+      TEST_UDP(test_udp_family_sendto6),
+      TEST_UDP(test_udp_family_sendto4),
+      TEST_UDP(test_udp_bind_v6_v4),
+      TEST_UDP(test_udp_bind_v4_v6),
+      TEST_UDP(test_udp_bind_v6only_v4),
+      TEST_UDP(test_udp_bind_v4_v6only),
+      TEST_UDP(test_udp_bind_reuse),
+      TEST_UDP(test_udp_bind_v6addr),
+    };
+
+  return cmocka_run_group_tests(udp_tests, NULL, NULL);
+}
diff --git a/testing/nettest/udp/test_udp.h b/testing/nettest/udp/test_udp.h
new file mode 100644
index 000000000..f7860054d
--- /dev/null
+++ b/testing/nettest/udp/test_udp.h
@@ -0,0 +1,165 @@
+/****************************************************************************
+ * apps/testing/nettest/udp/test_udp.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_UDP_TEST_UDP_H
+#define __APPS_TESTING_NETTEST_UDP_TEST_UDP_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdbool.h>
+#include <netinet/in.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define TEST_UDP_PORT    5100          /* First port; each test has its own */
+#define TEST_UDP_WAIT_US (200 * 1000)  /* Time for lo to deliver */
+#define TEST_UDP_NSOCKS  4             /* Sockets of one test */
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* The sockets of one test, closed by test_udp_teardown() also when an
+ * assertion ends the test.
+ */
+
+struct test_udp_state_s
+{
+  int sd[TEST_UDP_NSOCKS];
+  int nsd;
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: test_udp_setup, test_udp_teardown
+ ****************************************************************************/
+
+int test_udp_setup(FAR void **state);
+int test_udp_teardown(FAR void **state);
+
+/****************************************************************************
+ * Name: test_udp_set_v6only, test_udp_get_v6only
+ *
+ * Description:
+ *   Set IPV6_V6ONLY (the result of setsockopt()), or read it (the value,
+ *   or -errno).
+ *
+ ****************************************************************************/
+
+int test_udp_set_v6only(int sd, int val);
+int test_udp_get_v6only(int sd);
+
+/****************************************************************************
+ * Name: test_udp_socket, test_udp_bind
+ *
+ * Description:
+ *   A socket of 'domain' and 'type', kept in 'state'.  test_udp_socket()
+ *   sets IPV6_V6ONLY to 'v6only' (if >= 0) and SO_REUSEADDR (if 'reuse').
+ *   test_udp_bind()
+ *   binds it to the wildcard address and 'port' and gives the result of
+ *   bind(), with errno in 'err'.
+ *
+ ****************************************************************************/
+
+int test_udp_socket(FAR void **state, int domain, int type, int v6only,
+                    bool reuse);
+int test_udp_bind(int sd, int domain, int port, FAR int *err);
+
+/****************************************************************************
+ * Name: test_udp_send4, test_udp_send6, test_udp_recv
+ *
+ * Description:
+ *   Send one datagram to 127.0.0.1 or ::1 at 'port' and let lo deliver
+ *   it.  Read one datagram without waiting: its size, or -errno.
+ *
+ ****************************************************************************/
+
+void test_udp_send4(int port);
+void test_udp_send6(int port);
+int test_udp_recv(int sd, FAR struct sockaddr_in6 *from);
+
+/****************************************************************************
+ * Name: test_udp_v6only_*
+ *
+ * Description:
+ *   IPV6_V6ONLY on UDP and TCP sockets of AF_INET6.
+ *
+ ****************************************************************************/
+
+void test_udp_v6only_default(FAR void **state);
+void test_udp_v6only_mapped(FAR void **state);
+void test_udp_v6only_set0(FAR void **state);
+void test_udp_v6only_set1(FAR void **state);
+void test_udp_v6only_both(FAR void **state);
+void test_udp_v6only_send(FAR void **state);
+void test_udp_v6only_bound(FAR void **state);
+#if defined(CONFIG_NET_TCP) && defined(CONFIG_NET_TCPBACKLOG)
+void test_udp_v6only_tcp_set1(FAR void **state);
+void test_udp_v6only_tcp_set0(FAR void **state);
+void test_udp_v6only_tcp_ipv4(FAR void **state);
+void test_udp_v6only_tcp_bound(FAR void **state);
+#endif
+
+/****************************************************************************
+ * Name: test_udp_family_*
+ *
+ * Description:
+ *   A UDP socket of AF_INET gets no IPv6 datagram, a UDP socket of AF_INET6
+ *   on ::1 gets no IPv4 datagram, and a datagram to [::] or 0.0.0.0 goes
+ *   to the loopback address.
+ *
+ ****************************************************************************/
+
+void test_udp_family_alone(FAR void **state);
+void test_udp_family_both(FAR void **state);
+void test_udp_family_v6addr(FAR void **state);
+void test_udp_family_connect(FAR void **state);
+void test_udp_family_sendto6(FAR void **state);
+void test_udp_family_sendto4(FAR void **state);
+
+/****************************************************************************
+ * Name: test_udp_bind_*
+ *
+ * Description:
+ *   A dual-stack UDP socket of AF_INET6 and a UDP socket of AF_INET cannot
+ *   bind the same port, in either order, unless the IPv6 socket has
+ *   IPV6_V6ONLY or both have SO_REUSEADDR.
+ *
+ ****************************************************************************/
+
+void test_udp_bind_v6_v4(FAR void **state);
+void test_udp_bind_v4_v6(FAR void **state);
+void test_udp_bind_v6only_v4(FAR void **state);
+void test_udp_bind_v4_v6only(FAR void **state);
+void test_udp_bind_reuse(FAR void **state);
+void test_udp_bind_v6addr(FAR void **state);
+
+#endif /* __APPS_TESTING_NETTEST_UDP_TEST_UDP_H */
diff --git a/testing/nettest/udp/test_udp_bind.c 
b/testing/nettest/udp/test_udp_bind.c
new file mode 100644
index 000000000..d9ebaa435
--- /dev/null
+++ b/testing/nettest/udp/test_udp_bind.c
@@ -0,0 +1,212 @@
+/****************************************************************************
+ * apps/testing/nettest/udp/test_udp_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 <errno.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <cmocka.h>
+#include <sys/socket.h>
+
+#include "test_udp.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: test_udp_bind_v6_v4
+ *
+ * Description:
+ *   A dual-stack IPv6 socket on [::]:p, then an IPv4 socket on p: the
+ *   second bind() fails with EADDRINUSE.
+ *
+ ****************************************************************************/
+
+void test_udp_bind_v6_v4(FAR void **state)
+{
+  int port = TEST_UDP_PORT + 20;
+  int r6;
+  int r4;
+  int s6;
+  int s4;
+  int err;
+
+  s6 = test_udp_socket(state, AF_INET6, SOCK_DGRAM, -1, false);
+  r6 = test_udp_bind(s6, AF_INET6, port, &err);
+  assert_return_code(r6, err);
+  s4 = test_udp_socket(state, AF_INET, SOCK_DGRAM, -1, false);
+  r4 = test_udp_bind(s4, AF_INET, port, &err);
+  assert_int_equal(r4, -1);
+  assert_int_equal(err, EADDRINUSE);
+}
+
+/****************************************************************************
+ * Name: test_udp_bind_v4_v6
+ *
+ * Description:
+ *   An IPv4 socket on p, then a dual-stack IPv6 socket on [::]:p: the
+ *   second bind() fails with EADDRINUSE.
+ *
+ ****************************************************************************/
+
+void test_udp_bind_v4_v6(FAR void **state)
+{
+  int port = TEST_UDP_PORT + 21;
+  int r6;
+  int r4;
+  int s6;
+  int s4;
+  int err;
+
+  s4 = test_udp_socket(state, AF_INET, SOCK_DGRAM, -1, false);
+  r4 = test_udp_bind(s4, AF_INET, port, &err);
+  assert_return_code(r4, err);
+  s6 = test_udp_socket(state, AF_INET6, SOCK_DGRAM, -1, false);
+  r6 = test_udp_bind(s6, AF_INET6, port, &err);
+  assert_int_equal(r6, -1);
+  assert_int_equal(err, EADDRINUSE);
+}
+
+/****************************************************************************
+ * Name: test_udp_bind_v6only_v4
+ *
+ * Description:
+ *   With IPV6_V6ONLY on the IPv6 socket, both binds succeed (IPv6 first).
+ *
+ ****************************************************************************/
+
+void test_udp_bind_v6only_v4(FAR void **state)
+{
+  int port = TEST_UDP_PORT + 22;
+  int r6;
+  int r4;
+  int s6;
+  int s4;
+  int err;
+
+  s6 = test_udp_socket(state, AF_INET6, SOCK_DGRAM, 1, false);
+  r6 = test_udp_bind(s6, AF_INET6, port, &err);
+  assert_return_code(r6, err);
+  s4 = test_udp_socket(state, AF_INET, SOCK_DGRAM, -1, false);
+  r4 = test_udp_bind(s4, AF_INET, port, &err);
+  assert_return_code(r4, err);
+}
+
+/****************************************************************************
+ * Name: test_udp_bind_v4_v6only
+ *
+ * Description:
+ *   With IPV6_V6ONLY on the IPv6 socket, both binds succeed (IPv4 first).
+ *
+ ****************************************************************************/
+
+void test_udp_bind_v4_v6only(FAR void **state)
+{
+  int port = TEST_UDP_PORT + 23;
+  int r6;
+  int r4;
+  int s6;
+  int s4;
+  int err;
+
+  s4 = test_udp_socket(state, AF_INET, SOCK_DGRAM, -1, false);
+  r4 = test_udp_bind(s4, AF_INET, port, &err);
+  assert_return_code(r4, err);
+  s6 = test_udp_socket(state, AF_INET6, SOCK_DGRAM, 1, false);
+  r6 = test_udp_bind(s6, AF_INET6, port, &err);
+  assert_return_code(r6, err);
+}
+
+/****************************************************************************
+ * Name: test_udp_bind_reuse
+ *
+ * Description:
+ *   With SO_REUSEADDR on both, a dual-stack IPv6 socket and an IPv4 socket
+ *   bind the same port, in both orders.
+ *
+ ****************************************************************************/
+
+void test_udp_bind_reuse(FAR void **state)
+{
+  int port = TEST_UDP_PORT + 24;
+  int r6;
+  int r4;
+  int s6;
+  int s4;
+  int err;
+
+  s6 = test_udp_socket(state, AF_INET6, SOCK_DGRAM, -1, true);
+  r6 = test_udp_bind(s6, AF_INET6, port, &err);
+  assert_return_code(r6, err);
+  s4 = test_udp_socket(state, AF_INET, SOCK_DGRAM, -1, true);
+  r4 = test_udp_bind(s4, AF_INET, port, &err);
+  assert_return_code(r4, err);
+
+  s4 = test_udp_socket(state, AF_INET, SOCK_DGRAM, -1, true);
+  r4 = test_udp_bind(s4, AF_INET, port + 1, &err);
+  assert_return_code(r4, err);
+  s6 = test_udp_socket(state, AF_INET6, SOCK_DGRAM, -1, true);
+  r6 = test_udp_bind(s6, AF_INET6, port + 1, &err);
+  assert_return_code(r6, err);
+}
+
+/****************************************************************************
+ * Name: test_udp_bind_v6addr
+ *
+ * Description:
+ *   An IPv4 socket on 0.0.0.0:p, then a dual-stack IPv6 socket on [::1]:p:
+ *   ::1 takes no IPv4 traffic, so both binds succeed.
+ *
+ ****************************************************************************/
+
+void test_udp_bind_v6addr(FAR void **state)
+{
+  struct sockaddr_in6 addr;
+  int port = TEST_UDP_PORT + 26;
+  int r6;
+  int r4;
+  int s6;
+  int s4;
+  int err;
+
+  s4 = test_udp_socket(state, AF_INET, SOCK_DGRAM, -1, false);
+  r4 = test_udp_bind(s4, AF_INET, port, &err);
+  assert_return_code(r4, err);
+
+  s6 = test_udp_socket(state, AF_INET6, SOCK_DGRAM, -1, false);
+  memset(&addr, 0, sizeof(addr));
+  addr.sin6_family = AF_INET6;
+  addr.sin6_port   = htons(port);
+  addr.sin6_addr   = in6addr_loopback;
+  r6  = bind(s6, (FAR struct sockaddr *)&addr, sizeof(addr));
+  err = r6 < 0 ? errno : 0;
+  assert_return_code(r6, err);
+}
diff --git a/testing/nettest/udp/test_udp_common.c 
b/testing/nettest/udp/test_udp_common.c
new file mode 100644
index 000000000..e6a2e97b9
--- /dev/null
+++ b/testing/nettest/udp/test_udp_common.c
@@ -0,0 +1,226 @@
+/****************************************************************************
+ * apps/testing/nettest/udp/test_udp_common.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 <errno.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <cmocka.h>
+#include <sys/socket.h>
+
+#include "test_udp.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: test_udp_setup
+ ****************************************************************************/
+
+int test_udp_setup(FAR void **state)
+{
+  FAR struct test_udp_state_s *udp_state;
+
+  udp_state = zalloc(sizeof(*udp_state));
+  assert_non_null(udp_state);
+  *state = udp_state;
+  return 0;
+}
+
+/****************************************************************************
+ * Name: test_udp_teardown
+ ****************************************************************************/
+
+int test_udp_teardown(FAR void **state)
+{
+  FAR struct test_udp_state_s *udp_state = *state;
+  int i;
+
+  for (i = 0; i < udp_state->nsd; i++)
+    {
+      close(udp_state->sd[i]);
+    }
+
+  free(udp_state);
+  return 0;
+}
+
+/****************************************************************************
+ * Name: test_udp_set_v6only
+ ****************************************************************************/
+
+int test_udp_set_v6only(int sd, int val)
+{
+  return setsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
+}
+
+/****************************************************************************
+ * Name: test_udp_get_v6only
+ ****************************************************************************/
+
+int test_udp_get_v6only(int sd)
+{
+  socklen_t len = sizeof(int);
+  int val = -1;
+
+  if (getsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, &val, &len) < 0)
+    {
+      return -errno;
+    }
+
+  return val;
+}
+
+/****************************************************************************
+ * Name: test_udp_socket
+ ****************************************************************************/
+
+int test_udp_socket(FAR void **state, int domain, int type, int v6only,
+                    bool reuse)
+{
+  FAR struct test_udp_state_s *udp_state = *state;
+  int one = 1;
+  int ret;
+  int sd;
+
+  assert_true(udp_state->nsd < TEST_UDP_NSOCKS);
+  sd = socket(domain, type | SOCK_CLOEXEC, 0);
+  assert_return_code(sd, errno);
+  udp_state->sd[udp_state->nsd++] = sd;
+
+  if (v6only >= 0)
+    {
+      ret = test_udp_set_v6only(sd, v6only);
+      assert_return_code(ret, errno);
+    }
+
+  if (reuse)
+    {
+      ret = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+      assert_return_code(ret, errno);
+    }
+
+  return sd;
+}
+
+/****************************************************************************
+ * Name: test_udp_bind
+ ****************************************************************************/
+
+int test_udp_bind(int sd, int domain, int port, FAR int *err)
+{
+  struct sockaddr_in6 addr6;
+  struct sockaddr_in addr4;
+  int ret;
+
+  if (domain == AF_INET)
+    {
+      memset(&addr4, 0, sizeof(addr4));
+      addr4.sin_family      = AF_INET;
+      addr4.sin_port        = htons(port);
+      addr4.sin_addr.s_addr = htonl(INADDR_ANY);
+      ret = bind(sd, (FAR struct sockaddr *)&addr4, sizeof(addr4));
+    }
+  else
+    {
+      memset(&addr6, 0, sizeof(addr6));
+      addr6.sin6_family = AF_INET6;
+      addr6.sin6_port   = htons(port);
+      addr6.sin6_addr   = in6addr_any;
+      ret = bind(sd, (FAR struct sockaddr *)&addr6, sizeof(addr6));
+    }
+
+  *err = ret < 0 ? errno : 0;
+  return ret;
+}
+
+/****************************************************************************
+ * Name: test_udp_send4
+ ****************************************************************************/
+
+void test_udp_send4(int port)
+{
+  struct sockaddr_in addr;
+  int ret;
+  int sd;
+
+  sd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+  assert_return_code(sd, errno);
+
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family      = AF_INET;
+  addr.sin_port        = htons(port);
+  addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+  ret = sendto(sd, "v4", 2, 0, (FAR struct sockaddr *)&addr, sizeof(addr));
+  close(sd);
+  assert_int_equal(ret, 2);
+  usleep(TEST_UDP_WAIT_US);
+}
+
+/****************************************************************************
+ * Name: test_udp_send6
+ ****************************************************************************/
+
+void test_udp_send6(int port)
+{
+  struct sockaddr_in6 addr;
+  int ret;
+  int sd;
+
+  sd = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+  assert_return_code(sd, errno);
+
+  memset(&addr, 0, sizeof(addr));
+  addr.sin6_family = AF_INET6;
+  addr.sin6_port   = htons(port);
+  addr.sin6_addr   = in6addr_loopback;
+  ret = sendto(sd, "v6", 2, 0, (FAR struct sockaddr *)&addr, sizeof(addr));
+  close(sd);
+  assert_int_equal(ret, 2);
+  usleep(TEST_UDP_WAIT_US);
+}
+
+/****************************************************************************
+ * Name: test_udp_recv
+ ****************************************************************************/
+
+int test_udp_recv(int sd, FAR struct sockaddr_in6 *from)
+{
+  socklen_t len = sizeof(*from);
+  char buf[16];
+  int ret;
+
+  memset(from, 0, sizeof(*from));
+  ret = recvfrom(sd, buf, sizeof(buf), MSG_DONTWAIT,
+                 (FAR struct sockaddr *)from, &len);
+  return ret < 0 ? -errno : ret;
+}
diff --git a/testing/nettest/udp/test_udp_family.c 
b/testing/nettest/udp/test_udp_family.c
new file mode 100644
index 000000000..d3f0dbffc
--- /dev/null
+++ b/testing/nettest/udp/test_udp_family.c
@@ -0,0 +1,237 @@
+/****************************************************************************
+ * apps/testing/nettest/udp/test_udp_family.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 <errno.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <cmocka.h>
+#include <sys/socket.h>
+
+#include "test_udp.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: test_udp_family_alone
+ *
+ * Description:
+ *   An IPv4 socket alone on its port gets no IPv6 datagram.
+ *
+ ****************************************************************************/
+
+void test_udp_family_alone(FAR void **state)
+{
+  struct sockaddr_in6 from;
+  int port = TEST_UDP_PORT + 10;
+  int ret;
+  int err;
+  int s4;
+
+  s4  = test_udp_socket(state, AF_INET, SOCK_DGRAM, -1, false);
+  ret = test_udp_bind(s4, AF_INET, port, &err);
+  assert_return_code(ret, err);
+  test_udp_send6(port);
+  ret = test_udp_recv(s4, &from);
+  assert_int_equal(ret, -EAGAIN);
+}
+
+/****************************************************************************
+ * Name: test_udp_family_both
+ *
+ * Description:
+ *   An IPv4 socket, then an IPv6 socket with IPV6_V6ONLY on the same port:
+ *   the IPv6 datagram goes to the IPv6 socket only.
+ *
+ ****************************************************************************/
+
+void test_udp_family_both(FAR void **state)
+{
+  struct sockaddr_in6 from;
+  int port = TEST_UDP_PORT + 11;
+  int r4;
+  int r6;
+  int s4;
+  int s6;
+  int err;
+
+  s4 = test_udp_socket(state, AF_INET, SOCK_DGRAM, -1, false);
+  r4 = test_udp_bind(s4, AF_INET, port, &err);
+  assert_return_code(r4, err);
+  s6 = test_udp_socket(state, AF_INET6, SOCK_DGRAM, 1, false);
+  r6 = test_udp_bind(s6, AF_INET6, port, &err);
+  assert_return_code(r6, err);
+  test_udp_send6(port);
+  r6 = test_udp_recv(s6, &from);
+  r4 = test_udp_recv(s4, &from);
+  assert_int_equal(r4, -EAGAIN);
+  assert_int_equal(r6, 2);
+}
+
+/****************************************************************************
+ * Name: test_udp_family_v6addr
+ *
+ * Description:
+ *   A UDP socket of AF_INET6 on [::1]:p gets no IPv4 datagram to
+ *   127.0.0.1:p: ::1 is not an IPv4 address.
+ *
+ ****************************************************************************/
+
+void test_udp_family_v6addr(FAR void **state)
+{
+  struct sockaddr_in6 from;
+  struct sockaddr_in6 addr;
+  int port = TEST_UDP_PORT + 12;
+  int ret;
+  int err;
+  int s6;
+
+  s6 = test_udp_socket(state, AF_INET6, SOCK_DGRAM, -1, false);
+  memset(&addr, 0, sizeof(addr));
+  addr.sin6_family = AF_INET6;
+  addr.sin6_port   = htons(port);
+  addr.sin6_addr   = in6addr_loopback;
+  ret = bind(s6, (FAR struct sockaddr *)&addr, sizeof(addr));
+  err = ret < 0 ? errno : 0;
+  assert_return_code(ret, err);
+  test_udp_send4(port);
+  ret = test_udp_recv(s6, &from);
+  assert_int_equal(ret, -EAGAIN);
+}
+
+/****************************************************************************
+ * Name: test_udp_family_connect
+ *
+ * Description:
+ *   connect() to [::]:p connects to ::1, as connect() to 0.0.0.0 connects
+ *   to 127.0.0.1: a UDP socket of AF_INET6 on [::]:p gets the datagram.
+ *
+ ****************************************************************************/
+
+void test_udp_family_connect(FAR void **state)
+{
+  struct sockaddr_in6 from;
+  struct sockaddr_in6 addr;
+  int port = TEST_UDP_PORT + 13;
+  int ret;
+  int err;
+  int s6;
+  int sd;
+
+  s6  = test_udp_socket(state, AF_INET6, SOCK_DGRAM, -1, false);
+  ret = test_udp_bind(s6, AF_INET6, port, &err);
+  assert_return_code(ret, err);
+
+  sd = test_udp_socket(state, AF_INET6, SOCK_DGRAM, -1, false);
+  memset(&addr, 0, sizeof(addr));
+  addr.sin6_family = AF_INET6;
+  addr.sin6_port   = htons(port);
+  addr.sin6_addr   = in6addr_any;
+  ret = connect(sd, (FAR struct sockaddr *)&addr, sizeof(addr));
+  assert_return_code(ret, errno);
+  ret = send(sd, "v6", 2, 0);
+  assert_return_code(ret, errno);
+  usleep(TEST_UDP_WAIT_US);
+  ret = test_udp_recv(s6, &from);
+  assert_int_equal(ret, 2);
+  assert_true(IN6_IS_ADDR_LOOPBACK(&from.sin6_addr));
+}
+
+/****************************************************************************
+ * Name: test_udp_family_sendto6
+ *
+ * Description:
+ *   sendto() to [::]:p on a socket that is not connected sends to ::1.
+ *
+ ****************************************************************************/
+
+void test_udp_family_sendto6(FAR void **state)
+{
+  struct sockaddr_in6 from;
+  struct sockaddr_in6 addr;
+  int port = TEST_UDP_PORT + 14;
+  int ret;
+  int err;
+  int s6;
+  int sd;
+
+  s6  = test_udp_socket(state, AF_INET6, SOCK_DGRAM, -1, false);
+  ret = test_udp_bind(s6, AF_INET6, port, &err);
+  assert_return_code(ret, err);
+
+  sd = test_udp_socket(state, AF_INET6, SOCK_DGRAM, -1, false);
+  memset(&addr, 0, sizeof(addr));
+  addr.sin6_family = AF_INET6;
+  addr.sin6_port   = htons(port);
+  addr.sin6_addr   = in6addr_any;
+  ret = sendto(sd, "v6", 2, 0, (FAR struct sockaddr *)&addr, sizeof(addr));
+  assert_return_code(ret, errno);
+  usleep(TEST_UDP_WAIT_US);
+  ret = test_udp_recv(s6, &from);
+  assert_int_equal(ret, 2);
+  assert_true(IN6_IS_ADDR_LOOPBACK(&from.sin6_addr));
+}
+
+/****************************************************************************
+ * Name: test_udp_family_sendto4
+ *
+ * Description:
+ *   sendto() to 0.0.0.0:p on a socket that is not connected sends to
+ *   127.0.0.1.
+ *
+ ****************************************************************************/
+
+void test_udp_family_sendto4(FAR void **state)
+{
+  struct sockaddr_in6 from;
+  struct sockaddr_in addr;
+  int port = TEST_UDP_PORT + 15;
+  int ret;
+  int err;
+  int s4;
+  int sd;
+
+  s4  = test_udp_socket(state, AF_INET, SOCK_DGRAM, -1, false);
+  ret = test_udp_bind(s4, AF_INET, port, &err);
+  assert_return_code(ret, err);
+
+  sd = test_udp_socket(state, AF_INET, SOCK_DGRAM, -1, false);
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family      = AF_INET;
+  addr.sin_port        = htons(port);
+  addr.sin_addr.s_addr = htonl(INADDR_ANY);
+  ret = sendto(sd, "v4", 2, 0, (FAR struct sockaddr *)&addr, sizeof(addr));
+  assert_return_code(ret, errno);
+  usleep(TEST_UDP_WAIT_US);
+  ret = test_udp_recv(s4, &from);
+  assert_int_equal(ret, 2);
+}
diff --git a/testing/nettest/udp/test_udp_v6only.c 
b/testing/nettest/udp/test_udp_v6only.c
new file mode 100644
index 000000000..8d10fe671
--- /dev/null
+++ b/testing/nettest/udp/test_udp_v6only.c
@@ -0,0 +1,317 @@
+/****************************************************************************
+ * apps/testing/nettest/udp/test_udp_v6only.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 <errno.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <cmocka.h>
+#include <sys/socket.h>
+
+#include "test_udp.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: test_udp_v6only_default
+ ****************************************************************************/
+
+void test_udp_v6only_default(FAR void **state)
+{
+  int sd;
+
+  sd = test_udp_socket(state, AF_INET6, SOCK_DGRAM, -1, false);
+  assert_int_equal(test_udp_get_v6only(sd), 0);
+}
+
+/****************************************************************************
+ * Name: test_udp_v6only_mapped
+ *
+ * Description:
+ *   Without the option, an IPv6 socket on [::] gets an IPv4 datagram from
+ *   an IPv4-mapped address.
+ *
+ ****************************************************************************/
+
+void test_udp_v6only_mapped(FAR void **state)
+{
+  struct sockaddr_in6 from;
+  int port = TEST_UDP_PORT;
+  int ret;
+  int err;
+  int sd;
+
+  sd = test_udp_socket(state, AF_INET6, SOCK_DGRAM, -1, false);
+  ret = test_udp_bind(sd, AF_INET6, port, &err);
+  assert_return_code(ret, err);
+  test_udp_send4(port);
+  ret = test_udp_recv(sd, &from);
+  assert_int_equal(ret, 2);
+  assert_true(IN6_IS_ADDR_V4MAPPED(&from.sin6_addr));
+}
+
+/****************************************************************************
+ * Name: test_udp_v6only_set0
+ *
+ * Description:
+ *   Set 1, then 0 before bind(): the socket gets IPv4 datagrams.
+ *
+ ****************************************************************************/
+
+void test_udp_v6only_set0(FAR void **state)
+{
+  struct sockaddr_in6 from;
+  int port = TEST_UDP_PORT + 1;
+  int ret;
+  int err;
+  int sd;
+
+  sd = test_udp_socket(state, AF_INET6, SOCK_DGRAM, 1, false);
+  ret = test_udp_set_v6only(sd, 0);
+  assert_return_code(ret, errno);
+  assert_int_equal(test_udp_get_v6only(sd), 0);
+  ret = test_udp_bind(sd, AF_INET6, port, &err);
+  assert_return_code(ret, err);
+  test_udp_send4(port);
+  ret = test_udp_recv(sd, &from);
+  assert_int_equal(ret, 2);
+}
+
+/****************************************************************************
+ * Name: test_udp_v6only_set1
+ *
+ * Description:
+ *   With the option, an IPv6 socket on [::] gets no IPv4 datagram.
+ *
+ ****************************************************************************/
+
+void test_udp_v6only_set1(FAR void **state)
+{
+  struct sockaddr_in6 from;
+  int port = TEST_UDP_PORT + 2;
+  int ret;
+  int err;
+  int sd;
+
+  sd = test_udp_socket(state, AF_INET6, SOCK_DGRAM, 1, false);
+  assert_int_equal(test_udp_get_v6only(sd), 1);
+  ret = test_udp_bind(sd, AF_INET6, port, &err);
+  assert_return_code(ret, err);
+  test_udp_send4(port);
+  ret = test_udp_recv(sd, &from);
+  assert_int_equal(ret, -EAGAIN);
+}
+
+/****************************************************************************
+ * Name: test_udp_v6only_both
+ *
+ * Description:
+ *   An IPv6 socket with the option, then an IPv4 socket on the same port:
+ *   the IPv4 datagram goes to the IPv4 socket.
+ *
+ ****************************************************************************/
+
+void test_udp_v6only_both(FAR void **state)
+{
+  struct sockaddr_in6 from;
+  int port = TEST_UDP_PORT + 3;
+  int r6;
+  int r4;
+  int s6;
+  int s4;
+  int err;
+
+  s6 = test_udp_socket(state, AF_INET6, SOCK_DGRAM, 1, false);
+  r6 = test_udp_bind(s6, AF_INET6, port, &err);
+  assert_return_code(r6, err);
+  s4 = test_udp_socket(state, AF_INET, SOCK_DGRAM, -1, false);
+  r4 = test_udp_bind(s4, AF_INET, port, &err);
+  assert_return_code(r4, err);
+  test_udp_send4(port);
+  r6 = test_udp_recv(s6, &from);
+  r4 = test_udp_recv(s4, &from);
+  assert_int_equal(r6, -EAGAIN);
+  assert_int_equal(r4, 2);
+}
+
+/****************************************************************************
+ * Name: test_udp_v6only_send
+ *
+ * Description:
+ *   With the option, sendto() and connect() to ::ffff:127.0.0.1 fail with
+ *   ENETUNREACH.
+ *
+ ****************************************************************************/
+
+void test_udp_v6only_send(FAR void **state)
+{
+  struct sockaddr_in6 addr;
+  int ret;
+  int err;
+  int sd;
+
+  sd = test_udp_socket(state, AF_INET6, SOCK_DGRAM, 1, false);
+
+  memset(&addr, 0, sizeof(addr));
+  addr.sin6_family           = AF_INET6;
+  addr.sin6_port             = htons(TEST_UDP_PORT + 4);
+  addr.sin6_addr.s6_addr[10] = 0xff;
+  addr.sin6_addr.s6_addr[11] = 0xff;
+  addr.sin6_addr.s6_addr[12] = 127;
+  addr.sin6_addr.s6_addr[15] = 1;
+
+  ret = sendto(sd, "v6", 2, 0, (FAR struct sockaddr *)&addr, sizeof(addr));
+  err = ret < 0 ? errno : 0;
+  assert_int_equal(ret, -1);
+  assert_int_equal(err, ENETUNREACH);
+
+  ret = connect(sd, (FAR struct sockaddr *)&addr, sizeof(addr));
+  err = ret < 0 ? errno : 0;
+  assert_int_equal(ret, -1);
+  assert_int_equal(err, ENETUNREACH);
+}
+
+/****************************************************************************
+ * Name: test_udp_v6only_bound
+ *
+ * Description:
+ *   After bind(), setting the option fails with EINVAL.
+ *
+ ****************************************************************************/
+
+void test_udp_v6only_bound(FAR void **state)
+{
+  int ret;
+  int err;
+  int sd;
+
+  sd = test_udp_socket(state, AF_INET6, SOCK_DGRAM, -1, false);
+  ret = test_udp_bind(sd, AF_INET6, TEST_UDP_PORT + 5, &err);
+  assert_return_code(ret, err);
+  ret = test_udp_set_v6only(sd, 1);
+  err = ret < 0 ? errno : 0;
+  assert_int_equal(ret, -1);
+  assert_int_equal(err, EINVAL);
+}
+
+#if defined(CONFIG_NET_TCP) && defined(CONFIG_NET_TCPBACKLOG)
+/****************************************************************************
+ * Name: test_udp_v6only_tcp_set1
+ ****************************************************************************/
+
+void test_udp_v6only_tcp_set1(FAR void **state)
+{
+  int sd;
+
+  sd = test_udp_socket(state, AF_INET6, SOCK_STREAM, 1, false);
+  assert_int_equal(test_udp_get_v6only(sd), 1);
+}
+
+/****************************************************************************
+ * Name: test_udp_v6only_tcp_set0
+ *
+ * Description:
+ *   A TCP socket of AF_INET6 is always IPv6-only: 0 fails, get gives 1.
+ *
+ ****************************************************************************/
+
+void test_udp_v6only_tcp_set0(FAR void **state)
+{
+  int ret;
+  int err;
+  int sd;
+
+  sd = test_udp_socket(state, AF_INET6, SOCK_STREAM, -1, false);
+  ret = test_udp_set_v6only(sd, 0);
+  err = ret < 0 ? errno : 0;
+  assert_int_equal(ret, -1);
+  assert_int_equal(err, ENOPROTOOPT);
+  assert_int_equal(test_udp_get_v6only(sd), 1);
+}
+
+/****************************************************************************
+ * Name: test_udp_v6only_tcp_ipv4
+ *
+ * Description:
+ *   An IPv6 listener gets no IPv4 connection.
+ *
+ ****************************************************************************/
+
+void test_udp_v6only_tcp_ipv4(FAR void **state)
+{
+  struct sockaddr_in addr;
+  int port = TEST_UDP_PORT + 6;
+  int ret;
+  int err;
+  int ls;
+  int cs;
+
+  ls  = test_udp_socket(state, AF_INET6, SOCK_STREAM, -1, false);
+  ret = test_udp_bind(ls, AF_INET6, port, &err);
+  assert_return_code(ret, err);
+  ret = listen(ls, 2);
+  assert_return_code(ret, errno);
+
+  cs = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
+  assert_return_code(cs, errno);
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family      = AF_INET;
+  addr.sin_port        = htons(port);
+  addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+  ret = connect(cs, (FAR struct sockaddr *)&addr, sizeof(addr));
+  close(cs);
+  assert_int_equal(ret, -1);
+}
+
+/****************************************************************************
+ * Name: test_udp_v6only_tcp_bound
+ *
+ * Description:
+ *   After bind(), setting the option on a TCP socket fails with EINVAL.
+ *
+ ****************************************************************************/
+
+void test_udp_v6only_tcp_bound(FAR void **state)
+{
+  int ret;
+  int err;
+  int sd;
+
+  sd  = test_udp_socket(state, AF_INET6, SOCK_STREAM, -1, false);
+  ret = test_udp_bind(sd, AF_INET6, TEST_UDP_PORT + 7, &err);
+  assert_return_code(ret, err);
+  ret = test_udp_set_v6only(sd, 1);
+  err = ret < 0 ? errno : 0;
+  assert_int_equal(ret, -1);
+  assert_int_equal(err, EINVAL);
+}
+#endif

Reply via email to