2025-01-26 05:04 AM
In AZRTOS - NetXDuo ver 6.4, netx-duo-dhcpv6-client library,
if NX_DISABLE_ERROR_CHECKING is not defined (i.e. calling first _nxe_dhcpv6_client_create()),
function nx_dhcpv6_client_create() should check for valid input parameters and return errors according to error type.
From manual:
"
Create a DHCPv6 client instance
UINT nx_dhcpv6_client_create( NX_DHCPV6 *dhcpv6_ptr, NX_IP *ip_ptr, CHAR *name_ptr, NX_PACKET_POOL *packet_pool_ptr, VOID *stack_ptr, ULONG stack_size, VOID (*dhcpv6_state_change_notify)( struct NX_DHCPV6_STRUCT *dhcpv6_ptr, UINT old_state, UINT new_state), VOID (*dhcpv6_server_error_handler)( struct NX_DHCPV6_STRUCT *dhcpv6_ptr, UINT op_code, UINT status_code, UINT message_type));
This service creates a DHCPv6 client instance including callback functions.
dhcpv6_ptr: Pointer to DHCPv6 control block
ip_ptr: Pointer to Client IP instance
name_ptr: Pointer to name for DHCPv6 instance
packet_pool_ptr: Pointer to Client packet pool
stack_ptr: Pointer to Client stack memory
stack_size: Size of Client stack memory
dhcpv6_state_change_notify: Pointer to callback function invoked when the Client initiates a new DHCPv6 request to the server
dhcpv6_server_error_handler: Pointer to callback function invoked when the Client receives an error status from the server
NX_SUCCESS (0x00) Successful Client create
NX_PTR_ERROR (0x16) Invalid pointer input
NX_DHCPV6_PARAM_ERROR (0xE93) Invalid non pointer input
"
Actually if parameter
packet_pool_ptr: Pointer to Client packet pool
does not point to a packet pool ( as when the variable has been defined but not initialized ), the functions does not returns NX_DHCPV6_PARAM_ERROR (0xE93) Invalid non pointer input but NX_SUCCESS (0x00) Successful Client create.
As for every discrepancy between reference manual and actual code, could be that manual is inaccurate, but in this case it is mandatory to edit ASAP with correct wording.
2025-01-27 01:46 AM - edited 2025-01-27 01:50 AM
Hello @mbarg.1 ,
Just wanted to point out that as per the NetX documentation in GitHub implies:
"In the "Return Values" section in the following API descriptions, values in BOLD are not affected by the NX_DISABLE_ERROR_CHECKING define that is used to disable API error checking, while non-bold values are completely disabled."
and since only NX_SUCCESS is in bold and other return values are not those two are completely disabled.
just wanted to know how you are passing the uninitialized pointer to this function and are you sure NX_DISABLE_ERROR_CHECKING is not activated?
also, I want to point to you that issues related to Nextduo documentation should be input in Issues · eclipse-threadx/netxduo
Regards
2025-01-27 04:15 AM
I can confirm - because I did this very same mistake of forgetting to initialize packet pool - that IF packet_pool_ptr is not NULL, but data inside are all zero (non initialized pool) you get NX_SUCCESS (0x00) - NX_DISABLE_ERROR_CHECKING not activated.
Have a look at code below:
packet_pool_ptr is tested only for NULL ptr value in _nxe_dhcpv6_client_create()
and assigned to dhcpv6_ptr -> nx_dhcpv6_pool_ptr in _nx_dhcpv6_client_create().
Source code 1:
UINT _nxe_dhcpv6_client_create(NX_DHCPV6 *dhcpv6_ptr, NX_IP *ip_ptr, CHAR *name_ptr,
NX_PACKET_POOL *packet_pool_ptr, VOID *stack_ptr, ULONG stack_size,
VOID (*dhcpv6_state_change_notify)(struct NX_DHCPV6_STRUCT *dhcpv6_ptr, UINT old_state, UINT new_state),
VOID (*dhcpv6_server_error_handler)(struct NX_DHCPV6_STRUCT *dhcpv6_ptr, UINT op_code, UINT status_code, UINT message_type))
{
UINT status;
/* Check for invalid pointer input. */
if (!dhcpv6_ptr ||!ip_ptr || !packet_pool_ptr || !stack_ptr)
{
return NX_PTR_ERROR;
}
/* Check for invalid non pointer input. */
if ((ip_ptr -> nx_ip_id != NX_IP_ID) || (stack_size < TX_MINIMUM_STACK))
{
return NX_DHCPV6_PARAM_ERROR;
}
/* Call actual DHCPV6 create service. */
status = _nx_dhcpv6_client_create(dhcpv6_ptr, ip_ptr, name_ptr, packet_pool_ptr, stack_ptr, stack_size,
dhcpv6_state_change_notify, dhcpv6_server_error_handler);
/* Return status. */
return(status);
}
source code 2:
UINT _nx_dhcpv6_client_create(NX_DHCPV6 *dhcpv6_ptr, NX_IP *ip_ptr, CHAR *name_ptr,
NX_PACKET_POOL *packet_pool_ptr, VOID *stack_ptr, ULONG stack_size,
VOID (*dhcpv6_state_change_notify)(struct NX_DHCPV6_STRUCT *dhcpv6_ptr, UINT old_state, UINT new_state),
VOID (*dhcpv6_server_error_handler)(struct NX_DHCPV6_STRUCT *dhcpv6_ptr, UINT op_code, UINT status_code, UINT message_type))
{
UINT status;
/* Initialize the DHCPV6 control block to zero. */
memset((void *) dhcpv6_ptr, 0, sizeof(NX_DHCPV6));
/* Initialize the DHCPV6 Server and Relay multicast address. */
memset(&All_DHCPv6_Relay_Servers_Address, 0, sizeof(NXD_ADDRESS));
All_DHCPv6_Relay_Servers_Address.nxd_ip_version = NX_IP_VERSION_V6;
All_DHCPv6_Relay_Servers_Address.nxd_ip_address.v6[0] = 0xff020000;
All_DHCPv6_Relay_Servers_Address.nxd_ip_address.v6[1] = 0x00000000;
All_DHCPv6_Relay_Servers_Address.nxd_ip_address.v6[2] = 0x00000000;
All_DHCPv6_Relay_Servers_Address.nxd_ip_address.v6[3] = 0x00010002;
/* Set the destination address. */
COPY_NXD_ADDRESS(&All_DHCPv6_Relay_Servers_Address, &(dhcpv6_ptr -> nx_dhcpv6_client_destination_address));
/* Set the DHCPv6 IP pointer. */
dhcpv6_ptr -> nx_dhcpv6_ip_ptr = ip_ptr;
/* Set the DHCPV6 name. */
dhcpv6_ptr -> nx_dhcpv6_name = name_ptr;
/* If multihome support is available, default the client DHCP network to the primary interface. */
dhcpv6_ptr -> nx_dhcpv6_client_interface_index = 0;
/* Set the Client packet pool for sending messages to the Server. */
dhcpv6_ptr -> nx_dhcpv6_pool_ptr = packet_pool_ptr;
/* Create the IP timer event flag instance. */
status = tx_event_flags_create(&(dhcpv6_ptr -> nx_dhcpv6_events), "DHCPv6 Client Timer Events Queue");
/* Check for error. */
if (status != TX_SUCCESS)
{
return status;
}
/* Create the DHCPV6 client mutex. */
status = tx_mutex_create(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex), "DHCPV6 Client Process State", TX_NO_INHERIT);
/* Determine if the mutexes creation was successful. */
if (status)
{
/* Delete the flag queue. */
tx_event_flags_delete(&dhcpv6_ptr -> nx_dhcpv6_events);
/* No, return error status. */
return status;
}
/* Create the DHCPV6 timer for keeping track of the IP lease's time remaining before expiration. */
status = tx_timer_create(&(dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_timer), "NetX DHCPV6 Client IP Lease timer",
_nx_dhcpv6_IP_lifetime_timeout_entry, (ULONG)(ALIGN_TYPE)dhcpv6_ptr,
(NX_DHCPV6_IP_LIFETIME_TIMER_INTERVAL * NX_DHCPV6_TICKS_PER_SECOND),
(NX_DHCPV6_IP_LIFETIME_TIMER_INTERVAL * NX_DHCPV6_TICKS_PER_SECOND),
TX_NO_ACTIVATE);
NX_TIMER_EXTENSION_PTR_SET(&(dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_timer), dhcpv6_ptr)
/* Determine if the timer creation was successful. */
if (status)
{
/* Delete the mutex. */
tx_mutex_delete(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex));
/* Delete all the timers, since we don't know which create call fails. */
tx_timer_delete(&(dhcpv6_ptr -> nx_dhcpv6_session_timer));
/* Delete the UDP socket. */
nx_udp_socket_delete(&(dhcpv6_ptr -> nx_dhcpv6_socket));
/* Delete the packet pool. */
/* Delete the flag queue. */
tx_event_flags_delete(&dhcpv6_ptr -> nx_dhcpv6_events);
/* No, return error status. */
return status;
}
/* Create the DHCPV6 timer for keeping track of the DHCPv6 Client session time. */
status = tx_timer_create(&(dhcpv6_ptr -> nx_dhcpv6_session_timer), "NetX DHCPV6 Client Session Duration timer",
_nx_dhcpv6_session_timeout_entry, (ULONG)(ALIGN_TYPE)dhcpv6_ptr,
(NX_DHCPV6_SESSION_TIMER_INTERVAL * NX_DHCPV6_TICKS_PER_SECOND),
(NX_DHCPV6_SESSION_TIMER_INTERVAL * NX_DHCPV6_TICKS_PER_SECOND),
TX_NO_ACTIVATE);
NX_TIMER_EXTENSION_PTR_SET(&(dhcpv6_ptr -> nx_dhcpv6_session_timer), dhcpv6_ptr)
/* Determine if the timers creation was successful. */
if (status)
{
/* Delete the mutex. */
tx_mutex_delete(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex));
/* Delete all the timers, since we don't know which create call fails. */
tx_timer_delete(&(dhcpv6_ptr -> nx_dhcpv6_session_timer));
tx_timer_delete(&(dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_timer));
/* Delete the UDP socket. */
nx_udp_socket_delete(&(dhcpv6_ptr -> nx_dhcpv6_socket));
/* Delete the packet pool. */
/* Delete the flag queue. */
tx_event_flags_delete(&dhcpv6_ptr -> nx_dhcpv6_events);
/* No, return error status. */
return status;
}
/* Create the DHCPV6 processing thread. */
status = tx_thread_create(&(dhcpv6_ptr -> nx_dhcpv6_thread), "NetX DHCPV6 Client", _nx_dhcpv6_thread_entry,
(ULONG)(ALIGN_TYPE)dhcpv6_ptr, stack_ptr, stack_size,
NX_DHCPV6_THREAD_PRIORITY, NX_DHCPV6_THREAD_PRIORITY, 1, TX_DONT_START);
NX_THREAD_EXTENSION_PTR_SET(&(dhcpv6_ptr -> nx_dhcpv6_thread), dhcpv6_ptr)
/* Determine if the thread creation was successful. */
if (status)
{
/* Delete the timers. */
tx_timer_delete(&(dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_timer));
tx_timer_delete(&(dhcpv6_ptr -> nx_dhcpv6_session_timer));
/* Delete the mutex. */
tx_mutex_delete(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex));
/* Delete the flag queue. */
tx_event_flags_delete(&dhcpv6_ptr -> nx_dhcpv6_events);
/* No, return error status. */
return status;
}
/* Create the DHCP socket. */
status = nx_udp_socket_create(dhcpv6_ptr -> nx_dhcpv6_ip_ptr, &(dhcpv6_ptr -> nx_dhcpv6_socket), "NetX DHCPV6 Client",
NX_DHCPV6_TYPE_OF_SERVICE, NX_DONT_FRAGMENT,
NX_DHCPV6_TIME_TO_LIVE, NX_DHCPV6_QUEUE_DEPTH);
/* Was the socket creation successful? */
if (status != NX_SUCCESS)
{
/* Delete the timers. */
tx_timer_delete(&(dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_timer));
tx_timer_delete(&(dhcpv6_ptr -> nx_dhcpv6_session_timer));
/* Delete the mutex. */
tx_mutex_delete(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex));
/* Delete the flag queue. */
tx_event_flags_delete(&dhcpv6_ptr -> nx_dhcpv6_events);
tx_thread_delete(&dhcpv6_ptr -> nx_dhcpv6_thread);
/* No, return error status. */
return status;
}
/* Set the Client in the initial state. */
dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_INIT;
/* Set the 'time accrued' on the Client global IP address at zero seconds. */
dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued = 0;
/* Update the DHCPv6 Client ID. */
dhcpv6_ptr -> nx_dhcpv6_id = NX_DHCPV6_ID;
/* Save the DHCPV6 instance pointer in the socket. */
dhcpv6_ptr -> nx_dhcpv6_socket.nx_udp_socket_reserved_ptr = (void *) dhcpv6_ptr;
/* Set up the elapsed time for the anticipated message exchange with the DHCPv6 Server. */
dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_op_code = NX_DHCPV6_OP_ELAPSED_TIME;
dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0;
/* Set the elapsed time option data length, minus the option header. */
dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_op_length = sizeof(NX_DHCPV6_ELAPSED_TIME) - 4;
/* Set the option request option code. Cannot set the data length as yet. */
dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_code = NX_DHCPV6_OP_OPTION_REQUEST;
/* Assign the various handlers (server error messages and state change). */
dhcpv6_ptr -> nx_dhcpv6_state_change_callback = dhcpv6_state_change_notify;
dhcpv6_ptr -> nx_dhcpv6_server_error_handler = dhcpv6_server_error_handler;
#if !defined (NX_DISABLE_IPV6_DAD) && defined (NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY)
/* Set the callback function to detect DAD process.
If DAD failure, automatically set event to send DHCP decline meessage.
Notice: other modules should not set the address change notify function again. */
status = nxd_ipv6_address_change_notify(dhcpv6_ptr -> nx_dhcpv6_ip_ptr, _nx_dhcpv6_ipv6_address_DAD_notify);
/* Was the callback notify fucntion creation successful? */
if (status != NX_SUCCESS)
{
/* Delete the timers. */
tx_timer_delete(&(dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_timer));
tx_timer_delete(&(dhcpv6_ptr -> nx_dhcpv6_session_timer));
/* Delete the mutex. */
tx_mutex_delete(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex));
/* Delete the flag queue. */
tx_event_flags_delete(&dhcpv6_ptr -> nx_dhcpv6_events);
/* Delete the thread. */
tx_thread_delete(&dhcpv6_ptr -> nx_dhcpv6_thread);
/* Delete the thread. */
nx_udp_socket_delete(&(dhcpv6_ptr -> nx_dhcpv6_socket));
/* No, return error status. */
return status;
}
#endif
/* Keep the DHCPv6 instance for DAD callback notify. */
_nx_dhcpv6_DAD_ptr = dhcpv6_ptr;
/* Return a successful status. */
return(NX_SUCCESS);
}