diff options
| author | mzgrebnak <[email protected]> | 2026-05-28 22:23:22 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-05-28 16:23:22 -0400 |
| commit | 57410350d94bbcb5e6885d0fbc40c72b6d7ddd33 (patch) | |
| tree | 523f6e89bd960a4fbb3f849a87c7162a24639d9b | |
| parent | 5dca3d2af173318df6e0452bddddcbc34f459146 (diff) | |
Implemented BSD socket options improvements (#374)
● - initial support
- bsd: address PR review feedback
- Fix build failure: so_linger was stored on NX_TCP_SOCKET which has
no such field. Linger state is now kept in NX_BSD_SOCKET using the
new nx_bsd_option_linger field and the existing
NX_BSD_SOCKET_ENABLE_OPTION_LINGER flag.
- Fix sign-conversion warning in setsockopt(IP_TOS): read the value
as INT, validate range 0..0xFF, then cast to ULONG.
- Reject out-of-range INT values (< 0 or > 255) in
setsockopt(IP_TTL).
- Add lower-bound check for IPPROTO_IP options in getsockopt and
setsockopt so that SO_* option numbers are no longer silently
accepted at the IPPROTO_IP level.
- Add null check for raw sockets in IP_TOS and IP_TTL get/set paths;
return ENOPROTOOPT instead of dereferencing a NULL pointer.
- Validate
*option_length before writing in SO_BROADCAST, TCP_NODELAY,
SO_LINGER and IP_TOS getsockopt paths; set
*option_length to the
actual size returned on success.
- Separate ENOPROTOOPT (wrong socket type) from EINVAL (wrong length)
in SO_LINGER get/set error handling.
- Remove unused so_linger local variable from getsockopt.
- Replace C++-style // comments in the close/linger path with C99
/*
*/ comments.
- Add regression test netx_bsd_socket_options_test covering SO_LINGER,
IP_TOS, IP_TTL, SO_BROADCAST and TCP_NODELAY round-trips and error
paths; register in bsd_test_cases in regression/CMakeLists.txt.
Co-authored-by: Frédéric Desbiens [email protected]
Co-authored-by: Copilot [email protected]
| -rw-r--r-- | addons/BSD/nxd_bsd.c | 413 | ||||
| -rw-r--r-- | addons/BSD/nxd_bsd.h | 5 | ||||
| -rw-r--r-- | test/cmake/netxduo/regression/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | test/regression/bsd_test/netx_bsd_socket_options_test.c | 335 |
4 files changed, 731 insertions, 25 deletions
diff --git a/addons/BSD/nxd_bsd.c b/addons/BSD/nxd_bsd.c index ef27b0dd..202b39be 100644 --- a/addons/BSD/nxd_bsd.c +++ b/addons/BSD/nxd_bsd.c @@ -8,8 +8,7 @@ * * SPDX-License-Identifier: MIT **************************************************************************/ - -/**************************************************************************/ +/* Some portions generated by Copilot (claude-sonnet-4.6). */ /**************************************************************************/ /** */ /** BSD 4.3 Socket API Compatible Interface to NetX Duo */ @@ -4891,7 +4890,23 @@ UINT index; /* Release the mutex while disconnecting. */ tx_mutex_put(nx_bsd_protection_ptr); - nx_tcp_socket_disconnect(tcp_socket_ptr, timeout); + if (!(bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_OPTION_LINGER)) + { + /* SO_LINGER disabled: normal graceful close. */ + nx_tcp_socket_disconnect(tcp_socket_ptr, timeout); + } + else if (bsd_socket_ptr -> nx_bsd_option_linger.l_linger == 0) + { + /* l_linger == 0: abort immediately with RST. */ + nx_tcp_socket_disconnect(tcp_socket_ptr, NX_NO_WAIT); + } + else + { + /* l_linger > 0: wait up to l_linger seconds for graceful close. */ + ULONG ticks = (ULONG)(bsd_socket_ptr -> nx_bsd_option_linger.l_linger) * NX_IP_PERIODIC_RATE; + + nx_tcp_socket_disconnect(tcp_socket_ptr, ticks); + } tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); @@ -6092,7 +6107,7 @@ ULONG ticks; if (option_level == IPPROTO_IP) { - if((option_name <= SO_MAX) || (option_name > IP_OPTION_MAX)) + if ((option_name < IP_TOS) || (option_name > IP_OPTION_MAX)) { /* Error, one or more invalid arguments. */ @@ -6119,6 +6134,20 @@ ULONG ticks; return NX_SOC_ERROR; } } + else if(option_level == IPPROTO_TCP) + { + if((option_name != TCP_NODELAY)) + { + + /* Error, one or more invalid arguments. */ + + /* Set the socket error if extended socket options enabled. */ + nx_bsd_set_errno(ENOPROTOOPT); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + } else { @@ -6155,6 +6184,44 @@ ULONG ticks; switch (option_name) { + case IP_TOS: + + if (*option_length < (INT)sizeof(INT)) + { + + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + nx_bsd_set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + else if (bsd_socket_ptr -> nx_bsd_socket_tcp_socket) + { + ULONG tmp_option_value = bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_type_of_service; + *((INT *)option_value) = (INT)(tmp_option_value >> 16); + } + else if (bsd_socket_ptr -> nx_bsd_socket_udp_socket) + { + ULONG tmp_option_value = bsd_socket_ptr -> nx_bsd_socket_udp_socket -> nx_udp_socket_type_of_service; + *((INT *)option_value) = (INT)(tmp_option_value >> 16); + } + else + { + tx_mutex_put(nx_bsd_protection_ptr); + + /* Raw sockets do not support IP_TOS. */ + nx_bsd_set_errno(ENOPROTOOPT); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + + *option_length = (INT)sizeof(INT); + + break; + case SO_ERROR: { @@ -6195,6 +6262,26 @@ ULONG ticks; break; + case SO_BROADCAST: + + if (*option_length < (INT)sizeof(INT)) + { + + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + nx_bsd_set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + + /* This is the default behavior of NetX. All sockets have this capability. */ + *((INT *)option_value) = 1; + *option_length = (INT)sizeof(INT); + + break; + case SO_KEEPALIVE: /* Determine if NetX Duo supports keepalive. */ @@ -6222,6 +6309,40 @@ ULONG ticks; break; + case SO_LINGER: + + /* Only available to TCP BSD sockets. */ + if (!bsd_socket_ptr -> nx_bsd_socket_tcp_socket) + { + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + nx_bsd_set_errno(ENOPROTOOPT); + + /* Return an error status. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + + if (*option_length < (INT)sizeof(struct nx_bsd_linger)) + { + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + nx_bsd_set_errno(EINVAL); + + /* Return an error status. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + + (*((struct nx_bsd_linger *)option_value)).l_onoff = + (bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_OPTION_LINGER) ? 1 : 0; + (*((struct nx_bsd_linger *)option_value)).l_linger = bsd_socket_ptr -> nx_bsd_option_linger.l_linger; + *option_length = (INT)sizeof(struct nx_bsd_linger); + + break; + case SO_RCVTIMEO: /* Check if the receive time out is set. */ @@ -6250,6 +6371,20 @@ ULONG ticks; case SO_RCVBUF: + /* Only available to TCP sockets. */ + if (!bsd_socket_ptr -> nx_bsd_socket_tcp_socket) + { + + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + nx_bsd_set_errno(ENOPROTOOPT); + + /* Return an error status. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + soc_window_size = (struct nx_bsd_sock_winsize *)option_value; soc_window_size -> winsize = (INT)(bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_rx_window_default); *option_length = sizeof(soc_window_size); @@ -6277,10 +6412,31 @@ ULONG ticks; break; + case TCP_NODELAY: + + if (*option_length < (INT)sizeof(INT)) + { + + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + nx_bsd_set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + + /* This is the default behavior of NetX. All sockets have this attribute. */ + *((INT *)option_value) = 1; + *option_length = (INT)sizeof(INT); + + break; + + case IP_TTL: case IP_MULTICAST_TTL: /* Validate the option length. */ - if(*option_length != sizeof(UCHAR)) + if (*option_length < (INT)sizeof(UCHAR)) { tx_mutex_put(nx_bsd_protection_ptr); @@ -6305,23 +6461,63 @@ ULONG ticks; return NX_SOC_ERROR; } - /* Make sure socket is UDP type. */ - if(bsd_socket_ptr -> nx_bsd_socket_udp_socket == NX_NULL) + /* Socket is UDP type. */ + if (bsd_socket_ptr -> nx_bsd_socket_udp_socket != NX_NULL) + { + + /* Get the TTL value. */ + *(UCHAR *)option_value = (UCHAR)(bsd_socket_ptr -> nx_bsd_socket_udp_socket -> nx_udp_socket_time_to_live); + } + /* Socket is TCP type. */ + else if (bsd_socket_ptr -> nx_bsd_socket_tcp_socket != NX_NULL) + { + + if (option_name == IP_MULTICAST_TTL) + { + + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + nx_bsd_set_errno(ENOPROTOOPT); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + + /* Get the TTL value. */ + *(UCHAR *)option_value = (UCHAR)(bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_time_to_live); + } + else { tx_mutex_put(nx_bsd_protection_ptr); - /* Set the socket error if extended socket options enabled. */ + /* Raw sockets do not support IP_TTL/IP_MULTICAST_TTL. */ nx_bsd_set_errno(ENOPROTOOPT); NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); return NX_SOC_ERROR; } - /* Set the TTL value. */ - *(UCHAR*)option_value = (UCHAR)(bsd_socket_ptr -> nx_bsd_socket_udp_socket -> nx_udp_socket_time_to_live); + *option_length = (INT)sizeof(UCHAR); + break; + case IP_MULTICAST_IF: + + /* This is not supported yet. */ + + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + nx_bsd_set_errno(ENOPROTOOPT); + + /* Return an error status. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + + break; + default: tx_mutex_put(nx_bsd_protection_ptr); @@ -6431,7 +6627,7 @@ ULONG physical_addr_lsw; if (option_level == IPPROTO_IP) { - if((option_name <= SO_MAX) || (option_name > IP_OPTION_MAX)) + if ((option_name < IP_TOS) || (option_name > IP_OPTION_MAX)) { /* Error, one or more invalid arguments. */ @@ -6507,9 +6703,70 @@ ULONG physical_addr_lsw; switch (option_name) { + case IP_TOS: + + if (option_length != (INT)sizeof(INT)) + { + + /* Set the socket error if extended socket options enabled. */ + nx_bsd_set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + else + { + INT tos_in = *((const INT *)option_value); + + if ((tos_in < 0) || (tos_in > 0xFF)) + { + + /* Set the socket error if extended socket options enabled. */ + nx_bsd_set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + else + { + ULONG type_of_service = (ULONG)tos_in << 16; + + if (bsd_socket_ptr -> nx_bsd_socket_tcp_socket) + { + bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_type_of_service = type_of_service; + } + else if (bsd_socket_ptr -> nx_bsd_socket_udp_socket) + { + bsd_socket_ptr -> nx_bsd_socket_udp_socket -> nx_udp_socket_type_of_service = type_of_service; + } + else + { + + /* Raw sockets do not support IP_TOS. */ + nx_bsd_set_errno(ENOPROTOOPT); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + } + } + + break; + case SO_BROADCAST: /* This is the default behavior of NetX. All sockets have this capability. */ + if (*((INT *)option_value) == 0) + { + + nx_bsd_set_errno(EINVAL); + + /* Return an error status. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + + return NX_SOC_ERROR; + } + break; case SO_KEEPALIVE: @@ -6563,10 +6820,56 @@ ULONG physical_addr_lsw; break; case SO_LINGER: + { + INT l_linger_val; + + /* Only available to TCP BSD sockets. */ + if (!bsd_socket_ptr -> nx_bsd_socket_tcp_socket) + { + + /* Set the socket error if extended socket options enabled. */ + nx_bsd_set_errno(ENOPROTOOPT); + + /* Return an error status. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + + if (option_length != (INT)sizeof(struct nx_bsd_linger)) + { + + /* Set the socket error if extended socket options enabled. */ + nx_bsd_set_errno(EINVAL); + + /* Return an error status. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } - /* The Linger socket option is not supported in NetX Duo BSD. */ + l_linger_val = (*((const struct nx_bsd_linger *)option_value)).l_linger; + if (l_linger_val < 0) + { - return NX_NOT_ENABLED; + /* Negative linger time is invalid. */ + nx_bsd_set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + + if ((*((const struct nx_bsd_linger *)option_value)).l_onoff) + { + bsd_socket_ptr -> nx_bsd_socket_option_flags |= NX_BSD_SOCKET_ENABLE_OPTION_LINGER; + } + else + { + bsd_socket_ptr -> nx_bsd_socket_option_flags &= (ULONG)(~NX_BSD_SOCKET_ENABLE_OPTION_LINGER); + } + bsd_socket_ptr -> nx_bsd_option_linger.l_onoff = (*((const struct nx_bsd_linger *)option_value)).l_onoff; + bsd_socket_ptr -> nx_bsd_option_linger.l_linger = l_linger_val; + + break; + } case SO_SNDTIMEO: @@ -6640,13 +6943,24 @@ ULONG physical_addr_lsw; case TCP_NODELAY: /* This is the default behavior of NetX. All sockets have this attribute. */ + if (*((INT *)option_value) == 0) + { + + nx_bsd_set_errno(EINVAL); + + /* Return an error status. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + + return NX_SOC_ERROR; + } break; + case IP_TTL: case IP_MULTICAST_TTL: /* Validate the option length. */ - if(option_length != sizeof(UCHAR) && option_length != sizeof(INT)) + if ((option_length != (INT)sizeof(UCHAR)) && (option_length != (INT)sizeof(INT))) { /* Set the socket error if extended socket options enabled. */ @@ -6667,24 +6981,68 @@ ULONG physical_addr_lsw; return NX_SOC_ERROR; } - /* Make sure socket is UDP type. */ - if(bsd_socket_ptr -> nx_bsd_socket_udp_socket == NX_NULL) + /* When option_length == sizeof(INT), validate range 0..255. */ + if (option_length == (INT)sizeof(INT)) { - /* Set the socket error if extended socket options enabled. */ - nx_bsd_set_errno(ENOPROTOOPT); + INT ttl_in = *(const INT *)option_value; - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return NX_SOC_ERROR; + if ((ttl_in < 0) || (ttl_in > 0xFF)) + { + + /* Set the socket error if extended socket options enabled. */ + nx_bsd_set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } } - /* Set the TTL value. */ - if (option_length == sizeof(UCHAR)) + /* Socket is UDP type. */ + if (bsd_socket_ptr -> nx_bsd_socket_udp_socket != NX_NULL) { - bsd_socket_ptr -> nx_bsd_socket_udp_socket -> nx_udp_socket_time_to_live = *(UCHAR*)option_value; + + /* Set the TTL value. */ + if (option_length == (INT)sizeof(UCHAR)) + { + bsd_socket_ptr -> nx_bsd_socket_udp_socket -> nx_udp_socket_time_to_live = *(const UCHAR *)option_value; + } + else + { + bsd_socket_ptr -> nx_bsd_socket_udp_socket -> nx_udp_socket_time_to_live = (UCHAR)(*(const INT *)option_value); + } + } + /* Socket is TCP type. */ + else if (bsd_socket_ptr -> nx_bsd_socket_tcp_socket != NX_NULL) + { + + if (option_name == IP_MULTICAST_TTL) + { + + /* Set the socket error if extended socket options enabled. */ + nx_bsd_set_errno(ENOPROTOOPT); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + + /* Set the TTL value. */ + if (option_length == (INT)sizeof(UCHAR)) + { + bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_time_to_live = *(const UCHAR *)option_value; + } + else + { + bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_time_to_live = (UCHAR)(*(const INT *)option_value); + } } else { - bsd_socket_ptr -> nx_bsd_socket_udp_socket -> nx_udp_socket_time_to_live = (UCHAR)(*(INT*)option_value); + + /* Raw sockets do not support IP_TTL/IP_MULTICAST_TTL. */ + nx_bsd_set_errno(ENOPROTOOPT); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; } break; @@ -6698,6 +7056,13 @@ ULONG physical_addr_lsw; /* This is not supported yet. */ + /* Set the socket error if extended socket options enabled. */ + nx_bsd_set_errno(ENOPROTOOPT); + + /* Return an error status. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + break; #if defined(NX_BSD_RAW_SUPPORT) && defined(NX_ENABLE_VLAN) diff --git a/addons/BSD/nxd_bsd.h b/addons/BSD/nxd_bsd.h index a35fee4d..15d1c1ac 100644 --- a/addons/BSD/nxd_bsd.h +++ b/addons/BSD/nxd_bsd.h @@ -300,6 +300,7 @@ extern "C" { #define AF_INET 2 /* IPv4 socket (UDP, TCP, etc) */ #define AF_INET6 3 /* IPv6 socket (UDP, TCP, etc) */ #define AF_PACKET 4 /* Raw Packet type (Link Layer packets) */ +#define AF_MAX AF_PACKET /* Protocol families, same as address families. */ #define PF_INET AF_INET @@ -570,6 +571,8 @@ extern "C" { /* This second set of socket options take the socket level (category) IPPROTO_IP. */ +#define IP_TOS 25 /* Type Of Service */ +#define IP_TTL 26 /* Specify the TTL value. */ #define IP_MULTICAST_IF 27 /* Specify outgoing multicast interface */ #define IP_MULTICAST_TTL 28 /* Specify the TTL value to use for outgoing multicast packet. */ #define IP_MULTICAST_LOOP 29 /* Whether or not receive the outgoing multicast packet, loopbacloopbackk mode. */ @@ -960,6 +963,8 @@ typedef struct NX_BSD_SOCKET_STRUCT INT nx_bsd_option_linger_time; UINT nx_bsd_option_linger_time_closed; UINT nx_bsd_option_linger_start_close; + struct nx_bsd_linger + nx_bsd_option_linger; UINT nx_bsd_socket_time_wait_remaining; ULONG nx_bsd_option_receive_timeout; ULONG nx_bsd_option_send_timeout; diff --git a/test/cmake/netxduo/regression/CMakeLists.txt b/test/cmake/netxduo/regression/CMakeLists.txt index 23f626d2..7acc2783 100644 --- a/test/cmake/netxduo/regression/CMakeLists.txt +++ b/test/cmake/netxduo/regression/CMakeLists.txt @@ -53,7 +53,8 @@ if("-DNX_BSD_ENABLE" IN_LIST ${CMAKE_BUILD_TYPE}) ${SOURCE_DIR}/bsd_test/netx_bsd_tcp_getsockname_without_bind_test.c ${SOURCE_DIR}/bsd_test/netx_bsd_tcp_rcvbuf_test.c ${SOURCE_DIR}/bsd_test/netx_bsd_tcp_fionread_test.c - ${SOURCE_DIR}/bsd_test/netx_bsd_select_spurious_event_test.c) + ${SOURCE_DIR}/bsd_test/netx_bsd_select_spurious_event_test.c + ${SOURCE_DIR}/bsd_test/netx_bsd_socket_options_test.c) if("-DNX_BSD_RAW_SUPPORT" IN_LIST ${CMAKE_BUILD_TYPE}) list( APPEND diff --git a/test/regression/bsd_test/netx_bsd_socket_options_test.c b/test/regression/bsd_test/netx_bsd_socket_options_test.c new file mode 100644 index 00000000..bdc8f177 --- /dev/null +++ b/test/regression/bsd_test/netx_bsd_socket_options_test.c @@ -0,0 +1,335 @@ +/*************************************************************************** + * Copyright (C) 2026 Eclipse ThreadX contributors + * + * This program and the accompanying materials are made available under the + * terms of the MIT License which is available at + * https://opensource.org/licenses/MIT. + * + * AI Disclosure: This file was largely AI-generated by Copilot (Sonnet 4.6). + * The AI-generated portions may be considered public domain (CC0-1.0) + * and not subject to the project's licence. The human contributor has + * reviewed and verified that the code is correct. + * + * SPDX-License-Identifier: MIT and CC0-1.0 + **************************************************************************/ + +/* This test exercises setsockopt/getsockopt for SO_LINGER, IP_TOS, IP_TTL, + SO_BROADCAST and TCP_NODELAY, including error-path coverage introduced + by the PR #374 bug-fixes. */ + +#include "tx_api.h" +#include "nx_api.h" +#if defined(NX_BSD_ENABLE) && !defined(NX_DISABLE_IPV4) && defined(__PRODUCT_NETXDUO__) +#include "nxd_bsd.h" + +#define DEMO_STACK_SIZE 4096 +#define BSD_THREAD_PRIORITY 2 + +static TX_THREAD ntest_0; +static NX_PACKET_POOL pool_0; +static NX_IP ip_0; +static ULONG bsd_thread_area[DEMO_STACK_SIZE / sizeof(ULONG)]; +static ULONG error_counter; + +static ULONG packet_pool_area[(256 + sizeof(NX_PACKET)) * 16 / 4]; + +static void ntest_0_entry(ULONG thread_input); +extern void test_control_return(UINT status); +extern void _nx_ram_network_driver_256(struct NX_IP_DRIVER_STRUCT *driver_req); + +#ifdef CTEST +VOID test_application_define(void *first_unused_memory) +#else +void netx_bsd_socket_options_test_application_define(void *first_unused_memory) +#endif +{ +CHAR *pointer = (CHAR *)first_unused_memory; +UINT status; + + error_counter = 0; + + tx_thread_create(&ntest_0, "thread 0", ntest_0_entry, 0, + pointer, DEMO_STACK_SIZE, 3, 3, + TX_NO_TIME_SLICE, TX_AUTO_START); + pointer += DEMO_STACK_SIZE; + + nx_system_initialize(); + + status = nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", 256, + packet_pool_area, sizeof(packet_pool_area)); + if (status) + error_counter++; + + status = nx_ip_create(&ip_0, "NetX IP Instance 0", + IP_ADDRESS(1, 2, 3, 4), 0xFFFFFF00UL, + &pool_0, _nx_ram_network_driver_256, + pointer, 2048, 1); + pointer += 2048; + if (status) + error_counter++; + + status = nx_arp_enable(&ip_0, (void *)pointer, 1024); + pointer += 1024; + if (status) + error_counter++; + + status = nx_tcp_enable(&ip_0); + if (status) + error_counter++; + + status = nx_udp_enable(&ip_0); + if (status) + error_counter++; + + status = bsd_initialize(&ip_0, &pool_0, (CHAR *)&bsd_thread_area[0], + sizeof(bsd_thread_area), BSD_THREAD_PRIORITY); + if (status) + error_counter++; +} + +static void ntest_0_entry(ULONG thread_input) +{ +int tcp_sock; +int udp_sock; +struct nx_bsd_linger ling_set; +struct nx_bsd_linger ling_get; +INT opt_val; +INT opt_len; +INT ret; + + NX_PARAMETER_NOT_USED(thread_input); + + /* Create sockets. */ + tcp_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (tcp_sock < 0) + error_counter++; + + udp_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (udp_sock < 0) + error_counter++; + + /* ================================================================ + * SO_LINGER: round-trip on TCP socket + * ================================================================ */ + ling_set.l_onoff = 1; + ling_set.l_linger = 5; + ret = setsockopt(tcp_sock, SOL_SOCKET, SO_LINGER, + &ling_set, (INT)sizeof(ling_set)); + if (ret != 0) + error_counter++; + + opt_len = (INT)sizeof(ling_get); + ret = getsockopt(tcp_sock, SOL_SOCKET, SO_LINGER, + &ling_get, &opt_len); + if (ret != 0) + error_counter++; + if (ling_get.l_onoff != 1) + error_counter++; + if (ling_get.l_linger != 5) + error_counter++; + if (opt_len != (INT)sizeof(struct nx_bsd_linger)) + error_counter++; + + /* Disable linger and verify l_onoff is cleared. */ + ling_set.l_onoff = 0; + ling_set.l_linger = 0; + ret = setsockopt(tcp_sock, SOL_SOCKET, SO_LINGER, + &ling_set, (INT)sizeof(ling_set)); + if (ret != 0) + error_counter++; + + opt_len = (INT)sizeof(ling_get); + ret = getsockopt(tcp_sock, SOL_SOCKET, SO_LINGER, + &ling_get, &opt_len); + if (ret != 0) + error_counter++; + if (ling_get.l_onoff != 0) + error_counter++; + + /* Negative l_linger must be rejected with EINVAL. */ + ling_set.l_onoff = 1; + ling_set.l_linger = -1; + ret = setsockopt(tcp_sock, SOL_SOCKET, SO_LINGER, + &ling_set, (INT)sizeof(ling_set)); + if (ret == 0) + error_counter++; + + /* Short output buffer must be rejected with EINVAL. */ + opt_len = 1; + ret = getsockopt(tcp_sock, SOL_SOCKET, SO_LINGER, + &ling_get, &opt_len); + if (ret == 0) + error_counter++; + + /* SO_LINGER on a UDP socket must fail with ENOPROTOOPT. */ + ling_set.l_onoff = 1; + ling_set.l_linger = 1; + ret = setsockopt(udp_sock, SOL_SOCKET, SO_LINGER, + &ling_set, (INT)sizeof(ling_set)); + if (ret == 0) + error_counter++; + + /* ================================================================ + * IP_TOS: round-trip on TCP socket + * ================================================================ */ + opt_val = 0x10; + opt_len = (INT)sizeof(INT); + ret = setsockopt(tcp_sock, IPPROTO_IP, IP_TOS, &opt_val, opt_len); + if (ret != 0) + error_counter++; + + opt_val = 0; + opt_len = (INT)sizeof(INT); + ret = getsockopt(tcp_sock, IPPROTO_IP, IP_TOS, &opt_val, &opt_len); + if (ret != 0) + error_counter++; + if (opt_val != 0x10) + error_counter++; + if (opt_len != (INT)sizeof(INT)) + error_counter++; + + /* IP_TOS round-trip on UDP socket. */ + opt_val = 0x28; + opt_len = (INT)sizeof(INT); + ret = setsockopt(udp_sock, IPPROTO_IP, IP_TOS, &opt_val, opt_len); + if (ret != 0) + error_counter++; + + opt_val = 0; + opt_len = (INT)sizeof(INT); + ret = getsockopt(udp_sock, IPPROTO_IP, IP_TOS, &opt_val, &opt_len); + if (ret != 0) + error_counter++; + if (opt_val != 0x28) + error_counter++; + + /* IP_TOS: out-of-range values must be rejected. */ + opt_val = 256; + opt_len = (INT)sizeof(INT); + ret = setsockopt(tcp_sock, IPPROTO_IP, IP_TOS, &opt_val, opt_len); + if (ret == 0) + error_counter++; + + opt_val = -1; + opt_len = (INT)sizeof(INT); + ret = setsockopt(tcp_sock, IPPROTO_IP, IP_TOS, &opt_val, opt_len); + if (ret == 0) + error_counter++; + + /* A SO_* option number passed to IPPROTO_IP level must be rejected. */ + opt_val = 1; + opt_len = (INT)sizeof(INT); + ret = setsockopt(tcp_sock, IPPROTO_IP, SO_BROADCAST, &opt_val, opt_len); + if (ret == 0) + error_counter++; + + /* ================================================================ + * IP_TTL: round-trip on TCP socket with INT-sized input + * ================================================================ */ + opt_val = 64; + opt_len = (INT)sizeof(INT); + ret = setsockopt(tcp_sock, IPPROTO_IP, IP_TTL, &opt_val, opt_len); + if (ret != 0) + error_counter++; + + { + UCHAR ttl_get = 0; + INT ttl_len = (INT)sizeof(UCHAR); + + ret = getsockopt(tcp_sock, IPPROTO_IP, IP_TTL, &ttl_get, &ttl_len); + if (ret != 0) + error_counter++; + if (ttl_get != 64) + error_counter++; + } + + /* IP_TTL: round-trip on UDP socket. */ + opt_val = 128; + opt_len = (INT)sizeof(INT); + ret = setsockopt(udp_sock, IPPROTO_IP, IP_TTL, &opt_val, opt_len); + if (ret != 0) + error_counter++; + + { + UCHAR ttl_get = 0; + INT ttl_len = (INT)sizeof(UCHAR); + + ret = getsockopt(udp_sock, IPPROTO_IP, IP_TTL, &ttl_get, &ttl_len); + if (ret != 0) + error_counter++; + if (ttl_get != 128) + error_counter++; + } + + /* IP_TTL: out-of-range INT values must be rejected. */ + opt_val = 300; + opt_len = (INT)sizeof(INT); + ret = setsockopt(tcp_sock, IPPROTO_IP, IP_TTL, &opt_val, opt_len); + if (ret == 0) + error_counter++; + + opt_val = -1; + opt_len = (INT)sizeof(INT); + ret = setsockopt(tcp_sock, IPPROTO_IP, IP_TTL, &opt_val, opt_len); + if (ret == 0) + error_counter++; + + /* ================================================================ + * SO_BROADCAST: getsockopt validates option_length + * ================================================================ */ + opt_val = 0; + opt_len = (INT)sizeof(INT); + ret = getsockopt(tcp_sock, SOL_SOCKET, SO_BROADCAST, &opt_val, &opt_len); + if (ret != 0) + error_counter++; + if (opt_val != 1) + error_counter++; + if (opt_len != (INT)sizeof(INT)) + error_counter++; + + opt_val = 0; + opt_len = 1; + ret = getsockopt(tcp_sock, SOL_SOCKET, SO_BROADCAST, &opt_val, &opt_len); + if (ret == 0) + error_counter++; + + /* ================================================================ + * TCP_NODELAY: getsockopt validates option_length + * ================================================================ */ + opt_val = 0; + opt_len = (INT)sizeof(INT); + ret = getsockopt(tcp_sock, IPPROTO_TCP, TCP_NODELAY, &opt_val, &opt_len); + if (ret != 0) + error_counter++; + if (opt_val != 1) + error_counter++; + if (opt_len != (INT)sizeof(INT)) + error_counter++; + + opt_val = 0; + opt_len = 1; + ret = getsockopt(tcp_sock, IPPROTO_TCP, TCP_NODELAY, &opt_val, &opt_len); + if (ret == 0) + error_counter++; + + /* Clean up. */ + soc_close(tcp_sock); + soc_close(udp_sock); + + if (error_counter) + test_control_return(1); + else + test_control_return(0); +} + +#else +#ifdef CTEST +VOID test_application_define(void *first_unused_memory) +#else +void netx_bsd_socket_options_test_application_define(void *first_unused_memory) +#endif +{ + NX_PARAMETER_NOT_USED(first_unused_memory); + test_control_return(3); +} +#endif /* NX_BSD_ENABLE && !NX_DISABLE_IPV4 && __PRODUCT_NETXDUO__ */ |
